Compare commits

..

45 Commits

Author SHA1 Message Date
standardci 7f9e6e2f44 chore(release): publish new version
- @standardnotes/analytics@2.17.8
 - @standardnotes/api-gateway@1.41.3
 - @standardnotes/auth-server@1.70.9
 - @standardnotes/files-server@1.9.3
 - @standardnotes/revisions-server@1.10.3
 - @standardnotes/scheduler-server@1.16.4
 - @standardnotes/syncing-server@1.28.3
 - @standardnotes/websockets-server@1.5.3
 - @standardnotes/workspace-server@1.19.4
2022-12-28 07:07:42 +00:00
Karol Sójko d3c6c0d48e chore(upgrade): sentry deps 2022-12-28 08:05:42 +01:00
Karol Sójko 6c83476fd2 chore: workflow disptach name 2022-12-27 15:50:40 +01:00
Karol Sójko 9cdf7e2c51 Revert "feat: add workflow for tagging latest versions as stable"
This reverts commit a2c484e0f3.
2022-12-27 15:37:32 +01:00
Karol Sójko 599119e14e chore: move e2e test suite to self-hosted repo 2022-12-27 15:00:11 +01:00
Karol Sójko a2c484e0f3 feat: add workflow for tagging latest versions as stable 2022-12-27 14:43:36 +01:00
standardci 97ff4d5ac2 chore(release): publish new version
- @standardnotes/auth-server@1.70.8
2022-12-20 20:24:56 +00:00
Karol Sójko 5255cfbb25 fix(auth): move tracing sessions to session creation instead of cross service token creation 2022-12-20 21:22:24 +01:00
standardci 780358368b chore(release): publish new version
- @standardnotes/auth-server@1.70.7
2022-12-20 19:55:43 +00:00
Karol Sójko cf0b918913 fix(auth): change severity on tracing session errors - most probably hazardous reads 2022-12-20 20:53:26 +01:00
standardci 4ea690204e chore(release): publish new version
- @standardnotes/auth-server@1.70.6
2022-12-20 18:54:47 +00:00
Karol Sójko 14eb775749 fix(auth): query for session traces 2022-12-20 19:52:32 +01:00
standardci bf4a3be6d9 chore(release): publish new version
- @standardnotes/auth-server@1.70.5
2022-12-20 18:48:19 +00:00
Karol Sójko b9e1e47871 fix(auth): add session traces index 2022-12-20 19:46:05 +01:00
standardci ff532ecb22 chore(release): publish new version
- @standardnotes/scheduler-server@1.16.3
2022-12-20 18:21:59 +00:00
Karol Sójko eb21872db1 fix(scheduler): new pricing for subscription encouragement email 2022-12-20 19:19:59 +01:00
standardci 8e3df184dc chore(release): publish new version
- @standardnotes/analytics@2.17.7
2022-12-20 14:43:24 +00:00
Karol Sójko b34bbcac8b fix(analytics): monthly numbers of active users 2022-12-20 15:41:03 +01:00
standardci 226965a1d7 chore(release): publish new version
- @standardnotes/analytics@2.17.6
2022-12-20 14:04:05 +00:00
Karol Sójko 17b2ea126c fix(analytics): filtered counts for user activity check 2022-12-20 15:02:09 +01:00
standardci 59fc4a089c chore(release): publish new version
- @standardnotes/analytics@2.17.5
2022-12-20 13:16:57 +00:00
Karol Sójko ef26dc8cbb fix(analytics): accessing analytics in report 2022-12-20 14:13:54 +01:00
standardci 8a0fbb28b0 chore(release): publish new version
- @standardnotes/analytics@2.17.4
2022-12-20 12:48:03 +00:00
Karol Sójko 618d8d5b1a tmp(analytics): add console logs for html generation on the report 2022-12-20 13:44:22 +01:00
standardci 3a936dc9c1 chore(release): publish new version
- @standardnotes/analytics@2.17.3
2022-12-20 12:15:31 +00:00
Karol Sójko 031fcd75ee fix(analytics): add debug logs for the report 2022-12-20 13:13:14 +01:00
standardci c8cd23cb32 chore(release): publish new version
- @standardnotes/analytics@2.17.2
2022-12-20 11:27:58 +00:00
Karol Sójko a3049938a3 fix(analytics): calculating active users 2022-12-20 12:26:06 +01:00
standardci b23488e862 chore(release): publish new version
- @standardnotes/workspace-server@1.19.3
2022-12-20 10:32:06 +00:00
Karol Sójko c8203cf04c fix(workspace): specs 2022-12-20 11:30:09 +01:00
standardci 4f2616ef0a chore(release): publish new version
- @standardnotes/analytics@2.17.1
 - @standardnotes/api-gateway@1.41.2
 - @standardnotes/auth-server@1.70.4
 - @standardnotes/domain-events-infra@1.9.59
 - @standardnotes/domain-events@2.105.1
 - @standardnotes/event-store@1.6.56
 - @standardnotes/files-server@1.9.2
 - @standardnotes/revisions-server@1.10.2
 - @standardnotes/scheduler-server@1.16.2
 - @standardnotes/syncing-server@1.28.2
 - @standardnotes/websockets-server@1.5.2
 - @standardnotes/workspace-server@1.19.2
2022-12-20 10:04:02 +00:00
Karol Sójko 04ffc69e00 fix(analytics): container binding 2022-12-20 10:59:26 +01:00
Karol Sójko 5b4bb6e7a7 fix(auth): replace date object with number timestamp 2022-12-20 10:54:31 +01:00
standardci 2e953ba998 chore(release): publish new version
- @standardnotes/analytics@2.17.0
2022-12-20 09:14:37 +00:00
Karol Sójko ed5a4eb960 feat(analytics): add users activit to the report email 2022-12-20 10:12:42 +01:00
standardci 31b2c05084 chore(release): publish new version
- @standardnotes/analytics@2.16.0
2022-12-20 07:54:12 +00:00
Karol Sójko 6e1662038c feat(analytics): add active users stats to report 2022-12-20 08:52:19 +01:00
standardci df78d88f79 chore(release): publish new version
- @standardnotes/analytics@2.15.1
 - @standardnotes/auth-server@1.70.3
2022-12-20 07:47:55 +00:00
Karol Sójko addedb3091 fix(auth): add persisting statistics for all subscription plans 2022-12-20 08:45:43 +01:00
standardci 2ea17b2dea chore(release): publish new version
- @standardnotes/auth-server@1.70.2
2022-12-20 07:21:06 +00:00
Karol Sójko 85d2f42f47 fix(auth): docker command 2022-12-20 08:18:36 +01:00
standardci cdb655c1bd chore(release): publish new version
- @standardnotes/auth-server@1.70.1
2022-12-20 07:06:06 +00:00
Karol Sójko 3064d03aa9 fix(auth): saving subscription plan name in session traces 2022-12-20 08:04:11 +01:00
standardci 6af6417ca2 chore(release): publish new version
- @standardnotes/analytics@2.15.0
 - @standardnotes/auth-server@1.70.0
