mirror of
https://github.com/standardnotes/server
synced 2026-01-22 20:01:10 -05:00
Compare commits
57 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29674b02e6 | ||
|
|
572ea3febe | ||
|
|
f8334cf9d2 | ||
|
|
0ffec66bea | ||
|
|
becb386d10 | ||
|
|
0b9524eb26 | ||
|
|
ff5cd0128a | ||
|
|
b9225cd9b6 | ||
|
|
8f0ed3c5b3 | ||
|
|
12e3a768dd | ||
|
|
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 | ||
|
|
e7dda207fa | ||
|
|
7fd97fa194 | ||
|
|
ccbadfbd69 |
166
.pnp.cjs
generated
166
.pnp.cjs
generated
@@ -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"\
|
||||
}]\
|
||||
@@ -2480,7 +2476,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/jest", "npm:28.1.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
["ioredis", "npm:4.28.5"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"]\
|
||||
@@ -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,15 +2526,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["eslint", "npm:8.19.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
|
||||
["express", "npm:4.18.1"],\
|
||||
["helmet", "npm:4.4.1"],\
|
||||
["helmet", "npm:5.1.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["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"],\
|
||||
@@ -2601,12 +2596,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["express", "npm:4.18.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["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"],\
|
||||
@@ -2680,7 +2675,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
|
||||
["aws-sdk", "npm:2.1168.0"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
["ioredis", "npm:4.28.5"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
@@ -2725,7 +2720,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["eslint", "npm:8.19.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
@@ -2782,15 +2777,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
|
||||
["express", "npm:4.18.1"],\
|
||||
["express-winston", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:4.2.0"],\
|
||||
["helmet", "npm:4.6.0"],\
|
||||
["helmet", "npm:5.1.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["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"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["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,16 +3021,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["eslint", "npm:8.19.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
|
||||
["express", "npm:4.18.1"],\
|
||||
["helmet", "npm:4.3.1"],\
|
||||
["helmet", "npm:5.1.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["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": [\
|
||||
@@ -5744,13 +5731,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["denque", [\
|
||||
["npm:1.5.1", {\
|
||||
"packageLocation": "./.yarn/cache/denque-npm-1.5.1-2dd42d2dcb-4375ad19d5.zip/node_modules/denque/",\
|
||||
"packageDependencies": [\
|
||||
["denque", "npm:1.5.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.1", {\
|
||||
"packageLocation": "./.yarn/cache/denque-npm-2.0.1-4ba00e404b-ec398d1e3c.zip/node_modules/denque/",\
|
||||
"packageDependencies": [\
|
||||
@@ -7240,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"\
|
||||
}]\
|
||||
@@ -7585,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": [\
|
||||
@@ -7613,28 +7572,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["ioredis", [\
|
||||
["npm:4.28.5", {\
|
||||
"packageLocation": "./.yarn/cache/ioredis-npm-4.28.5-74671f2fa3-a8793c3324.zip/node_modules/ioredis/",\
|
||||
["npm:5.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/ioredis-npm-5.2.0-e2dd53ed39-37189fcd4b.zip/node_modules/ioredis/",\
|
||||
"packageDependencies": [\
|
||||
["ioredis", "npm:4.28.5"],\
|
||||
["cluster-key-slot", "npm:1.1.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
["denque", "npm:1.5.1"],\
|
||||
["lodash.defaults", "npm:4.2.0"],\
|
||||
["lodash.flatten", "npm:4.4.0"],\
|
||||
["lodash.isarguments", "npm:3.1.0"],\
|
||||
["p-map", "npm:2.1.0"],\
|
||||
["redis-commands", "npm:1.7.0"],\
|
||||
["redis-errors", "npm:1.2.0"],\
|
||||
["redis-parser", "npm:3.0.0"],\
|
||||
["standard-as-callback", "npm:2.1.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:5.1.0", {\
|
||||
"packageLocation": "./.yarn/cache/ioredis-npm-5.1.0-cc56f45bbf-7b1c137836.zip/node_modules/ioredis/",\
|
||||
"packageDependencies": [\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["@ioredis/commands", "npm:1.2.0"],\
|
||||
["cluster-key-slot", "npm:1.1.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
@@ -8921,15 +8862,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lodash.flatten", [\
|
||||
["npm:4.4.0", {\
|
||||
"packageLocation": "./.yarn/cache/lodash.flatten-npm-4.4.0-495935e617-0ac34a393d.zip/node_modules/lodash.flatten/",\
|
||||
"packageDependencies": [\
|
||||
["lodash.flatten", "npm:4.4.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lodash.includes", [\
|
||||
["npm:4.3.0", {\
|
||||
"packageLocation": "./.yarn/cache/lodash.includes-npm-4.3.0-3a2f6fa22c-71092c1305.zip/node_modules/lodash.includes/",\
|
||||
@@ -9810,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"],\
|
||||
@@ -10134,13 +10066,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["p-map", [\
|
||||
["npm:2.1.0", {\
|
||||
"packageLocation": "./.yarn/cache/p-map-npm-2.1.0-d9e865dc7c-9e3ad3c9f6.zip/node_modules/p-map/",\
|
||||
"packageDependencies": [\
|
||||
["p-map", "npm:2.1.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/p-map-npm-4.0.0-4677ae07c7-cb0ab21ec0.zip/node_modules/p-map/",\
|
||||
"packageDependencies": [\
|
||||
@@ -10999,15 +10924,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["redis-commands", [\
|
||||
["npm:1.7.0", {\
|
||||
"packageLocation": "./.yarn/cache/redis-commands-npm-1.7.0-528f61f9d8-d1ff7fbcb5.zip/node_modules/redis-commands/",\
|
||||
"packageDependencies": [\
|
||||
["redis-commands", "npm:1.7.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["redis-errors", [\
|
||||
["npm:1.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/redis-errors-npm-1.2.0-a81fd9b0f1-f28ac26921.zip/node_modules/redis-errors/",\
|
||||
@@ -12547,7 +12463,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["glob", "npm:7.2.3"],\
|
||||
["hdb-pool", null],\
|
||||
["ioredis", "npm:5.1.0"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["js-yaml", "npm:4.1.0"],\
|
||||
["mkdirp", "npm:1.0.4"],\
|
||||
["mongodb", null],\
|
||||
|
||||
Binary file not shown.
BIN
.yarn/cache/@newrelic-winston-enricher-npm-4.0.0-ebaf2d0d28-f737e7d952.zip
vendored
Normal file
BIN
.yarn/cache/@newrelic-winston-enricher-npm-4.0.0-ebaf2d0d28-f737e7d952.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/helmet-npm-5.1.1-d12265628c-b72ba26cc4.zip
vendored
Normal file
BIN
.yarn/cache/helmet-npm-5.1.1-d12265628c-b72ba26cc4.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/npm-check-updates-npm-16.0.1-fd143fcd27-1e747421f3.zip
vendored
Normal file
BIN
.yarn/cache/npm-check-updates-npm-16.0.1-fd143fcd27-1e747421f3.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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,52 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.12.1...@standardnotes/analytics@1.12.2) (2022-08-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** replace AND to OR operation on bitop ([572ea3f](https://github.com/standardnotes/server/commit/572ea3febe136518a33154937cf39347adf040ff))
|
||||
|
||||
## [1.12.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.12.0...@standardnotes/analytics@1.12.1) (2022-08-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** bitop over analytics time ([0ffec66](https://github.com/standardnotes/server/commit/0ffec66bea480fe9cec55415d90b608fddc26a84))
|
||||
|
||||
# [1.12.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.11.0...@standardnotes/analytics@1.12.0) (2022-08-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add total count of analytics over time ([0b9524e](https://github.com/standardnotes/server/commit/0b9524eb26c39aabe8ad0f9cdbb3aaca63a65b0e))
|
||||
|
||||
# [1.11.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.10.0...@standardnotes/analytics@1.11.0) (2022-08-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** format of changes over time to total count ([31c849c](https://github.com/standardnotes/server/commit/31c849cc2d13bc97690da1cbec3d1868ddb733dc))
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add calculating analytics over time ([977757d](https://github.com/standardnotes/server/commit/977757d346ba94794cc090f13d4dfdf489eb9d3a))
|
||||
|
||||
# [1.10.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.9.0...@standardnotes/analytics@1.10.0) (2022-08-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add marking server interaction as general activity in analytics ([a36764f](https://github.com/standardnotes/server/commit/a36764f1b058bed014b815fa2818370849053b18))
|
||||
|
||||
# [1.9.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.3...@standardnotes/analytics@1.9.0) (2022-07-26)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add limited discount offer purchased activity ([13201e7](https://github.com/standardnotes/server/commit/13201e7a9ec875796f527b2c500cf631345c36dd))
|
||||
|
||||
## [1.8.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.2...@standardnotes/analytics@1.8.3) (2022-07-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** change send_command to bitop function ([7fd97fa](https://github.com/standardnotes/server/commit/7fd97fa1940b6aab6b235a1ae2cb6ed2aa6ae917))
|
||||
|
||||
## [1.8.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.1...@standardnotes/analytics@1.8.2) (2022-07-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "1.8.2",
|
||||
"version": "1.12.2",
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <17.0.0"
|
||||
},
|
||||
@@ -26,11 +26,11 @@
|
||||
"test:unit": "jest spec --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ioredis": "^4.28.8",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"ioredis": "^4.28.5",
|
||||
"ioredis": "^5.2.0",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
},
|
||||
|
||||
@@ -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,9 @@ export interface AnalyticsStoreInterface {
|
||||
wasActivityDone(activity: AnalyticsActivity, analyticsId: number, period: Period): Promise<boolean>
|
||||
calculateActivityRetention(activity: AnalyticsActivity, firstPeriod: Period, secondPeriod: Period): Promise<number>
|
||||
calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number>
|
||||
calculateActivityChangesTotalCount(
|
||||
activity: AnalyticsActivity,
|
||||
period: Period,
|
||||
): Promise<Array<{ periodKey: string; totalCount: number }>>
|
||||
calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number>
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export enum Period {
|
||||
WeekBeforeLastWeek,
|
||||
ThisMonth,
|
||||
LastMonth,
|
||||
Last30Days,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('PeriodKeyGenerator', () => {
|
||||
const createGenerator = () => new PeriodKeyGenerator()
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers('modern')
|
||||
jest.useFakeTimers()
|
||||
jest.setSystemTime(1653395155000)
|
||||
})
|
||||
|
||||
@@ -13,6 +13,41 @@ describe('PeriodKeyGenerator', () => {
|
||||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it('should generate period keys for last 30 days', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Last30Days)).toEqual([
|
||||
'2022-4-24',
|
||||
'2022-4-25',
|
||||
'2022-4-26',
|
||||
'2022-4-27',
|
||||
'2022-4-28',
|
||||
'2022-4-29',
|
||||
'2022-4-30',
|
||||
'2022-5-1',
|
||||
'2022-5-2',
|
||||
'2022-5-3',
|
||||
'2022-5-4',
|
||||
'2022-5-5',
|
||||
'2022-5-6',
|
||||
'2022-5-7',
|
||||
'2022-5-8',
|
||||
'2022-5-9',
|
||||
'2022-5-10',
|
||||
'2022-5-11',
|
||||
'2022-5-12',
|
||||
'2022-5-13',
|
||||
'2022-5-14',
|
||||
'2022-5-15',
|
||||
'2022-5-16',
|
||||
'2022-5-17',
|
||||
'2022-5-18',
|
||||
'2022-5-19',
|
||||
'2022-5-20',
|
||||
'2022-5-21',
|
||||
'2022-5-22',
|
||||
'2022-5-23',
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate a period key for today', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.Today)).toEqual('2022-5-24')
|
||||
})
|
||||
@@ -55,4 +90,15 @@ describe('PeriodKeyGenerator', () => {
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should throw error on unsupported period for discrete generation', () => {
|
||||
let error = null
|
||||
try {
|
||||
createGenerator().getDiscretePeriodKeys(Period.Today)
|
||||
} catch (caughtError) {
|
||||
error = caughtError
|
||||
}
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,21 @@ import { Period } from './Period'
|
||||
import { PeriodKeyGeneratorInterface } from './PeriodKeyGeneratorInterface'
|
||||
|
||||
export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
getDiscretePeriodKeys(period: Period): string[] {
|
||||
const periodKeys = []
|
||||
|
||||
switch (period) {
|
||||
case Period.Last30Days:
|
||||
for (let i = 1; i <= 30; i++) {
|
||||
periodKeys.unshift(this.getDailyKey(this.getDateNDaysBefore(i)))
|
||||
}
|
||||
|
||||
return periodKeys
|
||||
default:
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
}
|
||||
|
||||
getPeriodKey(period: Period): string {
|
||||
switch (period) {
|
||||
case Period.Today:
|
||||
@@ -61,11 +76,15 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
return date.getDate().toString()
|
||||
}
|
||||
|
||||
private getYesterdayDate(): Date {
|
||||
const yesterday = new Date()
|
||||
yesterday.setDate(new Date().getDate() - 1)
|
||||
private getDateNDaysBefore(n: number) {
|
||||
const date = new Date()
|
||||
date.setDate(new Date().getDate() - n)
|
||||
|
||||
return yesterday
|
||||
return date
|
||||
}
|
||||
|
||||
private getYesterdayDate(): Date {
|
||||
return this.getDateNDaysBefore(1)
|
||||
}
|
||||
|
||||
private getDayBeforeYesterdayDate(): Date {
|
||||
|
||||
@@ -2,4 +2,5 @@ import { Period } from './Period'
|
||||
|
||||
export interface PeriodKeyGeneratorInterface {
|
||||
getPeriodKey(period: Period): string
|
||||
getDiscretePeriodKeys(period: Period): string[]
|
||||
}
|
||||
|
||||
@@ -23,12 +23,73 @@ describe('RedisAnalyticsStore', () => {
|
||||
redisClient.incr = jest.fn()
|
||||
redisClient.setbit = jest.fn()
|
||||
redisClient.getbit = jest.fn().mockReturnValue(1)
|
||||
redisClient.send_command = jest.fn()
|
||||
redisClient.bitop = jest.fn()
|
||||
|
||||
periodKeyGenerator = {} as jest.Mocked<PeriodKeyGeneratorInterface>
|
||||
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
|
||||
})
|
||||
|
||||
it('should calculate total count over time of activities', async () => {
|
||||
redisClient.bitcount = jest.fn().mockReturnValue(70)
|
||||
|
||||
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
|
||||
|
||||
await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.EditingItems, Period.Last30Days)
|
||||
|
||||
expect(redisClient.bitop).toHaveBeenCalledTimes(1)
|
||||
expect(redisClient.bitop).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'OR',
|
||||
'bitmap:action:editing-items:timespan:2022-4-24-2022-4-26',
|
||||
'bitmap:action:editing-items:timespan:2022-4-24',
|
||||
'bitmap:action:editing-items:timespan:2022-4-25',
|
||||
'bitmap:action:editing-items:timespan:2022-4-26',
|
||||
)
|
||||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-4-24-2022-4-26')
|
||||
})
|
||||
|
||||
it('should calculate total count changes of activities', async () => {
|
||||
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
|
||||
|
||||
redisClient.bitcount = jest.fn().mockReturnValueOnce(70).mockReturnValueOnce(71).mockReturnValueOnce(72)
|
||||
|
||||
expect(
|
||||
await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.Last30Days),
|
||||
).toEqual([
|
||||
{
|
||||
periodKey: '2022-4-24',
|
||||
totalCount: 70,
|
||||
},
|
||||
{
|
||||
periodKey: '2022-4-25',
|
||||
totalCount: 71,
|
||||
},
|
||||
{
|
||||
periodKey: '2022-4-26',
|
||||
totalCount: 72,
|
||||
},
|
||||
])
|
||||
|
||||
expect(redisClient.bitcount).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:2022-4-24')
|
||||
expect(redisClient.bitcount).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:2022-4-25')
|
||||
expect(redisClient.bitcount).toHaveBeenNthCalledWith(3, 'bitmap:action:editing-items:timespan:2022-4-26')
|
||||
})
|
||||
|
||||
it('should throw error on calculating total count changes of activities on unsupported period', async () => {
|
||||
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
|
||||
|
||||
redisClient.bitcount = jest.fn().mockReturnValueOnce(70).mockReturnValueOnce(71).mockReturnValueOnce(72)
|
||||
|
||||
let caughtError = null
|
||||
try {
|
||||
await createStore().calculateActivityChangesTotalCount(AnalyticsActivity.EditingItems, Period.LastWeek)
|
||||
} catch (error) {
|
||||
caughtError = error
|
||||
}
|
||||
|
||||
expect(caughtError).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should calculate total count of activities', async () => {
|
||||
redisClient.bitcount = jest.fn().mockReturnValue(70)
|
||||
|
||||
@@ -50,8 +111,7 @@ describe('RedisAnalyticsStore', () => {
|
||||
),
|
||||
).toEqual(70)
|
||||
|
||||
expect(redisClient.send_command).toHaveBeenCalledWith(
|
||||
'BITOP',
|
||||
expect(redisClient.bitop).toHaveBeenCalledWith(
|
||||
'AND',
|
||||
'bitmap:action:editing-items:timespan:period-key-period-key',
|
||||
'bitmap:action:editing-items:timespan:period-key',
|
||||
|
||||
@@ -8,6 +8,43 @@ import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreIn
|
||||
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
|
||||
|
||||
async calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number> {
|
||||
if (period !== Period.Last30Days) {
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
|
||||
await this.redisClient.bitop(
|
||||
'OR',
|
||||
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
|
||||
...periodKeys.map((p) => `bitmap:action:${activity}:timespan:${p}`),
|
||||
)
|
||||
|
||||
return this.redisClient.bitcount(
|
||||
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
|
||||
)
|
||||
}
|
||||
|
||||
async calculateActivityChangesTotalCount(
|
||||
activity: AnalyticsActivity,
|
||||
period: Period,
|
||||
): Promise<Array<{ periodKey: string; totalCount: number }>> {
|
||||
if (period !== Period.Last30Days) {
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
|
||||
const counts = []
|
||||
for (const periodKey of periodKeys) {
|
||||
counts.push({
|
||||
periodKey,
|
||||
totalCount: await this.redisClient.bitcount(`bitmap:action:${activity}:timespan:${periodKey}`),
|
||||
})
|
||||
}
|
||||
|
||||
return counts
|
||||
}
|
||||
|
||||
async markActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void> {
|
||||
const pipeline = this.redisClient.pipeline()
|
||||
|
||||
@@ -59,8 +96,7 @@ export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
|
||||
const diffKey = `bitmap:action:${activity}:timespan:${initialPeriodKey}-${subsequentPeriodKey}`
|
||||
|
||||
await this.redisClient.send_command(
|
||||
'BITOP',
|
||||
await this.redisClient.bitop(
|
||||
'AND',
|
||||
diffKey,
|
||||
`bitmap:action:${activity}:timespan:${initialPeriodKey}`,
|
||||
|
||||
@@ -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,78 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.11.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.1...@standardnotes/api-gateway@1.11.2) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.11.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.11.0...@standardnotes/api-gateway@1.11.1) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.11.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.10.0...@standardnotes/api-gateway@1.11.0) (2022-08-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add total count of analytics over time ([0b9524e](https://github.com/standardnotes/api-gateway/commit/0b9524eb26c39aabe8ad0f9cdbb3aaca63a65b0e))
|
||||
|
||||
# [1.10.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.9.1...@standardnotes/api-gateway@1.10.0) (2022-08-09)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add editing items count over time ([b9225cd](https://github.com/standardnotes/api-gateway/commit/b9225cd9b6496301da2d8edc44c2a9861e03406b))
|
||||
|
||||
## [1.9.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.9.0...@standardnotes/api-gateway@1.9.1) (2022-08-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** add general activity to calculating activity retention ([12e3a76](https://github.com/standardnotes/api-gateway/commit/12e3a768dd365198340ab4e2cd463e9392344e38))
|
||||
|
||||
# [1.9.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.8.0...@standardnotes/api-gateway@1.9.0) (2022-08-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add analytics over time to daily report event ([845f08b](https://github.com/standardnotes/api-gateway/commit/845f08b060beda5dea69e16fbda132150de7d5f2))
|
||||
|
||||
# [1.8.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.4...@standardnotes/api-gateway@1.8.0) (2022-08-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add marking server interaction as general activity in analytics ([a36764f](https://github.com/standardnotes/api-gateway/commit/a36764f1b058bed014b815fa2818370849053b18))
|
||||
|
||||
## [1.7.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.3...@standardnotes/api-gateway@1.7.4) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.7.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.2...@standardnotes/api-gateway@1.7.3) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.7.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.1...@standardnotes/api-gateway@1.7.2) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.7.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.7.0...@standardnotes/api-gateway@1.7.1) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.7.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.30...@standardnotes/api-gateway@1.7.0) (2022-07-26)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add limited discount offer purchased to analytics report ([d203ce1](https://github.com/standardnotes/api-gateway/commit/d203ce188af4f775e01bc1752d4c6d84fc5f1675))
|
||||
|
||||
## [1.6.30](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.29...@standardnotes/api-gateway@1.6.30) (2022-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.6.29](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.28...@standardnotes/api-gateway@1.6.29) (2022-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [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
|
||||
|
||||
## [1.6.27](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.26...@standardnotes/api-gateway@1.6.27) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -46,6 +46,52 @@ const requestReport = async (
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
retention: 0,
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.GeneralActivity,
|
||||
retention: await analyticsStore.calculateActivityRetention(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.DayBeforeYesterday,
|
||||
Period.Yesterday,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
],
|
||||
activityStatisticsOverTime: [
|
||||
{
|
||||
name: AnalyticsActivity.GeneralActivity,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.EditingItems,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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.27",
|
||||
"version": "1.11.2",
|
||||
"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,10 +34,10 @@
|
||||
"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.0.6",
|
||||
"ioredis": "^5.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"newrelic": "^8.14.1",
|
||||
"prettyjson": "^1.2.5",
|
||||
@@ -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,64 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.13.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.5...@standardnotes/auth-server@1.13.6) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.13.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.4...@standardnotes/auth-server@1.13.5) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.13.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.3...@standardnotes/auth-server@1.13.4) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.13.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.2...@standardnotes/auth-server@1.13.3) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.13.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.1...@standardnotes/auth-server@1.13.2) (2022-08-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.13.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.13.0...@standardnotes/auth-server@1.13.1) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.2...@standardnotes/auth-server@1.13.0) (2022-07-29)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** remove crypto-random-string in favour of @standardnotes/sncrypto-node ([35f931a](https://github.com/standardnotes/server/commit/35f931a708c7fead65fd40a9b4214a223831a5dc))
|
||||
|
||||
## [1.12.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.1...@standardnotes/auth-server@1.12.2) (2022-07-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.12.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.12.0...@standardnotes/auth-server@1.12.1) (2022-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.12.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.31...@standardnotes/auth-server@1.12.0) (2022-07-26)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add analytics for purchased subscription with a limited discount offer ([e936ac4](https://github.com/standardnotes/server/commit/e936ac4ce18fa43e47a50462c44f63a9ba1c1aa4))
|
||||
|
||||
## [1.11.31](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.30...@standardnotes/auth-server@1.11.31) (2022-07-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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.11.28](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.27...@standardnotes/auth-server@1.11.28) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.11.28",
|
||||
"version": "1.13.6",
|
||||
"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,13 +49,12 @@
|
||||
"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",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.0.6",
|
||||
"ioredis": "^5.2.0",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^8.14.1",
|
||||
"otplib": "12.0.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,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.7.30](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.29...@standardnotes/domain-events-infra@1.7.30) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [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.7.25](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.24...@standardnotes/domain-events-infra@1.7.25) (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.25",
|
||||
"version": "1.7.30",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -26,14 +26,14 @@
|
||||
"dependencies": {
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"aws-sdk": "^2.1082.0",
|
||||
"ioredis": "^4.28.5",
|
||||
"ioredis": "^5.2.0",
|
||||
"newrelic": "^8.8.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sqs-consumer": "^5.6.0",
|
||||
"winston": "^3.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ioredis": "^4.28.8",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.4",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
|
||||
@@ -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.
|
||||
|
||||
# [2.53.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.52.0...@standardnotes/domain-events@2.53.0) (2022-08-09)
|
||||
|
||||
### Features
|
||||
|
||||
* add total count of analytics over time ([0b9524e](https://github.com/standardnotes/server/commit/0b9524eb26c39aabe8ad0f9cdbb3aaca63a65b0e))
|
||||
|
||||
# [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.53.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -12,5 +12,14 @@ export interface DailyAnalyticsReportGeneratedEventPayload {
|
||||
retention: number
|
||||
totalCount: number
|
||||
}>
|
||||
activityStatisticsOverTime: Array<{
|
||||
name: string
|
||||
period: number
|
||||
counts: Array<{
|
||||
periodKey: string
|
||||
totalCount: number
|
||||
}>
|
||||
totalCount: number
|
||||
}>
|
||||
outOfSyncIncidents: number
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@ export interface SubscriptionPurchasedEventPayload {
|
||||
subscriptionExpiresAt: number
|
||||
timestamp: number
|
||||
offline: boolean
|
||||
discountCode: string | null
|
||||
}
|
||||
|
||||
@@ -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.1.29](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.28...@standardnotes/event-store@1.1.29) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [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.1.24](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.23...@standardnotes/event-store@1.1.24) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.1.24",
|
||||
"version": "1.1.29",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
@@ -37,7 +37,7 @@
|
||||
"aws-sdk": "^2.1159.0",
|
||||
"dotenv": "^16.0.1",
|
||||
"inversify": "^6.0.1",
|
||||
"ioredis": "^5.0.6",
|
||||
"ioredis": "^5.2.0",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^8.14.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.5.32](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.31...@standardnotes/files-server@1.5.32) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [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
|
||||
|
||||
## [1.5.25](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.24...@standardnotes/files-server@1.5.25) (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.25",
|
||||
"version": "1.5.32",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -41,10 +41,10 @@
|
||||
"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.0.6",
|
||||
"ioredis": "^5.2.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"newrelic": "^8.14.1",
|
||||
"nodemon": "^2.0.19",
|
||||
@@ -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,87 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.6](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.5...@standardnotes/scheduler-server@1.10.6) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [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.5.22](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.5.21...@standardnotes/scheduler-server@1.5.22) (2022-07-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.5.22",
|
||||
"version": "1.10.6",
|
||||
"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,8 +34,8 @@
|
||||
"aws-sdk": "^2.1158.0",
|
||||
"dayjs": "^1.11.3",
|
||||
"dotenv": "^16.0.1",
|
||||
"inversify": "5.0.5",
|
||||
"ioredis": "^5.0.6",
|
||||
"inversify": "^6.0.1",
|
||||
"ioredis": "^5.2.0",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^8.14.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
@@ -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,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
export type UpdatePredicateStatusResponse =
|
||||
| {
|
||||
success: true
|
||||
allPredicatesChecked: boolean
|
||||
}
|
||||
| { success: false }
|
||||
export type UpdatePredicateStatusResponse = {
|
||||
success: boolean
|
||||
}
|
||||
|
||||
@@ -3,6 +3,54 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.39](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.38...@standardnotes/syncing-server@1.6.39) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.38](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.37...@standardnotes/syncing-server@1.6.38) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.6.37](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.36...@standardnotes/syncing-server@1.6.37) (2022-08-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [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
|
||||
|
||||
## [1.6.27](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.6.26...@standardnotes/syncing-server@1.6.27) (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.27",
|
||||
"version": "1.6.39",
|
||||
"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,10 +40,10 @@
|
||||
"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.0.6",
|
||||
"ioredis": "^5.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^8.14.1",
|
||||
@@ -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({
|
||||
|
||||
163
yarn.lock
163
yarn.lock
@@ -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
|
||||
|
||||
@@ -1752,11 +1751,11 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/analytics@workspace:packages/analytics"
|
||||
dependencies:
|
||||
"@types/ioredis": ^4.28.8
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.4
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
ioredis: ^4.28.5
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
reflect-metadata: ^0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
@@ -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,15 +1788,15 @@ __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.0.6
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
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
|
||||
@@ -1861,12 +1859,12 @@ __metadata:
|
||||
express: ^4.18.1
|
||||
inversify: ^6.0.1
|
||||
inversify-express-utils: ^6.4.3
|
||||
ioredis: ^5.0.6
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
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
|
||||
@@ -1920,13 +1918,13 @@ __metadata:
|
||||
resolution: "@standardnotes/domain-events-infra@workspace:packages/domain-events-infra"
|
||||
dependencies:
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@types/ioredis": ^4.28.8
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.4
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
aws-sdk: ^2.1082.0
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
ioredis: ^4.28.5
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
newrelic: ^8.8.0
|
||||
reflect-metadata: ^0.1.13
|
||||
@@ -1985,7 +1983,7 @@ __metadata:
|
||||
eslint: ^8.14.0
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
inversify: ^6.0.1
|
||||
ioredis: ^5.0.6
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
mysql2: ^2.3.3
|
||||
newrelic: ^8.14.1
|
||||
@@ -2039,15 +2037,15 @@ __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.0.6
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
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
|
||||
ioredis: ^5.0.6
|
||||
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,16 +2261,16 @@ __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.0.6
|
||||
ioredis: ^5.2.0
|
||||
jest: ^28.1.2
|
||||
jsonwebtoken: 8.5.1
|
||||
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
|
||||
@@ -2517,7 +2515,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/ioredis@npm:^4.28.10, @types/ioredis@npm:^4.28.8":
|
||||
"@types/ioredis@npm:^4.28.10":
|
||||
version: 4.28.10
|
||||
resolution: "@types/ioredis@npm:4.28.10"
|
||||
dependencies:
|
||||
@@ -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"
|
||||
@@ -4387,13 +4376,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"denque@npm:^1.1.0":
|
||||
version: 1.5.1
|
||||
resolution: "denque@npm:1.5.1"
|
||||
checksum: 4375ad19d5cea99f90effa82a8cecdaa10f4eb261fbcd7e47cd753ff2737f037aac8f7f4e031cc77f3966314c491c86a0d3b20c128aeee57f791b4662c45108e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"denque@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "denque@npm:2.0.1"
|
||||
@@ -5617,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
|
||||
|
||||
@@ -5935,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"
|
||||
@@ -5949,28 +5910,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ioredis@npm:^4.28.5":
|
||||
version: 4.28.5
|
||||
resolution: "ioredis@npm:4.28.5"
|
||||
dependencies:
|
||||
cluster-key-slot: ^1.1.0
|
||||
debug: ^4.3.1
|
||||
denque: ^1.1.0
|
||||
lodash.defaults: ^4.2.0
|
||||
lodash.flatten: ^4.4.0
|
||||
lodash.isarguments: ^3.1.0
|
||||
p-map: ^2.1.0
|
||||
redis-commands: 1.7.0
|
||||
redis-errors: ^1.2.0
|
||||
redis-parser: ^3.0.0
|
||||
standard-as-callback: ^2.1.0
|
||||
checksum: a8793c3324cd69fa55b4baacbda118ce6724e574260157761276b31411dd3e168c75490f7155c6ce34d79e01488efa98e0cdb162991970fd56da7cbcdafb8fb8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ioredis@npm:^5.0.6":
|
||||
version: 5.1.0
|
||||
resolution: "ioredis@npm:5.1.0"
|
||||
"ioredis@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "ioredis@npm:5.2.0"
|
||||
dependencies:
|
||||
"@ioredis/commands": ^1.1.1
|
||||
cluster-key-slot: ^1.1.0
|
||||
@@ -5981,7 +5923,7 @@ __metadata:
|
||||
redis-errors: ^1.2.0
|
||||
redis-parser: ^3.0.0
|
||||
standard-as-callback: ^2.1.0
|
||||
checksum: 7b1c137836ee136a634926df4ec68cc2393772a32ecda8e30dd305d7b9182af02d600456e661f96a6ceada17560ce7b6458948fd09b8adc277a1d287325777dd
|
||||
checksum: 37189fcd4bd834d66aabb28a754d97da9147a6162c16bd971647750dbb81cbe7d93f4c07a623efdc0fdcb61bca243678b864229ddbcc2b8692755d7be40a2227
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7067,13 +7009,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.flatten@npm:^4.4.0":
|
||||
version: 4.4.0
|
||||
resolution: "lodash.flatten@npm:4.4.0"
|
||||
checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.includes@npm:^4.3.0":
|
||||
version: 4.3.0
|
||||
resolution: "lodash.includes@npm:4.3.0"
|
||||
@@ -7871,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
|
||||
@@ -7905,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
|
||||
|
||||
@@ -8173,13 +8108,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-map@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "p-map@npm:2.1.0"
|
||||
checksum: 9e3ad3c9f6d75a5b5661bcad78c91f3a63849189737cd75e4f1225bf9ac205194e5c44aac2ef6f09562b1facdb9bd1425584d7ac375bfaa17b3f1a142dab936d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-map@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "p-map@npm:4.0.0"
|
||||
@@ -8943,13 +8871,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"redis-commands@npm:1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "redis-commands@npm:1.7.0"
|
||||
checksum: d1ff7fbcb5e54768c77f731f1d49679d2a62c3899522c28addb4e2e5813aea8bcac3f22519d71d330224c3f2937f935dfc3d8dc65e90db0f5fe22dc2c1515aa7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"redis-errors@npm:^1.0.0, redis-errors@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "redis-errors@npm:1.2.0"
|
||||
|
||||
Reference in New Issue
Block a user