mirror of
https://github.com/standardnotes/server
synced 2026-04-21 05:02:25 -04:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a04ab5b0e8 | |||
| 845f08b060 | |||
| 31c849cc2d | |||
| 977757d346 | |||
| f2c549158d | |||
| a36764f1b0 | |||
| 033bc25d8f | |||
| 31bd253a73 | |||
| 2f4977be63 | |||
| 35f931a708 | |||
| 3e23d8d5d5 | |||
| 004de0a655 | |||
| 47a1af4be1 | |||
| 7b17c4caa8 | |||
| fa29885b3f | |||
| beece69f9e | |||
| 600ff1d62b | |||
| 094dc192a9 | |||
| 939bf30138 | |||
| d203ce188a | |||
| 268fed19f9 | |||
| 04bf414de4 | |||
| 28e1c65631 | |||
| e936ac4ce1 | |||
| 13201e7a9e | |||
| 9740b28764 | |||
| 1fa94efa02 | |||
| 44172e1a8e | |||
| 4ab0d24d24 | |||
| 049e66770a | |||
| bf12687f63 | |||
| 10389d9029 | |||
| 40996f9d48 | |||
| 3d284461f3 | |||
| 6642641c11 | |||
| 3e637a482e | |||
| 6374248132 | |||
| b9661d74ee | |||
| 0a5b956cb9 | |||
| be88fd941d | |||
| 48af9e7c1c | |||
| 71684350e9 | |||
| 9a1924b7c6 | |||
| fc20697d81 |
@@ -122,7 +122,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["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"],\
|
||||
["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"]\
|
||||
@@ -1868,27 +1868,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:8.14.1"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/newrelic",\
|
||||
"@types/winston",\
|
||||
"newrelic",\
|
||||
"winston"\
|
||||
"newrelic"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
@@ -2508,7 +2504,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,7 +2526,7 @@ 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"],\
|
||||
@@ -2538,7 +2534,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["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 +2559,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 +2589,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"],\
|
||||
@@ -2606,7 +2601,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["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"],\
|
||||
@@ -2782,7 +2777,7 @@ 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"],\
|
||||
@@ -2790,7 +2785,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["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 +2856,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 +2872,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"],\
|
||||
["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"],\
|
||||
@@ -2928,7 +2923,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["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"],\
|
||||
["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 +2991,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,7 +3021,7 @@ 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"],\
|
||||
@@ -3035,7 +3030,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["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 +5508,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 +7220,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 +7551,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": [\
|
||||
@@ -9776,10 +9742,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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -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"
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "1.8.3",
|
||||
"version": "1.11.0",
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export enum AnalyticsActivity {
|
||||
GeneralActivity = 'general-activity',
|
||||
EditingItems = 'editing-items',
|
||||
Login = 'login',
|
||||
EmailUnbackedUpData = 'email-unbacked-up-data',
|
||||
EmailBackup = 'email-backup',
|
||||
LimitedDiscountOfferPurchased = 'limited-discount-offer-purchased',
|
||||
}
|
||||
|
||||
@@ -7,4 +7,8 @@ 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 }>>
|
||||
}
|
||||
|
||||
@@ -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,48 @@ describe('RedisAnalyticsStore', () => {
|
||||
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
|
||||
})
|
||||
|
||||
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,26 @@ import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreIn
|
||||
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
|
||||
|
||||
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')
|
||||
|
||||
@@ -3,6 +3,48 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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
|
||||
|
||||
## [1.6.28](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.27...@standardnotes/api-gateway@1.6.28) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -46,6 +46,24 @@ const requestReport = async (
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
retention: 0,
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
],
|
||||
activityStatisticsOverTime: [
|
||||
{
|
||||
name: AnalyticsActivity.GeneralActivity,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.6.28",
|
||||
"version": "1.9.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,7 +34,7 @@
|
||||
"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",
|
||||
@@ -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,
|
||||
|
||||
@@ -3,6 +3,48 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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
|
||||
|
||||
* **auth:** marking predicate verification result if user is not existing ([40996f9](https://github.com/standardnotes/server/commit/40996f9d485686f92ee57fe6337102d94378b39b))
|
||||
|
||||
## [1.11.30](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.29...@standardnotes/auth-server@1.11.30) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.11.29](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.28...@standardnotes/auth-server@1.11.29) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.11.29",
|
||||
"version": "1.13.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -30,7 +30,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 +49,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",
|
||||
@@ -82,7 +81,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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -96,7 +96,7 @@ describe('PredicateVerificationRequestedEventHandler', () => {
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not verify a predicate if user is missing', async () => {
|
||||
it('should mark a predicate verification with undetermined result if user is missing', async () => {
|
||||
event.meta = {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
@@ -110,6 +110,6 @@ describe('PredicateVerificationRequestedEventHandler', () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(verifyPredicate.execute).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
DomainEventPublisherInterface,
|
||||
PredicateVerificationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@@ -28,7 +29,13 @@ export class PredicateVerificationRequestedEventHandler implements DomainEventHa
|
||||
if (event.meta.correlation.userIdentifierType === 'email') {
|
||||
const user = await this.userRepository.findOneByEmail(event.meta.correlation.userIdentifier)
|
||||
if (user === null) {
|
||||
this.logger.warn(`Could not find user ${event.meta.correlation.userIdentifier} for predicate verification`)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createPredicateVerifiedEvent({
|
||||
predicate: event.payload.predicate,
|
||||
predicateVerificationResult: PredicateVerificationResult.CouldNotBeDetermined,
|
||||
userUuid,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ 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'
|
||||
|
||||
describe('SubscriptionPurchasedEventHandler', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
@@ -29,6 +31,7 @@ describe('SubscriptionPurchasedEventHandler', () => {
|
||||
let event: SubscriptionPurchasedEvent
|
||||
let subscriptionExpiresAt: number
|
||||
let subscriptionSettingService: SubscriptionSettingServiceInterface
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
let timestamp: number
|
||||
|
||||
const createHandler = () =>
|
||||
@@ -38,6 +41,7 @@ describe('SubscriptionPurchasedEventHandler', () => {
|
||||
offlineUserSubscriptionRepository,
|
||||
roleService,
|
||||
subscriptionSettingService,
|
||||
analyticsStore,
|
||||
logger,
|
||||
)
|
||||
|
||||
@@ -83,11 +87,15 @@ describe('SubscriptionPurchasedEventHandler', () => {
|
||||
subscriptionExpiresAt,
|
||||
timestamp: dayjs.utc().valueOf(),
|
||||
offline: false,
|
||||
discountCode: null,
|
||||
}
|
||||
|
||||
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
|
||||
subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription = jest.fn()
|
||||
|
||||
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
|
||||
analyticsStore.markActivity = jest.fn()
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
logger.warn = jest.fn()
|
||||
@@ -134,6 +142,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,7 @@ 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'
|
||||
|
||||
@injectable()
|
||||
export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInterface {
|
||||
@@ -23,6 +24,7 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
|
||||
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
|
||||
@inject(TYPES.RoleService) private roleService: RoleServiceInterface,
|
||||
@inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
|
||||
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
|
||||
@@ -62,6 +64,16 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
|
||||
userSubscription,
|
||||
event.payload.subscriptionName,
|
||||
)
|
||||
|
||||
const limitedDiscountPurchased = event.payload.discountCode === 'limited-10'
|
||||
if (limitedDiscountPurchased) {
|
||||
const analyticsEntity = await user.analyticsEntity
|
||||
if (analyticsEntity) {
|
||||
await this.analyticsStore.markActivity([AnalyticsActivity.LimitedDiscountOfferPurchased], analyticsEntity.id, [
|
||||
Period.Today,
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async addUserRole(user: User, subscriptionName: SubscriptionName): Promise<void> {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { RevokedSession } from './RevokedSession'
|
||||
import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
|
||||
import { LogSessionUserAgentOption } from '@standardnotes/settings'
|
||||
import { Setting } from '../Setting/Setting'
|
||||
import { CryptoNode } from '@standardnotes/sncrypto-node'
|
||||
|
||||
describe('SessionService', () => {
|
||||
let sessionRepository: SessionRepositoryInterface
|
||||
@@ -25,6 +26,7 @@ describe('SessionService', () => {
|
||||
let deviceDetector: UAParser
|
||||
let timer: TimerInterface
|
||||
let logger: winston.Logger
|
||||
let cryptoNode: CryptoNode
|
||||
|
||||
const createService = () =>
|
||||
new SessionService(
|
||||
@@ -37,6 +39,7 @@ describe('SessionService', () => {
|
||||
123,
|
||||
234,
|
||||
settingService,
|
||||
cryptoNode,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -96,6 +99,10 @@ describe('SessionService', () => {
|
||||
logger.warn = jest.fn()
|
||||
logger.error = jest.fn()
|
||||
logger.debug = jest.fn()
|
||||
|
||||
cryptoNode = {} as jest.Mocked<CryptoNode>
|
||||
cryptoNode.generateRandomKey = jest.fn().mockReturnValue('foo bar')
|
||||
cryptoNode.base64URLEncode = jest.fn().mockReturnValue('foobar')
|
||||
})
|
||||
|
||||
it('should mark a revoked session as received', async () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as crypto from 'crypto'
|
||||
import * as winston from 'winston'
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as cryptoRandomString from 'crypto-random-string'
|
||||
import { UAParser } from 'ua-parser-js'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
@@ -20,6 +19,7 @@ import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
|
||||
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/settings'
|
||||
import { SessionBody } from '@standardnotes/responses'
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { CryptoNode } from '@standardnotes/sncrypto-node'
|
||||
|
||||
@injectable()
|
||||
export class SessionService implements SessionServiceInterface {
|
||||
@@ -35,6 +35,7 @@ export class SessionService implements SessionServiceInterface {
|
||||
@inject(TYPES.ACCESS_TOKEN_AGE) private accessTokenAge: number,
|
||||
@inject(TYPES.REFRESH_TOKEN_AGE) private refreshTokenAge: number,
|
||||
@inject(TYPES.SettingService) private settingService: SettingServiceInterface,
|
||||
@inject(TYPES.CryptoNode) private cryptoNode: CryptoNode,
|
||||
) {}
|
||||
|
||||
async createNewSessionForUser(dto: {
|
||||
@@ -263,8 +264,8 @@ export class SessionService implements SessionServiceInterface {
|
||||
}
|
||||
|
||||
private async createTokens(session: Session): Promise<SessionBody> {
|
||||
const accessToken = cryptoRandomString({ length: 16, type: 'url-safe' })
|
||||
const refreshToken = cryptoRandomString({ length: 16, type: 'url-safe' })
|
||||
const accessToken = this.cryptoNode.base64URLEncode(await this.cryptoNode.generateRandomKey(48))
|
||||
const refreshToken = this.cryptoNode.base64URLEncode(await this.cryptoNode.generateRandomKey(48))
|
||||
|
||||
const hashedAccessToken = crypto.createHash('sha256').update(accessToken).digest('hex')
|
||||
const hashedRefreshToken = crypto.createHash('sha256').update(refreshToken).digest('hex')
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.7.29](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.28...@standardnotes/domain-events-infra@1.7.29) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.28](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.27...@standardnotes/domain-events-infra@1.7.28) (2022-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.27](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.26...@standardnotes/domain-events-infra@1.7.27) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.26](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.25...@standardnotes/domain-events-infra@1.7.26) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.7.26",
|
||||
"version": "1.7.29",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.52.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.51.0...@standardnotes/domain-events@2.52.0) (2022-08-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add analytics over time to daily report event ([845f08b](https://github.com/standardnotes/server/commit/845f08b060beda5dea69e16fbda132150de7d5f2))
|
||||
|
||||
# [2.51.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.50.2...@standardnotes/domain-events@2.51.0) (2022-07-26)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-events:** add discount code to subscription purchased event ([28e1c65](https://github.com/standardnotes/server/commit/28e1c656312ae9a7c4afec1aa65bb104f788b8b6))
|
||||
|
||||
## [2.50.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.50.1...@standardnotes/domain-events@2.50.2) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
## [2.50.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.50.0...@standardnotes/domain-events@2.50.1) (2022-07-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.50.1",
|
||||
"version": "2.52.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -12,5 +12,13 @@ export interface DailyAnalyticsReportGeneratedEventPayload {
|
||||
retention: number
|
||||
totalCount: number
|
||||
}>
|
||||
activityStatisticsOverTime: Array<{
|
||||
name: string
|
||||
period: number
|
||||
counts: Array<{
|
||||
periodKey: string
|
||||
totalCount: number
|
||||
}>
|
||||
}>
|
||||
outOfSyncIncidents: number
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export interface SubscriptionPurchasedEventPayload {
|
||||
subscriptionExpiresAt: number
|
||||
timestamp: number
|
||||
offline: boolean
|
||||
discountCode: string | null
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.28](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.27...@standardnotes/event-store@1.1.28) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.1.27](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.26...@standardnotes/event-store@1.1.27) (2022-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.1.26](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.25...@standardnotes/event-store@1.1.26) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.1.25](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.24...@standardnotes/event-store@1.1.25) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.1.25",
|
||||
"version": "1.1.28",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.5.31](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.30...@standardnotes/files-server@1.5.31) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.30](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.29...@standardnotes/files-server@1.5.30) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.29](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.28...@standardnotes/files-server@1.5.29) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.28](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.27...@standardnotes/files-server@1.5.28) (2022-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.27](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.26...@standardnotes/files-server@1.5.27) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.26](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.25...@standardnotes/files-server@1.5.26) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as busboy from 'connect-busboy'
|
||||
import '../src/Controller/HealthCheckController'
|
||||
import '../src/Controller/FilesController'
|
||||
|
||||
import * as helmet from 'helmet'
|
||||
import helmet from 'helmet'
|
||||
import * as cors from 'cors'
|
||||
import { urlencoded, json, raw, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express'
|
||||
import * as winston from 'winston'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.5.26",
|
||||
"version": "1.5.31",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -41,7 +41,7 @@
|
||||
"dotenv": "^16.0.1",
|
||||
"express": "^4.18.1",
|
||||
"express-winston": "^4.0.5",
|
||||
"helmet": "^4.3.1",
|
||||
"helmet": "^5.1.1",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.2.0",
|
||||
@@ -69,7 +69,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",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.2.6...@standardnotes/predicates@1.3.0) (2022-07-25)
|
||||
|
||||
### Features
|
||||
|
||||
* **predicates:** add could-not-be-determined predicate verification result ([6642641](https://github.com/standardnotes/server/commit/6642641c1161986a1c1186698f6b8151ce3aee87))
|
||||
|
||||
## [1.2.6](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.2.5...@standardnotes/predicates@1.2.6) (2022-07-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/predicates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/predicates",
|
||||
"version": "1.2.6",
|
||||
"version": "1.3.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum PredicateVerificationResult {
|
||||
Affirmed = 'affirmed',
|
||||
Denied = 'denied',
|
||||
CouldNotBeDetermined = 'could-not-be-determined',
|
||||
}
|
||||
|
||||
@@ -3,6 +3,79 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.5](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.4...@standardnotes/scheduler-server@1.10.5) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.3...@standardnotes/scheduler-server@1.10.4) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.3](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.2...@standardnotes/scheduler-server@1.10.3) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.1...@standardnotes/scheduler-server@1.10.2) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.0...@standardnotes/scheduler-server@1.10.1) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.10.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.9.2...@standardnotes/scheduler-server@1.10.0) (2022-07-26)
|
||||
|
||||
### Features
|
||||
|
||||
* **scheduler:** enable discount applying and withdraw for everyone ([04bf414](https://github.com/standardnotes/server/commit/04bf414de41ecba255b068fd8e72bc569ace9ed1))
|
||||
|
||||
## [1.9.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.9.1...@standardnotes/scheduler-server@1.9.2) (2022-07-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** change the discount code to an absolute discount ([1fa94ef](https://github.com/standardnotes/server/commit/1fa94efa02f169ee25d11e9403ab3368b696cc33))
|
||||
|
||||
## [1.9.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.9.0...@standardnotes/scheduler-server@1.9.1) (2022-07-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** eliminate read/write concurrency hazzard while updating predicate status ([4ab0d24](https://github.com/standardnotes/server/commit/4ab0d24d24b62babf5d0e36fbcb3a6364abb71bc))
|
||||
|
||||
# [1.9.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.8.2...@standardnotes/scheduler-server@1.9.0) (2022-07-25)
|
||||
|
||||
### Features
|
||||
|
||||
* **scheduler:** add job interpreting logs ([bf12687](https://github.com/standardnotes/server/commit/bf12687f63738a6eac46ab1778826de5d076e4ab))
|
||||
|
||||
## [1.8.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.8.1...@standardnotes/scheduler-server@1.8.2) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.8.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.8.0...@standardnotes/scheduler-server@1.8.1) (2022-07-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** checking for predicates fullfillment on applying discount ([6374248](https://github.com/standardnotes/server/commit/637424813278b7dd81969e1783cbc38d1a916cab))
|
||||
|
||||
# [1.8.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.7.0...@standardnotes/scheduler-server@1.8.0) (2022-07-25)
|
||||
|
||||
### Features
|
||||
|
||||
* **scheduler:** add feature flag behind applying and withdrawing discounts ([0a5b956](https://github.com/standardnotes/server/commit/0a5b956cb9586d353ac68c79e8473d74f8d9796a))
|
||||
|
||||
# [1.7.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.6.0...@standardnotes/scheduler-server@1.7.0) (2022-07-25)
|
||||
|
||||
### Features
|
||||
|
||||
* **scheduler:** add creating discount apply/withdraw events ([7168435](https://github.com/standardnotes/server/commit/71684350e94053d884ae907e5d3deba4bc027f1b))
|
||||
* **scheduler:** add publishing discount apply/withdraw events ([48af9e7](https://github.com/standardnotes/server/commit/48af9e7c1cfb582389af83e15977b930bf067f8d))
|
||||
|
||||
# [1.6.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.5.23...@standardnotes/scheduler-server@1.6.0) (2022-07-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **scheduler:** schedule apply and withdraw subscription discounts upon registration ([fc20697](https://github.com/standardnotes/server/commit/fc20697d81419827c4f51c5c80804dd98804f33f))
|
||||
|
||||
## [1.5.23](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.5.22...@standardnotes/scheduler-server@1.5.23) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.5.23",
|
||||
"version": "1.10.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -24,7 +24,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/common": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
@@ -34,7 +34,7 @@
|
||||
"aws-sdk": "^2.1158.0",
|
||||
"dayjs": "^1.11.3",
|
||||
"dotenv": "^16.0.1",
|
||||
"inversify": "5.0.5",
|
||||
"inversify": "^6.0.1",
|
||||
"ioredis": "^5.2.0",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^8.14.1",
|
||||
@@ -50,7 +50,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.2",
|
||||
"npm-check-updates": "^15.3.3",
|
||||
"npm-check-updates": "^16.0.1",
|
||||
"ts-jest": "^28.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import { UserRegisteredEventHandler } from '../Domain/Handler/UserRegisteredEven
|
||||
import { SubscriptionCancelledEventHandler } from '../Domain/Handler/SubscriptionCancelledEventHandler'
|
||||
|
||||
// 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> {
|
||||
@@ -60,9 +60,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({
|
||||
|
||||
@@ -19,6 +19,52 @@ describe('DomainEventFactory', () => {
|
||||
timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
|
||||
})
|
||||
|
||||
it('should create a DISCOUNT_APPLY_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createDiscountApplyRequestedEvent({
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'off-10',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'scheduler',
|
||||
},
|
||||
payload: {
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'off-10',
|
||||
},
|
||||
type: 'DISCOUNT_APPLY_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a DISCOUNT_WITHDRAW_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createDiscountWithdrawRequestedEvent({
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'off-10',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'scheduler',
|
||||
},
|
||||
payload: {
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'off-10',
|
||||
},
|
||||
type: 'DISCOUNT_WITHDRAW_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a EMAIL_MESSAGE_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createEmailMessageRequestedEvent({
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { EmailMessageIdentifier } from '@standardnotes/common'
|
||||
import {
|
||||
DiscountApplyRequestedEvent,
|
||||
DiscountWithdrawRequestedEvent,
|
||||
DomainEventService,
|
||||
EmailMessageRequestedEvent,
|
||||
PredicateVerificationRequestedEvent,
|
||||
@@ -16,6 +18,39 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
|
||||
|
||||
createDiscountApplyRequestedEvent(dto: { userEmail: string; discountCode: string }): DiscountApplyRequestedEvent {
|
||||
return {
|
||||
type: 'DISCOUNT_APPLY_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: dto.userEmail,
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: DomainEventService.Scheduler,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
}
|
||||
|
||||
createDiscountWithdrawRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
discountCode: string
|
||||
}): DiscountWithdrawRequestedEvent {
|
||||
return {
|
||||
type: 'DISCOUNT_WITHDRAW_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: dto.userEmail,
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: DomainEventService.Scheduler,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
}
|
||||
|
||||
createEmailMessageRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
messageIdentifier: EmailMessageIdentifier
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { EmailMessageIdentifier } from '@standardnotes/common'
|
||||
import { EmailMessageRequestedEvent, PredicateVerificationRequestedEvent } from '@standardnotes/domain-events'
|
||||
import {
|
||||
DiscountApplyRequestedEvent,
|
||||
DiscountWithdrawRequestedEvent,
|
||||
EmailMessageRequestedEvent,
|
||||
PredicateVerificationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
|
||||
import { Job } from '../Job/Job'
|
||||
import { Predicate } from '../Predicate/Predicate'
|
||||
@@ -11,4 +16,6 @@ export interface DomainEventFactoryInterface {
|
||||
messageIdentifier: EmailMessageIdentifier
|
||||
context: Record<string, unknown>
|
||||
}): EmailMessageRequestedEvent
|
||||
createDiscountApplyRequestedEvent(dto: { userEmail: string; discountCode: string }): DiscountApplyRequestedEvent
|
||||
createDiscountWithdrawRequestedEvent(dto: { userEmail: string; discountCode: string }): DiscountWithdrawRequestedEvent
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
|
||||
await this.scheduleEncourageEmailBackupsJob(event)
|
||||
|
||||
await this.scheduleEncourageSubscriptionPurchasing(event)
|
||||
|
||||
await this.scheduleSubscriptionDiscountApplying(event)
|
||||
|
||||
await this.scheduleSubscriptionDiscountWithdraw(event)
|
||||
}
|
||||
|
||||
private async scheduleEncourageEmailBackupsJob(event: UserRegisteredEvent): Promise<void> {
|
||||
@@ -65,4 +69,36 @@ export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
|
||||
|
||||
await this.predicateRepository.save(predicate)
|
||||
}
|
||||
|
||||
private async scheduleSubscriptionDiscountApplying(event: UserRegisteredEvent): Promise<void> {
|
||||
const job = new Job()
|
||||
job.name = JobName.APPLY_SUBSCRIPTION_DISCOUNT
|
||||
job.scheduledAt = this.timer.convertDateToMicroseconds(this.timer.getUTCDateNDaysAhead(7))
|
||||
job.createdAt = this.timer.getTimestampInMicroseconds()
|
||||
job.status = JobStatus.Pending
|
||||
job.userIdentifier = event.payload.email
|
||||
job.userIdentifierType = 'email'
|
||||
|
||||
await this.jobRepository.save(job)
|
||||
|
||||
const predicate = new Predicate()
|
||||
predicate.name = PredicateName.SubscriptionPurchased
|
||||
predicate.status = PredicateStatus.Pending
|
||||
predicate.authority = PredicateAuthority.Auth
|
||||
predicate.job = Promise.resolve(job)
|
||||
|
||||
await this.predicateRepository.save(predicate)
|
||||
}
|
||||
|
||||
private async scheduleSubscriptionDiscountWithdraw(event: UserRegisteredEvent): Promise<void> {
|
||||
const job = new Job()
|
||||
job.name = JobName.WITHDRAW_SUBSCRIPTION_DISCOUNT
|
||||
job.scheduledAt = this.timer.convertDateToMicroseconds(this.timer.getUTCDateNDaysAhead(12))
|
||||
job.createdAt = this.timer.getTimestampInMicroseconds()
|
||||
job.status = JobStatus.Pending
|
||||
job.userIdentifier = event.payload.email
|
||||
job.userIdentifierType = 'email'
|
||||
|
||||
await this.jobRepository.save(job)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { DomainEventPublisherInterface, EmailMessageRequestedEvent } from '@standardnotes/domain-events'
|
||||
import {
|
||||
DiscountApplyRequestedEvent,
|
||||
DiscountWithdrawRequestedEvent,
|
||||
DomainEventPublisherInterface,
|
||||
EmailMessageRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { PredicateName } from '@standardnotes/predicates'
|
||||
import 'reflect-metadata'
|
||||
import { Logger } from 'winston'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
import { Predicate } from '../Predicate/Predicate'
|
||||
import { PredicateRepositoryInterface } from '../Predicate/PredicateRepositoryInterface'
|
||||
@@ -18,9 +24,10 @@ describe('JobDoneInterpreter', () => {
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
let domainEventPublisher: DomainEventPublisherInterface
|
||||
let job: Job
|
||||
let logger: Logger
|
||||
|
||||
const createInterpreter = () =>
|
||||
new JobDoneInterpreter(jobRepository, predicateRepository, domainEventFactory, domainEventPublisher)
|
||||
new JobDoneInterpreter(jobRepository, predicateRepository, domainEventFactory, domainEventPublisher, logger)
|
||||
|
||||
beforeEach(() => {
|
||||
job = {} as jest.Mocked<Job>
|
||||
@@ -35,9 +42,19 @@ describe('JobDoneInterpreter', () => {
|
||||
domainEventFactory.createEmailMessageRequestedEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<EmailMessageRequestedEvent>)
|
||||
domainEventFactory.createDiscountApplyRequestedEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<DiscountApplyRequestedEvent>)
|
||||
domainEventFactory.createDiscountWithdrawRequestedEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<DiscountWithdrawRequestedEvent>)
|
||||
|
||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
logger.warn = jest.fn()
|
||||
})
|
||||
|
||||
it('should do nothing if job is not found', async () => {
|
||||
@@ -172,6 +189,69 @@ describe('JobDoneInterpreter', () => {
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should request discount apply', async () => {
|
||||
jobRepository.findOneByUuid = jest.fn().mockReturnValue({
|
||||
name: JobName.APPLY_SUBSCRIPTION_DISCOUNT,
|
||||
userIdentifier: 'test@standardnotes.com',
|
||||
userIdentifierType: 'email',
|
||||
} as jest.Mocked<Job>)
|
||||
predicateRepository.findByJobUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue([
|
||||
{ name: PredicateName.SubscriptionPurchased, status: PredicateStatus.Denied } as jest.Mocked<Predicate>,
|
||||
])
|
||||
|
||||
await createInterpreter().interpret('1-2-3')
|
||||
|
||||
expect(domainEventFactory.createDiscountApplyRequestedEvent).toHaveBeenCalledWith({
|
||||
userEmail: 'test@standardnotes.com',
|
||||
discountCode: 'limited-10',
|
||||
})
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not request discount apply if email is missing', async () => {
|
||||
jobRepository.findOneByUuid = jest.fn().mockReturnValue({
|
||||
name: JobName.APPLY_SUBSCRIPTION_DISCOUNT,
|
||||
userIdentifier: '2-3-4',
|
||||
userIdentifierType: 'uuid',
|
||||
} as jest.Mocked<Job>)
|
||||
|
||||
await createInterpreter().interpret('1-2-3')
|
||||
|
||||
expect(domainEventFactory.createDiscountApplyRequestedEvent).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should request discount withdraw', async () => {
|
||||
jobRepository.findOneByUuid = jest.fn().mockReturnValue({
|
||||
name: JobName.WITHDRAW_SUBSCRIPTION_DISCOUNT,
|
||||
userIdentifier: 'test@standardnotes.com',
|
||||
userIdentifierType: 'email',
|
||||
} as jest.Mocked<Job>)
|
||||
|
||||
await createInterpreter().interpret('1-2-3')
|
||||
|
||||
expect(domainEventFactory.createDiscountWithdrawRequestedEvent).toHaveBeenCalledWith({
|
||||
userEmail: 'test@standardnotes.com',
|
||||
discountCode: 'limited-10',
|
||||
})
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not request discount withdraw if email is missing', async () => {
|
||||
jobRepository.findOneByUuid = jest.fn().mockReturnValue({
|
||||
name: JobName.WITHDRAW_SUBSCRIPTION_DISCOUNT,
|
||||
userIdentifier: '2-3-4',
|
||||
userIdentifierType: 'uuid',
|
||||
} as jest.Mocked<Job>)
|
||||
|
||||
await createInterpreter().interpret('1-2-3')
|
||||
|
||||
expect(domainEventFactory.createDiscountWithdrawRequestedEvent).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should do nothing if there is no interpretation for a given job', async () => {
|
||||
jobRepository.findOneByUuid = jest.fn().mockReturnValue({
|
||||
name: 'foobar' as JobName,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { EmailMessageIdentifier } from '@standardnotes/common'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { PredicateName } from '@standardnotes/predicates'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
@@ -20,6 +21,7 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
@inject(TYPES.PredicateRepository) private predicateRepository: PredicateRepositoryInterface,
|
||||
@inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
|
||||
@inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
|
||||
async interpret(jobUuid: string): Promise<void> {
|
||||
@@ -29,14 +31,18 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
return
|
||||
}
|
||||
|
||||
this.logger.info(`[${jobUuid}]${job.name}: Interpreting job as done.`)
|
||||
|
||||
if (!(await this.predicatesAreFulfilled(job))) {
|
||||
this.logger.info(`[${jobUuid}]${job.name}: predicates are not fulfilled.`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch (job.name) {
|
||||
case JobName.ENCOURAGE_EMAIL_BACKUPS:
|
||||
if (job.userIdentifierType === 'email') {
|
||||
await this.requestEmailBackupEncouragementEmail(job.userIdentifier)
|
||||
await this.requestEmailBackupEncouragementEmail(job)
|
||||
}
|
||||
return
|
||||
case JobName.ENCOURAGE_SUBSCRIPTION_PURCHASING:
|
||||
@@ -46,18 +52,32 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
return
|
||||
case JobName.EXIT_INTERVIEW:
|
||||
if (job.userIdentifierType === 'email') {
|
||||
await this.requestExitInterviewEmail(job.userIdentifier)
|
||||
await this.requestExitInterviewEmail(job)
|
||||
}
|
||||
return
|
||||
case JobName.APPLY_SUBSCRIPTION_DISCOUNT:
|
||||
if (job.userIdentifierType === 'email') {
|
||||
await this.requestDiscountApply(job)
|
||||
}
|
||||
return
|
||||
case JobName.WITHDRAW_SUBSCRIPTION_DISCOUNT:
|
||||
if (job.userIdentifierType === 'email') {
|
||||
await this.requestDiscountWithdraw(job)
|
||||
}
|
||||
return
|
||||
default:
|
||||
this.logger.warn(`[${jobUuid}]${job.name}: job is not interpretable.`)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private async requestEmailBackupEncouragementEmail(userEmail: string): Promise<void> {
|
||||
private async requestEmailBackupEncouragementEmail(job: Job): Promise<void> {
|
||||
this.logger.info(`[${job.uuid}]${job.name}: requesting email backup encouragement email.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createEmailMessageRequestedEvent({
|
||||
userEmail,
|
||||
userEmail: job.userIdentifier,
|
||||
messageIdentifier: EmailMessageIdentifier.ENCOURAGE_EMAIL_BACKUPS,
|
||||
context: {},
|
||||
}),
|
||||
@@ -65,6 +85,8 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
}
|
||||
|
||||
private async requestSubscriptionPurchaseEncouragementEmail(job: Job): Promise<void> {
|
||||
this.logger.info(`[${job.uuid}]${job.name}: requesting subscription purchase encouragement email.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createEmailMessageRequestedEvent({
|
||||
userEmail: job.userIdentifier,
|
||||
@@ -76,16 +98,40 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
)
|
||||
}
|
||||
|
||||
private async requestExitInterviewEmail(userEmail: string): Promise<void> {
|
||||
private async requestExitInterviewEmail(job: Job): Promise<void> {
|
||||
this.logger.info(`[${job.uuid}]${job.name}: requesting exit interview email.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createEmailMessageRequestedEvent({
|
||||
userEmail,
|
||||
userEmail: job.userIdentifier,
|
||||
messageIdentifier: EmailMessageIdentifier.EXIT_INTERVIEW,
|
||||
context: {},
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private async requestDiscountApply(job: Job): Promise<void> {
|
||||
this.logger.info(`[${job.uuid}]${job.name}: requesting discount applying.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createDiscountApplyRequestedEvent({
|
||||
userEmail: job.userIdentifier,
|
||||
discountCode: 'limited-10',
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private async requestDiscountWithdraw(job: Job): Promise<void> {
|
||||
this.logger.info(`[${job.uuid}]${job.name}: requesting discount withdraw.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createDiscountWithdrawRequestedEvent({
|
||||
userEmail: job.userIdentifier,
|
||||
discountCode: 'limited-10',
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private async predicatesAreFulfilled(job: Job): Promise<boolean> {
|
||||
const predicates = await this.predicateRepository.findByJobUuid(job.uuid)
|
||||
|
||||
@@ -96,6 +142,7 @@ export class JobDoneInterpreter implements JobDoneInterpreterInterface {
|
||||
PredicateStatus.Denied
|
||||
)
|
||||
case JobName.ENCOURAGE_SUBSCRIPTION_PURCHASING:
|
||||
case JobName.APPLY_SUBSCRIPTION_DISCOUNT:
|
||||
return (
|
||||
predicates.find((predicate) => predicate.name === PredicateName.SubscriptionPurchased)?.status ===
|
||||
PredicateStatus.Denied
|
||||
|
||||
@@ -3,4 +3,6 @@ export enum JobName {
|
||||
ENCOURAGE_EMAIL_BACKUPS = 'encourage-email-backups',
|
||||
ENCOURAGE_SUBSCRIPTION_PURCHASING = 'encourage-subscription-purchasing',
|
||||
EXIT_INTERVIEW = 'exit-interview',
|
||||
APPLY_SUBSCRIPTION_DISCOUNT = 'apply-subscription-discount',
|
||||
WITHDRAW_SUBSCRIPTION_DISCOUNT = 'withdraw-subscription-discount',
|
||||
}
|
||||
|
||||
+4
-46
@@ -1,8 +1,7 @@
|
||||
import { PredicateAuthority, PredicateName, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { JobDoneInterpreterInterface } from '../../Job/JobDoneInterpreterInterface'
|
||||
import { JobRepositoryInterface } from '../../Job/JobRepositoryInterface'
|
||||
import { PredicateAuthority, PredicateName, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
|
||||
import { Predicate } from '../../Predicate/Predicate'
|
||||
import { PredicateRepositoryInterface } from '../../Predicate/PredicateRepositoryInterface'
|
||||
import { PredicateStatus } from '../../Predicate/PredicateStatus'
|
||||
@@ -11,12 +10,10 @@ import { UpdatePredicateStatus } from './UpdatePredicateStatus'
|
||||
|
||||
describe('UpdatePredicateStatus', () => {
|
||||
let predicateRepository: PredicateRepositoryInterface
|
||||
let jobRepository: JobRepositoryInterface
|
||||
let jobDoneInterpreter: JobDoneInterpreterInterface
|
||||
let predicateComplete: Predicate
|
||||
let predicateIncomplete: Predicate
|
||||
|
||||
const createUseCase = () => new UpdatePredicateStatus(predicateRepository, jobRepository, jobDoneInterpreter)
|
||||
const createUseCase = () => new UpdatePredicateStatus(predicateRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
predicateComplete = {
|
||||
@@ -33,15 +30,9 @@ describe('UpdatePredicateStatus', () => {
|
||||
predicateRepository = {} as jest.Mocked<PredicateRepositoryInterface>
|
||||
predicateRepository.findByJobUuid = jest.fn().mockReturnValue([predicateComplete, predicateIncomplete])
|
||||
predicateRepository.save = jest.fn()
|
||||
|
||||
jobRepository = {} as jest.Mocked<JobRepositoryInterface>
|
||||
jobRepository.markJobAsDone = jest.fn()
|
||||
|
||||
jobDoneInterpreter = {} as jest.Mocked<JobDoneInterpreterInterface>
|
||||
jobDoneInterpreter.interpret = jest.fn()
|
||||
})
|
||||
|
||||
it('should mark a predicate as complete and update job as done', async () => {
|
||||
it('should mark a predicate as complete', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
predicate: { name: PredicateName.EmailBackupsEnabled, jobUuid: '1-2-3', authority: PredicateAuthority.Auth },
|
||||
@@ -49,7 +40,6 @@ describe('UpdatePredicateStatus', () => {
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
allPredicatesChecked: true,
|
||||
})
|
||||
|
||||
expect(predicateRepository.save).toHaveBeenCalledWith({
|
||||
@@ -57,37 +47,5 @@ describe('UpdatePredicateStatus', () => {
|
||||
name: 'email-backups-enabled',
|
||||
status: 'denied',
|
||||
})
|
||||
|
||||
expect(jobRepository.markJobAsDone).toHaveBeenCalled()
|
||||
expect(jobDoneInterpreter.interpret).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should mark a predicate as complete and not update job as done if there are still incomplete predicates', async () => {
|
||||
predicateRepository.findByJobUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue([
|
||||
predicateComplete,
|
||||
predicateIncomplete,
|
||||
{ uuid: '3-4-5', status: PredicateStatus.Pending } as jest.Mocked<Predicate>,
|
||||
])
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
predicate: { name: PredicateName.EmailBackupsEnabled, jobUuid: '1-2-3', authority: PredicateAuthority.Auth },
|
||||
predicateVerificationResult: PredicateVerificationResult.Denied,
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
allPredicatesChecked: false,
|
||||
})
|
||||
|
||||
expect(predicateRepository.save).toHaveBeenCalledWith({
|
||||
uuid: '2-3-4',
|
||||
name: 'email-backups-enabled',
|
||||
status: 'denied',
|
||||
})
|
||||
|
||||
expect(jobRepository.markJobAsDone).not.toHaveBeenCalled()
|
||||
expect(jobDoneInterpreter.interpret).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
+1
-18
@@ -1,8 +1,6 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { JobDoneInterpreterInterface } from '../../Job/JobDoneInterpreterInterface'
|
||||
import { JobRepositoryInterface } from '../../Job/JobRepositoryInterface'
|
||||
import { PredicateRepositoryInterface } from '../../Predicate/PredicateRepositoryInterface'
|
||||
import { PredicateStatus } from '../../Predicate/PredicateStatus'
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
@@ -12,35 +10,20 @@ import { UpdatePredicateStatusResponse } from './UpdatePredicateStatusResponse'
|
||||
|
||||
@injectable()
|
||||
export class UpdatePredicateStatus implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.PredicateRepository) private predicateRepository: PredicateRepositoryInterface,
|
||||
@inject(TYPES.JobRepository) private jobRepository: JobRepositoryInterface,
|
||||
@inject(TYPES.JobDoneInterpreter) private jobDoneInterpreter: JobDoneInterpreterInterface,
|
||||
) {}
|
||||
constructor(@inject(TYPES.PredicateRepository) private predicateRepository: PredicateRepositoryInterface) {}
|
||||
|
||||
async execute(dto: UpdatePredicateStatusDTO): Promise<UpdatePredicateStatusResponse> {
|
||||
const predicates = await this.predicateRepository.findByJobUuid(dto.predicate.jobUuid)
|
||||
|
||||
let allPredicatesChecked = true
|
||||
for (const predicate of predicates) {
|
||||
if (predicate.name === dto.predicate.name) {
|
||||
predicate.status = dto.predicateVerificationResult as unknown as PredicateStatus
|
||||
await this.predicateRepository.save(predicate)
|
||||
}
|
||||
if (predicate.status === PredicateStatus.Pending) {
|
||||
allPredicatesChecked = false
|
||||
}
|
||||
}
|
||||
|
||||
if (allPredicatesChecked) {
|
||||
await this.jobDoneInterpreter.interpret(dto.predicate.jobUuid)
|
||||
|
||||
await this.jobRepository.markJobAsDone(dto.predicate.jobUuid)
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
allPredicatesChecked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -1,6 +1,3 @@
|
||||
export type UpdatePredicateStatusResponse =
|
||||
| {
|
||||
success: true
|
||||
allPredicatesChecked: boolean
|
||||
}
|
||||
| { success: false }
|
||||
export type UpdatePredicateStatusResponse = {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.36](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.35...@standardnotes/syncing-server@1.6.36) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.35](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.34...@standardnotes/syncing-server@1.6.35) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.34](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.33...@standardnotes/syncing-server@1.6.34) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.33](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.32...@standardnotes/syncing-server@1.6.33) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.32](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.31...@standardnotes/syncing-server@1.6.32) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.31](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.30...@standardnotes/syncing-server@1.6.31) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.30](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.29...@standardnotes/syncing-server@1.6.30) (2022-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.29](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.28...@standardnotes/syncing-server@1.6.29) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.28](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.27...@standardnotes/syncing-server@1.6.28) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -8,7 +8,7 @@ import '../src/Controller/HealthCheckController'
|
||||
import '../src/Controller/RevisionsController'
|
||||
import '../src/Controller/ItemsController'
|
||||
|
||||
import * as helmet from 'helmet'
|
||||
import helmet from 'helmet'
|
||||
import * as cors from 'cors'
|
||||
import { urlencoded, json, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express'
|
||||
import * as winston from 'winston'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.6.28",
|
||||
"version": "1.6.36",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -24,7 +24,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/common": "workspace:*",
|
||||
@@ -40,7 +40,7 @@
|
||||
"cors": "2.8.5",
|
||||
"dotenv": "^16.0.1",
|
||||
"express": "^4.18.1",
|
||||
"helmet": "4.3.1",
|
||||
"helmet": "^5.1.1",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.2.0",
|
||||
@@ -71,7 +71,7 @@
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.2",
|
||||
"npm-check-updates": "^15.3.3",
|
||||
"npm-check-updates": "^16.0.1",
|
||||
"ts-jest": "^28.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface'
|
||||
import { Repository } from 'typeorm'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicWinstonEnricher = require('@newrelic/winston-enricher')
|
||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
|
||||
@@ -110,9 +110,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({
|
||||
|
||||
@@ -1260,13 +1260,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/winston-enricher@npm:^2.1.0":
|
||||
version: 2.1.2
|
||||
resolution: "@newrelic/winston-enricher@npm:2.1.2"
|
||||
"@newrelic/winston-enricher@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "@newrelic/winston-enricher@npm:4.0.0"
|
||||
peerDependencies:
|
||||
newrelic: ">=6.2.0"
|
||||
winston: ^3.0.0
|
||||
checksum: d001c131665470be698912accf3782b1b2871f5f2f0711527d423b47e967912ebe873da99f3cdfb0d367c62ac90aab87f448ac5ce89bae9a91a36d049b024003
|
||||
newrelic: ">=8.13.0"
|
||||
checksum: f737e7d9528b69ab771d0dd7d2262400291de60791767e09d477f700f1221df734a3f6a13b8907b909b4c190ccf20d4d3380d691f378422e789a2b448ab4fc7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1767,7 +1766,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway"
|
||||
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:*"
|
||||
@@ -1789,7 +1788,7 @@ __metadata:
|
||||
eslint: ^8.14.0
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
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
|
||||
@@ -1797,7 +1796,7 @@ __metadata:
|
||||
jsonwebtoken: 8.5.1
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.19
|
||||
npm-check-updates: ^15.3.3
|
||||
npm-check-updates: ^16.0.1
|
||||
prettyjson: ^1.2.5
|
||||
reflect-metadata: 0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
@@ -1823,7 +1822,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/auth-server@workspace:packages/auth"
|
||||
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
|
||||
@@ -1853,7 +1852,6 @@ __metadata:
|
||||
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
|
||||
eslint: ^8.14.0
|
||||
@@ -1866,7 +1864,7 @@ __metadata:
|
||||
mysql2: ^2.3.3
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.19
|
||||
npm-check-updates: ^15.3.3
|
||||
npm-check-updates: ^16.0.1
|
||||
otplib: 12.0.1
|
||||
prettyjson: ^1.2.5
|
||||
reflect-metadata: 0.1.13
|
||||
@@ -2039,7 +2037,7 @@ __metadata:
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
express: ^4.18.1
|
||||
express-winston: ^4.0.5
|
||||
helmet: ^4.3.1
|
||||
helmet: ^5.1.1
|
||||
inversify: ^6.0.1
|
||||
inversify-express-utils: ^6.4.3
|
||||
ioredis: ^5.2.0
|
||||
@@ -2047,7 +2045,7 @@ __metadata:
|
||||
jsonwebtoken: ^8.5.1
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.19
|
||||
npm-check-updates: ^15.3.3
|
||||
npm-check-updates: ^16.0.1
|
||||
prettyjson: ^1.2.5
|
||||
reflect-metadata: ^0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
@@ -2111,7 +2109,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/scheduler-server@workspace:packages/scheduler"
|
||||
dependencies:
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@newrelic/winston-enricher": ^4.0.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/common": "workspace:*"
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
@@ -2127,12 +2125,12 @@ __metadata:
|
||||
dayjs: ^1.11.3
|
||||
dotenv: ^16.0.1
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
inversify: 5.0.5
|
||||
inversify: ^6.0.1
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
mysql2: ^2.3.3
|
||||
newrelic: ^8.14.1
|
||||
npm-check-updates: ^15.3.3
|
||||
npm-check-updates: ^16.0.1
|
||||
reflect-metadata: ^0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
typeorm: ^0.3.6
|
||||
@@ -2174,7 +2172,7 @@ __metadata:
|
||||
eslint-config-prettier: ^8.5.0
|
||||
ini: ^3.0.0
|
||||
newrelic: ^8.14.1
|
||||
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
|
||||
@@ -2233,7 +2231,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/syncing-server@workspace:packages/syncing-server"
|
||||
dependencies:
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@newrelic/winston-enricher": ^4.0.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": "workspace:*"
|
||||
"@standardnotes/common": "workspace:*"
|
||||
@@ -2263,7 +2261,7 @@ __metadata:
|
||||
eslint: ^8.14.0
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
express: ^4.18.1
|
||||
helmet: 4.3.1
|
||||
helmet: ^5.1.1
|
||||
inversify: ^6.0.1
|
||||
inversify-express-utils: ^6.4.3
|
||||
ioredis: ^5.2.0
|
||||
@@ -2272,7 +2270,7 @@ __metadata:
|
||||
mysql2: ^2.3.3
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.19
|
||||
npm-check-updates: ^15.3.3
|
||||
npm-check-updates: ^16.0.1
|
||||
prettyjson: ^1.2.5
|
||||
reflect-metadata: 0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
@@ -4220,15 +4218,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"crypto-random-string@npm:3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "crypto-random-string@npm:3.3.0"
|
||||
dependencies:
|
||||
type-fest: ^0.8.1
|
||||
checksum: deff9866311a3a17ffd26ecdcebbbe9e1e12cf2fca5dd6e89993c9a03342d6da83f9f82cb0bfd7b31265d45eea710f376bc2af37bf3b053ef0cade920b8b04ba
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"crypto-random-string@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "crypto-random-string@npm:4.0.0"
|
||||
@@ -5610,24 +5599,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"helmet@npm:4.3.1":
|
||||
version: 4.3.1
|
||||
resolution: "helmet@npm:4.3.1"
|
||||
checksum: 47f59d8b9935eec24dadc5ce83bb7c149fc72f9355d3655babf0518740326b97fb83dc5f566cdcaf97753988003973848eb336ad3c784803a13e5056bca92bf7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"helmet@npm:4.4.1":
|
||||
version: 4.4.1
|
||||
resolution: "helmet@npm:4.4.1"
|
||||
checksum: cfe385e185e1ef6e4cd2ade4c54e160b05dd0454f270a663c528a8666402cbcad14e0ff0df09567fa62b0b4ac3371bbd1c8a253f6e7af37656a22339fe98c869
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"helmet@npm:^4.3.1":
|
||||
version: 4.6.0
|
||||
resolution: "helmet@npm:4.6.0"
|
||||
checksum: 139ad678d1cab207b043c206f50f6744eff2ef1f463e4626d36718b45b337485c77d10260ef9d89d292fa678da5153d86b08172b3b365cc8e680241015ed3a49
|
||||
"helmet@npm:^5.1.1":
|
||||
version: 5.1.1
|
||||
resolution: "helmet@npm:5.1.1"
|
||||
checksum: b72ba26cc431804ad3b8ecdc18db95409a492cbb7a7e825efc27fc502b9433fec39fc083f2aad4fe7ed1a89a4287560b59f4435f9689eebbae6a2b61a1ec1b7d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5928,13 +5903,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inversify@npm:5.0.5":
|
||||
version: 5.0.5
|
||||
resolution: "inversify@npm:5.0.5"
|
||||
checksum: a4bf1a6a62cacfeb7f82f85c4c00eea2326cd6e30d5d47582a6323ef8aacc5adc72f9aa3d86c373e27387b4ed37fcab7cfac728cdd5bdb252c6d27f849a151f1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inversify@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "inversify@npm:6.0.1"
|
||||
@@ -7838,9 +7806,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"npm-check-updates@npm:^15.3.3":
|
||||
version: 15.3.3
|
||||
resolution: "npm-check-updates@npm:15.3.3"
|
||||
"npm-check-updates@npm:^16.0.1":
|
||||
version: 16.0.1
|
||||
resolution: "npm-check-updates@npm:16.0.1"
|
||||
dependencies:
|
||||
chalk: ^5.0.1
|
||||
cli-table: ^0.3.11
|
||||
@@ -7872,7 +7840,7 @@ __metadata:
|
||||
bin:
|
||||
ncu: build/src/bin/cli.js
|
||||
npm-check-updates: build/src/bin/cli.js
|
||||
checksum: 3ee33fe369961d9548cdfde50085540e432a45a1166df4c1e6bacd5c25d36761efd156f6f358d1a51dd10db09d030106f87edec4d4a16637e35c09549a919cd5
|
||||
checksum: 1e747421f3d34055183037335437db91cd300448dccaad305925499719d4d34e6c1adfa3ce35a178f209106a40dcd57da088d9125dab2bd125ae54f5ae1c131c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user