2022-12-19 14:22:24 +00:00
Karol Sójko a35271fbb3 feat(auth): add requesting persisting statistics 2022-12-19 15:19:49 +01:00
63 changed files with 892 additions and 349 deletions
@@ -190,9 +190,9 @@ jobs:
uses: convictional/trigger-workflow-and-wait@master uses: convictional/trigger-workflow-and-wait@master
with: with:
owner: standardnotes owner: standardnotes
repo: e2e repo: self-hosted
github_token: ${{ secrets.CI_PAT_TOKEN }} github_token: ${{ secrets.CI_PAT_TOKEN }}
workflow_file_name: testing-with-stable-client.yml workflow_file_name: testing-with-updating-client-and-server.yml
wait_interval: 30 wait_interval: 30
client_payload: '{"${{ inputs.e2e_tag_parameter_name }}": "${{ github.sha }}"}' client_payload: '{"${{ inputs.e2e_tag_parameter_name }}": "${{ github.sha }}"}'
propagate_failure: true propagate_failure: true
Generated
+64 -13
View File
@@ -126,7 +126,7 @@ const RAW_RUNTIME_STATE =
["@lerna-lite/cli", "npm:1.6.0"],\ ["@lerna-lite/cli", "npm:1.6.0"],\
["@lerna-lite/list", "npm:1.6.0"],\ ["@lerna-lite/list", "npm:1.6.0"],\
["@lerna-lite/run", "npm:1.6.0"],\ ["@lerna-lite/run", "npm:1.6.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@types/jest", "npm:29.1.1"],\ ["@types/jest", "npm:29.1.1"],\
["@types/newrelic", "npm:7.0.4"],\ ["@types/newrelic", "npm:7.0.4"],\
["@types/node", "npm:18.11.9"],\ ["@types/node", "npm:18.11.9"],\
@@ -2447,6 +2447,16 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:1.14.1"]\ ["tslib", "npm:1.14.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\
["npm:7.28.1", {\
"packageLocation": "./.yarn/cache/@sentry-core-npm-7.28.1-a468033ea8-f29d747d3e.zip/node_modules/@sentry/core/",\
"packageDependencies": [\
["@sentry/core", "npm:7.28.1"],\
["@sentry/types", "npm:7.28.1"],\
["@sentry/utils", "npm:7.28.1"],\
["tslib", "npm:1.14.1"]\
],\
"linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@sentry/hub", [\ ["@sentry/hub", [\
@@ -2476,6 +2486,20 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:1.14.1"]\ ["tslib", "npm:1.14.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\
["npm:7.28.1", {\
"packageLocation": "./.yarn/cache/@sentry-node-npm-7.28.1-b0e124fdfc-b4922d1f0a.zip/node_modules/@sentry/node/",\
"packageDependencies": [\
["@sentry/node", "npm:7.28.1"],\
["@sentry/core", "npm:7.28.1"],\
["@sentry/types", "npm:7.28.1"],\
["@sentry/utils", "npm:7.28.1"],\
["cookie", "npm:0.4.2"],\
["https-proxy-agent", "npm:5.0.1"],\
["lru_map", "npm:0.3.3"],\
["tslib", "npm:1.14.1"]\
],\
"linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@sentry/profiling-node", [\ ["@sentry/profiling-node", [\
@@ -2506,6 +2530,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:1.14.1"]\ ["tslib", "npm:1.14.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\
["npm:7.28.1", {\
"packageLocation": "./.yarn/cache/@sentry-tracing-npm-7.28.1-e15d453d8e-be501ca9d7.zip/node_modules/@sentry/tracing/",\
"packageDependencies": [\
["@sentry/tracing", "npm:7.28.1"],\
["@sentry/core", "npm:7.28.1"],\
["@sentry/types", "npm:7.28.1"],\
["@sentry/utils", "npm:7.28.1"],\
["tslib", "npm:1.14.1"]\
],\
"linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@sentry/types", [\ ["@sentry/types", [\
@@ -2515,6 +2550,13 @@ const RAW_RUNTIME_STATE =
["@sentry/types", "npm:7.27.0"]\ ["@sentry/types", "npm:7.27.0"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\
["npm:7.28.1", {\
"packageLocation": "./.yarn/cache/@sentry-types-npm-7.28.1-42d9a8574c-7dc6639cb7.zip/node_modules/@sentry/types/",\
"packageDependencies": [\
["@sentry/types", "npm:7.28.1"]\
],\
"linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@sentry/utils", [\ ["@sentry/utils", [\
@@ -2526,6 +2568,15 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:1.14.1"]\ ["tslib", "npm:1.14.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\
["npm:7.28.1", {\
"packageLocation": "./.yarn/cache/@sentry-utils-npm-7.28.1-71eaeb767f-a4b5f73db0.zip/node_modules/@sentry/utils/",\
"packageDependencies": [\
["@sentry/utils", "npm:7.28.1"],\
["@sentry/types", "npm:7.28.1"],\
["tslib", "npm:1.14.1"]\
],\
"linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@sinclair/typebox", [\ ["@sinclair/typebox", [\
@@ -2581,7 +2632,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/analytics", "workspace:packages/analytics"],\ ["@standardnotes/analytics", "workspace:packages/analytics"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -2633,7 +2684,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\ ["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\ ["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
@@ -2689,9 +2740,9 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/auth-server", "workspace:packages/auth"],\ ["@standardnotes/auth-server", "workspace:packages/auth"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@sentry/profiling-node", "npm:0.0.12"],\ ["@sentry/profiling-node", "npm:0.0.12"],\
["@sentry/tracing", "npm:7.27.0"],\ ["@sentry/tracing", "npm:7.28.1"],\
["@standardnotes/api", "npm:1.19.0"],\ ["@standardnotes/api", "npm:1.19.0"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
@@ -2915,7 +2966,7 @@ const RAW_RUNTIME_STATE =
"packageLocation": "./packages/files/",\ "packageLocation": "./packages/files/",\
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/files-server", "workspace:packages/files"],\ ["@standardnotes/files-server", "workspace:packages/files"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/config", "npm:2.4.3"],\ ["@standardnotes/config", "npm:2.4.3"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -3050,7 +3101,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/revisions-server", "workspace:packages/revisions"],\ ["@standardnotes/revisions-server", "workspace:packages/revisions"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/api", "npm:1.19.0"],\ ["@standardnotes/api", "npm:1.19.0"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
@@ -3095,7 +3146,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\ ["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -3156,7 +3207,7 @@ const RAW_RUNTIME_STATE =
["@lerna-lite/cli", "npm:1.6.0"],\ ["@lerna-lite/cli", "npm:1.6.0"],\
["@lerna-lite/list", "npm:1.6.0"],\ ["@lerna-lite/list", "npm:1.6.0"],\
["@lerna-lite/run", "npm:1.6.0"],\ ["@lerna-lite/run", "npm:1.6.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@types/jest", "npm:29.1.1"],\ ["@types/jest", "npm:29.1.1"],\
["@types/newrelic", "npm:7.0.4"],\ ["@types/newrelic", "npm:7.0.4"],\
["@types/node", "npm:18.11.9"],\ ["@types/node", "npm:18.11.9"],\
@@ -3222,9 +3273,9 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\ ["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@sentry/profiling-node", "npm:0.0.12"],\ ["@sentry/profiling-node", "npm:0.0.12"],\
["@sentry/tracing", "npm:7.27.0"],\ ["@sentry/tracing", "npm:7.28.1"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -3324,7 +3375,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/websockets-server", "workspace:packages/websockets"],\ ["@standardnotes/websockets-server", "workspace:packages/websockets"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/api", "npm:1.19.0"],\ ["@standardnotes/api", "npm:1.19.0"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\ ["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -3364,7 +3415,7 @@ const RAW_RUNTIME_STATE =
"packageDependencies": [\ "packageDependencies": [\
["@standardnotes/workspace-server", "workspace:packages/workspace"],\ ["@standardnotes/workspace-server", "workspace:packages/workspace"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\ ["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
["@sentry/node", "npm:7.27.0"],\ ["@sentry/node", "npm:7.28.1"],\
["@standardnotes/api", "npm:1.19.0"],\ ["@standardnotes/api", "npm:1.19.0"],\
["@standardnotes/common", "workspace:packages/common"],\ ["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -61,7 +61,7 @@
}, },
"packageManager": "yarn@4.0.0-rc.25", "packageManager": "yarn@4.0.0-rc.25",
"dependencies": { "dependencies": {
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"newrelic": "^9.6.0" "newrelic": "^9.6.0"
} }
} }
+69
View File
@@ -3,6 +3,75 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.17.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.7...@standardnotes/analytics@2.17.8) (2022-12-28)
**Note:** Version bump only for package @standardnotes/analytics
## [2.17.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.6...@standardnotes/analytics@2.17.7) (2022-12-20)
### Bug Fixes
* **analytics:** monthly numbers of active users ([b34bbca](https://github.com/standardnotes/server/commit/b34bbcac8b9604283b3a5959ab3218c468ce8a00))
## [2.17.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.5...@standardnotes/analytics@2.17.6) (2022-12-20)
### Bug Fixes
* **analytics:** filtered counts for user activity check ([17b2ea1](https://github.com/standardnotes/server/commit/17b2ea126c5ad2d7cf07657def63f9977f239a3c))
## [2.17.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.4...@standardnotes/analytics@2.17.5) (2022-12-20)
### Bug Fixes
* **analytics:** accessing analytics in report ([ef26dc8](https://github.com/standardnotes/server/commit/ef26dc8cbb967e088ae7387ff6dbec1e60dc3ee4))
## [2.17.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.3...@standardnotes/analytics@2.17.4) (2022-12-20)
**Note:** Version bump only for package @standardnotes/analytics
## [2.17.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.2...@standardnotes/analytics@2.17.3) (2022-12-20)
### Bug Fixes
* **analytics:** add debug logs for the report ([031fcd7](https://github.com/standardnotes/server/commit/031fcd75eecdcf4c2f17257754a0ba3f24ba6d6e))
## [2.17.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.1...@standardnotes/analytics@2.17.2) (2022-12-20)
### Bug Fixes
* **analytics:** calculating active users ([a304993](https://github.com/standardnotes/server/commit/a3049938a31e21a5867a314ac62bee6aa4990d57))
## [2.17.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.0...@standardnotes/analytics@2.17.1) (2022-12-20)
### Bug Fixes
* **analytics:** container binding ([04ffc69](https://github.com/standardnotes/server/commit/04ffc69e000803107d8834c286de97b3d213a842))
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
# [2.17.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.16.0...@standardnotes/analytics@2.17.0) (2022-12-20)
### Features
* **analytics:** add users activit to the report email ([ed5a4eb](https://github.com/standardnotes/server/commit/ed5a4eb960a6c8fe9d0c77331f29dc3c7ffb9100))
# [2.16.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.15.1...@standardnotes/analytics@2.16.0) (2022-12-20)
### Features
* **analytics:** add active users stats to report ([6e16620](https://github.com/standardnotes/server/commit/6e1662038c3340fb60939464616789bab7639160))
## [2.15.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.15.0...@standardnotes/analytics@2.15.1) (2022-12-20)
### Bug Fixes
* **auth:** add persisting statistics for all subscription plans ([addedb3](https://github.com/standardnotes/server/commit/addedb3091ddae81618d56663e18f2ae76a43c4e))
# [2.15.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.14.0...@standardnotes/analytics@2.15.0) (2022-12-19)
### Features
* **auth:** add requesting persisting statistics ([a35271f](https://github.com/standardnotes/server/commit/a35271fbb399b68a3ac7021395d8063707fba222))
# [2.14.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.13.0...@standardnotes/analytics@2.14.0) (2022-12-19) # [2.14.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.13.0...@standardnotes/analytics@2.14.0) (2022-12-19)
### Features ### Features
+4
View File
@@ -121,6 +121,10 @@ const requestReport = async (
StatisticMeasureName.NAMES.FiveYearPlansMRR, StatisticMeasureName.NAMES.FiveYearPlansMRR,
StatisticMeasureName.NAMES.PlusPlansMRR, StatisticMeasureName.NAMES.PlusPlansMRR,
StatisticMeasureName.NAMES.ProPlansMRR, StatisticMeasureName.NAMES.ProPlansMRR,
StatisticMeasureName.NAMES.ActiveUsers,
StatisticMeasureName.NAMES.ActiveFreeUsers,
StatisticMeasureName.NAMES.ActivePlusUsers,
StatisticMeasureName.NAMES.ActiveProUsers,
] ]
for (const statisticName of thirtyDaysStatisticsNames) { for (const statisticName of thirtyDaysStatisticsNames) {
statisticsOverTime.push({ statisticsOverTime.push({
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/analytics", "name": "@standardnotes/analytics",
"version": "2.14.0", "version": "2.17.8",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -38,7 +38,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
"@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events": "workspace:*",
@@ -218,6 +218,7 @@ export class ContainerConfigLoader {
.toConstantValue( .toConstantValue(
new StatisticPersistenceRequestedEventHandler( new StatisticPersistenceRequestedEventHandler(
container.get(TYPES.PersistStatistic), container.get(TYPES.PersistStatistic),
container.get(TYPES.Timer),
container.get(TYPES.Logger), container.get(TYPES.Logger),
), ),
) )
@@ -5,6 +5,38 @@ import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
import { StatisticMeasureName } from '../Statistics/StatisticMeasureName' import { StatisticMeasureName } from '../Statistics/StatisticMeasureName'
import { Period } from '../Time/Period' import { Period } from '../Time/Period'
const countActiveUsers = (measureName: string, data: any): { yesterday: number; last30Days: number } => {
const totalActiveUsersLast30DaysIncludingToday = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === measureName && a.period === 27,
)
const totalActiveUsersYesterday =
totalActiveUsersLast30DaysIncludingToday.counts[totalActiveUsersLast30DaysIncludingToday.counts.length - 2]
.totalCount
const filteredCounts = totalActiveUsersLast30DaysIncludingToday.counts.filter(
(count: { totalCount: number }) => count.totalCount !== 0,
)
if (filteredCounts.length === 0) {
return {
yesterday: 0,
last30Days: 0,
}
}
const last30DaysNumbers = filteredCounts.map((count: { totalCount: number }) => count.totalCount)
const last30DaysCount = last30DaysNumbers.reduce((previousValue: number, currentValue: number) => {
return previousValue + currentValue
})
const averageActiveUsersLast30Days = Math.floor(last30DaysCount / last30DaysNumbers.length)
return {
yesterday: totalActiveUsersYesterday,
last30Days: averageActiveUsersLast30Days,
}
}
const getChartUrls = ( const getChartUrls = (
data: any, data: any,
): { ): {
@@ -12,7 +44,6 @@ const getChartUrls = (
users: string users: string
quarterlyPerformance: string quarterlyPerformance: string
churn: string churn: string
mrr: string
mrrMonthly: string mrrMonthly: string
} => { } => {
const subscriptionPurchasingOverTime = data.activityStatisticsOverTime.find( const subscriptionPurchasingOverTime = data.activityStatisticsOverTime.find(
@@ -237,82 +268,6 @@ const getChartUrls = (
}, },
} }
const mrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'mrr' && a.period === 27,
)
const monthlyPlansMrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'monthly-plans-mrr' && a.period === 27,
)
const annualPlansMrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'annual-plans-mrr' && a.period === 27,
)
const fiveYearPlansMrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'five-year-plans-mrr' && a.period === 27,
)
const proPlansMrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'pro-plans-mrr' && a.period === 27,
)
const plusPlansMrrOverTime = data.statisticsOverTime.find(
(a: { name: string; period: number }) => a.name === 'plus-plans-mrr' && a.period === 27,
)
const mrrOverTimeConfig = {
type: 'line',
data: {
labels: mrrOverTime?.counts.map((count: { periodKey: any }) => count.periodKey),
datasets: [
{
label: 'MRR',
backgroundColor: 'rgb(25, 255, 140)',
borderColor: 'rgb(25, 255, 140)',
data: mrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
{
label: 'MRR - Monthly Plans',
backgroundColor: 'rgb(54, 162, 235)',
borderColor: 'rgb(54, 162, 235)',
data: monthlyPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
{
label: 'MRR - Annual Plans',
backgroundColor: 'rgb(255, 221, 51)',
borderColor: 'rgb(255, 221, 51)',
data: annualPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
{
label: 'MRR - Five Year Plans',
backgroundColor: 'rgb(255, 120, 120)',
borderColor: 'rgb(255, 120, 120)',
data: fiveYearPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
{
label: 'MRR - PRO Plans',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: proPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
{
label: 'MRR - PLUS Plans',
backgroundColor: 'rgb(221, 51, 255)',
borderColor: 'rgb(221, 51, 255)',
data: plusPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
fill: false,
pointRadius: 2,
},
],
},
}
const mrrMonthlyOverTime = data.statisticsOverTime const mrrMonthlyOverTime = data.statisticsOverTime
.find((a: { name: string; period: Period }) => a.name === 'mrr' && a.period === Period.ThisYear) .find((a: { name: string; period: Period }) => a.name === 'mrr' && a.period === Period.ThisYear)
?.counts.map((count: { totalCount: number }) => +count.totalCount.toFixed(2)) ?.counts.map((count: { totalCount: number }) => +count.totalCount.toFixed(2))
@@ -371,7 +326,6 @@ const getChartUrls = (
JSON.stringify(quarterlyConfig), JSON.stringify(quarterlyConfig),
)}`, )}`,
churn: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(churnConfig))}`, churn: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(churnConfig))}`,
mrr: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(mrrOverTimeConfig))}`,
mrrMonthly: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(mrrMonthlyConfig))}`, mrrMonthly: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(mrrMonthlyConfig))}`,
} }
} }
@@ -608,12 +562,39 @@ export const html = (data: any, timer: TimerInterface) => {
(value: { periodKey: string }) => value.periodKey === thisMonthPeriodKey, (value: { periodKey: string }) => value.periodKey === thisMonthPeriodKey,
) )
const totalActiveUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveUsers, data)
const totalActiveFreeUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveFreeUsers, data)
const totalActivePlusUsers = countActiveUsers(StatisticMeasureName.NAMES.ActivePlusUsers, data)
const totalActiveProUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveProUsers, data)
return ` <div> return ` <div>
<p>Hello,</p> <p>Hello,</p>
<p> <p>
<strong>Here are some statistics from yesterday:</strong> <strong>Here are some statistics from yesterday:</strong>
</p> </p>
<ul> <ul>
<li>
<b>Active Users</b>
<ul>
<li>
<b>Total:</b> ${totalActiveUsers.yesterday.toLocaleString('en-US')}
</li>
<li>
<b>By Subscription Type:</b>
<ul>
<li>
<b>FREE:</b> ${totalActiveFreeUsers.yesterday.toLocaleString('en-US')}
</li>
<li>
<b>PLUS:</b> ${totalActivePlusUsers.yesterday.toLocaleString('en-US')}
</li>
<li>
<b>PRO:</b> ${totalActiveProUsers.yesterday.toLocaleString('en-US')}
</li>
</ul>
</li>
</ul>
</li>
<li> <li>
<b>Payments</b> <b>Payments</b>
<ul> <ul>
@@ -812,6 +793,28 @@ export const html = (data: any, timer: TimerInterface) => {
<strong>Here are some statistics from last 30 days:</strong> <strong>Here are some statistics from last 30 days:</strong>
</p> </p>
<ul> <ul>
<li>
<b>Active Users (Average)</b>
<ul>
<li>
<b>Total:</b> ${totalActiveUsers.last30Days.toLocaleString('en-US')}
</li>
<li>
<b>By Subscription Type:</b>
<ul>
<li>
<b>FREE:</b> ${totalActiveFreeUsers.last30Days.toLocaleString('en-US')}
</li>
<li>
<b>PLUS:</b> ${totalActivePlusUsers.last30Days.toLocaleString('en-US')}
</li>
<li>
<b>PRO:</b> ${totalActiveProUsers.last30Days.toLocaleString('en-US')}
</li>
</ul>
</li>
</ul>
</li>
<li> <li>
<b>Payments (This Month)</b> <b>Payments (This Month)</b>
<ul> <ul>
@@ -944,10 +947,6 @@ export const html = (data: any, timer: TimerInterface) => {
</ul> </ul>
</li> </li>
</ul> </ul>
<p>
<strong>Here is the MRR chart over 30 days:</strong>
</p>
<img src=${chartUrls.mrr}></img>
<p> <p>
<strong>Here is the MRR Monthly chart this year:</strong> <strong>Here is the MRR Monthly chart this year:</strong>
</p> </p>
@@ -1,13 +1,14 @@
import { DomainEventHandlerInterface, StatisticPersistenceRequestedEvent } from '@standardnotes/domain-events' import { DomainEventHandlerInterface, StatisticPersistenceRequestedEvent } from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
import { Logger } from 'winston' import { Logger } from 'winston'
import { PersistStatistic } from '../UseCase/PersistStatistic/PersistStatistic' import { PersistStatistic } from '../UseCase/PersistStatistic/PersistStatistic'
export class StatisticPersistenceRequestedEventHandler implements DomainEventHandlerInterface { export class StatisticPersistenceRequestedEventHandler implements DomainEventHandlerInterface {
constructor(private persistStatistic: PersistStatistic, private logger: Logger) {} constructor(private persistStatistic: PersistStatistic, private timer: TimerInterface, private logger: Logger) {}
async handle(event: StatisticPersistenceRequestedEvent): Promise<void> { async handle(event: StatisticPersistenceRequestedEvent): Promise<void> {
const result = await this.persistStatistic.execute({ const result = await this.persistStatistic.execute({
date: event.payload.date, date: this.timer.convertMicrosecondsToDate(event.payload.date),
statisticMeasureName: event.payload.statisticMeasureName, statisticMeasureName: event.payload.statisticMeasureName,
value: event.payload.value, value: event.payload.value,
}) })
@@ -26,6 +26,10 @@ export class StatisticMeasureName extends ValueObject<StatisticMeasureNameProps>
FiveYearPlansMRR: 'five-year-plans-mrr', FiveYearPlansMRR: 'five-year-plans-mrr',
ProPlansMRR: 'pro-plans-mrr', ProPlansMRR: 'pro-plans-mrr',
PlusPlansMRR: 'plus-plans-mrr', PlusPlansMRR: 'plus-plans-mrr',
ActiveUsers: 'active-users',
ActiveProUsers: 'active-pro-users',
ActivePlusUsers: 'active-plus-users',
ActiveFreeUsers: 'active-free-users',
} }
get value(): string { get value(): string {
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.41.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.2...@standardnotes/api-gateway@1.41.3) (2022-12-28)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.41.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.1...@standardnotes/api-gateway@1.41.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.41.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.0...@standardnotes/api-gateway@1.41.1) (2022-12-19) ## [1.41.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.0...@standardnotes/api-gateway@1.41.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/api-gateway **Note:** Version bump only for package @standardnotes/api-gateway
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/api-gateway", "name": "@standardnotes/api-gateway",
"version": "1.41.1", "version": "1.41.3",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -21,7 +21,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/common": "workspace:^", "@standardnotes/common": "workspace:^",
"@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events": "workspace:*",
"@standardnotes/domain-events-infra": "workspace:*", "@standardnotes/domain-events-infra": "workspace:*",
+2 -2
View File
@@ -13,8 +13,8 @@ ENCRYPTION_SERVER_KEY=change-me-!
PORT=3000 PORT=3000
DB_HOST=localhost DB_HOST=127.0.0.1
DB_REPLICA_HOST=localhost DB_REPLICA_HOST=127.0.0.1
DB_PORT=3306 DB_PORT=3306
DB_USERNAME=auth DB_USERNAME=auth
DB_PASSWORD=changeme123 DB_PASSWORD=changeme123
+58
View File
@@ -3,6 +3,64 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.70.9](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.8...@standardnotes/auth-server@1.70.9) (2022-12-28)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.70.8](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.7...@standardnotes/auth-server@1.70.8) (2022-12-20)
### Bug Fixes
* **auth:** move tracing sessions to session creation instead of cross service token creation ([5255cfb](https://github.com/standardnotes/server/commit/5255cfbb257cc9e6ac437fe0c5b28d938e3e599b))
## [1.70.7](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.6...@standardnotes/auth-server@1.70.7) (2022-12-20)
### Bug Fixes
* **auth:** change severity on tracing session errors - most probably hazardous reads ([cf0b918](https://github.com/standardnotes/server/commit/cf0b91891370e1c1799ad80c10ee9f6b98087a94))
## [1.70.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.5...@standardnotes/auth-server@1.70.6) (2022-12-20)
### Bug Fixes
* **auth:** query for session traces ([14eb775](https://github.com/standardnotes/server/commit/14eb775749bfa9972dc3c07049505f3d15f0b556))
## [1.70.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.4...@standardnotes/auth-server@1.70.5) (2022-12-20)
### Bug Fixes
* **auth:** add session traces index ([b9e1e47](https://github.com/standardnotes/server/commit/b9e1e4787129f00fab8f98cb721141f2e7d75600))
## [1.70.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.3...@standardnotes/auth-server@1.70.4) (2022-12-20)
### Bug Fixes
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
## [1.70.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.2...@standardnotes/auth-server@1.70.3) (2022-12-20)
### Bug Fixes
* **auth:** add persisting statistics for all subscription plans ([addedb3](https://github.com/standardnotes/server/commit/addedb3091ddae81618d56663e18f2ae76a43c4e))
## [1.70.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.1...@standardnotes/auth-server@1.70.2) (2022-12-20)
### Bug Fixes
* **auth:** docker command ([85d2f42](https://github.com/standardnotes/server/commit/85d2f42f473110e8dfca975bfecc7a56823bdef4))
## [1.70.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.0...@standardnotes/auth-server@1.70.1) (2022-12-20)
### Bug Fixes
* **auth:** saving subscription plan name in session traces ([3064d03](https://github.com/standardnotes/server/commit/3064d03aa9a2ac9ca3acfff30480ea8629faeb14))
# [1.70.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.69.1...@standardnotes/auth-server@1.70.0) (2022-12-19)
### Features
* **auth:** add requesting persisting statistics ([a35271f](https://github.com/standardnotes/server/commit/a35271fbb399b68a3ac7021395d8063707fba222))
## [1.69.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.69.0...@standardnotes/auth-server@1.69.1) (2022-12-19) ## [1.69.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.69.0...@standardnotes/auth-server@1.69.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/auth-server **Note:** Version bump only for package @standardnotes/auth-server
+40
View File
@@ -0,0 +1,40 @@
import 'reflect-metadata'
import 'newrelic'
import { Logger } from 'winston'
import { TimerInterface } from '@standardnotes/time'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { PersistStatistics } from '../src/Domain/UseCase/PersistStatistics/PersistStatistics'
const container = new ContainerConfigLoader()
void container.load().then((container) => {
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Logger)
logger.info('Starting session traces cleanup')
const persistStats: PersistStatistics = container.get(TYPES.PersistStatistics)
const timer: TimerInterface = container.get(TYPES.Timer)
Promise.resolve(
persistStats.execute({
sessionsInADay: timer.getUTCDateNDaysAgo(1),
}),
)
.then(() => {
logger.info('Stats persisted.')
process.exit(0)
})
.catch((error) => {
logger.error(`Could not persist stats: ${error.message}`)
process.exit(1)
})
})
+5
View File
@@ -24,6 +24,11 @@ case "$COMMAND" in
yarn workspace @standardnotes/auth-server cleanup yarn workspace @standardnotes/auth-server cleanup
;; ;;
'stats' )
echo "[Docker] Starting Persisting Stats..."
yarn workspace @standardnotes/auth-server stats
;;
'email-daily-backup' ) 'email-daily-backup' )
echo "[Docker] Starting Email Daily Backup..." echo "[Docker] Starting Email Daily Backup..."
yarn workspace @standardnotes/auth-server daily-backup:email yarn workspace @standardnotes/auth-server daily-backup:email
@@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class addSessionTracesCompoundIndex1671561748264 implements MigrationInterface {
name = 'addSessionTracesCompoundIndex1671561748264'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
'CREATE UNIQUE INDEX `user_uuid_and_creation_date` ON `session_traces` (`user_uuid`, `creation_date`)',
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('DROP INDEX `user_uuid_and_creation_date` ON `session_traces`')
}
}
+4 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/auth-server", "name": "@standardnotes/auth-server",
"version": "1.69.1", "version": "1.70.9",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -20,6 +20,7 @@
"start": "yarn node dist/bin/server.js", "start": "yarn node dist/bin/server.js",
"worker": "yarn node dist/bin/worker.js", "worker": "yarn node dist/bin/worker.js",
"cleanup": "yarn node dist/bin/cleanup.js", "cleanup": "yarn node dist/bin/cleanup.js",
"stats": "yarn node dist/bin/stats.js",
"daily-backup:email": "yarn node dist/bin/backup.js email daily", "daily-backup:email": "yarn node dist/bin/backup.js email daily",
"user-email-backup": "yarn node dist/bin/user_email_backup.js", "user-email-backup": "yarn node dist/bin/user_email_backup.js",
"daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily", "daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily",
@@ -32,9 +33,9 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@sentry/profiling-node": "^0.0.12", "@sentry/profiling-node": "^0.0.12",
"@sentry/tracing": "^7.27.0", "@sentry/tracing": "^7.28.1",
"@standardnotes/api": "^1.19.0", "@standardnotes/api": "^1.19.0",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
+11
View File
@@ -202,6 +202,7 @@ import { SessionTrace } from '../Domain/Session/SessionTrace'
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace' import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
import { TraceSession } from '../Domain/UseCase/TraceSession/TraceSession' import { TraceSession } from '../Domain/UseCase/TraceSession/TraceSession'
import { CleanupSessionTraces } from '../Domain/UseCase/CleanupSessionTraces/CleanupSessionTraces' import { CleanupSessionTraces } from '../Domain/UseCase/CleanupSessionTraces/CleanupSessionTraces'
import { PersistStatistics } from '../Domain/UseCase/PersistStatistics/PersistStatistics'
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicFormatter = require('@newrelic/winston-enricher') const newrelicFormatter = require('@newrelic/winston-enricher')
@@ -500,6 +501,16 @@ export class ContainerConfigLoader {
container.get(TYPES.SESSION_TRACE_DAYS_TTL), container.get(TYPES.SESSION_TRACE_DAYS_TTL),
), ),
) )
container
.bind<PersistStatistics>(TYPES.PersistStatistics)
.toConstantValue(
new PersistStatistics(
container.get(TYPES.SessionTraceRepository),
container.get(TYPES.DomainEventPublisher),
container.get(TYPES.DomainEventFactory),
container.get(TYPES.Timer),
),
)
container container
.bind<CleanupSessionTraces>(TYPES.CleanupSessionTraces) .bind<CleanupSessionTraces>(TYPES.CleanupSessionTraces)
+1
View File
@@ -126,6 +126,7 @@ const TYPES = {
ProcessUserRequest: Symbol.for('ProcessUserRequest'), ProcessUserRequest: Symbol.for('ProcessUserRequest'),
TraceSession: Symbol.for('TraceSession'), TraceSession: Symbol.for('TraceSession'),
CleanupSessionTraces: Symbol.for('CleanupSessionTraces'), CleanupSessionTraces: Symbol.for('CleanupSessionTraces'),
PersistStatistics: Symbol.for('PersistStatistics'),
// Handlers // Handlers
UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'), UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'), AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
@@ -19,6 +19,7 @@ import {
UserContentSizeRecalculationRequestedEvent, UserContentSizeRecalculationRequestedEvent,
MuteEmailsSettingChangedEvent, MuteEmailsSettingChangedEvent,
EmailRequestedEvent, EmailRequestedEvent,
StatisticPersistenceRequestedEvent,
} from '@standardnotes/domain-events' } from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates' import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time' import { TimerInterface } from '@standardnotes/time'
@@ -31,6 +32,25 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
export class DomainEventFactory implements DomainEventFactoryInterface { export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(@inject(TYPES.Timer) private timer: TimerInterface) {} constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
createStatisticPersistenceRequestedEvent(dto: {
statisticMeasureName: string
value: number
date: number
}): StatisticPersistenceRequestedEvent {
return {
type: 'STATISTIC_PERSISTENCE_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: '-',
userIdentifierType: 'email',
},
origin: DomainEventService.Auth,
},
payload: dto,
}
}
createMuteEmailsSettingChangedEvent(dto: { createMuteEmailsSettingChangedEvent(dto: {
username: string username: string
mute: boolean mute: boolean
@@ -17,6 +17,7 @@ import {
UserContentSizeRecalculationRequestedEvent, UserContentSizeRecalculationRequestedEvent,
MuteEmailsSettingChangedEvent, MuteEmailsSettingChangedEvent,
EmailRequestedEvent, EmailRequestedEvent,
StatisticPersistenceRequestedEvent,
} from '@standardnotes/domain-events' } from '@standardnotes/domain-events'
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType' import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
@@ -88,4 +89,9 @@ export interface DomainEventFactoryInterface {
mute: boolean mute: boolean
emailSubscriptionRejectionLevel: string emailSubscriptionRejectionLevel: string
}): MuteEmailsSettingChangedEvent }): MuteEmailsSettingChangedEvent
createStatisticPersistenceRequestedEvent(dto: {
statisticMeasureName: string
value: number
date: number
}): StatisticPersistenceRequestedEvent
} }
@@ -41,4 +41,23 @@ describe('RoleToSubscriptionMap', () => {
}, },
]) ])
}) })
it('should filter our subscription roles from an array of roles', () => {
const roles = [
{
name: RoleName.CoreUser,
} as jest.Mocked<Role>,
{
name: RoleName.FilesBetaUser,
} as jest.Mocked<Role>,
{
name: RoleName.PlusUser,
} as jest.Mocked<Role>,
]
expect(createMap().filterSubscriptionRoles(roles)).toEqual([
{
name: RoleName.PlusUser,
},
])
})
}) })
@@ -17,6 +17,10 @@ export class RoleToSubscriptionMap implements RoleToSubscriptionMapInterface {
return roles.filter((role) => this.nonSubscriptionRoles.includes(role.name as RoleName)) return roles.filter((role) => this.nonSubscriptionRoles.includes(role.name as RoleName))
} }
filterSubscriptionRoles(roles: Role[]): Array<Role> {
return roles.filter((role) => !this.nonSubscriptionRoles.includes(role.name as RoleName))
}
getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined { getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined {
return this.roleNameToSubscriptionNameMap.get(roleName) return this.roleNameToSubscriptionNameMap.get(roleName)
} }
@@ -3,6 +3,7 @@ import { Role } from './Role'
export interface RoleToSubscriptionMapInterface { export interface RoleToSubscriptionMapInterface {
filterNonSubscriptionRoles(roles: Role[]): Array<Role> filterNonSubscriptionRoles(roles: Role[]): Array<Role>
filterSubscriptionRoles(roles: Role[]): Array<Role>
getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined
getRoleNameForSubscriptionName(subscriptionName: SubscriptionName): RoleName | undefined getRoleNameForSubscriptionName(subscriptionName: SubscriptionName): RoleName | undefined
} }
@@ -15,6 +15,10 @@ import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
import { LogSessionUserAgentOption } from '@standardnotes/settings' import { LogSessionUserAgentOption } from '@standardnotes/settings'
import { Setting } from '../Setting/Setting' import { Setting } from '../Setting/Setting'
import { CryptoNode } from '@standardnotes/sncrypto-node' import { CryptoNode } from '@standardnotes/sncrypto-node'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { TraceSession } from '../UseCase/TraceSession/TraceSession'
import { UserSubscription } from '../Subscription/UserSubscription'
import { Result } from '@standardnotes/domain-core'
describe('SessionService', () => { describe('SessionService', () => {
let sessionRepository: SessionRepositoryInterface let sessionRepository: SessionRepositoryInterface
@@ -28,6 +32,8 @@ describe('SessionService', () => {
let timer: TimerInterface let timer: TimerInterface
let logger: winston.Logger let logger: winston.Logger
let cryptoNode: CryptoNode let cryptoNode: CryptoNode
let traceSession: TraceSession
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
const createService = () => const createService = () =>
new SessionService( new SessionService(
@@ -41,6 +47,8 @@ describe('SessionService', () => {
234, 234,
settingService, settingService,
cryptoNode, cryptoNode,
traceSession,
userSubscriptionRepository,
) )
beforeEach(() => { beforeEach(() => {
@@ -106,6 +114,14 @@ describe('SessionService', () => {
cryptoNode = {} as jest.Mocked<CryptoNode> cryptoNode = {} as jest.Mocked<CryptoNode>
cryptoNode.generateRandomKey = jest.fn().mockReturnValue('foo bar') cryptoNode.generateRandomKey = jest.fn().mockReturnValue('foo bar')
cryptoNode.base64URLEncode = jest.fn().mockReturnValue('foobar') cryptoNode.base64URLEncode = jest.fn().mockReturnValue('foobar')
traceSession = {} as jest.Mocked<TraceSession>
traceSession.execute = jest.fn()
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue({
planName: 'PRO_PLAN',
} as jest.Mocked<UserSubscription>)
}) })
it('should mark a revoked session as received', async () => { it('should mark a revoked session as received', async () => {
@@ -204,6 +220,129 @@ describe('SessionService', () => {
}) })
}) })
it('should trace a session', async () => {
const user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = 'test@test.te'
await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
readonlyAccess: false,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '123',
username: 'test@test.te',
subscriptionPlanName: 'PRO_PLAN',
})
})
it('should trace a session without a subscription', async () => {
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
const user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = 'test@test.te'
await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
readonlyAccess: false,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '123',
username: 'test@test.te',
subscriptionPlanName: null,
})
})
it('should create a session if tracing session throws an error', async () => {
traceSession.execute = jest.fn().mockRejectedValue(new Error('foo bar'))
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
const user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
readonlyAccess: false,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '123',
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
refresh_token: expect.any(String),
readonly_access: false,
})
})
it('should create a session if tracing session throws an error', async () => {
traceSession.execute = jest.fn().mockRejectedValue(new Error('foo bar'))
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
const user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
readonlyAccess: false,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '123',
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
refresh_token: expect.any(String),
readonly_access: false,
})
})
it('should create a session if tracing session fails', async () => {
traceSession.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
const user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
readonlyAccess: false,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '123',
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
refresh_token: expect.any(String),
readonly_access: false,
})
})
it('should create new ephemeral session for a user', async () => { it('should create new ephemeral session for a user', async () => {
const user = {} as jest.Mocked<User> const user = {} as jest.Mocked<User>
user.uuid = '123' user.uuid = '123'
@@ -1,10 +1,14 @@
import * as crypto from 'crypto' import * as crypto from 'crypto'
import * as winston from 'winston'
import * as dayjs from 'dayjs' import * as dayjs from 'dayjs'
import { UAParser } from 'ua-parser-js' import { UAParser } from 'ua-parser-js'
import { inject, injectable } from 'inversify' import { inject, injectable } from 'inversify'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { TimerInterface } from '@standardnotes/time' import { TimerInterface } from '@standardnotes/time'
import { Logger } from 'winston'
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/settings'
import { SessionBody } from '@standardnotes/responses'
import { Uuid } from '@standardnotes/common'
import { CryptoNode } from '@standardnotes/sncrypto-node'
import TYPES from '../../Bootstrap/Types' import TYPES from '../../Bootstrap/Types'
import { Session } from './Session' import { Session } from './Session'
@@ -16,10 +20,8 @@ import { EphemeralSession } from './EphemeralSession'
import { RevokedSession } from './RevokedSession' import { RevokedSession } from './RevokedSession'
import { RevokedSessionRepositoryInterface } from './RevokedSessionRepositoryInterface' import { RevokedSessionRepositoryInterface } from './RevokedSessionRepositoryInterface'
import { SettingServiceInterface } from '../Setting/SettingServiceInterface' import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/settings' import { TraceSession } from '../UseCase/TraceSession/TraceSession'
import { SessionBody } from '@standardnotes/responses' import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { Uuid } from '@standardnotes/common'
import { CryptoNode } from '@standardnotes/sncrypto-node'
@injectable() @injectable()
export class SessionService implements SessionServiceInterface { export class SessionService implements SessionServiceInterface {
@@ -31,11 +33,13 @@ export class SessionService implements SessionServiceInterface {
@inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface, @inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
@inject(TYPES.DeviceDetector) private deviceDetector: UAParser, @inject(TYPES.DeviceDetector) private deviceDetector: UAParser,
@inject(TYPES.Timer) private timer: TimerInterface, @inject(TYPES.Timer) private timer: TimerInterface,
@inject(TYPES.Logger) private logger: winston.Logger, @inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ACCESS_TOKEN_AGE) private accessTokenAge: number, @inject(TYPES.ACCESS_TOKEN_AGE) private accessTokenAge: number,
@inject(TYPES.REFRESH_TOKEN_AGE) private refreshTokenAge: number, @inject(TYPES.REFRESH_TOKEN_AGE) private refreshTokenAge: number,
@inject(TYPES.SettingService) private settingService: SettingServiceInterface, @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
@inject(TYPES.CryptoNode) private cryptoNode: CryptoNode, @inject(TYPES.CryptoNode) private cryptoNode: CryptoNode,
@inject(TYPES.TraceSession) private traceSession: TraceSession,
@inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
) {} ) {}
async createNewSessionForUser(dto: { async createNewSessionForUser(dto: {
@@ -53,6 +57,20 @@ export class SessionService implements SessionServiceInterface {
await this.sessionRepository.save(session) await this.sessionRepository.save(session)
try {
const userSubscription = await this.userSubscriptionRepository.findOneByUserUuid(dto.user.uuid)
const traceSessionResult = await this.traceSession.execute({
userUuid: dto.user.uuid,
username: dto.user.email,
subscriptionPlanName: userSubscription ? userSubscription.planName : null,
})
if (traceSessionResult.isFailed()) {
this.logger.error(traceSessionResult.getError())
}
} catch (error) {
this.logger.error(`Could not trace session while creating cross service token.: ${(error as Error).message}`)
}
return sessionPayload return sessionPayload
} }
@@ -1,4 +1,4 @@
import { Uuid } from '@standardnotes/domain-core' import { SubscriptionPlanName, Uuid } from '@standardnotes/domain-core'
import { SessionTrace } from './SessionTrace' import { SessionTrace } from './SessionTrace'
@@ -6,4 +6,6 @@ export interface SessionTraceRepositoryInterface {
save(sessionTrace: SessionTrace): Promise<void> save(sessionTrace: SessionTrace): Promise<void>
removeExpiredBefore(date: Date): Promise<void> removeExpiredBefore(date: Date): Promise<void>
findOneByUserUuidAndDate(userUuid: Uuid, date: Date): Promise<SessionTrace | null> findOneByUserUuidAndDate(userUuid: Uuid, date: Date): Promise<SessionTrace | null>
countByDate(date: Date): Promise<number>
countByDateAndSubscriptionPlanName(date: Date, subscriptionPlanName: SubscriptionPlanName): Promise<number>
} }
@@ -8,10 +8,6 @@ import { Role } from '../../Role/Role'
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface' import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
import { CreateCrossServiceToken } from './CreateCrossServiceToken' import { CreateCrossServiceToken } from './CreateCrossServiceToken'
import { RoleToSubscriptionMapInterface } from '../../Role/RoleToSubscriptionMapInterface'
import { TraceSession } from '../TraceSession/TraceSession'
import { Logger } from 'winston'
import { Result, RoleName, SubscriptionPlanName } from '@standardnotes/domain-core'
describe('CreateCrossServiceToken', () => { describe('CreateCrossServiceToken', () => {
let userProjector: ProjectorInterface<User> let userProjector: ProjectorInterface<User>
@@ -19,9 +15,6 @@ describe('CreateCrossServiceToken', () => {
let roleProjector: ProjectorInterface<Role> let roleProjector: ProjectorInterface<Role>
let tokenEncoder: TokenEncoderInterface<CrossServiceTokenData> let tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>
let userRepository: UserRepositoryInterface let userRepository: UserRepositoryInterface
let roleToSubscriptionMap: RoleToSubscriptionMapInterface
let traceSession: TraceSession
let logger: Logger
const jwtTTL = 60 const jwtTTL = 60
let session: Session let session: Session
@@ -29,17 +22,7 @@ describe('CreateCrossServiceToken', () => {
let role: Role let role: Role
const createUseCase = () => const createUseCase = () =>
new CreateCrossServiceToken( new CreateCrossServiceToken(userProjector, sessionProjector, roleProjector, tokenEncoder, userRepository, jwtTTL)
userProjector,
sessionProjector,
roleProjector,
tokenEncoder,
userRepository,
jwtTTL,
roleToSubscriptionMap,
traceSession,
logger,
)
beforeEach(() => { beforeEach(() => {
session = {} as jest.Mocked<Session> session = {} as jest.Mocked<Session>
@@ -65,18 +48,6 @@ describe('CreateCrossServiceToken', () => {
userRepository = {} as jest.Mocked<UserRepositoryInterface> userRepository = {} as jest.Mocked<UserRepositoryInterface>
userRepository.findOneByUuid = jest.fn().mockReturnValue(user) userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
roleToSubscriptionMap = {} as jest.Mocked<RoleToSubscriptionMapInterface>
roleToSubscriptionMap.filterNonSubscriptionRoles = jest.fn().mockReturnValue([RoleName.NAMES.PlusUser])
roleToSubscriptionMap.getSubscriptionNameForRoleName = jest
.fn()
.mockReturnValue(SubscriptionPlanName.NAMES.PlusPlan)
traceSession = {} as jest.Mocked<TraceSession>
traceSession.execute = jest.fn()
logger = {} as jest.Mocked<Logger>
logger.error = jest.fn()
}) })
it('should create a cross service token for user', async () => { it('should create a cross service token for user', async () => {
@@ -85,11 +56,6 @@ describe('CreateCrossServiceToken', () => {
session, session,
}) })
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '1-2-3',
username: 'test@test.te',
subscriptionPlanName: 'PLUS_PLAN',
})
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith( expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
{ {
roles: [ roles: [
@@ -168,126 +134,4 @@ describe('CreateCrossServiceToken', () => {
expect(caughtError).not.toBeNull() expect(caughtError).not.toBeNull()
}) })
it('should trace session without a subscription role', async () => {
roleToSubscriptionMap.filterNonSubscriptionRoles = jest.fn().mockReturnValue([])
await createUseCase().execute({
user,
session,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '1-2-3',
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
{
roles: [
{
name: 'role1',
uuid: '1-3-4',
},
],
session: {
test: 'test',
},
user: {
email: 'test@test.te',
uuid: '1-2-3',
},
},
60,
)
})
it('should trace session without a subscription', async () => {
roleToSubscriptionMap.getSubscriptionNameForRoleName = jest.fn().mockReturnValue(undefined)
await createUseCase().execute({
user,
session,
})
expect(traceSession.execute).toHaveBeenCalledWith({
userUuid: '1-2-3',
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
{
roles: [
{
name: 'role1',
uuid: '1-3-4',
},
],
session: {
test: 'test',
},
user: {
email: 'test@test.te',
uuid: '1-2-3',
},
},
60,
)
})
it('should create token if tracing session throws an error', async () => {
traceSession.execute = jest.fn().mockRejectedValue(new Error('test'))
await createUseCase().execute({
user,
session,
})
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
{
roles: [
{
name: 'role1',
uuid: '1-3-4',
},
],
session: {
test: 'test',
},
user: {
email: 'test@test.te',
uuid: '1-2-3',
},
},
60,
)
})
it('should create token if tracing session fails', async () => {
traceSession.execute = jest.fn().mockReturnValue(Result.fail('Ooops'))
await createUseCase().execute({
user,
session,
})
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
{
roles: [
{
name: 'role1',
uuid: '1-3-4',
},
],
session: {
test: 'test',
},
user: {
email: 'test@test.te',
uuid: '1-2-3',
},
},
60,
)
})
}) })
@@ -1,16 +1,13 @@
import { RoleName } from '@standardnotes/common' import { RoleName } from '@standardnotes/common'
import { TokenEncoderInterface, CrossServiceTokenData } from '@standardnotes/security' import { TokenEncoderInterface, CrossServiceTokenData } from '@standardnotes/security'
import { inject, injectable } from 'inversify' import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
import TYPES from '../../../Bootstrap/Types' import TYPES from '../../../Bootstrap/Types'
import { ProjectorInterface } from '../../../Projection/ProjectorInterface' import { ProjectorInterface } from '../../../Projection/ProjectorInterface'
import { Role } from '../../Role/Role' import { Role } from '../../Role/Role'
import { RoleToSubscriptionMapInterface } from '../../Role/RoleToSubscriptionMapInterface'
import { Session } from '../../Session/Session' import { Session } from '../../Session/Session'
import { User } from '../../User/User' import { User } from '../../User/User'
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface' import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
import { TraceSession } from '../TraceSession/TraceSession'
import { UseCaseInterface } from '../UseCaseInterface' import { UseCaseInterface } from '../UseCaseInterface'
import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO' import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO'
@@ -25,9 +22,6 @@ export class CreateCrossServiceToken implements UseCaseInterface {
@inject(TYPES.CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>, @inject(TYPES.CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface, @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
@inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number, @inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number,
@inject(TYPES.RoleToSubscriptionMap) private roleToSubscriptionMap: RoleToSubscriptionMapInterface,
@inject(TYPES.TraceSession) private traceSession: TraceSession,
@inject(TYPES.Logger) private logger: Logger,
) {} ) {}
async execute(dto: CreateCrossServiceTokenDTO): Promise<CreateCrossServiceTokenResponse> { async execute(dto: CreateCrossServiceTokenDTO): Promise<CreateCrossServiceTokenResponse> {
@@ -51,19 +45,6 @@ export class CreateCrossServiceToken implements UseCaseInterface {
authTokenData.session = this.projectSession(dto.session) authTokenData.session = this.projectSession(dto.session)
} }
try {
const traceSessionResult = await this.traceSession.execute({
userUuid: user.uuid,
username: user.email,
subscriptionPlanName: this.getSubscriptionNameFromRoles(roles),
})
if (traceSessionResult.isFailed()) {
this.logger.error(traceSessionResult.getError())
}
} catch (error) {
this.logger.error(`Could not trace session while creating cross service token: ${(error as Error).message}`)
}
return { return {
token: this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL), token: this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL),
} }
@@ -100,17 +81,4 @@ export class CreateCrossServiceToken implements UseCaseInterface {
private projectRoles(roles: Array<Role>): Array<{ uuid: string; name: RoleName }> { private projectRoles(roles: Array<Role>): Array<{ uuid: string; name: RoleName }> {
return roles.map((role) => <{ uuid: string; name: RoleName }>this.roleProjector.projectSimple(role)) return roles.map((role) => <{ uuid: string; name: RoleName }>this.roleProjector.projectSimple(role))
} }
private getSubscriptionNameFromRoles(roles: Array<Role>): string | null {
const nonSubscriptionRoles = this.roleToSubscriptionMap.filterNonSubscriptionRoles(roles)
if (nonSubscriptionRoles.length === 0) {
return null
}
const subscriptionName = this.roleToSubscriptionMap.getSubscriptionNameForRoleName(
nonSubscriptionRoles[0].name as RoleName,
)
return subscriptionName === undefined ? null : subscriptionName
}
} }
@@ -0,0 +1,40 @@
import { DomainEventPublisherInterface, StatisticPersistenceRequestedEvent } from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
import { PersistStatistics } from './PersistStatistics'
describe('PersistStatistics', () => {
let sessionTracesRepository: SessionTraceRepositoryInterface
let domainEventPublisher: DomainEventPublisherInterface
let domainEventFactory: DomainEventFactoryInterface
let timer: TimerInterface
const createUseCase = () =>
new PersistStatistics(sessionTracesRepository, domainEventPublisher, domainEventFactory, timer)
beforeEach(() => {
sessionTracesRepository = {} as jest.Mocked<SessionTraceRepositoryInterface>
sessionTracesRepository.countByDate = jest.fn().mockReturnValue(1)
sessionTracesRepository.countByDateAndSubscriptionPlanName = jest.fn().mockReturnValue(2)
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
domainEventFactory.createStatisticPersistenceRequestedEvent = jest
.fn()
.mockReturnValue({} as jest.Mocked<StatisticPersistenceRequestedEvent>)
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
domainEventPublisher.publish = jest.fn()
timer = {} as jest.Mocked<TimerInterface>
timer.convertDateToMicroseconds = jest.fn().mockReturnValue(3)
})
it('should request statistic persistence', async () => {
await createUseCase().execute({ sessionsInADay: new Date() })
expect(domainEventPublisher.publish).toHaveBeenCalledTimes(4)
})
})
@@ -0,0 +1,64 @@
import { Result, SubscriptionPlanName, UseCaseInterface } from '@standardnotes/domain-core'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
import { PersistStatisticsDTO } from './PersistStatisticsDTO'
export class PersistStatistics implements UseCaseInterface<string> {
constructor(
private sessionTracesRepository: SessionTraceRepositoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
private domainEventFactory: DomainEventFactoryInterface,
private timer: TimerInterface,
) {}
async execute(dto: PersistStatisticsDTO): Promise<Result<string>> {
const countSessionsInADay = await this.sessionTracesRepository.countByDate(dto.sessionsInADay)
await this.domainEventPublisher.publish(
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
statisticMeasureName: 'active-users',
value: countSessionsInADay,
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
}),
)
const proSubscriptionPlanName = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.ProPlan).getValue()
const countProSessionsInADay = await this.sessionTracesRepository.countByDateAndSubscriptionPlanName(
dto.sessionsInADay,
proSubscriptionPlanName,
)
await this.domainEventPublisher.publish(
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
statisticMeasureName: 'active-pro-users',
value: countProSessionsInADay,
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
}),
)
const plusSubscriptionPlanName = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.PlusPlan).getValue()
const countPlusSessionsInADay = await this.sessionTracesRepository.countByDateAndSubscriptionPlanName(
dto.sessionsInADay,
plusSubscriptionPlanName,
)
await this.domainEventPublisher.publish(
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
statisticMeasureName: 'active-plus-users',
value: countPlusSessionsInADay,
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
}),
)
const countFreeSessionsInADay = countSessionsInADay - countProSessionsInADay - countPlusSessionsInADay
await this.domainEventPublisher.publish(
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
statisticMeasureName: 'active-free-users',
value: countFreeSessionsInADay,
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
}),
)
return Result.ok('Statistics persisted.')
}
}
@@ -0,0 +1,3 @@
export interface PersistStatisticsDTO {
sessionsInADay: Date
}
@@ -1,4 +1,4 @@
import { MapperInterface, Uuid } from '@standardnotes/domain-core' import { MapperInterface, SubscriptionPlanName, Uuid } from '@standardnotes/domain-core'
import { Repository } from 'typeorm' import { Repository } from 'typeorm'
import { SessionTrace } from '../../Domain/Session/SessionTrace' import { SessionTrace } from '../../Domain/Session/SessionTrace'
import { SessionTraceRepositoryInterface } from '../../Domain/Session/SessionTraceRepositoryInterface' import { SessionTraceRepositoryInterface } from '../../Domain/Session/SessionTraceRepositoryInterface'
@@ -10,6 +10,27 @@ export class MySQLSessionTraceRepository implements SessionTraceRepositoryInterf
private mapper: MapperInterface<SessionTrace, TypeORMSessionTrace>, private mapper: MapperInterface<SessionTrace, TypeORMSessionTrace>,
) {} ) {}
async countByDateAndSubscriptionPlanName(date: Date, subscriptionPlanName: SubscriptionPlanName): Promise<number> {
return this.ormRepository
.createQueryBuilder('trace')
.where('trace.creation_date = :creationDate', {
creationDate: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`,
})
.andWhere('trace.subscription_plan_name = :subscriptionPlanName', {
subscriptionPlanName: subscriptionPlanName.value,
})
.getCount()
}
async countByDate(date: Date): Promise<number> {
return this.ormRepository
.createQueryBuilder('trace')
.where('trace.creation_date = :creationDate', {
creationDate: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`,
})
.getCount()
}
async removeExpiredBefore(date: Date): Promise<void> { async removeExpiredBefore(date: Date): Promise<void> {
await this.ormRepository await this.ormRepository
.createQueryBuilder() .createQueryBuilder()
@@ -23,7 +44,7 @@ export class MySQLSessionTraceRepository implements SessionTraceRepositoryInterf
.createQueryBuilder('trace') .createQueryBuilder('trace')
.where('trace.user_uuid = :userUuid AND trace.creation_date = :creationDate', { .where('trace.user_uuid = :userUuid AND trace.creation_date = :creationDate', {
userUuid: userUuid.value, userUuid: userUuid.value,
creationDate: new Date(date.getFullYear(), date.getMonth(), date.getDate()), creationDate: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`,
}) })
.getOne() .getOne()
@@ -1,6 +1,7 @@
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm' import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
@Entity({ name: 'session_traces' }) @Entity({ name: 'session_traces' })
@Index('user_uuid_and_creation_date', ['userUuid', 'creationDate'], { unique: true })
export class TypeORMSessionTrace { export class TypeORMSessionTrace {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
declare uuid: string declare uuid: string
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.59](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.58...@standardnotes/domain-events-infra@1.9.59) (2022-12-20)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.9.58](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.57...@standardnotes/domain-events-infra@1.9.58) (2022-12-19) ## [1.9.58](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.57...@standardnotes/domain-events-infra@1.9.58) (2022-12-19)
**Note:** Version bump only for package @standardnotes/domain-events-infra **Note:** Version bump only for package @standardnotes/domain-events-infra
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/domain-events-infra", "name": "@standardnotes/domain-events-infra",
"version": "1.9.58", "version": "1.9.59",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.105.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.105.0...@standardnotes/domain-events@2.105.1) (2022-12-20)
### Bug Fixes
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
# [2.105.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.104.2...@standardnotes/domain-events@2.105.0) (2022-12-19) # [2.105.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.104.2...@standardnotes/domain-events@2.105.0) (2022-12-19)
### Features ### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/domain-events", "name": "@standardnotes/domain-events",
"version": "2.105.0", "version": "2.105.1",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -1,5 +1,5 @@
export interface StatisticPersistenceRequestedEventPayload { export interface StatisticPersistenceRequestedEventPayload {
statisticMeasureName: string statisticMeasureName: string
value: number value: number
date: Date date: number
} }
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.6.56](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.55...@standardnotes/event-store@1.6.56) (2022-12-20)
**Note:** Version bump only for package @standardnotes/event-store
## [1.6.55](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.54...@standardnotes/event-store@1.6.55) (2022-12-19) ## [1.6.55](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.54...@standardnotes/event-store@1.6.55) (2022-12-19)
**Note:** Version bump only for package @standardnotes/event-store **Note:** Version bump only for package @standardnotes/event-store
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/event-store", "name": "@standardnotes/event-store",
"version": "1.6.55", "version": "1.6.56",
"description": "Event Store Service", "description": "Event Store Service",
"private": true, "private": true,
"main": "dist/src/index.js", "main": "dist/src/index.js",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.2...@standardnotes/files-server@1.9.3) (2022-12-28)
**Note:** Version bump only for package @standardnotes/files-server
## [1.9.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.1...@standardnotes/files-server@1.9.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/files-server
## [1.9.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.0...@standardnotes/files-server@1.9.1) (2022-12-19) ## [1.9.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.0...@standardnotes/files-server@1.9.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/files-server **Note:** Version bump only for package @standardnotes/files-server
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/files-server", "name": "@standardnotes/files-server",
"version": "1.9.1", "version": "1.9.3",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -25,7 +25,7 @@
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'" "upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
}, },
"dependencies": { "dependencies": {
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events": "workspace:*",
"@standardnotes/domain-events-infra": "workspace:*", "@standardnotes/domain-events-infra": "workspace:*",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.10.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.2...@standardnotes/revisions-server@1.10.3) (2022-12-28)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.10.2](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.1...@standardnotes/revisions-server@1.10.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.10.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.0...@standardnotes/revisions-server@1.10.1) (2022-12-19) ## [1.10.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.0...@standardnotes/revisions-server@1.10.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/revisions-server **Note:** Version bump only for package @standardnotes/revisions-server
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/revisions-server", "name": "@standardnotes/revisions-server",
"version": "1.10.1", "version": "1.10.3",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -24,7 +24,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/api": "^1.19.0", "@standardnotes/api": "^1.19.0",
"@standardnotes/common": "workspace:^", "@standardnotes/common": "workspace:^",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.16.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.3...@standardnotes/scheduler-server@1.16.4) (2022-12-28)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.16.3](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.2...@standardnotes/scheduler-server@1.16.3) (2022-12-20)
### Bug Fixes
* **scheduler:** new pricing for subscription encouragement email ([eb21872](https://github.com/standardnotes/server/commit/eb21872db1726c4f8a55b5d16de712650c5e946b))
## [1.16.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.1...@standardnotes/scheduler-server@1.16.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.16.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.0...@standardnotes/scheduler-server@1.16.1) (2022-12-19) ## [1.16.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.0...@standardnotes/scheduler-server@1.16.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/scheduler-server **Note:** Version bump only for package @standardnotes/scheduler-server
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/scheduler-server", "name": "@standardnotes/scheduler-server",
"version": "1.16.1", "version": "1.16.4",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -25,7 +25,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
"@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events": "workspace:*",
@@ -5,7 +5,5 @@ export function getSubject(): string {
} }
export function getBody(registrationDate: string): string { export function getBody(registrationDate: string): string {
const body = html return html(registrationDate, 90, 120)
return body.replace('%%REGISTRATION_DATE%%', registrationDate)
} }
@@ -1,4 +1,4 @@
export const html = `<div> export const html = (registrationDate: string, annualPlusPrice: number, annualProPrice: number) => `<div>
<p>Hi there,</p> <p>Hi there,</p>
<p> <p>
We hope you've been finding great use out of Standard Notes. We built Standard Notes to be a secure place for We hope you've been finding great use out of Standard Notes. We built Standard Notes to be a secure place for
@@ -7,7 +7,7 @@ export const html = `<div>
<p> <p>
As a reminder, As a reminder,
<strong> <strong>
<em>you signed up for the Standard Notes free plan on %%REGISTRATION_DATE%%</em> <em>you signed up for the Standard Notes free plan on ${registrationDate}</em>
</strong> </strong>
Your free account comes with standard features like end-to-end encryption, multiple-device sync, and Your free account comes with standard features like end-to-end encryption, multiple-device sync, and
two-factor authentication. two-factor authentication.
@@ -19,13 +19,13 @@ export const html = `<div>
<ul> <ul>
<li> <li>
<p> <p>
<strong>Productivity</strong> <strong>($59/year)</strong> powers up your editing experience with unique <strong>Productivity</strong> <strong>($${annualPlusPrice}/year)</strong> powers up your editing experience with unique
and special-built note-types for markdown, rich text, spreadsheets, todo, and more. and special-built note-types for markdown, rich text, spreadsheets, todo, and more.
</p> </p>
</li> </li>
<li> <li>
<p> <p>
<strong>Professional</strong> <strong>($99/year)</strong> gives you all the power of Productivity plus <strong>Professional</strong> <strong>($${annualProPrice}/year)</strong> gives you all the power of Productivity plus
100GB of end-to-end encrypted file storage for your private photos, videos, and documents, plus family 100GB of end-to-end encrypted file storage for your private photos, videos, and documents, plus family
subscription sharing with up to 5 people. subscription sharing with up to 5 people.
</p> </p>
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.28.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.2...@standardnotes/syncing-server@1.28.3) (2022-12-28)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.28.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.1...@standardnotes/syncing-server@1.28.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/syncing-server
## [1.28.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.0...@standardnotes/syncing-server@1.28.1) (2022-12-19) ## [1.28.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.0...@standardnotes/syncing-server@1.28.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/syncing-server **Note:** Version bump only for package @standardnotes/syncing-server
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/syncing-server", "name": "@standardnotes/syncing-server",
"version": "1.28.1", "version": "1.28.3",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -27,9 +27,9 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@sentry/profiling-node": "^0.0.12", "@sentry/profiling-node": "^0.0.12",
"@sentry/tracing": "^7.27.0", "@sentry/tracing": "^7.28.1",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
"@standardnotes/domain-events": "workspace:*", "@standardnotes/domain-events": "workspace:*",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.5.3](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.2...@standardnotes/websockets-server@1.5.3) (2022-12-28)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.5.2](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.1...@standardnotes/websockets-server@1.5.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.5.1](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.0...@standardnotes/websockets-server@1.5.1) (2022-12-19) ## [1.5.1](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.0...@standardnotes/websockets-server@1.5.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/websockets-server **Note:** Version bump only for package @standardnotes/websockets-server
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/websockets-server", "name": "@standardnotes/websockets-server",
"version": "1.5.1", "version": "1.5.3",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -23,7 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/api": "^1.19.0", "@standardnotes/api": "^1.19.0",
"@standardnotes/common": "workspace:^", "@standardnotes/common": "workspace:^",
"@standardnotes/domain-events": "workspace:^", "@standardnotes/domain-events": "workspace:^",
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.19.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.3...@standardnotes/workspace-server@1.19.4) (2022-12-28)
**Note:** Version bump only for package @standardnotes/workspace-server
## [1.19.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.2...@standardnotes/workspace-server@1.19.3) (2022-12-20)
### Bug Fixes
* **workspace:** specs ([c8203cf](https://github.com/standardnotes/server/commit/c8203cf04cb93cc65d30b69f10fb275f5e6be449))
## [1.19.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.1...@standardnotes/workspace-server@1.19.2) (2022-12-20)
**Note:** Version bump only for package @standardnotes/workspace-server
## [1.19.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.0...@standardnotes/workspace-server@1.19.1) (2022-12-19) ## [1.19.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.0...@standardnotes/workspace-server@1.19.1) (2022-12-19)
**Note:** Version bump only for package @standardnotes/workspace-server **Note:** Version bump only for package @standardnotes/workspace-server
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@standardnotes/workspace-server", "name": "@standardnotes/workspace-server",
"version": "1.19.1", "version": "1.19.4",
"engines": { "engines": {
"node": ">=18.0.0 <19.0.0" "node": ">=18.0.0 <19.0.0"
}, },
@@ -23,7 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@newrelic/winston-enricher": "^4.0.0", "@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.27.0", "@sentry/node": "^7.28.1",
"@standardnotes/api": "^1.19.0", "@standardnotes/api": "^1.19.0",
"@standardnotes/common": "workspace:*", "@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-core": "workspace:^",
@@ -5,7 +5,7 @@ import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInvite
import { InviteToWorkspace } from './InviteToWorkspace' import { InviteToWorkspace } from './InviteToWorkspace'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { DomainEventPublisherInterface, WorkspaceInviteCreatedEvent } from '@standardnotes/domain-events' import { DomainEventPublisherInterface, EmailRequestedEvent } from '@standardnotes/domain-events'
import { WorkspaceAccessLevel } from '@standardnotes/common' import { WorkspaceAccessLevel } from '@standardnotes/common'
describe('InviteToWorkspace', () => { describe('InviteToWorkspace', () => {
@@ -33,9 +33,7 @@ describe('InviteToWorkspace', () => {
domainEventPublisher.publish = jest.fn() domainEventPublisher.publish = jest.fn()
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface> domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
domainEventFactory.createWorkspaceInviteCreatedEvent = jest domainEventFactory.createEmailRequestedEvent = jest.fn().mockReturnValue({} as jest.Mocked<EmailRequestedEvent>)
.fn()
.mockReturnValue({} as jest.Mocked<WorkspaceInviteCreatedEvent>)
}) })
it('should create an invite', async () => { it('should create an invite', async () => {
+69 -14
View File
@@ -1717,6 +1717,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/core@npm:7.28.1":
version: 7.28.1
resolution: "@sentry/core@npm:7.28.1"
dependencies:
"@sentry/types": "npm:7.28.1"
"@sentry/utils": "npm:7.28.1"
tslib: "npm:^1.9.3"
checksum: f29d747d3e15000d8010fe3c192260a78927f37d30a3bb82cd533f3a5beca0c7fd81353ec57420c4295daea5384a045bde70ff6d3af1468ec1201b1d84131d6d
languageName: node
linkType: hard
"@sentry/hub@npm:^7.16.0": "@sentry/hub@npm:^7.16.0":
version: 7.27.0 version: 7.27.0
resolution: "@sentry/hub@npm:7.27.0" resolution: "@sentry/hub@npm:7.27.0"
@@ -1729,7 +1740,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/node@npm:^7.16.0, @sentry/node@npm:^7.27.0": "@sentry/node@npm:^7.16.0":
version: 7.27.0 version: 7.27.0
resolution: "@sentry/node@npm:7.27.0" resolution: "@sentry/node@npm:7.27.0"
dependencies: dependencies:
@@ -1744,6 +1755,21 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/node@npm:^7.28.1":
version: 7.28.1
resolution: "@sentry/node@npm:7.28.1"
dependencies:
"@sentry/core": "npm:7.28.1"
"@sentry/types": "npm:7.28.1"
"@sentry/utils": "npm:7.28.1"
cookie: "npm:^0.4.1"
https-proxy-agent: "npm:^5.0.0"
lru_map: "npm:^0.3.3"
tslib: "npm:^1.9.3"
checksum: b4922d1f0a1b1e96cd73e5381871d0a2d20c4a05dd09f1cb9def6795c5fbe099b2e2b97025262cac595d19a42ebc82a34a8f9e59f87c0176e5206ae1f6377532
languageName: node
linkType: hard
"@sentry/profiling-node@npm:^0.0.12": "@sentry/profiling-node@npm:^0.0.12":
version: 0.0.12 version: 0.0.12
resolution: "@sentry/profiling-node@npm:0.0.12" resolution: "@sentry/profiling-node@npm:0.0.12"
@@ -1760,7 +1786,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/tracing@npm:^7.16.0, @sentry/tracing@npm:^7.27.0": "@sentry/tracing@npm:^7.16.0":
version: 7.27.0 version: 7.27.0
resolution: "@sentry/tracing@npm:7.27.0" resolution: "@sentry/tracing@npm:7.27.0"
dependencies: dependencies:
@@ -1772,6 +1798,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/tracing@npm:^7.28.1":
version: 7.28.1
resolution: "@sentry/tracing@npm:7.28.1"
dependencies:
"@sentry/core": "npm:7.28.1"
"@sentry/types": "npm:7.28.1"
"@sentry/utils": "npm:7.28.1"
tslib: "npm:^1.9.3"
checksum: be501ca9d727f4893121c208f80fa82589964970c5a01155ba1d24cfd7ebdb2a1d6e325ea5556f0747d16519631013315781ad1c178f8721e5eab77de2446b63
languageName: node
linkType: hard
"@sentry/types@npm:7.27.0, @sentry/types@npm:^7.16.0": "@sentry/types@npm:7.27.0, @sentry/types@npm:^7.16.0":
version: 7.27.0 version: 7.27.0
resolution: "@sentry/types@npm:7.27.0" resolution: "@sentry/types@npm:7.27.0"
@@ -1779,6 +1817,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/types@npm:7.28.1":
version: 7.28.1
resolution: "@sentry/types@npm:7.28.1"
checksum: 7dc6639cb7645c37bd8f759b60dbf2a149573b8a24dfb06baf7d7978f785e4635a65b3fb9e007f0eea56d33b543043fcfa1c1a376a83aa9824bb2d25be1a56dc
languageName: node
linkType: hard
"@sentry/utils@npm:7.27.0, @sentry/utils@npm:^7.16.0": "@sentry/utils@npm:7.27.0, @sentry/utils@npm:^7.16.0":
version: 7.27.0 version: 7.27.0
resolution: "@sentry/utils@npm:7.27.0" resolution: "@sentry/utils@npm:7.27.0"
@@ -1789,6 +1834,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@sentry/utils@npm:7.28.1":
version: 7.28.1
resolution: "@sentry/utils@npm:7.28.1"
dependencies:
"@sentry/types": "npm:7.28.1"
tslib: "npm:^1.9.3"
checksum: a4b5f73db0e287e49b2eab5da80d6bbf1f6c7e11e1cc06ae06f49a9477d2b45de98310b143198207f3ae1fdd25ef76c90984eb99553a8308f6516e12c0c9c98c
languageName: node
linkType: hard
"@sinclair/typebox@npm:^0.24.1": "@sinclair/typebox@npm:^0.24.1":
version: 0.24.44 version: 0.24.44
resolution: "@sinclair/typebox@npm:0.24.44" resolution: "@sinclair/typebox@npm:0.24.44"
@@ -1833,7 +1888,7 @@ __metadata:
resolution: "@standardnotes/analytics@workspace:packages/analytics" resolution: "@standardnotes/analytics@workspace:packages/analytics"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"
"@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events": "workspace:*"
@@ -1867,7 +1922,7 @@ __metadata:
resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway" resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/common": "workspace:^" "@standardnotes/common": "workspace:^"
"@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events": "workspace:*"
"@standardnotes/domain-events-infra": "workspace:*" "@standardnotes/domain-events-infra": "workspace:*"
@@ -1925,9 +1980,9 @@ __metadata:
resolution: "@standardnotes/auth-server@workspace:packages/auth" resolution: "@standardnotes/auth-server@workspace:packages/auth"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@sentry/profiling-node": "npm:^0.0.12" "@sentry/profiling-node": "npm:^0.0.12"
"@sentry/tracing": "npm:^7.27.0" "@sentry/tracing": "npm:^7.28.1"
"@standardnotes/api": "npm:^1.19.0" "@standardnotes/api": "npm:^1.19.0"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"
@@ -2147,7 +2202,7 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@standardnotes/files-server@workspace:packages/files" resolution: "@standardnotes/files-server@workspace:packages/files"
dependencies: dependencies:
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/config": "npm:2.4.3" "@standardnotes/config": "npm:2.4.3"
"@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events": "workspace:*"
@@ -2277,7 +2332,7 @@ __metadata:
resolution: "@standardnotes/revisions-server@workspace:packages/revisions" resolution: "@standardnotes/revisions-server@workspace:packages/revisions"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/api": "npm:^1.19.0" "@standardnotes/api": "npm:^1.19.0"
"@standardnotes/common": "workspace:^" "@standardnotes/common": "workspace:^"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"
@@ -2320,7 +2375,7 @@ __metadata:
resolution: "@standardnotes/scheduler-server@workspace:packages/scheduler" resolution: "@standardnotes/scheduler-server@workspace:packages/scheduler"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"
"@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events": "workspace:*"
@@ -2377,7 +2432,7 @@ __metadata:
"@lerna-lite/cli": "npm:^1.5.1" "@lerna-lite/cli": "npm:^1.5.1"
"@lerna-lite/list": "npm:^1.5.1" "@lerna-lite/list": "npm:^1.5.1"
"@lerna-lite/run": "npm:^1.5.1" "@lerna-lite/run": "npm:^1.5.1"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@types/jest": "npm:^29.1.1" "@types/jest": "npm:^29.1.1"
"@types/newrelic": "npm:^7.0.4" "@types/newrelic": "npm:^7.0.4"
"@types/node": "npm:^18.11.9" "@types/node": "npm:^18.11.9"
@@ -2436,9 +2491,9 @@ __metadata:
resolution: "@standardnotes/syncing-server@workspace:packages/syncing-server" resolution: "@standardnotes/syncing-server@workspace:packages/syncing-server"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@sentry/profiling-node": "npm:^0.0.12" "@sentry/profiling-node": "npm:^0.0.12"
"@sentry/tracing": "npm:^7.27.0" "@sentry/tracing": "npm:^7.28.1"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"
"@standardnotes/domain-events": "workspace:*" "@standardnotes/domain-events": "workspace:*"
@@ -2534,7 +2589,7 @@ __metadata:
resolution: "@standardnotes/websockets-server@workspace:packages/websockets" resolution: "@standardnotes/websockets-server@workspace:packages/websockets"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/api": "npm:^1.19.0" "@standardnotes/api": "npm:^1.19.0"
"@standardnotes/common": "workspace:^" "@standardnotes/common": "workspace:^"
"@standardnotes/domain-events": "workspace:^" "@standardnotes/domain-events": "workspace:^"
@@ -2572,7 +2627,7 @@ __metadata:
resolution: "@standardnotes/workspace-server@workspace:packages/workspace" resolution: "@standardnotes/workspace-server@workspace:packages/workspace"
dependencies: dependencies:
"@newrelic/winston-enricher": "npm:^4.0.0" "@newrelic/winston-enricher": "npm:^4.0.0"
"@sentry/node": "npm:^7.27.0" "@sentry/node": "npm:^7.28.1"
"@standardnotes/api": "npm:^1.19.0" "@standardnotes/api": "npm:^1.19.0"
"@standardnotes/common": "workspace:*" "@standardnotes/common": "workspace:*"
"@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-core": "workspace:^"