Compare commits

..

53 Commits

Author SHA1 Message Date
standardci fba6cfd62c chore(release): publish new version
- @standardnotes/event-store@1.1.31
2022-08-12 10:07:02 +00:00
Karol Sójko 1ba5ba5ff6 fix(event-store): add listening to offline subscription token created events 2022-08-12 12:05:19 +02:00
standardci 31b6988f17 chore(release): publish new version
- @standardnotes/analytics@1.15.0
 - @standardnotes/api-gateway@1.13.0
 - @standardnotes/auth-server@1.17.0
 - @standardnotes/syncing-server@1.6.43
2022-08-11 07:28:16 +00:00
Karol Sójko 16076382ba feat: add analytics for subscription cancelling, refunding and account deletion 2022-08-11 09:26:21 +02:00
standardci 666c919b70 chore(release): publish new version
- @standardnotes/api-gateway@1.12.0
2022-08-10 13:44:58 +00:00
Karol Sójko dea5fd717d feat(api-gateway): add publishing subscription purchased, renewed and registration analytics 2022-08-10 15:43:30 +02:00
standardci 02a4b6f721 chore(release): publish new version
- @standardnotes/api-gateway@1.11.5
 - @standardnotes/auth-server@1.16.2
 - @standardnotes/domain-events-infra@1.7.31
 - @standardnotes/event-store@1.1.30
 - @standardnotes/files-server@1.5.33
 - @standardnotes/scheduler-server@1.10.7
 - @standardnotes/syncing-server@1.6.42
2022-08-10 09:29:01 +00:00
Karol Sójko 815a6c4e3b chore(dep): upgrade newrelic version 2022-08-10 11:27:30 +02:00
standardci ac26024990 chore(release): publish new version
- @standardnotes/auth-server@1.16.1
2022-08-10 09:21:31 +00:00
Karol Sójko f67be9d3ba fix(auth): docker entrypoing command for single user backup 2022-08-10 11:19:53 +02:00
standardci bb85e3ef11 chore(release): publish new version
- @standardnotes/auth-server@1.16.0
2022-08-10 09:19:42 +00:00
Karol Sójko edd254531d feat(auth): add triggering email backup for a single user 2022-08-10 11:18:01 +02:00
standardci 0f1ff97a60 chore(release): publish new version
- @standardnotes/analytics@1.14.0
 - @standardnotes/api-gateway@1.11.4
 - @standardnotes/auth-server@1.15.0
 - @standardnotes/syncing-server@1.6.41
2022-08-09 18:49:11 +00:00
Karol Sójko 24e439f017 feat(auth): add subscription events to analytics 2022-08-09 20:47:29 +02:00
standardci 0a01fd58eb chore(release): publish new version
- @standardnotes/analytics@1.13.0
 - @standardnotes/api-gateway@1.11.3
 - @standardnotes/auth-server@1.14.0
 - @standardnotes/syncing-server@1.6.40
2022-08-09 18:20:44 +00:00
Karol Sójko f25195b2c1 feat(auth): track registration in analytics 2022-08-09 20:18:53 +02:00
standardci 29674b02e6 chore(release): publish new version
- @standardnotes/analytics@1.12.2
 - @standardnotes/api-gateway@1.11.2
 - @standardnotes/auth-server@1.13.6
 - @standardnotes/syncing-server@1.6.39
2022-08-09 13:24:49 +00:00
Karol Sójko 572ea3febe fix(analytics): replace AND to OR operation on bitop 2022-08-09 15:23:10 +02:00
standardci f8334cf9d2 chore(release): publish new version
- @standardnotes/analytics@1.12.1
 - @standardnotes/api-gateway@1.11.1
 - @standardnotes/auth-server@1.13.5
 - @standardnotes/syncing-server@1.6.38
2022-08-09 13:00:18 +00:00
Karol Sójko 0ffec66bea fix(analytics): bitop over analytics time 2022-08-09 14:58:37 +02:00
standardci becb386d10 chore(release): publish new version
- @standardnotes/analytics@1.12.0
 - @standardnotes/api-gateway@1.11.0
 - @standardnotes/auth-server@1.13.4
 - @standardnotes/domain-events-infra@1.7.30
 - @standardnotes/domain-events@2.53.0
 - @standardnotes/event-store@1.1.29
 - @standardnotes/files-server@1.5.32
 - @standardnotes/scheduler-server@1.10.6
 - @standardnotes/syncing-server@1.6.37
2022-08-09 12:23:19 +00:00
Karol Sójko 0b9524eb26 feat: add total count of analytics over time 2022-08-09 14:21:04 +02:00
standardci ff5cd0128a chore(release): publish new version
- @standardnotes/api-gateway@1.10.0
2022-08-09 11:08:58 +00:00
Karol Sójko b9225cd9b6 feat(api-gateway): add editing items count over time 2022-08-09 13:07:26 +02:00
standardci 8f0ed3c5b3 chore(release): publish new version
- @standardnotes/api-gateway@1.9.1
2022-08-08 19:11:13 +00:00
Karol Sójko 12e3a768dd fix(api-gateway): add general activity to calculating activity retention 2022-08-08 21:09:11 +02:00
standardci a04ab5b0e8 chore(release): publish new version
- @standardnotes/analytics@1.11.0
 - @standardnotes/api-gateway@1.9.0
 - @standardnotes/auth-server@1.13.3
 - @standardnotes/domain-events-infra@1.7.29
 - @standardnotes/domain-events@2.52.0
 - @standardnotes/event-store@1.1.28
 - @standardnotes/files-server@1.5.31
 - @standardnotes/scheduler-server@1.10.5
 - @standardnotes/syncing-server@1.6.36
2022-08-08 19:07:09 +00:00
Karol Sójko 845f08b060 feat(api-gateway): add analytics over time to daily report event 2022-08-08 21:05:31 +02:00
Karol Sójko 31c849cc2d fix(analytics): format of changes over time to total count 2022-08-08 21:04:54 +02:00
Karol Sójko 977757d346 feat(analytics): add calculating analytics over time 2022-08-08 20:48:18 +02:00
standardci f2c549158d chore(release): publish new version
- @standardnotes/analytics@1.10.0
 - @standardnotes/api-gateway@1.8.0
 - @standardnotes/auth-server@1.13.2
 - @standardnotes/syncing-server@1.6.35
2022-08-08 18:16:43 +00:00
Karol Sójko a36764f1b0 feat(api-gateway): add marking server interaction as general activity in analytics 2022-08-08 20:14:55 +02:00
standardci 033bc25d8f chore(release): publish new version
- @standardnotes/api-gateway@1.7.4
 - @standardnotes/auth-server@1.13.1
 - @standardnotes/scheduler-server@1.10.4
 - @standardnotes/syncing-server@1.6.34
2022-07-29 09:40:04 +00:00
Karol Sójko 31bd253a73 chore(deps): fix newrelic winston enricher initialization 2022-07-29 11:38:03 +02:00
standardci 2f4977be63 chore(release): publish new version
- @standardnotes/auth-server@1.13.0
2022-07-29 07:09:52 +00:00
Karol Sójko 35f931a708 feat(auth): remove crypto-random-string in favour of @standardnotes/sncrypto-node 2022-07-29 09:08:22 +02:00
standardci 3e23d8d5d5 chore(release): publish new version
- @standardnotes/api-gateway@1.7.3
 - @standardnotes/auth-server@1.12.2
 - @standardnotes/scheduler-server@1.10.3
 - @standardnotes/syncing-server@1.6.33
2022-07-29 06:35:21 +00:00
Karol Sójko 004de0a655 chore(deps): upgrade @newrelic/winston-enricher 2022-07-29 08:33:29 +02:00
standardci 47a1af4be1 chore(release): publish new version
- @standardnotes/scheduler-server@1.10.2
2022-07-29 06:30:08 +00:00
Karol Sójko 7b17c4caa8 chore(deps): upgrade inversify 2022-07-29 08:27:57 +02:00
standardci fa29885b3f chore(release): publish new version
- @standardnotes/api-gateway@1.7.2
 - @standardnotes/files-server@1.5.30
 - @standardnotes/syncing-server@1.6.32
2022-07-27 11:40:47 +00:00
Karol Sójko beece69f9e chore(deps): upgrade helmet 2022-07-27 13:39:19 +02:00
standardci 600ff1d62b chore(release): publish new version
- @standardnotes/api-gateway@1.7.1
 - @standardnotes/auth-server@1.12.1
 - @standardnotes/files-server@1.5.29
 - @standardnotes/scheduler-server@1.10.1
 - @standardnotes/syncing-server@1.6.31
2022-07-27 11:14:05 +00:00
Karol Sójko 094dc192a9 chore(deps): upgrade npm-check-updates 2022-07-27 13:12:25 +02:00
standardci 939bf30138 chore(release): publish new version
- @standardnotes/api-gateway@1.7.0
2022-07-26 13:00:56 +00:00
Karol Sójko d203ce188a feat(api-gateway): add limited discount offer purchased to analytics report 2022-07-26 14:59:23 +02:00
standardci 268fed19f9 chore(release): publish new version
- @standardnotes/analytics@1.9.0
 - @standardnotes/api-gateway@1.6.30
 - @standardnotes/auth-server@1.12.0
 - @standardnotes/domain-events-infra@1.7.28
 - @standardnotes/domain-events@2.51.0
 - @standardnotes/event-store@1.1.27
 - @standardnotes/files-server@1.5.28
 - @standardnotes/scheduler-server@1.10.0
 - @standardnotes/syncing-server@1.6.30
2022-07-26 11:54:06 +00:00
Karol Sójko 04bf414de4 feat(scheduler): enable discount applying and withdraw for everyone 2022-07-26 13:52:34 +02:00
Karol Sójko 28e1c65631 feat(domain-events): add discount code to subscription purchased event 2022-07-26 13:52:34 +02:00
Karol Sójko e936ac4ce1 feat(auth): add analytics for purchased subscription with a limited discount offer 2022-07-26 13:52:34 +02:00
Karol Sójko 13201e7a9e feat(analytics): add limited discount offer purchased activity 2022-07-26 13:52:34 +02:00
standardci 9740b28764 chore(release): publish new version
- @standardnotes/scheduler-server@1.9.2
2022-07-26 10:37:12 +00:00
Karol Sójko 1fa94efa02 fix(scheduler): change the discount code to an absolute discount 2022-07-26 12:35:16 +02:00
128 changed files with 1316 additions and 324 deletions
Generated
+69 -104
View File
@@ -121,8 +121,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint", "npm:8.19.0"],\
["eslint-config-prettier", "virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:8.5.0"],\
["ini", "npm:3.0.0"],\
["newrelic", "npm:8.14.1"],\
["npm-check-updates", "npm:15.3.3"],\
["newrelic", "npm:9.0.0"],\
["npm-check-updates", "npm:16.0.1"],\
["prettier", "npm:2.7.1"],\
["ts-node", "virtual:c0eab07e71af57f5501e97e7ca7a2a4f4965035bd2455ad124a8b09fa55780657c55fe3df41019fa6c2c44487c897668c842a0939e380b3c1f13b3756d128543#npm:10.8.2"],\
["typescript", "patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353"]\
@@ -1788,20 +1788,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@newrelic/aws-sdk", [\
["npm:4.1.2", {\
"packageLocation": "./.yarn/cache/@newrelic-aws-sdk-npm-4.1.2-9930120a02-610f6353a7.zip/node_modules/@newrelic/aws-sdk/",\
["npm:5.0.0", {\
"packageLocation": "./.yarn/cache/@newrelic-aws-sdk-npm-5.0.0-7d9d10d58f-b467b7306f.zip/node_modules/@newrelic/aws-sdk/",\
"packageDependencies": [\
["@newrelic/aws-sdk", "npm:4.1.2"]\
["@newrelic/aws-sdk", "npm:5.0.0"]\
],\
"linkType": "SOFT"\
}],\
["virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:4.1.2", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-aws-sdk-virtual-a259cc13ec/0/cache/@newrelic-aws-sdk-npm-4.1.2-9930120a02-610f6353a7.zip/node_modules/@newrelic/aws-sdk/",\
["virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:5.0.0", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-aws-sdk-virtual-e9040e4121/0/cache/@newrelic-aws-sdk-npm-5.0.0-7d9d10d58f-b467b7306f.zip/node_modules/@newrelic/aws-sdk/",\
"packageDependencies": [\
["@newrelic/aws-sdk", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:4.1.2"],\
["@newrelic/aws-sdk", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:5.0.0"],\
["@types/newrelic", null],\
["newrelic", "npm:8.14.1"],\
["semver", "npm:7.3.7"]\
["newrelic", "npm:9.0.0"]\
],\
"packagePeers": [\
"@types/newrelic",\
@@ -1811,19 +1810,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@newrelic/koa", [\
["npm:6.1.2", {\
"packageLocation": "./.yarn/cache/@newrelic-koa-npm-6.1.2-df0f7c71b5-e269d37b13.zip/node_modules/@newrelic/koa/",\
["npm:7.0.0", {\
"packageLocation": "./.yarn/cache/@newrelic-koa-npm-7.0.0-903c251b9f-13fb2bf0df.zip/node_modules/@newrelic/koa/",\
"packageDependencies": [\
["@newrelic/koa", "npm:6.1.2"]\
["@newrelic/koa", "npm:7.0.0"]\
],\
"linkType": "SOFT"\
}],\
["virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:6.1.2", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-koa-virtual-2df93240b5/0/cache/@newrelic-koa-npm-6.1.2-df0f7c71b5-e269d37b13.zip/node_modules/@newrelic/koa/",\
["virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:7.0.0", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-koa-virtual-d6376894e6/0/cache/@newrelic-koa-npm-7.0.0-903c251b9f-13fb2bf0df.zip/node_modules/@newrelic/koa/",\
"packageDependencies": [\
["@newrelic/koa", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:6.1.2"],\
["@newrelic/koa", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:7.0.0"],\
["@types/newrelic", null],\
["newrelic", "npm:8.14.1"]\
["newrelic", "npm:9.0.0"]\
],\
"packagePeers": [\
"@types/newrelic",\
@@ -1833,10 +1832,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@newrelic/native-metrics", [\
["npm:8.0.0", {\
"packageLocation": "./.yarn/unplugged/@newrelic-native-metrics-npm-8.0.0-c254393d6e/node_modules/@newrelic/native-metrics/",\
["npm:9.0.0", {\
"packageLocation": "./.yarn/unplugged/@newrelic-native-metrics-npm-9.0.0-590d2e713a/node_modules/@newrelic/native-metrics/",\
"packageDependencies": [\
["@newrelic/native-metrics", "npm:8.0.0"],\
["@newrelic/native-metrics", "npm:9.0.0"],\
["https-proxy-agent", "npm:5.0.1"],\
["nan", "npm:2.16.0"],\
["node-gyp", "npm:9.0.0"],\
@@ -1846,19 +1845,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@newrelic/superagent", [\
["npm:5.1.1", {\
"packageLocation": "./.yarn/cache/@newrelic-superagent-npm-5.1.1-0d3c1fccf8-b43f7b9bb6.zip/node_modules/@newrelic/superagent/",\
["npm:6.0.0", {\
"packageLocation": "./.yarn/cache/@newrelic-superagent-npm-6.0.0-db8b77d0f3-d9e9b20d75.zip/node_modules/@newrelic/superagent/",\
"packageDependencies": [\
["@newrelic/superagent", "npm:5.1.1"]\
["@newrelic/superagent", "npm:6.0.0"]\
],\
"linkType": "SOFT"\
}],\
["virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:5.1.1", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-superagent-virtual-d7de4099d8/0/cache/@newrelic-superagent-npm-5.1.1-0d3c1fccf8-b43f7b9bb6.zip/node_modules/@newrelic/superagent/",\
["virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:6.0.0", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-superagent-virtual-c2a5d7b8a8/0/cache/@newrelic-superagent-npm-6.0.0-db8b77d0f3-d9e9b20d75.zip/node_modules/@newrelic/superagent/",\
"packageDependencies": [\
["@newrelic/superagent", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:5.1.1"],\
["@newrelic/superagent", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:6.0.0"],\
["@types/newrelic", null],\
["newrelic", "npm:8.14.1"]\
["newrelic", "npm:9.0.0"]\
],\
"packagePeers": [\
"@types/newrelic",\
@@ -1868,27 +1867,23 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["@newrelic/winston-enricher", [\
["npm:2.1.2", {\
"packageLocation": "./.yarn/cache/@newrelic-winston-enricher-npm-2.1.2-732878a1b2-d001c13166.zip/node_modules/@newrelic/winston-enricher/",\
["npm:4.0.0", {\
"packageLocation": "./.yarn/cache/@newrelic-winston-enricher-npm-4.0.0-ebaf2d0d28-f737e7d952.zip/node_modules/@newrelic/winston-enricher/",\
"packageDependencies": [\
["@newrelic/winston-enricher", "npm:2.1.2"]\
["@newrelic/winston-enricher", "npm:4.0.0"]\
],\
"linkType": "SOFT"\
}],\
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-winston-enricher-virtual-193127fbcd/0/cache/@newrelic-winston-enricher-npm-2.1.2-732878a1b2-d001c13166.zip/node_modules/@newrelic/winston-enricher/",\
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0", {\
"packageLocation": "./.yarn/__virtual__/@newrelic-winston-enricher-virtual-766a341e22/0/cache/@newrelic-winston-enricher-npm-4.0.0-ebaf2d0d28-f737e7d952.zip/node_modules/@newrelic/winston-enricher/",\
"packageDependencies": [\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
["@types/newrelic", "npm:7.0.3"],\
["@types/winston", null],\
["newrelic", "npm:8.14.1"],\
["winston", "npm:3.8.1"]\
["newrelic", "npm:9.0.0"]\
],\
"packagePeers": [\
"@types/newrelic",\
"@types/winston",\
"newrelic",\
"winston"\
"newrelic"\
],\
"linkType": "HARD"\
}]\
@@ -2508,7 +2503,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/api-gateway/",\
"packageDependencies": [\
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
["@sentry/node", "npm:7.5.0"],\
["@standardnotes/analytics", "workspace:packages/analytics"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -2530,15 +2525,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint", "npm:8.19.0"],\
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
["express", "npm:4.18.1"],\
["helmet", "npm:4.4.1"],\
["helmet", "npm:5.1.1"],\
["inversify", "npm:6.0.1"],\
["inversify-express-utils", "npm:6.4.3"],\
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["jsonwebtoken", "npm:8.5.1"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["nodemon", "npm:2.0.19"],\
["npm-check-updates", "npm:15.3.3"],\
["npm-check-updates", "npm:16.0.1"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
@@ -2563,7 +2558,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/auth/",\
"packageDependencies": [\
["@standardnotes/auth-server", "workspace:packages/auth"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
["@sentry/node", "npm:7.5.0"],\
["@standardnotes/analytics", "workspace:packages/analytics"],\
["@standardnotes/api", "npm:1.1.19"],\
@@ -2593,7 +2588,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["axios", "npm:0.27.2"],\
["bcryptjs", "npm:2.4.3"],\
["cors", "npm:2.8.5"],\
["crypto-random-string", "npm:3.3.0"],\
["dayjs", "npm:1.11.3"],\
["dotenv", "npm:16.0.1"],\
["eslint", "npm:8.19.0"],\
@@ -2604,9 +2598,9 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["mysql2", "npm:2.3.3"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["nodemon", "npm:2.0.19"],\
["npm-check-updates", "npm:15.3.3"],\
["npm-check-updates", "npm:16.0.1"],\
["otplib", "npm:12.0.1"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
@@ -2682,7 +2676,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["reflect-metadata", "npm:0.1.13"],\
["sqs-consumer", "virtual:685a6222c3349423674bb7f0684ba34e2ab20912010f352e04dcf707a156e13183fc382e2417cb37a60f3e7b52fd0178c53181674890e1773eb83e190dc13378#npm:5.7.0"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
@@ -2728,7 +2722,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["mysql2", "npm:2.3.3"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["reflect-metadata", "npm:0.1.13"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.7"],\
@@ -2782,15 +2776,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
["express", "npm:4.18.1"],\
["express-winston", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:4.2.0"],\
["helmet", "npm:4.6.0"],\
["helmet", "npm:5.1.1"],\
["inversify", "npm:6.0.1"],\
["inversify-express-utils", "npm:6.4.3"],\
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["jsonwebtoken", "npm:8.5.1"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["nodemon", "npm:2.0.19"],\
["npm-check-updates", "npm:15.3.3"],\
["npm-check-updates", "npm:16.0.1"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
@@ -2861,7 +2855,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/scheduler/",\
"packageDependencies": [\
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
["@sentry/node", "npm:7.5.0"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
@@ -2877,12 +2871,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["dayjs", "npm:1.11.3"],\
["dotenv", "npm:16.0.1"],\
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
["inversify", "npm:5.0.5"],\
["inversify", "npm:6.0.1"],\
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["mysql2", "npm:2.3.3"],\
["newrelic", "npm:8.14.1"],\
["npm-check-updates", "npm:15.3.3"],\
["newrelic", "npm:9.0.0"],\
["npm-check-updates", "npm:16.0.1"],\
["reflect-metadata", "npm:0.1.13"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.7"],\
@@ -2927,8 +2921,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint", "npm:8.19.0"],\
["eslint-config-prettier", "virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:8.5.0"],\
["ini", "npm:3.0.0"],\
["newrelic", "npm:8.14.1"],\
["npm-check-updates", "npm:15.3.3"],\
["newrelic", "npm:9.0.0"],\
["npm-check-updates", "npm:16.0.1"],\
["prettier", "npm:2.7.1"],\
["ts-node", "virtual:c0eab07e71af57f5501e97e7ca7a2a4f4965035bd2455ad124a8b09fa55780657c55fe3df41019fa6c2c44487c897668c842a0939e380b3c1f13b3756d128543#npm:10.8.2"],\
["typescript", "patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353"]\
@@ -2996,7 +2990,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/syncing-server/",\
"packageDependencies": [\
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
["@sentry/node", "npm:7.5.0"],\
["@standardnotes/analytics", "workspace:packages/analytics"],\
["@standardnotes/common", "workspace:packages/common"],\
@@ -3026,16 +3020,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint", "npm:8.19.0"],\
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
["express", "npm:4.18.1"],\
["helmet", "npm:4.3.1"],\
["helmet", "npm:5.1.1"],\
["inversify", "npm:6.0.1"],\
["inversify-express-utils", "npm:6.4.3"],\
["ioredis", "npm:5.2.0"],\
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
["jsonwebtoken", "npm:8.5.1"],\
["mysql2", "npm:2.3.3"],\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["nodemon", "npm:2.0.19"],\
["npm-check-updates", "npm:15.3.3"],\
["npm-check-updates", "npm:16.0.1"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
@@ -5513,14 +5507,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["crypto-random-string", [\
["npm:3.3.0", {\
"packageLocation": "./.yarn/cache/crypto-random-string-npm-3.3.0-4f73472f10-deff986631.zip/node_modules/crypto-random-string/",\
"packageDependencies": [\
["crypto-random-string", "npm:3.3.0"],\
["type-fest", "npm:0.8.1"]\
],\
"linkType": "HARD"\
}],\
["npm:4.0.0", {\
"packageLocation": "./.yarn/cache/crypto-random-string-npm-4.0.0-b9f0f76168-91f148f27b.zip/node_modules/crypto-random-string/",\
"packageDependencies": [\
@@ -7233,24 +7219,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["helmet", [\
["npm:4.3.1", {\
"packageLocation": "./.yarn/cache/helmet-npm-4.3.1-22cd4b53d2-47f59d8b99.zip/node_modules/helmet/",\
["npm:5.1.1", {\
"packageLocation": "./.yarn/cache/helmet-npm-5.1.1-d12265628c-b72ba26cc4.zip/node_modules/helmet/",\
"packageDependencies": [\
["helmet", "npm:4.3.1"]\
],\
"linkType": "HARD"\
}],\
["npm:4.4.1", {\
"packageLocation": "./.yarn/cache/helmet-npm-4.4.1-286ac392ee-cfe385e185.zip/node_modules/helmet/",\
"packageDependencies": [\
["helmet", "npm:4.4.1"]\
],\
"linkType": "HARD"\
}],\
["npm:4.6.0", {\
"packageLocation": "./.yarn/cache/helmet-npm-4.6.0-f244fd965c-139ad678d1.zip/node_modules/helmet/",\
"packageDependencies": [\
["helmet", "npm:4.6.0"]\
["helmet", "npm:5.1.1"]\
],\
"linkType": "HARD"\
}]\
@@ -7578,13 +7550,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["inversify", [\
["npm:5.0.5", {\
"packageLocation": "./.yarn/cache/inversify-npm-5.0.5-4d1f1420a9-a4bf1a6a62.zip/node_modules/inversify/",\
"packageDependencies": [\
["inversify", "npm:5.0.5"]\
],\
"linkType": "HARD"\
}],\
["npm:6.0.1", {\
"packageLocation": "./.yarn/cache/inversify-npm-6.0.1-39ef6784da-b6c9b56ef7.zip/node_modules/inversify/",\
"packageDependencies": [\
@@ -9574,16 +9539,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["newrelic", [\
["npm:8.14.1", {\
"packageLocation": "./.yarn/cache/newrelic-npm-8.14.1-b659d4d19c-cd12bb2ac9.zip/node_modules/newrelic/",\
["npm:9.0.0", {\
"packageLocation": "./.yarn/cache/newrelic-npm-9.0.0-65e8703d5d-e92af072fd.zip/node_modules/newrelic/",\
"packageDependencies": [\
["newrelic", "npm:8.14.1"],\
["newrelic", "npm:9.0.0"],\
["@grpc/grpc-js", "npm:1.6.7"],\
["@grpc/proto-loader", "npm:0.6.13"],\
["@newrelic/aws-sdk", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:4.1.2"],\
["@newrelic/koa", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:6.1.2"],\
["@newrelic/native-metrics", "npm:8.0.0"],\
["@newrelic/superagent", "virtual:b659d4d19ce37732618223b586685dc7b27d11c52dca80d8411fdda38a4e6a7967776a5d7bdcce0be779cd6a41e2d84f8bbd3d3b5c06ce5ae40ad814517dfcfb#npm:5.1.1"],\
["@newrelic/aws-sdk", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:5.0.0"],\
["@newrelic/koa", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:7.0.0"],\
["@newrelic/native-metrics", "npm:9.0.0"],\
["@newrelic/superagent", "virtual:65e8703d5df08d5ff3f7296fcb759f276254ee430ae6f3cc1f03da392ff63066a3c6c59591c38f36f19d3e877285287a834b5c55e22d764dc2cb0938f7128707#npm:6.0.0"],\
["@tyriar/fibonacci-heap", "npm:2.0.9"],\
["async", "npm:3.2.4"],\
["concat-stream", "npm:2.0.0"],\
@@ -9776,10 +9741,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["npm-check-updates", [\
["npm:15.3.3", {\
"packageLocation": "./.yarn/cache/npm-check-updates-npm-15.3.3-146d2ff74b-3ee33fe369.zip/node_modules/npm-check-updates/",\
["npm:16.0.1", {\
"packageLocation": "./.yarn/cache/npm-check-updates-npm-16.0.1-fd143fcd27-1e747421f3.zip/node_modules/npm-check-updates/",\
"packageDependencies": [\
["npm-check-updates", "npm:15.3.3"],\
["npm-check-updates", "npm:16.0.1"],\
["chalk", "npm:5.0.1"],\
["cli-table", "npm:0.3.11"],\
["commander", "npm:9.3.0"],\
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,17 @@
### v9.0.0 (2022-08-01)
* **BREAKING** Removed support for Node 12.
The minimum supported version is now Node v14. For further information on our support policy, see: https://docs.newrelic.com/docs/agents/nodejs-agent/getting-started/compatibility-requirements-nodejs-agent.
* Added support for Node 18.
* Fixed GC binder to properly record Garbage Collection metrics in Node 18.
* Resolved several dev-dependency audit warnings.
* Bumped minimum `nan` version to ^2.16.0.
### v8.0.0 (2022-03-22)
* **BREAKING** Removed RUSageMeter. This was used to get resource usage statistics via `libuv`. It is no longer needed since Node.js version 12 has support via `process.cpuUsage`.
@@ -59,16 +59,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
### nan
This product includes source derived from [nan](https://github.com/nodejs/nan) ([v2.15.0](https://github.com/nodejs/nan/tree/v2.15.0)), distributed under the [MIT License](https://github.com/nodejs/nan/blob/v2.15.0/LICENSE.md):
This product includes source derived from [nan](https://github.com/nodejs/nan) ([v2.16.0](https://github.com/nodejs/nan/tree/v2.16.0)), distributed under the [MIT License](https://github.com/nodejs/nan/blob/v2.16.0/LICENSE.md):
```
The MIT License (MIT)
=====================
Copyright (c) 2018 NAN contributors
-----------------------------------
*NAN contributors listed at <https://github.com/nodejs/nan#contributors>*
Copyright (c) 2018 [NAN contributors](<https://github.com/nodejs/nan#wg-members--collaborators>)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -106,7 +102,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
### @newrelic/eslint-config
This product includes source derived from [@newrelic/eslint-config](https://github.com/newrelic/eslint-config-newrelic) ([v0.0.2](https://github.com/newrelic/eslint-config-newrelic/tree/v0.0.2)), distributed under the [Apache-2.0 License](https://github.com/newrelic/eslint-config-newrelic/blob/v0.0.2/LICENSE):
This product includes source derived from [@newrelic/eslint-config](https://github.com/newrelic/eslint-config-newrelic) ([v0.0.4](https://github.com/newrelic/eslint-config-newrelic/tree/v0.0.4)), distributed under the [Apache-2.0 License](https://github.com/newrelic/eslint-config-newrelic/blob/v0.0.4/LICENSE):
```
Apache License
@@ -539,7 +535,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
### async
This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.0](https://github.com/caolan/async/tree/v3.2.0)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.0/LICENSE):
This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.3](https://github.com/caolan/async/tree/v3.2.3)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.3/LICENSE):
```
Copyright (c) 2010-2018 Caolan McMahon
@@ -1081,12 +1077,12 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
### tap
This product includes source derived from [tap](https://github.com/tapjs/node-tap) ([v15.0.9](https://github.com/tapjs/node-tap/tree/v15.0.9)), distributed under the [ISC License](https://github.com/tapjs/node-tap/blob/v15.0.9/LICENSE):
This product includes source derived from [tap](https://github.com/tapjs/node-tap) ([v16.0.1](https://github.com/tapjs/node-tap/tree/v16.0.1)), distributed under the [ISC License](https://github.com/tapjs/node-tap/blob/v16.0.1/LICENSE):
```
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Copyright (c) 2011-2022 Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -326,8 +326,8 @@ ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
endif
quiet_cmd_regen_makefile = ACTION Regenerating $@
cmd_regen_makefile = cd $(srcdir); /Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/karolsojko/Library/Caches/node-gyp/16.15.1" "-Dnode_gyp_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp" "-Dnode_lib_file=/Users/karolsojko/Library/Caches/node-gyp/16.15.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-8.0.0-c254393d6e/node_modules/@newrelic/native-metrics" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-8.0.0-c254393d6e/node_modules/@newrelic/native-metrics/build/config.gypi -I/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi -I/Users/karolsojko/Library/Caches/node-gyp/16.15.1/include/node/common.gypi "--toplevel-dir=." binding.gyp
Makefile: $(srcdir)/../../../../node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../../../../Library/Caches/node-gyp/16.15.1/include/node/common.gypi $(srcdir)/binding.gyp $(srcdir)/build/config.gypi
cmd_regen_makefile = cd $(srcdir); /Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/karolsojko/Library/Caches/node-gyp/16.15.1" "-Dnode_gyp_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp" "-Dnode_lib_file=/Users/karolsojko/Library/Caches/node-gyp/16.15.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-9.0.0-590d2e713a/node_modules/@newrelic/native-metrics" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-9.0.0-590d2e713a/node_modules/@newrelic/native-metrics/build/config.gypi -I/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi -I/Users/karolsojko/Library/Caches/node-gyp/16.15.1/include/node/common.gypi "--toplevel-dir=." binding.gyp
Makefile: $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../Library/Caches/node-gyp/16.15.1/include/node/common.gypi $(srcdir)/build/config.gypi $(srcdir)/../../../../node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi
$(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
@@ -5,20 +5,36 @@
'use strict'
var EventEmitter = require('events').EventEmitter
var util = require('util')
var preBuild = require('./lib/pre-build')
var natives = preBuild.load('native_metrics')
const EventEmitter = require('events').EventEmitter
const util = require('util')
const preBuild = require('./lib/pre-build')
const natives = preBuild.load('native_metrics')
const semver = require('semver')
var DEFAULT_TIMEOUT = 15 * 1000 // 15 seconds
var GC_TYPE_NAMES = {
1: 'Scavenge',
2: 'MarkSweepCompact',
4: 'IncrementalMarking',
8: 'ProcessWeakCallbacks',
const DEFAULT_TIMEOUT = 15 * 1000 // 15 seconds
let GC_TYPE_NAMES = null
3: 'All', // Node v4 and earlier only have Scavenge and MarkSweepCompact.
15: 'All'
// In Node 18(v8 10) the GCType enum added `MinorMarkCompact`
// we have to update our mapping to properly account for this
if (semver.satisfies(process.version, '>=18')) {
GC_TYPE_NAMES = {
1: 'Scavenge',
2: 'MinorMarkCompact',
4: 'MarkSweepCompact',
8: 'IncrementalMarking',
16: 'ProcessWeakCallbacks',
31: 'All'
}
} else {
GC_TYPE_NAMES = {
1: 'Scavenge',
2: 'MarkSweepCompact',
4: 'IncrementalMarking',
8: 'ProcessWeakCallbacks',
3: 'All', // Node v4 and earlier only have Scavenge and MarkSweepCompact.
15: 'All'
}
}
/**
@@ -135,11 +151,11 @@ NativeMetricEmitter.prototype.getLoopMetrics = function getLoopMetrics() {
* information on the GC events that happened.
*/
NativeMetricEmitter.prototype.getGCMetrics = function getGCMetrics() {
var gcMetrics = this._gcBinder.read()
var results = Object.create(null)
for (var typeId in gcMetrics) {
const gcMetrics = this._gcBinder.read()
const results = Object.create(null)
for (const typeId in gcMetrics) {
if (gcMetrics.hasOwnProperty(typeId) && gcMetrics[typeId].count > 0) {
var typeName = GC_TYPE_NAMES[String(typeId)]
const typeName = GC_TYPE_NAMES[String(typeId)]
results[typeName] = {
typeId: parseInt(typeId, 10),
type: typeName,
@@ -151,7 +167,7 @@ NativeMetricEmitter.prototype.getGCMetrics = function getGCMetrics() {
return results
}
var emitter = null
let emitter = null
/**
* Retrieves the {@link NativeMetricEmitter} singleton instance.
@@ -237,8 +237,8 @@ function download(target, cb) {
return cb(new Error('Failed to download ' + url + ': code ' + res.statusCode))
}
var unzip = zlib.createGunzip()
var buffers = []
const unzip = zlib.createGunzip()
const buffers = []
let size = 0
res.pipe(unzip).on('data', function onResData(data) {
buffers.push(data)
@@ -1,6 +1,6 @@
{
"name": "@newrelic/native-metrics",
"version": "8.0.0",
"version": "9.0.0",
"description": "A module for generating metrics from V8.",
"main": "index.js",
"scripts": {
@@ -73,14 +73,14 @@
],
"license": "Apache-2.0",
"engines": {
"node": ">=12",
"node": ">=14",
"npm": ">=6"
},
"devDependencies": {
"@newrelic/eslint-config": "^0.0.2",
"@newrelic/eslint-config": "^0.0.4",
"@newrelic/newrelic-oss-cli": "^0.1.2",
"@newrelic/proxy": "^2.0.0",
"async": "^3.2.0",
"async": "^3.2.2",
"aws-sdk": "^2.266.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
@@ -93,11 +93,11 @@
"prettier": "^2.3.2",
"segfault-handler": "^1.3.0",
"sinon": "^11.1.2",
"tap": "^15.0.9"
"tap": "^16.0.1"
},
"dependencies": {
"https-proxy-agent": "^5.0.0",
"nan": "^2.15.0",
"nan": "^2.16.0",
"semver": "^5.5.1"
},
"files": [
+2 -2
View File
@@ -58,7 +58,7 @@
"eslint": "^8.17.0",
"eslint-config-prettier": "^8.5.0",
"ini": "^3.0.0",
"npm-check-updates": "^15.3.3",
"npm-check-updates": "^16.0.1",
"prettier": "^2.7.1",
"ts-node": "^10.8.1",
"typescript": "^4.7.4"
@@ -66,6 +66,6 @@
"packageManager": "yarn@3.2.1",
"dependencies": {
"@sentry/node": "^7.3.0",
"newrelic": "^8.14.1"
"newrelic": "^9.0.0"
}
}
+58
View File
@@ -3,6 +3,64 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.15.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.14.0...@standardnotes/analytics@1.15.0) (2022-08-11)
### Features
* add analytics for subscription cancelling, refunding and account deletion ([1607638](https://github.com/standardnotes/server/commit/16076382bae74552a35901bb5474e2c2c2d96f43))
# [1.14.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.13.0...@standardnotes/analytics@1.14.0) (2022-08-09)
### Features
* **auth:** add subscription events to analytics ([24e439f](https://github.com/standardnotes/server/commit/24e439f017df23d0158940848c10e0b3398720b2))
# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.12.2...@standardnotes/analytics@1.13.0) (2022-08-09)
### Features
* **auth:** track registration in analytics ([f25195b](https://github.com/standardnotes/server/commit/f25195b2c156fa03ca5806ef568c4195da7b688a))
## [1.12.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.12.1...@standardnotes/analytics@1.12.2) (2022-08-09)
### Bug Fixes
* **analytics:** replace AND to OR operation on bitop ([572ea3f](https://github.com/standardnotes/server/commit/572ea3febe136518a33154937cf39347adf040ff))
## [1.12.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.12.0...@standardnotes/analytics@1.12.1) (2022-08-09)
### Bug Fixes
* **analytics:** bitop over analytics time ([0ffec66](https://github.com/standardnotes/server/commit/0ffec66bea480fe9cec55415d90b608fddc26a84))
# [1.12.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.11.0...@standardnotes/analytics@1.12.0) (2022-08-09)
### Features
* add total count of analytics over time ([0b9524e](https://github.com/standardnotes/server/commit/0b9524eb26c39aabe8ad0f9cdbb3aaca63a65b0e))
# [1.11.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.10.0...@standardnotes/analytics@1.11.0) (2022-08-08)
### Bug Fixes
* **analytics:** format of changes over time to total count ([31c849c](https://github.com/standardnotes/server/commit/31c849cc2d13bc97690da1cbec3d1868ddb733dc))
### Features
* **analytics:** add calculating analytics over time ([977757d](https://github.com/standardnotes/server/commit/977757d346ba94794cc090f13d4dfdf489eb9d3a))
# [1.10.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.9.0...@standardnotes/analytics@1.10.0) (2022-08-08)
### Features
* **api-gateway:** add marking server interaction as general activity in analytics ([a36764f](https://github.com/standardnotes/server/commit/a36764f1b058bed014b815fa2818370849053b18))
# [1.9.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.3...@standardnotes/analytics@1.9.0) (2022-07-26)
### Features
* **analytics:** add limited discount offer purchased activity ([13201e7](https://github.com/standardnotes/server/commit/13201e7a9ec875796f527b2c500cf631345c36dd))
## [1.8.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.2...@standardnotes/analytics@1.8.3) (2022-07-15)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "1.8.3",
"version": "1.15.0",
"engines": {
"node": ">=14.0.0 <17.0.0"
},
@@ -1,6 +1,14 @@
export enum AnalyticsActivity {
GeneralActivity = 'general-activity',
EditingItems = 'editing-items',
Login = 'login',
Register = 'register',
DeleteAccount = 'DeleteAccount',
SubscriptionPurchased = 'subscription-purchased',
SubscriptionRenewed = 'subscription-renewed',
SubscriptionRefunded = 'subscription-refunded',
SubscriptionCancelled = 'subscription-cancelled',
EmailUnbackedUpData = 'email-unbacked-up-data',
EmailBackup = 'email-backup',
LimitedDiscountOfferPurchased = 'limited-discount-offer-purchased',
}
@@ -7,4 +7,9 @@ export interface AnalyticsStoreInterface {
wasActivityDone(activity: AnalyticsActivity, analyticsId: number, period: Period): Promise<boolean>
calculateActivityRetention(activity: AnalyticsActivity, firstPeriod: Period, secondPeriod: Period): Promise<number>
calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number>
calculateActivityChangesTotalCount(
activity: AnalyticsActivity,
period: Period,
): Promise<Array<{ periodKey: string; totalCount: number }>>
calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number>
}
@@ -7,4 +7,5 @@ export enum Period {
WeekBeforeLastWeek,
ThisMonth,
LastMonth,
Last30Days,
}
@@ -5,7 +5,7 @@ describe('PeriodKeyGenerator', () => {
const createGenerator = () => new PeriodKeyGenerator()
beforeEach(() => {
jest.useFakeTimers('modern')
jest.useFakeTimers()
jest.setSystemTime(1653395155000)
})
@@ -13,6 +13,41 @@ describe('PeriodKeyGenerator', () => {
jest.useRealTimers()
})
it('should generate period keys for last 30 days', () => {
expect(createGenerator().getDiscretePeriodKeys(Period.Last30Days)).toEqual([
'2022-4-24',
'2022-4-25',
'2022-4-26',
'2022-4-27',
'2022-4-28',
'2022-4-29',
'2022-4-30',
'2022-5-1',
'2022-5-2',
'2022-5-3',
'2022-5-4',
'2022-5-5',
'2022-5-6',
'2022-5-7',
'2022-5-8',
'2022-5-9',
'2022-5-10',
'2022-5-11',
'2022-5-12',
'2022-5-13',
'2022-5-14',
'2022-5-15',
'2022-5-16',
'2022-5-17',
'2022-5-18',
'2022-5-19',
'2022-5-20',
'2022-5-21',
'2022-5-22',
'2022-5-23',
])
})
it('should generate a period key for today', () => {
expect(createGenerator().getPeriodKey(Period.Today)).toEqual('2022-5-24')
})
@@ -55,4 +90,15 @@ describe('PeriodKeyGenerator', () => {
expect(error).not.toBeNull()
})
it('should throw error on unsupported period for discrete generation', () => {
let error = null
try {
createGenerator().getDiscretePeriodKeys(Period.Today)
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
})
@@ -2,6 +2,21 @@ import { Period } from './Period'
import { PeriodKeyGeneratorInterface } from './PeriodKeyGeneratorInterface'
export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
getDiscretePeriodKeys(period: Period): string[] {
const periodKeys = []
switch (period) {
case Period.Last30Days:
for (let i = 1; i <= 30; i++) {
periodKeys.unshift(this.getDailyKey(this.getDateNDaysBefore(i)))
}
return periodKeys
default:
throw new Error(`Unsuporrted period: ${period}`)
}
}
getPeriodKey(period: Period): string {
switch (period) {
case Period.Today:
@@ -61,11 +76,15 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
return date.getDate().toString()
}
private getYesterdayDate(): Date {
const yesterday = new Date()
yesterday.setDate(new Date().getDate() - 1)
private getDateNDaysBefore(n: number) {
const date = new Date()
date.setDate(new Date().getDate() - n)
return yesterday
return date
}
private getYesterdayDate(): Date {
return this.getDateNDaysBefore(1)
}
private getDayBeforeYesterdayDate(): Date {
@@ -2,4 +2,5 @@ import { Period } from './Period'
export interface PeriodKeyGeneratorInterface {
getPeriodKey(period: Period): string
getDiscretePeriodKeys(period: Period): string[]
}
@@ -29,6 +29,67 @@ describe('RedisAnalyticsStore', () => {
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
})
it('should calculate total count over time of activities', async () => {
redisClient.bitcount = jest.fn().mockReturnValue(70)
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.EditingItems, Period.Last30Days)
expect(redisClient.bitop).toHaveBeenCalledTimes(1)
expect(redisClient.bitop).toHaveBeenNthCalledWith(
1,
'OR',
'bitmap:action:editing-items:timespan:2022-4-24-2022-4-26',
'bitmap:action:editing-items:timespan:2022-4-24',
'bitmap:action:editing-items:timespan:2022-4-25',
'bitmap:action:editing-items:timespan:2022-4-26',
)
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-4-24-2022-4-26')
})
it('should calculate total count changes of activities', async () => {
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
redisClient.bitcount = jest.fn().mockReturnValueOnce(70).mockReturnValueOnce(71).mockReturnValueOnce(72)
expect(
await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.Last30Days),
).toEqual([
{
periodKey: '2022-4-24',
totalCount: 70,
},
{
periodKey: '2022-4-25',
totalCount: 71,
},
{
periodKey: '2022-4-26',
totalCount: 72,
},
])
expect(redisClient.bitcount).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-4-24')
expect(redisClient.bitcount).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-4-25')
expect(redisClient.bitcount).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-4-26')
})
it('should throw error on calculating total count changes of activities on unsupported period', async () => {
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
redisClient.bitcount = jest.fn().mockReturnValueOnce(70).mockReturnValueOnce(71).mockReturnValueOnce(72)
let caughtError = null
try {
await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.LastWeek)
} catch (error) {
caughtError = error
}
expect(caughtError).not.toBeNull()
})
it('should calculate total count of activities', async () => {
redisClient.bitcount = jest.fn().mockReturnValue(70)
@@ -8,6 +8,43 @@ import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreIn
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
async calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number> {
if (period !== Period.Last30Days) {
throw new Error(`Unsuporrted period: ${period}`)
}
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
await this.redisClient.bitop(
'OR',
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
...periodKeys.map((p) => `bitmap:action:${activity}:timespan:${p}`),
)
return this.redisClient.bitcount(
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
)
}
async calculateActivityChangesTotalCount(
activity: AnalyticsActivity,
period: Period,
): Promise<Array<{ periodKey: string; totalCount: number }>> {
if (period !== Period.Last30Days) {
throw new Error(`Unsuporrted period: ${period}`)
}
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
const counts = []
for (const periodKey of periodKeys) {
counts.push({
periodKey,
totalCount: await this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${periodKey}`),
})
}
return counts
}
async markActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void> {
const pipeline = this.redisClient.pipeline()
@@ -21,7 +21,6 @@ describe('RedisStatisticsStore', () => {
redisClient.incr = jest.fn()
redisClient.setbit = jest.fn()
redisClient.getbit = jest.fn().mockReturnValue(1)
redisClient.send_command = jest.fn()
periodKeyGenerator = {} as jest.Mocked<PeriodKeyGeneratorInterface>
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
+88
View File
@@ -3,6 +3,94 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.13.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.12.0...@standardnotes/api-gateway@1.13.0) (2022-08-11)
### Features
* add analytics for subscription cancelling, refunding and account deletion ([1607638](https://github.com/standardnotes/api-gateway/commit/16076382bae74552a35901bb5474e2c2c2d96f43))
# [1.12.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.5...@standardnotes/api-gateway@1.12.0) (2022-08-10)
### Features
* **api-gateway:** add publishing subscription purchased, renewed and registration analytics ([dea5fd7](https://github.com/standardnotes/api-gateway/commit/dea5fd717d222d96bcbbd16a8d84a84ed20144a8))
## [1.11.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.4...@standardnotes/api-gateway@1.11.5) (2022-08-10)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.11.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.3...@standardnotes/api-gateway@1.11.4) (2022-08-09)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.11.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.2...@standardnotes/api-gateway@1.11.3) (2022-08-09)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.11.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.1...@standardnotes/api-gateway@1.11.2) (2022-08-09)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.11.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.0...@standardnotes/api-gateway@1.11.1) (2022-08-09)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.11.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.10.0...@standardnotes/api-gateway@1.11.0) (2022-08-09)
### Features
* add total count of analytics over time ([0b9524e](https://github.com/standardnotes/api-gateway/commit/0b9524eb26c39aabe8ad0f9cdbb3aaca63a65b0e))
# [1.10.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.9.1...@standardnotes/api-gateway@1.10.0) (2022-08-09)
### Features
* **api-gateway:** add editing items count over time ([b9225cd](https://github.com/standardnotes/api-gateway/commit/b9225cd9b6496301da2d8edc44c2a9861e03406b))
## [1.9.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.9.0...@standardnotes/api-gateway@1.9.1) (2022-08-08)
### Bug Fixes
* **api-gateway:** add general activity to calculating activity retention ([12e3a76](https://github.com/standardnotes/api-gateway/commit/12e3a768dd365198340ab4e2cd463e9392344e38))
# [1.9.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.8.0...@standardnotes/api-gateway@1.9.0) (2022-08-08)
### Features
* **api-gateway:** add analytics over time to daily report event ([845f08b](https://github.com/standardnotes/api-gateway/commit/845f08b060beda5dea69e16fbda132150de7d5f2))
# [1.8.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.4...@standardnotes/api-gateway@1.8.0) (2022-08-08)
### Features
* **api-gateway:** add marking server interaction as general activity in analytics ([a36764f](https://github.com/standardnotes/api-gateway/commit/a36764f1b058bed014b815fa2818370849053b18))
## [1.7.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.3...@standardnotes/api-gateway@1.7.4) (2022-07-29)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.7.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.2...@standardnotes/api-gateway@1.7.3) (2022-07-29)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.7.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.1...@standardnotes/api-gateway@1.7.2) (2022-07-27)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.7.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.0...@standardnotes/api-gateway@1.7.1) (2022-07-27)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.7.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.30...@standardnotes/api-gateway@1.7.0) (2022-07-26)
### Features
* **api-gateway:** add limited discount offer purchased to analytics report ([d203ce1](https://github.com/standardnotes/api-gateway/commit/d203ce188af4f775e01bc1752d4c6d84fc5f1675))
## [1.6.30](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.29...@standardnotes/api-gateway@1.6.30) (2022-07-26)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.6.29](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.28...@standardnotes/api-gateway@1.6.29) (2022-07-25)
**Note:** Version bump only for package @standardnotes/api-gateway
+118
View File
@@ -46,6 +46,124 @@ const requestReport = async (
Period.Yesterday,
),
},
{
name: AnalyticsActivity.LimitedDiscountOfferPurchased,
retention: 0,
totalCount: await analyticsStore.calculateActivityTotalCount(
AnalyticsActivity.LimitedDiscountOfferPurchased,
Period.Yesterday,
),
},
{
name: AnalyticsActivity.GeneralActivity,
retention: await analyticsStore.calculateActivityRetention(
AnalyticsActivity.GeneralActivity,
Period.DayBeforeYesterday,
Period.Yesterday,
),
totalCount: await analyticsStore.calculateActivityTotalCount(
AnalyticsActivity.GeneralActivity,
Period.Yesterday,
),
},
],
activityStatisticsOverTime: [
{
name: AnalyticsActivity.GeneralActivity,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.GeneralActivity,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.GeneralActivity,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.EditingItems,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.EditingItems,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.EditingItems,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.SubscriptionPurchased,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.SubscriptionPurchased,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.SubscriptionPurchased,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.Register,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.Register,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.Register,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.SubscriptionRenewed,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.SubscriptionRenewed,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.SubscriptionRenewed,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.DeleteAccount,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.DeleteAccount,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.DeleteAccount,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.SubscriptionCancelled,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.SubscriptionCancelled,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.SubscriptionCancelled,
Period.Last30Days,
),
},
{
name: AnalyticsActivity.SubscriptionRefunded,
period: Period.Last30Days,
counts: await analyticsStore.calculateActivityChangesTotalCount(
AnalyticsActivity.SubscriptionRefunded,
Period.Last30Days,
),
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
AnalyticsActivity.SubscriptionRefunded,
Period.Last30Days,
),
},
],
},
}
+1 -1
View File
@@ -23,7 +23,7 @@ import '../src/Controller/v1/SubscriptionInvitesController'
import '../src/Controller/v2/PaymentsControllerV2'
import '../src/Controller/v2/ActionsControllerV2'
import * as helmet from 'helmet'
import helmet from 'helmet'
import * as cors from 'cors'
import { text, json, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express'
import * as winston from 'winston'
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.6.29",
"version": "1.13.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -22,7 +22,7 @@
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
},
"dependencies": {
"@newrelic/winston-enricher": "^2.1.0",
"@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.3.0",
"@standardnotes/analytics": "workspace:*",
"@standardnotes/domain-events": "workspace:*",
@@ -34,12 +34,12 @@
"cors": "2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"helmet": "4.4.1",
"helmet": "^5.1.1",
"inversify": "^6.0.1",
"inversify-express-utils": "^6.4.3",
"ioredis": "^5.2.0",
"jsonwebtoken": "8.5.1",
"newrelic": "^8.14.1",
"newrelic": "^9.0.0",
"prettyjson": "^1.2.5",
"reflect-metadata": "0.1.13",
"winston": "^3.8.1"
@@ -57,7 +57,7 @@
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.2",
"nodemon": "^2.0.19",
"npm-check-updates": "^15.3.3",
"npm-check-updates": "^16.0.1",
"ts-jest": "^28.0.5"
}
}
@@ -24,7 +24,7 @@ import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTo
import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicWinstonEnricher = require('@newrelic/winston-enricher')
const newrelicFormatter = require('@newrelic/winston-enricher')
export class ContainerConfigLoader {
async load(): Promise<Container> {
@@ -33,9 +33,10 @@ export class ContainerConfigLoader {
const container = new Container()
const newrelicWinstonFormatter = newrelicFormatter(winston)
const winstonFormatters = [winston.format.splat(), winston.format.json()]
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
winstonFormatters.push(newrelicWinstonEnricher())
winstonFormatters.push(newrelicWinstonFormatter())
}
const logger = winston.createLogger({
@@ -1,4 +1,5 @@
import { CrossServiceTokenData } from '@standardnotes/security'
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { TimerInterface } from '@standardnotes/time'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'
@@ -19,6 +20,7 @@ export class AuthMiddleware extends BaseMiddleware {
@inject(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL) private crossServiceTokenCacheTTL: number,
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.Timer) private timer: TimerInterface,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.Logger) private logger: Logger,
) {
super()
@@ -73,6 +75,10 @@ export class AuthMiddleware extends BaseMiddleware {
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
await this.analyticsStore.markActivity([AnalyticsActivity.GeneralActivity], decodedToken.analyticsId as number, [
Period.Today,
])
if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
await this.crossServiceTokenCache.set({
authorizationHeaderValue: authHeaderValue,
+78
View File
@@ -3,6 +3,84 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.17.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.16.2...@standardnotes/auth-server@1.17.0) (2022-08-11)
### Features
* add analytics for subscription cancelling, refunding and account deletion ([1607638](https://github.com/standardnotes/server/commit/16076382bae74552a35901bb5474e2c2c2d96f43))
## [1.16.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.16.1...@standardnotes/auth-server@1.16.2) (2022-08-10)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.16.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.16.0...@standardnotes/auth-server@1.16.1) (2022-08-10)
### Bug Fixes
* **auth:** docker entrypoing command for single user backup ([f67be9d](https://github.com/standardnotes/server/commit/f67be9d3ba56f67ad63cb067c6304766de3f3b69))
# [1.16.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.15.0...@standardnotes/auth-server@1.16.0) (2022-08-10)
### Features
* **auth:** add triggering email backup for a single user ([edd2545](https://github.com/standardnotes/server/commit/edd254531ddff6726aa4395193e489023358e422))
# [1.15.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.14.0...@standardnotes/auth-server@1.15.0) (2022-08-09)
### Features
* **auth:** add subscription events to analytics ([24e439f](https://github.com/standardnotes/server/commit/24e439f017df23d0158940848c10e0b3398720b2))
# [1.14.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.6...@standardnotes/auth-server@1.14.0) (2022-08-09)
### Features
* **auth:** track registration in analytics ([f25195b](https://github.com/standardnotes/server/commit/f25195b2c156fa03ca5806ef568c4195da7b688a))
## [1.13.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.5...@standardnotes/auth-server@1.13.6) (2022-08-09)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.13.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.4...@standardnotes/auth-server@1.13.5) (2022-08-09)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.13.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.3...@standardnotes/auth-server@1.13.4) (2022-08-09)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.13.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.2...@standardnotes/auth-server@1.13.3) (2022-08-08)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.13.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.1...@standardnotes/auth-server@1.13.2) (2022-08-08)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.13.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.0...@standardnotes/auth-server@1.13.1) (2022-07-29)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.2...@standardnotes/auth-server@1.13.0) (2022-07-29)
### Features
* **auth:** remove crypto-random-string in favour of @standardnotes/sncrypto-node ([35f931a](https://github.com/standardnotes/server/commit/35f931a708c7fead65fd40a9b4214a223831a5dc))
## [1.12.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.1...@standardnotes/auth-server@1.12.2) (2022-07-29)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.12.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.0...@standardnotes/auth-server@1.12.1) (2022-07-27)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.12.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.31...@standardnotes/auth-server@1.12.0) (2022-07-26)
### Features
* **auth:** add analytics for purchased subscription with a limited discount offer ([e936ac4](https://github.com/standardnotes/server/commit/e936ac4ce18fa43e47a50462c44f63a9ba1c1aa4))
## [1.11.31](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.30...@standardnotes/auth-server@1.11.31) (2022-07-25)
### Bug Fixes
+123
View File
@@ -0,0 +1,123 @@
import 'reflect-metadata'
import 'newrelic'
import { Logger } from 'winston'
import * as dayjs from 'dayjs'
import * as utc from 'dayjs/plugin/utc'
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
import { SettingRepositoryInterface } from '../src/Domain/Setting/SettingRepositoryInterface'
import { MuteFailedBackupsEmailsOption, SettingName } from '@standardnotes/settings'
import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
import { PermissionName } from '@standardnotes/features'
import { AnalyticsEntityRepositoryInterface } from '../src/Domain/Analytics/AnalyticsEntityRepositoryInterface'
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
const inputArgs = process.argv.slice(2)
const backupEmail = inputArgs[0]
const requestBackups = async (
userRepository: UserRepositoryInterface,
settingRepository: SettingRepositoryInterface,
roleService: RoleServiceInterface,
domainEventFactory: DomainEventFactoryInterface,
domainEventPublisher: DomainEventPublisherInterface,
analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
analyticsStore: AnalyticsStoreInterface,
): Promise<void> => {
const permissionName = PermissionName.DailyEmailBackup
const muteEmailsSettingName = SettingName.MuteFailedBackupsEmails
const muteEmailsSettingValue = MuteFailedBackupsEmailsOption.Muted
if (!backupEmail) {
throw new Error('Could not trigger email backup for user - missing email parameter')
}
const user = await userRepository.findOneByEmail(backupEmail)
if (user === null) {
throw new Error(`Could not find user with email: ${backupEmail}`)
}
const userIsPermittedForEmailBackups = await roleService.userHasPermission(user.uuid, permissionName)
if (!userIsPermittedForEmailBackups) {
throw new Error(`User ${backupEmail} is not permitted for email backups`)
}
let userHasEmailsMuted = false
const emailsMutedSetting = await settingRepository.findOneByNameAndUserUuid(muteEmailsSettingName, user.uuid)
if (emailsMutedSetting !== null && emailsMutedSetting.value !== null) {
userHasEmailsMuted = emailsMutedSetting.value === muteEmailsSettingValue
}
const analyticsEntity = await analyticsEntityRepository.findOneByUserUuid(user.uuid)
if (analyticsEntity === null) {
return
}
await domainEventPublisher.publish(
domainEventFactory.createEmailBackupRequestedEvent(
user.uuid,
emailsMutedSetting?.uuid as string,
userHasEmailsMuted,
),
)
await analyticsStore.markActivity([AnalyticsActivity.EmailBackup], analyticsEntity.id, [
Period.Today,
Period.ThisWeek,
])
await analyticsStore.unmarkActivity([AnalyticsActivity.EmailUnbackedUpData], analyticsEntity.id, [
Period.Today,
Period.ThisWeek,
])
return
}
const container = new ContainerConfigLoader()
void container.load().then((container) => {
dayjs.extend(utc)
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Logger)
logger.info(`Starting email backup requesting for ${backupEmail} ...`)
const settingRepository: SettingRepositoryInterface = container.get(TYPES.SettingRepository)
const userRepository: UserRepositoryInterface = container.get(TYPES.UserRepository)
const roleService: RoleServiceInterface = container.get(TYPES.RoleService)
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
const analyticsEntityRepository: AnalyticsEntityRepositoryInterface = container.get(TYPES.AnalyticsEntityRepository)
const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore)
Promise.resolve(
requestBackups(
userRepository,
settingRepository,
roleService,
domainEventFactory,
domainEventPublisher,
analyticsEntityRepository,
analyticsStore,
),
)
.then(() => {
logger.info(`Email backup requesting complete for ${backupEmail}`)
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish email backup requesting for ${backupEmail}: ${error.message}`)
process.exit(1)
})
})
+6
View File
@@ -29,6 +29,12 @@ case "$COMMAND" in
yarn workspace @standardnotes/auth-server weekly-backup:email
;;
'email-backup' )
echo "Starting Email Backup For Single User..."
EMAIL=$1 && shift 1
yarn workspace @standardnotes/auth-server user-email-backup $EMAIL
;;
'dropbox-daily-backup' )
echo "Starting Dropbox Daily Backup..."
yarn workspace @standardnotes/auth-server daily-backup:dropbox
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.11.31",
"version": "1.17.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -21,6 +21,7 @@
"start": "yarn node dist/bin/server.js",
"worker": "yarn node dist/bin/worker.js",
"daily-backup:email": "yarn node dist/bin/backup.js email daily",
"user-email-backup": "yarn node dist/bin/user_email_backup.js",
"daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily",
"daily-backup:google_drive": "yarn node dist/bin/backup.js google_drive daily",
"daily-backup:one_drive": "yarn node dist/bin/backup.js one_drive daily",
@@ -30,7 +31,7 @@
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
},
"dependencies": {
"@newrelic/winston-enricher": "^2.1.0",
"@newrelic/winston-enricher": "^4.0.0",
"@sentry/node": "^7.3.0",
"@standardnotes/analytics": "workspace:*",
"@standardnotes/api": "^1.1.19",
@@ -49,7 +50,6 @@
"axios": "^0.27.2",
"bcryptjs": "2.4.3",
"cors": "2.8.5",
"crypto-random-string": "3.3.0",
"dayjs": "^1.11.3",
"dotenv": "^16.0.1",
"express": "^4.18.1",
@@ -57,7 +57,7 @@
"inversify-express-utils": "^6.4.3",
"ioredis": "^5.2.0",
"mysql2": "^2.3.3",
"newrelic": "^8.14.1",
"newrelic": "^9.0.0",
"otplib": "12.0.1",
"prettyjson": "^1.2.5",
"reflect-metadata": "0.1.13",
@@ -82,7 +82,7 @@
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.2",
"nodemon": "^2.0.19",
"npm-check-updates": "^15.3.3",
"npm-check-updates": "^16.0.1",
"ts-jest": "^28.0.5"
}
}
+3 -2
View File
@@ -193,7 +193,7 @@ import { PredicateVerificationRequestedEventHandler } from '../Domain/Handler/Pr
import { MuteMarketingEmails } from '../Domain/UseCase/MuteMarketingEmails/MuteMarketingEmails'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicWinstonEnricher = require('@newrelic/winston-enricher')
const newrelicFormatter = require('@newrelic/winston-enricher')
export class ContainerConfigLoader {
async load(): Promise<Container> {
@@ -215,9 +215,10 @@ export class ContainerConfigLoader {
container.bind(TYPES.Redis).toConstantValue(redis)
const newrelicWinstonFormatter = newrelicFormatter(winston)
const winstonFormatters = [winston.format.splat(), winston.format.json()]
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
winstonFormatters.push(newrelicWinstonEnricher())
winstonFormatters.push(newrelicWinstonFormatter())
}
const logger = winston.createLogger({
@@ -11,6 +11,8 @@ import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterfac
import { User } from '../User/User'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { AccountDeletionRequestedEventHandler } from './AccountDeletionRequestedEventHandler'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
describe('AccountDeletionRequestedEventHandler', () => {
let userRepository: UserRepositoryInterface
@@ -23,6 +25,8 @@ describe('AccountDeletionRequestedEventHandler', () => {
let revokedSession: RevokedSession
let user: User
let event: AccountDeletionRequestedEvent
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
const createHandler = () =>
new AccountDeletionRequestedEventHandler(
@@ -30,6 +34,8 @@ describe('AccountDeletionRequestedEventHandler', () => {
sessionRepository,
ephemeralSessionRepository,
revokedSessionRepository,
getUserAnalyticsId,
analyticsStore,
logger,
)
@@ -72,6 +78,12 @@ describe('AccountDeletionRequestedEventHandler', () => {
regularSubscriptionUuid: '2-3-4',
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
logger = {} as jest.Mocked<Logger>
logger.info = jest.fn()
logger.warn = jest.fn()
@@ -1,3 +1,4 @@
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { AccountDeletionRequestedEvent, DomainEventHandlerInterface } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
@@ -5,6 +6,7 @@ import TYPES from '../../Bootstrap/Types'
import { EphemeralSessionRepositoryInterface } from '../Session/EphemeralSessionRepositoryInterface'
import { RevokedSessionRepositoryInterface } from '../Session/RevokedSessionRepositoryInterface'
import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterface'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
@injectable()
@@ -14,6 +16,8 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
@inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface,
@inject(TYPES.EphemeralSessionRepository) private ephemeralSessionRepository: EphemeralSessionRepositoryInterface,
@inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.Logger) private logger: Logger,
) {}
@@ -28,6 +32,13 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
await this.removeSessions(event.payload.userUuid)
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
await this.analyticsStore.markActivity([AnalyticsActivity.DeleteAccount], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
await this.userRepository.remove(user)
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
@@ -8,17 +8,41 @@ import * as dayjs from 'dayjs'
import { SubscriptionCancelledEventHandler } from './SubscriptionCancelledEventHandler'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { User } from '../User/User'
describe('SubscriptionCancelledEventHandler', () => {
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
let offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface
let event: SubscriptionCancelledEvent
let userRepository: UserRepositoryInterface
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let timestamp: number
const createHandler = () =>
new SubscriptionCancelledEventHandler(userSubscriptionRepository, offlineUserSubscriptionRepository)
new SubscriptionCancelledEventHandler(
userSubscriptionRepository,
offlineUserSubscriptionRepository,
userRepository,
getUserAnalyticsId,
analyticsStore,
)
beforeEach(() => {
const user = { uuid: '1-2-3' } as jest.Mocked<User>
userRepository = {} as jest.Mocked<UserRepositoryInterface>
userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
userSubscriptionRepository.updateCancelled = jest.fn()
@@ -42,6 +66,16 @@ describe('SubscriptionCancelledEventHandler', () => {
await createHandler().handle(event)
expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, timestamp)
expect(analyticsStore.markActivity).toHaveBeenCalled()
})
it('should update subscription cancelled - user not found', async () => {
userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
await createHandler().handle(event)
expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, timestamp)
expect(analyticsStore.markActivity).not.toHaveBeenCalled()
})
it('should update offline subscription cancelled', async () => {
@@ -4,6 +4,9 @@ import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
@injectable()
export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
@@ -11,6 +14,9 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
@inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
@inject(TYPES.OfflineUserSubscriptionRepository)
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
) {}
async handle(event: SubscriptionCancelledEvent): Promise<void> {
if (event.payload.offline) {
@@ -20,6 +26,16 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
}
await this.updateSubscriptionCancelled(event.payload.subscriptionId, event.payload.timestamp)
const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
if (user !== null) {
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionCancelled], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
}
}
private async updateSubscriptionCancelled(subscriptionId: number, timestamp: number): Promise<void> {
@@ -16,6 +16,9 @@ import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/Offl
import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription'
import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
import { AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { AnalyticsEntity } from '../Analytics/AnalyticsEntity'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
describe('SubscriptionPurchasedEventHandler', () => {
let userRepository: UserRepositoryInterface
@@ -29,6 +32,8 @@ describe('SubscriptionPurchasedEventHandler', () => {
let event: SubscriptionPurchasedEvent
let subscriptionExpiresAt: number
let subscriptionSettingService: SubscriptionSettingServiceInterface
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
let timestamp: number
const createHandler = () =>
@@ -38,6 +43,8 @@ describe('SubscriptionPurchasedEventHandler', () => {
offlineUserSubscriptionRepository,
roleService,
subscriptionSettingService,
getUserAnalyticsId,
analyticsStore,
logger,
)
@@ -83,11 +90,18 @@ describe('SubscriptionPurchasedEventHandler', () => {
subscriptionExpiresAt,
timestamp: dayjs.utc().valueOf(),
offline: false,
discountCode: null,
}
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription = jest.fn()
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
logger = {} as jest.Mocked<Logger>
logger.info = jest.fn()
logger.warn = jest.fn()
@@ -134,6 +148,28 @@ describe('SubscriptionPurchasedEventHandler', () => {
})
})
it('should update analytics on limited discount offer purchasing', async () => {
const analyticsEntity = { id: 3 } as jest.Mocked<AnalyticsEntity>
user = {
uuid: '123',
email: 'test@test.com',
roles: Promise.resolve([
{
name: RoleName.CoreUser,
},
]),
analyticsEntity: Promise.resolve(analyticsEntity),
} as jest.Mocked<User>
userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
event.payload.discountCode = 'limited-10'
await createHandler().handle(event)
expect(analyticsStore.markActivity).toHaveBeenCalledWith(['limited-discount-offer-purchased'], 3, [Period.Today])
})
it('should create an offline subscription', async () => {
event.payload.offline = true
@@ -13,6 +13,8 @@ import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInterface {
@@ -23,6 +25,8 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
@inject(TYPES.RoleService) private roleService: RoleServiceInterface,
@inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.Logger) private logger: Logger,
) {}
@@ -62,6 +66,20 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
userSubscription,
event.payload.subscriptionName,
)
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionPurchased], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
const limitedDiscountPurchased = event.payload.discountCode === 'limited-10'
if (limitedDiscountPurchased) {
await this.analyticsStore.markActivity([AnalyticsActivity.LimitedDiscountOfferPurchased], analyticsId, [
Period.Today,
])
}
}
private async addUserRole(user: User, subscriptionName: SubscriptionName): Promise<void> {
@@ -13,6 +13,8 @@ import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscri
import { RoleServiceInterface } from '../Role/RoleServiceInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { UserSubscription } from '../Subscription/UserSubscription'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
describe('SubscriptionRefundedEventHandler', () => {
let userRepository: UserRepositoryInterface
@@ -23,6 +25,8 @@ describe('SubscriptionRefundedEventHandler', () => {
let user: User
let event: SubscriptionRefundedEvent
let timestamp: number
let getUserAnalyticsId: GetUserAnalyticsId
let analyticsStore: AnalyticsStoreInterface
const createHandler = () =>
new SubscriptionRefundedEventHandler(
@@ -30,6 +34,8 @@ describe('SubscriptionRefundedEventHandler', () => {
userSubscriptionRepository,
offlineUserSubscriptionRepository,
roleService,
getUserAnalyticsId,
analyticsStore,
logger,
)
@@ -72,6 +78,12 @@ describe('SubscriptionRefundedEventHandler', () => {
offline: false,
}
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
analyticsStore.markActivity = jest.fn()
logger = {} as jest.Mocked<Logger>
logger.info = jest.fn()
logger.warn = jest.fn()
@@ -8,6 +8,8 @@ import { RoleServiceInterface } from '../Role/RoleServiceInterface'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
@injectable()
export class SubscriptionRefundedEventHandler implements DomainEventHandlerInterface {
@@ -17,6 +19,8 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
@inject(TYPES.OfflineUserSubscriptionRepository)
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
@inject(TYPES.RoleService) private roleService: RoleServiceInterface,
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
@inject(TYPES.Logger) private logger: Logger,
) {}
@@ -36,6 +40,13 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
await this.updateSubscriptionEndsAt(event.payload.subscriptionId, event.payload.timestamp)
await this.removeRoleFromSubscriptionUsers(event.payload.subscriptionId, event.payload.subscriptionName)
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRefunded], analyticsId, [
Period.Today,
Period.ThisWeek,
Period.ThisMonth,
])
}
private async removeRoleFromSubscriptionUsers(

Some files were not shown because too many files have changed in this diff Show More