mirror of
https://github.com/standardnotes/server
synced 2026-01-17 23:04:34 -05:00
Compare commits
91 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff091918aa | ||
|
|
91b76edce1 | ||
|
|
5ae5c83bf5 | ||
|
|
9d90f276de | ||
|
|
245f091e22 | ||
|
|
ae2f8f086b | ||
|
|
5e5eb7f937 | ||
|
|
748630e1f1 | ||
|
|
43064c8c55 | ||
|
|
4559a3047c | ||
|
|
de8064ee5c | ||
|
|
48c8dba342 | ||
|
|
31a515b2f1 | ||
|
|
294f56e189 | ||
|
|
70596a0aac | ||
|
|
74bc79116b | ||
|
|
e6bd50ae77 | ||
|
|
308662550f | ||
|
|
d94a7e7157 | ||
|
|
630b264754 | ||
|
|
5f2be44b85 | ||
|
|
f68ece68af | ||
|
|
70c829a2c9 | ||
|
|
e3b6ac4874 | ||
|
|
a762d5a22c | ||
|
|
3686a26019 | ||
|
|
80daec748d | ||
|
|
94359f1299 | ||
|
|
59dda1bb99 | ||
|
|
806a732cbc | ||
|
|
7816be7ba7 | ||
|
|
5f3bd5137f | ||
|
|
6c9fc5fb86 | ||
|
|
f7e0b68643 | ||
|
|
b283bbaca9 | ||
|
|
92ba759b1c | ||
|
|
0acc9d8d68 | ||
|
|
daa7a9ff61 | ||
|
|
455f35e0c1 | ||
|
|
1fa655b56e | ||
|
|
e553222b4b | ||
|
|
f1b6f48926 | ||
|
|
14ab1cae69 | ||
|
|
5f9cf90b16 | ||
|
|
97b367d4ee | ||
|
|
47119fb346 | ||
|
|
d77eb7f5f1 | ||
|
|
1b0a2bb34c | ||
|
|
a363039fa1 | ||
|
|
32c740b58e | ||
|
|
822ee890af | ||
|
|
b0406dd8aa | ||
|
|
8d152ddfcb | ||
|
|
1a16d2e4f4 | ||
|
|
1ca8531305 | ||
|
|
6190e7d092 | ||
|
|
a6542dd638 | ||
|
|
840777a851 | ||
|
|
5c9dff38c9 | ||
|
|
abfbacb8c2 | ||
|
|
03afdbf431 | ||
|
|
507d43b328 | ||
|
|
be214c0599 | ||
|
|
91f36c3a3f | ||
|
|
f60c15ed2e | ||
|
|
1ec072373d | ||
|
|
a7d039082e | ||
|
|
d5c06bfa58 | ||
|
|
c8f3a0ce7b | ||
|
|
edbedc181b | ||
|
|
94afa34780 | ||
|
|
74dd0ab6cd | ||
|
|
6c43a331d0 | ||
|
|
67835ba0c0 | ||
|
|
fe1b2a0e07 | ||
|
|
2e82be47ed | ||
|
|
15dfd6dcba | ||
|
|
dfd38943b0 | ||
|
|
500756d582 | ||
|
|
f855f541d8 | ||
|
|
590ec6643d | ||
|
|
b9efd35b50 | ||
|
|
3be1bfe58a | ||
|
|
bfbd2de778 | ||
|
|
50f7ae338a | ||
|
|
280fdc89c1 | ||
|
|
0f94e2ad0c | ||
|
|
d0036600e9 | ||
|
|
f766fefbf0 | ||
|
|
2178ed2a31 | ||
|
|
79511aea5f |
46
.github/workflows/revisions.yml
vendored
Normal file
46
.github/workflows/revisions.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Revisions Server
|
||||
|
||||
concurrency:
|
||||
group: revisions_server
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*standardnotes/revisions-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call_server_application_workflow:
|
||||
name: Server Application
|
||||
uses: standardnotes/server/.github/workflows/common-server-application.yml@main
|
||||
with:
|
||||
service_name: revisions
|
||||
workspace_name: "@standardnotes/revisions-server"
|
||||
e2e_tag_parameter_name: revisions_image_tag
|
||||
package_path: packages/revisions
|
||||
secrets: inherit
|
||||
|
||||
newrelic:
|
||||
needs: call_server_application_workflow
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create New Relic deployment marker for Web
|
||||
uses: newrelic/deployment-marker-action@v1
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_REVISIONS_WEB_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
- name: Create New Relic deployment marker for Worker
|
||||
uses: newrelic/deployment-marker-action@v1
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_REVISIONS_WORKER_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
130
.pnp.cjs
generated
130
.pnp.cjs
generated
@@ -29,6 +29,10 @@ const RAW_RUNTIME_STATE =
|
||||
"name": "@standardnotes/common",\
|
||||
"reference": "workspace:packages/common"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/domain-core",\
|
||||
"reference": "workspace:packages/domain-core"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/domain-events",\
|
||||
"reference": "workspace:packages/domain-events"\
|
||||
@@ -49,6 +53,10 @@ const RAW_RUNTIME_STATE =
|
||||
"name": "@standardnotes/predicates",\
|
||||
"reference": "workspace:packages/predicates"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/revisions-server",\
|
||||
"reference": "workspace:packages/revisions"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/scheduler-server",\
|
||||
"reference": "workspace:packages/scheduler"\
|
||||
@@ -89,11 +97,13 @@ const RAW_RUNTIME_STATE =
|
||||
["@standardnotes/api-gateway", ["workspace:packages/api-gateway"]],\
|
||||
["@standardnotes/auth-server", ["workspace:packages/auth"]],\
|
||||
["@standardnotes/common", ["workspace:packages/common"]],\
|
||||
["@standardnotes/domain-core", ["workspace:packages/domain-core"]],\
|
||||
["@standardnotes/domain-events", ["workspace:packages/domain-events"]],\
|
||||
["@standardnotes/domain-events-infra", ["workspace:packages/domain-events-infra"]],\
|
||||
["@standardnotes/event-store", ["workspace:packages/event-store"]],\
|
||||
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
||||
["@standardnotes/predicates", ["workspace:packages/predicates"]],\
|
||||
["@standardnotes/revisions-server", ["workspace:packages/revisions"]],\
|
||||
["@standardnotes/scheduler-server", ["workspace:packages/scheduler"]],\
|
||||
["@standardnotes/security", ["workspace:packages/security"]],\
|
||||
["@standardnotes/server-monorepo", ["workspace:."]],\
|
||||
@@ -116,7 +126,6 @@ const RAW_RUNTIME_STATE =
|
||||
["@lerna-lite/cli", "npm:1.6.0"],\
|
||||
["@lerna-lite/list", "npm:1.6.0"],\
|
||||
["@lerna-lite/run", "npm:1.6.0"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
@@ -2528,10 +2537,10 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/analytics/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/analytics", "workspace:packages/analytics"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
@@ -2539,9 +2548,8 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["dayjs", "npm:1.11.6"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint", "npm:8.25.0"],\
|
||||
@@ -2552,11 +2560,9 @@ const RAW_RUNTIME_STATE =
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:9.6.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["shallow-equal-object", "npm:1.1.1"],\
|
||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.0.3"],\
|
||||
["typeorm", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:0.3.10"],\
|
||||
["typescript", "patch:typescript@npm%3A4.8.4#optional!builtin<compat/typescript>::version=4.8.4&hash=701156"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.8.2"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -2583,7 +2589,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/api-gateway/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
@@ -2599,7 +2604,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@types/prettyjson", "npm:0.0.30"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["axios", "npm:1.1.3"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
@@ -2640,7 +2645,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/auth/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/auth-server", "workspace:packages/auth"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/api", "npm:1.19.0"],\
|
||||
@@ -2666,7 +2670,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/ua-parser-js", "npm:0.7.36"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["axios", "npm:1.1.3"],\
|
||||
["bcryptjs", "npm:2.4.3"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
@@ -2701,7 +2705,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/common/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
@@ -2728,12 +2731,34 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/domain-core", [\
|
||||
["workspace:packages/domain-core", {\
|
||||
"packageLocation": "./packages/domain-core/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.53.1"],\
|
||||
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
["eslint-plugin-prettier", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:4.2.1"],\
|
||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.2"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["shallow-equal-object", "npm:1.1.1"],\
|
||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.0.3"],\
|
||||
["typescript", "patch:typescript@npm%3A4.8.4#optional!builtin<compat/typescript>::version=4.8.4&hash=701156"],\
|
||||
["uuid", "npm:9.0.0"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/domain-events", [\
|
||||
["workspace:packages/domain-events", {\
|
||||
"packageLocation": "./packages/domain-events/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.53.1"],\
|
||||
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
||||
@@ -2754,13 +2779,12 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/domain-events-infra/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@types/ioredis", "npm:5.0.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["eslint-plugin-prettier", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:4.2.1"],\
|
||||
["ioredis", "npm:5.2.4"],\
|
||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.2"],\
|
||||
@@ -2794,7 +2818,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/event-store/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/event-store", "workspace:packages/event-store"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
@@ -2803,7 +2826,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@types/nodemailer", "npm:6.4.6"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint", "npm:8.25.0"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
@@ -2850,7 +2873,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/files/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/files-server", "workspace:packages/files"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/config", "npm:2.4.3"],\
|
||||
@@ -2870,7 +2892,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/prettyjson", "npm:0.0.30"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["connect-busboy", "npm:1.0.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dayjs", "npm:1.11.6"],\
|
||||
@@ -2944,7 +2966,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/predicates/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
@@ -2981,12 +3002,56 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/revisions-server", [\
|
||||
["workspace:packages/revisions", {\
|
||||
"packageLocation": "./packages/revisions/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/revisions-server", "workspace:packages/revisions"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/api", "npm:1.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
["@types/cors", "npm:2.8.12"],\
|
||||
["@types/dotenv", "npm:8.2.0"],\
|
||||
["@types/express", "npm:4.17.14"],\
|
||||
["@types/inversify-express-utils", "npm:2.0.0"],\
|
||||
["@types/ioredis", "npm:5.0.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint", "npm:8.25.0"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
["express", "npm:4.18.2"],\
|
||||
["helmet", "npm:6.0.0"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.2.4"],\
|
||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.2"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:9.6.0"],\
|
||||
["npm-check-updates", "npm:16.0.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.0.3"],\
|
||||
["typeorm", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:0.3.10"],\
|
||||
["typescript", "patch:typescript@npm%3A4.8.4#optional!builtin<compat/typescript>::version=4.8.4&hash=701156"],\
|
||||
["winston", "npm:3.8.2"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/scheduler-server", [\
|
||||
["workspace:packages/scheduler", {\
|
||||
"packageLocation": "./packages/scheduler/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
@@ -2999,7 +3064,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["dayjs", "npm:1.11.6"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint", "npm:8.25.0"],\
|
||||
@@ -3024,7 +3089,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/security/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/jsonwebtoken", "npm:8.5.9"],\
|
||||
@@ -3049,7 +3113,6 @@ const RAW_RUNTIME_STATE =
|
||||
["@lerna-lite/cli", "npm:1.6.0"],\
|
||||
["@lerna-lite/list", "npm:1.6.0"],\
|
||||
["@lerna-lite/run", "npm:1.6.0"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
@@ -3072,7 +3135,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/settings/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/settings", "workspace:packages/settings"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
["eslint-plugin-prettier", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:4.2.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
@@ -3096,7 +3158,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/sncrypto-node/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.13.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/node", "npm:18.11.9"],\
|
||||
@@ -3117,10 +3178,10 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/syncing-server/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/payloads", "npm:1.5.1"],\
|
||||
@@ -3140,7 +3201,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/ua-parser-js", "npm:0.7.36"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["axios", "npm:1.1.3"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
@@ -3174,7 +3235,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/time/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/microtime", "npm:2.1.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.30.5"],\
|
||||
@@ -3218,7 +3278,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/websockets/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/websockets-server", "workspace:packages/websockets"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/api", "npm:1.19.0"],\
|
||||
@@ -3232,7 +3291,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["axios", "npm:1.1.3"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
@@ -3259,7 +3318,6 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/workspace/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/workspace-server", "workspace:packages/workspace"],\
|
||||
["@newrelic/native-metrics", "npm:9.0.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.19.0"],\
|
||||
["@standardnotes/api", "npm:1.19.0"],\
|
||||
@@ -3275,7 +3333,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@types/jest", "npm:29.1.1"],\
|
||||
["@types/newrelic", "npm:7.0.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.40.1"],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint", "npm:8.25.0"],\
|
||||
@@ -4742,10 +4800,10 @@ const RAW_RUNTIME_STATE =
|
||||
}]\
|
||||
]],\
|
||||
["aws-sdk", [\
|
||||
["npm:2.1253.0", {\
|
||||
"packageLocation": "./.yarn/cache/aws-sdk-npm-2.1253.0-2cf60975ab-faa4af2949.zip/node_modules/aws-sdk/",\
|
||||
["npm:2.1260.0", {\
|
||||
"packageLocation": "./.yarn/cache/aws-sdk-npm-2.1260.0-0145998ab1-9a1b2e4cb5.zip/node_modules/aws-sdk/",\
|
||||
"packageDependencies": [\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["buffer", "npm:4.9.2"],\
|
||||
["events", "npm:1.1.1"],\
|
||||
["ieee754", "npm:1.1.13"],\
|
||||
@@ -12512,7 +12570,7 @@ const RAW_RUNTIME_STATE =
|
||||
"packageDependencies": [\
|
||||
["sqs-consumer", "virtual:685a6222c3349423674bb7f0684ba34e2ab20912010f352e04dcf707a156e13183fc382e2417cb37a60f3e7b52fd0178c53181674890e1773eb83e190dc13378#npm:5.7.0"],\
|
||||
["@types/aws-sdk", null],\
|
||||
["aws-sdk", "npm:2.1253.0"],\
|
||||
["aws-sdk", "npm:2.1260.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
||||
Binary file not shown.
@@ -21,6 +21,7 @@
|
||||
"lint:websockets": "yarn workspace @standardnotes/websockets-server lint",
|
||||
"lint:workspace": "yarn workspace @standardnotes/workspace-server lint",
|
||||
"lint:analytics": "yarn workspace @standardnotes/analytics lint",
|
||||
"lint:revisions": "yarn workspace @standardnotes/revisions-server lint",
|
||||
"clean": "yarn workspaces foreach -p --verbose run clean",
|
||||
"setup:env": "cp .env.sample .env && yarn workspaces foreach -p --verbose run setup:env",
|
||||
"start:auth": "yarn workspace @standardnotes/auth-server start",
|
||||
@@ -34,6 +35,7 @@
|
||||
"start:websockets": "yarn workspace @standardnotes/websockets-server start",
|
||||
"start:workspace": "yarn workspace @standardnotes/workspace-server start",
|
||||
"start:analytics": "yarn workspace @standardnotes/analytics worker",
|
||||
"start:revisions": "yarn workspace @standardnotes/revisions-server start",
|
||||
"release": "lerna version --conventional-graduate --conventional-commits --yes -m \"chore(release): publish new version\"",
|
||||
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
|
||||
"postversion": "./scripts/push-tags-one-by-one.sh",
|
||||
@@ -59,7 +61,6 @@
|
||||
},
|
||||
"packageManager": "yarn@4.0.0-rc.25",
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"@sentry/node": "^7.19.0",
|
||||
"newrelic": "^9.6.0"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,94 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.11.13](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.12...@standardnotes/analytics@2.11.13) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.12](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.11...@standardnotes/analytics@2.11.12) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.11](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.10...@standardnotes/analytics@2.11.11) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.10](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.9...@standardnotes/analytics@2.11.10) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.8...@standardnotes/analytics@2.11.9) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.7...@standardnotes/analytics@2.11.8) (2022-11-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.6...@standardnotes/analytics@2.11.7) (2022-11-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* binding of sns and sqs with additional config ([74bc791](https://github.com/standardnotes/server/commit/74bc79116bc50d9a5af1a558db1b7108dcda6d0e))
|
||||
|
||||
## [2.11.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.5...@standardnotes/analytics@2.11.6) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.4...@standardnotes/analytics@2.11.5) (2022-11-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.3...@standardnotes/analytics@2.11.4) (2022-11-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.2...@standardnotes/analytics@2.11.3) (2022-11-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.11.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.1...@standardnotes/analytics@2.11.2) (2022-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** specs ([507d43b](https://github.com/standardnotes/server/commit/507d43b3289d1e178644df6d3e15d1d55e56c7bb))
|
||||
|
||||
## [2.11.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.11.0...@standardnotes/analytics@2.11.1) (2022-11-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* mapper interface imports ([1ec0723](https://github.com/standardnotes/server/commit/1ec072373d640c4e2f24b9bb12fec0c678b48032))
|
||||
|
||||
# [2.11.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.3...@standardnotes/analytics@2.11.0) (2022-11-16)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add publishing churn calculation values in the report ([6c43a33](https://github.com/standardnotes/server/commit/6c43a331d09c2dcf1300742509da6a1d8ef2f5b7))
|
||||
|
||||
## [2.10.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.2...@standardnotes/analytics@2.10.3) (2022-11-16)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** exclude five year plans from mrr stats ([fe1b2a0](https://github.com/standardnotes/server/commit/fe1b2a0e0744417e592f3f61f42610765b416ce6))
|
||||
|
||||
## [2.10.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.1...@standardnotes/analytics@2.10.2) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** imports from domain-core ([15dfd6d](https://github.com/standardnotes/server/commit/15dfd6dcba75a772000eeb01b78a532067b01d5b))
|
||||
|
||||
## [2.10.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.0...@standardnotes/analytics@2.10.1) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** retrieving revisions ([50f7ae3](https://github.com/standardnotes/server/commit/50f7ae338ad66d3465fa16c31e7c47c57b1e0c3c))
|
||||
|
||||
# [2.10.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.9.9...@standardnotes/analytics@2.10.0) (2022-11-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** extract domain core into a separate package ([0f94e2a](https://github.com/standardnotes/server/commit/0f94e2ad0c8927733eac31f130cbe649dce765f9))
|
||||
|
||||
## [2.9.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.9.6...@standardnotes/analytics@2.9.9) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -175,6 +175,9 @@ const requestReport = async (
|
||||
const churnRates: Array<{
|
||||
rate: number
|
||||
periodKey: string
|
||||
averageCustomersCount: number
|
||||
existingCustomersChurn: number
|
||||
newCustomersChurn: number
|
||||
}> = []
|
||||
for (const monthPeriodKey of monthlyPeriodKeys) {
|
||||
const monthPeriod = periodKeyGenerator.convertPeriodKeyToPeriod(monthPeriodKey)
|
||||
@@ -204,6 +207,9 @@ const requestReport = async (
|
||||
churnRates.push({
|
||||
periodKey: monthPeriodKey,
|
||||
rate: averageCustomersCount ? (totalChurn / averageCustomersCount) * 100 : 0,
|
||||
averageCustomersCount,
|
||||
existingCustomersChurn,
|
||||
newCustomersChurn,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.9.9",
|
||||
"version": "2.11.13",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -29,7 +29,6 @@
|
||||
"@types/jest": "^29.1.1",
|
||||
"@types/newrelic": "^7.0.4",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
@@ -38,14 +37,14 @@
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"@newrelic/winston-enricher": "^4.0.0",
|
||||
"@sentry/node": "^7.19.0",
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/domain-core": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
"@standardnotes/time": "workspace:*",
|
||||
"aws-sdk": "^2.1253.0",
|
||||
"aws-sdk": "^2.1260.0",
|
||||
"dayjs": "^1.11.6",
|
||||
"dotenv": "^16.0.1",
|
||||
"inversify": "^6.0.1",
|
||||
@@ -53,9 +52,7 @@
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "^9.6.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"shallow-equal-object": "^1.1.1",
|
||||
"typeorm": "^0.3.10",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DomainEventMessageHandlerInterface,
|
||||
DomainEventSubscriberFactoryInterface,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { MapperInterface } from '@standardnotes/domain-core'
|
||||
|
||||
import { Env } from './Env'
|
||||
import TYPES from './Types'
|
||||
@@ -47,7 +48,6 @@ import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEv
|
||||
import { RevenueModificationRepositoryInterface } from '../Domain/Revenue/RevenueModificationRepositoryInterface'
|
||||
import { MySQLRevenueModificationRepository } from '../Infra/MySQL/MySQLRevenueModificationRepository'
|
||||
import { TypeORMRevenueModification } from '../Infra/TypeORM/TypeORMRevenueModification'
|
||||
import { MapInterface } from '../Domain/Map/MapInterface'
|
||||
import { RevenueModification } from '../Domain/Revenue/RevenueModification'
|
||||
import { RevenueModificationMap } from '../Domain/Map/RevenueModificationMap'
|
||||
import { SaveRevenueModification } from '../Domain/UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
@@ -89,13 +89,24 @@ export class ContainerConfigLoader {
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
if (env.get('SNS_AWS_REGION', true)) {
|
||||
container.bind<AWS.SNS>(TYPES.SNS).toConstantValue(
|
||||
new AWS.SNS({
|
||||
apiVersion: 'latest',
|
||||
region: env.get('SNS_AWS_REGION', true),
|
||||
}),
|
||||
)
|
||||
if (env.get('SNS_TOPIC_ARN', true)) {
|
||||
const snsConfig: AWS.SNS.Types.ClientConfiguration = {
|
||||
apiVersion: 'latest',
|
||||
region: env.get('SNS_AWS_REGION', true),
|
||||
}
|
||||
if (env.get('SNS_ENDPOINT', true)) {
|
||||
snsConfig.endpoint = env.get('SNS_ENDPOINT', true)
|
||||
}
|
||||
if (env.get('SNS_DISABLE_SSL', true) === 'true') {
|
||||
snsConfig.sslEnabled = false
|
||||
}
|
||||
if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) {
|
||||
snsConfig.credentials = {
|
||||
accessKeyId: env.get('SNS_ACCESS_KEY_ID', true),
|
||||
secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true),
|
||||
}
|
||||
}
|
||||
container.bind<AWS.SNS>(TYPES.SNS).toConstantValue(new AWS.SNS(snsConfig))
|
||||
}
|
||||
|
||||
if (env.get('SQS_QUEUE_URL', true)) {
|
||||
@@ -172,7 +183,7 @@ export class ContainerConfigLoader {
|
||||
|
||||
// Maps
|
||||
container
|
||||
.bind<MapInterface<RevenueModification, TypeORMRevenueModification>>(TYPES.RevenueModificationMap)
|
||||
.bind<MapperInterface<RevenueModification, TypeORMRevenueModification>>(TYPES.RevenueModificationMap)
|
||||
.to(RevenueModificationMap)
|
||||
|
||||
// Services
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { Period } from '../Time/Period'
|
||||
|
||||
import { DomainEventFactory } from './DomainEventFactory'
|
||||
|
||||
describe('DomainEventFactory', () => {
|
||||
let timer: TimerInterface
|
||||
|
||||
const createFactory = () => new DomainEventFactory(timer)
|
||||
|
||||
beforeEach(() => {
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
|
||||
timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
|
||||
})
|
||||
|
||||
it('should create a DAILY_ANALYTICS_REPORT_GENERATED event', () => {
|
||||
expect(
|
||||
createFactory().createDailyAnalyticsReportGeneratedEvent({
|
||||
activityStatistics: [
|
||||
{
|
||||
name: AnalyticsActivity.Register,
|
||||
retention: 24,
|
||||
totalCount: 45,
|
||||
},
|
||||
],
|
||||
statisticMeasures: [
|
||||
{
|
||||
name: StatisticsMeasure.Income,
|
||||
totalValue: 43,
|
||||
average: 23,
|
||||
increments: 5,
|
||||
period: Period.Today,
|
||||
},
|
||||
],
|
||||
activityStatisticsOverTime: [
|
||||
{
|
||||
name: AnalyticsActivity.Register,
|
||||
period: Period.Last30Days,
|
||||
counts: [
|
||||
{
|
||||
periodKey: '2022-10-9',
|
||||
totalCount: 3,
|
||||
},
|
||||
],
|
||||
totalCount: 123,
|
||||
},
|
||||
],
|
||||
statisticsOverTime: [
|
||||
{
|
||||
name: StatisticsMeasure.MRR,
|
||||
period: Period.Last30Days,
|
||||
counts: [
|
||||
{
|
||||
periodKey: '2022-10-9',
|
||||
totalCount: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
churn: {
|
||||
periodKeys: ['2022-10-9'],
|
||||
values: [
|
||||
{
|
||||
rate: 12,
|
||||
periodKey: '2022-10-9',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'analytics',
|
||||
},
|
||||
payload: {
|
||||
activityStatistics: [
|
||||
{
|
||||
name: 'register',
|
||||
retention: 24,
|
||||
totalCount: 45,
|
||||
},
|
||||
],
|
||||
activityStatisticsOverTime: [
|
||||
{
|
||||
counts: [
|
||||
{
|
||||
periodKey: '2022-10-9',
|
||||
totalCount: 3,
|
||||
},
|
||||
],
|
||||
name: 'register',
|
||||
period: 9,
|
||||
totalCount: 123,
|
||||
},
|
||||
],
|
||||
statisticsOverTime: [
|
||||
{
|
||||
counts: [
|
||||
{
|
||||
periodKey: '2022-10-9',
|
||||
totalCount: 3,
|
||||
},
|
||||
],
|
||||
name: 'mrr',
|
||||
period: 9,
|
||||
},
|
||||
],
|
||||
churn: {
|
||||
periodKeys: ['2022-10-9'],
|
||||
values: [
|
||||
{
|
||||
periodKey: '2022-10-9',
|
||||
rate: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
statisticMeasures: [
|
||||
{
|
||||
average: 23,
|
||||
increments: 5,
|
||||
name: 'income',
|
||||
period: 0,
|
||||
totalValue: 43,
|
||||
},
|
||||
],
|
||||
},
|
||||
type: 'DAILY_ANALYTICS_REPORT_GENERATED',
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
|
||||
import { DomainEventService, DailyAnalyticsReportGeneratedEvent } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { inject, injectable } from 'inversify'
|
||||
@@ -43,6 +45,9 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
values: Array<{
|
||||
rate: number
|
||||
periodKey: string
|
||||
averageCustomersCount: number
|
||||
existingCustomersChurn: number
|
||||
newCustomersChurn: number
|
||||
}>
|
||||
}
|
||||
}): DailyAnalyticsReportGeneratedEvent {
|
||||
|
||||
@@ -36,6 +36,9 @@ export interface DomainEventFactoryInterface {
|
||||
values: Array<{
|
||||
rate: number
|
||||
periodKey: string
|
||||
averageCustomersCount: number
|
||||
existingCustomersChurn: number
|
||||
newCustomersChurn: number
|
||||
}>
|
||||
}
|
||||
}): DailyAnalyticsReportGeneratedEvent
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionName } from '@standardnotes/common'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { SubscriptionCancelledEvent } from '@standardnotes/domain-events'
|
||||
|
||||
import { SubscriptionCancelledEventHandler } from './SubscriptionCancelledEventHandler'
|
||||
@@ -9,7 +10,6 @@ import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { Period } from '../Time/Period'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionCancelledEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { Email } from '../Common/Email'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
|
||||
@@ -2,13 +2,13 @@ import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionName } from '@standardnotes/common'
|
||||
import { SubscriptionExpiredEvent } from '@standardnotes/domain-events'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionExpiredEventHandler } from './SubscriptionExpiredEventHandler'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionExpiredEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { Email } from '../Common/Email'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionName } from '@standardnotes/common'
|
||||
import { SubscriptionPurchasedEvent } from '@standardnotes/domain-events'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionPurchasedEventHandler } from './SubscriptionPurchasedEventHandler'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
@@ -9,7 +10,6 @@ import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { Period } from '../Time/Period'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionPurchasedEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { Email } from '../Common/Email'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionName } from '@standardnotes/common'
|
||||
import { SubscriptionRefundedEvent } from '@standardnotes/domain-events'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
@@ -10,7 +11,6 @@ import { SubscriptionRefundedEventHandler } from './SubscriptionRefundedEventHan
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { Period } from '../Time/Period'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionRefundedEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { Email } from '../Common/Email'
|
||||
import { StatisticsMeasure } from '../Statistics/StatisticsMeasure'
|
||||
import { StatisticsStoreInterface } from '../Statistics/StatisticsStoreInterface'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
|
||||
@@ -2,13 +2,13 @@ import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionName } from '@standardnotes/common'
|
||||
import { SubscriptionRenewedEvent } from '@standardnotes/domain-events'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionRenewedEventHandler } from './SubscriptionRenewedEventHandler'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { Result } from '../Core/Result'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('SubscriptionRenewedEventHandler', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionRenewedEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
@@ -7,7 +8,6 @@ import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { AnalyticsStoreInterface } from '../Analytics/AnalyticsStoreInterface'
|
||||
import { Period } from '../Time/Period'
|
||||
import { SaveRevenueModification } from '../UseCase/SaveRevenueModification/SaveRevenueModification'
|
||||
import { Email } from '../Common/Email'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
import { SubscriptionPlanName } from '../Subscription/SubscriptionPlanName'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface MapInterface<T, U> {
|
||||
toDomain(persistence: U): T
|
||||
toPersistence(domain: T): U
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
import { injectable } from 'inversify'
|
||||
import { Email, MapperInterface, UniqueEntityId } from '@standardnotes/domain-core'
|
||||
|
||||
import { TypeORMRevenueModification } from '../../Infra/TypeORM/TypeORMRevenueModification'
|
||||
import { UniqueEntityId } from '../Core/UniqueEntityId'
|
||||
import { MonthlyRevenue } from '../Revenue/MonthlyRevenue'
|
||||
import { RevenueModification } from '../Revenue/RevenueModification'
|
||||
import { Subscription } from '../Subscription/Subscription'
|
||||
import { User } from '../User/User'
|
||||
import { MapInterface } from './MapInterface'
|
||||
import { Email } from '../Common/Email'
|
||||
import { SubscriptionPlanName } from '../Subscription/SubscriptionPlanName'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
|
||||
@injectable()
|
||||
export class RevenueModificationMap implements MapInterface<RevenueModification, TypeORMRevenueModification> {
|
||||
export class RevenueModificationMap implements MapperInterface<RevenueModification, TypeORMRevenueModification> {
|
||||
toDomain(persistence: TypeORMRevenueModification): RevenueModification {
|
||||
const userOrError = User.create(
|
||||
{
|
||||
@@ -61,7 +59,7 @@ export class RevenueModificationMap implements MapInterface<RevenueModification,
|
||||
return revenuModificationOrError.getValue()
|
||||
}
|
||||
|
||||
toPersistence(domain: RevenueModification): TypeORMRevenueModification {
|
||||
toProjection(domain: RevenueModification): TypeORMRevenueModification {
|
||||
const { subscription, user } = domain.props
|
||||
const persistence = new TypeORMRevenueModification()
|
||||
persistence.uuid = domain.id.toString()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { Result, ValueObject } from '@standardnotes/domain-core'
|
||||
|
||||
import { MonthlyRevenueProps } from './MonthlyRevenueProps'
|
||||
|
||||
export class MonthlyRevenue extends ValueObject<MonthlyRevenueProps> {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Email } from '../Common/Email'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import { Subscription } from '../Subscription/Subscription'
|
||||
import { SubscriptionEventType } from '../Subscription/SubscriptionEventType'
|
||||
import { SubscriptionPlanName } from '../Subscription/SubscriptionPlanName'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Aggregate } from '../Core/Aggregate'
|
||||
import { Result } from '../Core/Result'
|
||||
import { UniqueEntityId } from '../Core/UniqueEntityId'
|
||||
import { Aggregate, UniqueEntityId, Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { RevenueModificationProps } from './RevenueModificationProps'
|
||||
|
||||
export class RevenueModification extends Aggregate<RevenueModificationProps> {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Uuid } from '../Common/Uuid'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { RevenueModification } from './RevenueModification'
|
||||
|
||||
export interface RevenueModificationRepositoryInterface {
|
||||
findLastByUserUuid(userUuid: Uuid): Promise<RevenueModification | null>
|
||||
sumMRRDiff(dto: { planName?: string; billingFrequency?: number }): Promise<number>
|
||||
sumMRRDiff(dto: { billingFrequencies: number[]; planNames?: string[] }): Promise<number>
|
||||
save(revenueModification: RevenueModification): Promise<RevenueModification>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Entity } from '../Core/Entity'
|
||||
import { Result } from '../Core/Result'
|
||||
import { UniqueEntityId } from '../Core/UniqueEntityId'
|
||||
import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionProps } from './SubscriptionProps'
|
||||
|
||||
export class Subscription extends Entity<SubscriptionProps> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { ValueObject, Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionEventTypeProps } from './SubscriptionEventTypeProps'
|
||||
|
||||
export class SubscriptionEventType extends ValueObject<SubscriptionEventTypeProps> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { Result, ValueObject } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionPlanNameProps } from './SubscriptionPlanNameProps'
|
||||
|
||||
export class SubscriptionPlanName extends ValueObject<SubscriptionPlanNameProps> {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { SubscriptionBillingFrequency, SubscriptionName } from '@standardnotes/common'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { Result } from '../../Core/Result'
|
||||
import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue'
|
||||
import { RevenueModificationRepositoryInterface } from '../../Revenue/RevenueModificationRepositoryInterface'
|
||||
import { StatisticsMeasure } from '../../Statistics/StatisticsMeasure'
|
||||
@@ -19,7 +20,9 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
) {}
|
||||
|
||||
async execute(_dto: CalculateMonthlyRecurringRevenueDTO): Promise<Result<MonthlyRevenue>> {
|
||||
const mrrDiff = await this.revenueModificationRepository.sumMRRDiff({})
|
||||
const mrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
billingFrequencies: [SubscriptionBillingFrequency.Annual, SubscriptionBillingFrequency.Monthly],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.MRR, mrrDiff, [
|
||||
Period.Today,
|
||||
@@ -28,7 +31,7 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
])
|
||||
|
||||
const monthlyPlansMrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
billingFrequency: SubscriptionBillingFrequency.Monthly,
|
||||
billingFrequencies: [SubscriptionBillingFrequency.Monthly],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.MonthlyPlansMRR, monthlyPlansMrrDiff, [
|
||||
@@ -38,7 +41,7 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
])
|
||||
|
||||
const annualPlansMrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
billingFrequency: SubscriptionBillingFrequency.Annual,
|
||||
billingFrequencies: [SubscriptionBillingFrequency.Annual],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.AnnualPlansMRR, annualPlansMrrDiff, [
|
||||
@@ -48,7 +51,7 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
])
|
||||
|
||||
const fiveYearPlansMrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
billingFrequency: SubscriptionBillingFrequency.FiveYear,
|
||||
billingFrequencies: [SubscriptionBillingFrequency.FiveYear],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.FiveYearPlansMRR, fiveYearPlansMrrDiff, [
|
||||
@@ -58,7 +61,8 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
])
|
||||
|
||||
const proPlansMrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
planName: SubscriptionName.ProPlan,
|
||||
planNames: [SubscriptionName.ProPlan],
|
||||
billingFrequencies: [SubscriptionBillingFrequency.Annual, SubscriptionBillingFrequency.Monthly],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.ProPlansMRR, proPlansMrrDiff, [
|
||||
@@ -68,7 +72,8 @@ export class CalculateMonthlyRecurringRevenue implements DomainUseCaseInterface<
|
||||
])
|
||||
|
||||
const plusPlansMrrDiff = await this.revenueModificationRepository.sumMRRDiff({
|
||||
planName: SubscriptionName.PlusPlan,
|
||||
planNames: [SubscriptionName.PlusPlan],
|
||||
billingFrequencies: [SubscriptionBillingFrequency.Annual, SubscriptionBillingFrequency.Monthly],
|
||||
})
|
||||
|
||||
await this.statisticsStore.setMeasure(StatisticsMeasure.PlusPlansMRR, plusPlansMrrDiff, [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Result } from '../Core/Result'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
|
||||
export interface DomainUseCaseInterface<T> {
|
||||
execute(...args: any[]): Promise<Result<T>>
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('GetUserAnalyticsId', () => {
|
||||
beforeEach(() => {
|
||||
analyticsEntity = {
|
||||
id: 123,
|
||||
userUuid: '1-2-3',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userEmail: 'test@test.te',
|
||||
} as jest.Mocked<AnalyticsEntity>
|
||||
|
||||
@@ -24,11 +24,11 @@ describe('GetUserAnalyticsId', () => {
|
||||
})
|
||||
|
||||
it('should return analytics id for a user by uuid', async () => {
|
||||
expect(await (await createUseCase().execute({ userUuid: '1-2-3' })).analyticsId).toEqual(123)
|
||||
expect((await createUseCase().execute({ userUuid: '1-2-3' })).analyticsId).toEqual(123)
|
||||
})
|
||||
|
||||
it('should return analytics id for a user by email', async () => {
|
||||
expect(await (await createUseCase().execute({ userEmail: 'test@test.te' })).analyticsId).toEqual(123)
|
||||
expect((await createUseCase().execute({ userEmail: 'test@test.te' })).analyticsId).toEqual(123)
|
||||
})
|
||||
|
||||
it('should throw error if user is missing analytics entity', async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Email, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { Email } from '../../Common/Email'
|
||||
import { Uuid } from '../../Common/Uuid'
|
||||
import { AnalyticsEntityRepositoryInterface } from '../../Entity/AnalyticsEntityRepositoryInterface'
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
import { GetUserAnalyticsIdDTO } from './GetUserAnalyticsIdDTO'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Email } from '../../Common/Email'
|
||||
import { Uuid } from '../../Common/Uuid'
|
||||
import { Email, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export type GetUserAnalyticsIdResponse = {
|
||||
analyticsId: number
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { Email, Result, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { Email } from '../../Common/Email'
|
||||
import { Uuid } from '../../Common/Uuid'
|
||||
import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue'
|
||||
|
||||
import { RevenueModification } from '../../Revenue/RevenueModification'
|
||||
@@ -12,7 +11,6 @@ import { SubscriptionEventType } from '../../Subscription/SubscriptionEventType'
|
||||
import { SubscriptionPlanName } from '../../Subscription/SubscriptionPlanName'
|
||||
import { SaveRevenueModification } from './SaveRevenueModification'
|
||||
import { User } from '../../User/User'
|
||||
import { Result } from '../../Core/Result'
|
||||
import { Subscription } from '../../Subscription/Subscription'
|
||||
|
||||
describe('SaveRevenueModification', () => {
|
||||
@@ -48,7 +46,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeFalsy()
|
||||
@@ -66,7 +64,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeFalsy()
|
||||
@@ -84,7 +82,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeFalsy()
|
||||
@@ -104,7 +102,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeFalsy()
|
||||
@@ -125,7 +123,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeTruthy()
|
||||
@@ -145,7 +143,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeTruthy()
|
||||
@@ -165,7 +163,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeTruthy()
|
||||
@@ -185,7 +183,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeTruthy()
|
||||
@@ -205,7 +203,7 @@ describe('SaveRevenueModification', () => {
|
||||
planName: SubscriptionPlanName.create('PRO_PLAN').getValue(),
|
||||
subscriptionId: 1234,
|
||||
userEmail: Email.create('test@test.te').getValue(),
|
||||
userUuid: Uuid.create('1-2-3').getValue(),
|
||||
userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
|
||||
})
|
||||
|
||||
expect(revenueOrError.isFailed()).toBeTruthy()
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Result, UniqueEntityId } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { UniqueEntityId } from '../../Core/UniqueEntityId'
|
||||
import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue'
|
||||
import { RevenueModification } from '../../Revenue/RevenueModification'
|
||||
import { RevenueModificationRepositoryInterface } from '../../Revenue/RevenueModificationRepositoryInterface'
|
||||
import { Subscription } from '../../Subscription/Subscription'
|
||||
import { User } from '../../User/User'
|
||||
import { Result } from '../../Core/Result'
|
||||
import { DomainUseCaseInterface } from '../DomainUseCaseInterface'
|
||||
import { SaveRevenueModificationDTO } from './SaveRevenueModificationDTO'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Email } from '../../Common/Email'
|
||||
import { Uuid } from '../../Common/Uuid'
|
||||
import { Email, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SubscriptionEventType } from '../../Subscription/SubscriptionEventType'
|
||||
import { SubscriptionPlanName } from '../../Subscription/SubscriptionPlanName'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Email } from '../Common/Email'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
import { User } from './User'
|
||||
|
||||
describe('User', () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Entity } from '../Core/Entity'
|
||||
import { Result } from '../Core/Result'
|
||||
import { UniqueEntityId } from '../Core/UniqueEntityId'
|
||||
import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
|
||||
|
||||
import { UserProps } from './UserProps'
|
||||
|
||||
export class User extends Entity<UserProps> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Email } from '../Common/Email'
|
||||
import { Email } from '@standardnotes/domain-core'
|
||||
|
||||
export interface UserProps {
|
||||
email: Email
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Repository } from 'typeorm'
|
||||
import { MapperInterface, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { Uuid } from '../../Domain/Common/Uuid'
|
||||
import { MapInterface } from '../../Domain/Map/MapInterface'
|
||||
import { RevenueModification } from '../../Domain/Revenue/RevenueModification'
|
||||
import { RevenueModificationRepositoryInterface } from '../../Domain/Revenue/RevenueModificationRepositoryInterface'
|
||||
import { TypeORMRevenueModification } from '../TypeORM/TypeORMRevenueModification'
|
||||
@@ -14,17 +13,17 @@ export class MySQLRevenueModificationRepository implements RevenueModificationRe
|
||||
@inject(TYPES.ORMRevenueModificationRepository)
|
||||
private ormRepository: Repository<TypeORMRevenueModification>,
|
||||
@inject(TYPES.RevenueModificationMap)
|
||||
private revenueModificationMap: MapInterface<RevenueModification, TypeORMRevenueModification>,
|
||||
private revenueModificationMap: MapperInterface<RevenueModification, TypeORMRevenueModification>,
|
||||
) {}
|
||||
|
||||
async sumMRRDiff(dto: { planName?: string; billingFrequency?: number }): Promise<number> {
|
||||
async sumMRRDiff(dto: { billingFrequencies: number[]; planNames?: string[] }): Promise<number> {
|
||||
const query = this.ormRepository.createQueryBuilder().select('sum(new_mrr - previous_mrr)', 'mrrDiff')
|
||||
|
||||
if (dto.planName !== undefined) {
|
||||
query.where('subscription_plan = :planName', { planName: dto.planName })
|
||||
if (dto.billingFrequencies.length > 0) {
|
||||
query.where('billing_frequency IN (:...billingFrequencies)', { billingFrequencies: dto.billingFrequencies })
|
||||
}
|
||||
if (dto.billingFrequency !== undefined) {
|
||||
query.where('billing_frequency = :billingFrequency', { billingFrequency: dto.billingFrequency })
|
||||
if (dto.planNames && dto.planNames.length > 0) {
|
||||
query.andWhere('subscription_plan IN (:...planNames)', { planNames: dto.planNames })
|
||||
}
|
||||
|
||||
const result = await query.getRawOne()
|
||||
@@ -52,7 +51,7 @@ export class MySQLRevenueModificationRepository implements RevenueModificationRe
|
||||
}
|
||||
|
||||
async save(revenueModification: RevenueModification): Promise<RevenueModification> {
|
||||
let persistence = this.revenueModificationMap.toPersistence(revenueModification)
|
||||
let persistence = this.revenueModificationMap.toProjection(revenueModification)
|
||||
|
||||
persistence = await this.ormRepository.save(persistence)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ WORKSPACE_SERVER_URL=http://workspace:3000
|
||||
WEB_SOCKET_SERVER_URL=http://websockets:3000
|
||||
PAYMENTS_SERVER_URL=http://payments:3000
|
||||
FILES_SERVER_URL=http://files:3000
|
||||
REVISIONS_SERVER_URL=http://revisions:3000
|
||||
|
||||
HTTP_CALL_TIMEOUT=60000
|
||||
|
||||
|
||||
@@ -3,6 +3,44 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.39.2...@standardnotes/api-gateway@1.39.3) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.39.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.39.1...@standardnotes/api-gateway@1.39.2) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.39.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.39.0...@standardnotes/api-gateway@1.39.1) (2022-11-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.39.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.9...@standardnotes/api-gateway@1.39.0) (2022-11-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add v2 revisions controller ([92ba759](https://github.com/standardnotes/api-gateway/commit/92ba759b1c3719e773f989707ddd6d7a9ec57d1c))
|
||||
|
||||
## [1.38.9](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.8...@standardnotes/api-gateway@1.38.9) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.38.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.7...@standardnotes/api-gateway@1.38.8) (2022-11-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.38.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.6...@standardnotes/api-gateway@1.38.7) (2022-11-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.38.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.5...@standardnotes/api-gateway@1.38.6) (2022-11-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.38.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.4...@standardnotes/api-gateway@1.38.5) (2022-11-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.38.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.38.1...@standardnotes/api-gateway@1.38.4) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -24,6 +24,7 @@ import '../src/Controller/v1/InvitesController'
|
||||
|
||||
import '../src/Controller/v2/PaymentsControllerV2'
|
||||
import '../src/Controller/v2/ActionsControllerV2'
|
||||
import '../src/Controller/v2/RevisionsControllerV2'
|
||||
|
||||
import helmet from 'helmet'
|
||||
import * as cors from 'cors'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.38.4",
|
||||
"version": "1.39.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -20,7 +20,6 @@
|
||||
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"@newrelic/winston-enricher": "^4.0.0",
|
||||
"@sentry/node": "^7.19.0",
|
||||
"@standardnotes/common": "workspace:^",
|
||||
@@ -28,7 +27,7 @@
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
"@standardnotes/security": "workspace:*",
|
||||
"@standardnotes/time": "workspace:*",
|
||||
"aws-sdk": "^2.1253.0",
|
||||
"aws-sdk": "^2.1260.0",
|
||||
"axios": "^1.1.3",
|
||||
"cors": "2.8.5",
|
||||
"dotenv": "^16.0.1",
|
||||
|
||||
@@ -54,6 +54,7 @@ export class ContainerConfigLoader {
|
||||
// env vars
|
||||
container.bind(TYPES.SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL'))
|
||||
container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL'))
|
||||
container.bind(TYPES.REVISIONS_SERVER_URL).toConstantValue(env.get('REVISIONS_SERVER_URL'))
|
||||
container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
|
||||
container.bind(TYPES.FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true))
|
||||
container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
|
||||
|
||||
@@ -7,6 +7,7 @@ const TYPES = {
|
||||
AUTH_SERVER_URL: Symbol.for('AUTH_SERVER_URL'),
|
||||
PAYMENTS_SERVER_URL: Symbol.for('PAYMENTS_SERVER_URL'),
|
||||
FILES_SERVER_URL: Symbol.for('FILES_SERVER_URL'),
|
||||
REVISIONS_SERVER_URL: Symbol.for('REVISIONS_SERVER_URL'),
|
||||
WORKSPACE_SERVER_URL: Symbol.for('WORKSPACE_SERVER_URL'),
|
||||
WEB_SOCKET_SERVER_URL: Symbol.for('WEB_SOCKET_SERVER_URL'),
|
||||
AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'),
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v2/items/:item_id/revisions', TYPES.AuthMiddleware)
|
||||
export class RevisionsControllerV2 extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/')
|
||||
async getRevisions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callRevisionsServer(request, response, `items/${request.params.item_id}/revisions`)
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
@inject(TYPES.FILES_SERVER_URL) private filesServerUrl: string,
|
||||
@inject(TYPES.WORKSPACE_SERVER_URL) private workspaceServerUrl: string,
|
||||
@inject(TYPES.WEB_SOCKET_SERVER_URL) private webSocketServerUrl: string,
|
||||
@inject(TYPES.REVISIONS_SERVER_URL) private revisionsServerUrl: string,
|
||||
@inject(TYPES.HTTP_CALL_TIMEOUT) private httpCallTimeout: number,
|
||||
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
@@ -32,6 +33,15 @@ export class HttpService implements HttpServiceInterface {
|
||||
await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callRevisionsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServer(this.revisionsServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callLegacySyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
|
||||
@@ -13,6 +13,12 @@ export interface HttpServiceInterface {
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callRevisionsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callSyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
|
||||
@@ -3,6 +3,68 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.60.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.10...@standardnotes/auth-server@1.60.11) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.10](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.9...@standardnotes/auth-server@1.60.10) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.9](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.8...@standardnotes/auth-server@1.60.9) (2022-11-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.8](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.7...@standardnotes/auth-server@1.60.8) (2022-11-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* binding of sns and sqs with additional config ([74bc791](https://github.com/standardnotes/server/commit/74bc79116bc50d9a5af1a558db1b7108dcda6d0e))
|
||||
|
||||
## [1.60.7](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.6...@standardnotes/auth-server@1.60.7) (2022-11-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** remove temporary email campaign check for team member ([5f2be44](https://github.com/standardnotes/server/commit/5f2be44b853e83abb6c4e758efd477e899381e07))
|
||||
|
||||
## [1.60.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.5...@standardnotes/auth-server@1.60.6) (2022-11-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* sns binding ([3686a26](https://github.com/standardnotes/server/commit/3686a260192468c00b52087590dd2edf76ada939))
|
||||
|
||||
## [1.60.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.4...@standardnotes/auth-server@1.60.5) (2022-11-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** tmp send email campaign only to team ([94359f1](https://github.com/standardnotes/server/commit/94359f1299a2bb009099af163d3929c4adc7e274))
|
||||
|
||||
## [1.60.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.3...@standardnotes/auth-server@1.60.4) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.2...@standardnotes/auth-server@1.60.3) (2022-11-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.1...@standardnotes/auth-server@1.60.2) (2022-11-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.60.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.60.0...@standardnotes/auth-server@1.60.1) (2022-11-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.60.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.59.11...@standardnotes/auth-server@1.60.0) (2022-11-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add content size recalculation procedure trigger ([590ec66](https://github.com/standardnotes/server/commit/590ec6643db57adf3e202c6ccab4bac36aae8b59))
|
||||
|
||||
## [1.59.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.59.10...@standardnotes/auth-server@1.59.11) (2022-11-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.59.10](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.59.7...@standardnotes/auth-server@1.59.10) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
74
packages/auth/bin/content.ts
Normal file
74
packages/auth/bin/content.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as utc from 'dayjs/plugin/utc'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
||||
import { Stream } from 'stream'
|
||||
|
||||
const requestRecalculation = async (
|
||||
userRepository: UserRepositoryInterface,
|
||||
domainEventFactory: DomainEventFactoryInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
logger: Logger,
|
||||
): Promise<void> => {
|
||||
const stream = await userRepository.streamAll()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
stream
|
||||
.pipe(
|
||||
new Stream.Transform({
|
||||
objectMode: true,
|
||||
transform: async (rawUserData, _encoding, callback) => {
|
||||
try {
|
||||
await domainEventPublisher.publish(
|
||||
domainEventFactory.createUserContentSizeRecalculationRequestedEvent(rawUserData.user_uuid),
|
||||
)
|
||||
} catch (error) {
|
||||
logger.error(`Could not process user ${rawUserData.user_uuid}: ${(error as Error).message}`)
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
}),
|
||||
)
|
||||
.on('finish', resolve)
|
||||
.on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Logger)
|
||||
|
||||
logger.info('Starting content size recalculation requests ...')
|
||||
|
||||
const userRepository: UserRepositoryInterface = container.get(TYPES.UserRepository)
|
||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
|
||||
|
||||
Promise.resolve(requestRecalculation(userRepository, domainEventFactory, domainEventPublisher, logger))
|
||||
.then(() => {
|
||||
logger.info('content size recalculation requesting complete')
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not finish content size recalculation requesting : ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -56,6 +56,11 @@ case "$COMMAND" in
|
||||
yarn workspace @standardnotes/auth-server email-campaign $MESSAGE_IDENTIFIER
|
||||
;;
|
||||
|
||||
'content-recalculation' )
|
||||
echo "Starting Content Size Recalculation..."
|
||||
yarn workspace @standardnotes/auth-server content-recalculation
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "Unknown command"
|
||||
;;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.59.10",
|
||||
"version": "1.60.11",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -25,12 +25,12 @@
|
||||
"daily-backup:google_drive": "yarn node dist/bin/backup.js google_drive daily",
|
||||
"daily-backup:one_drive": "yarn node dist/bin/backup.js one_drive daily",
|
||||
"weekly-backup:email": "yarn node dist/bin/backup.js email weekly",
|
||||
"content-recalculation": "yarn node dist/bin/content.js",
|
||||
"email-campaign": "yarn node dist/bin/email.js",
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"@newrelic/winston-enricher": "^4.0.0",
|
||||
"@sentry/node": "^7.19.0",
|
||||
"@standardnotes/api": "^1.19.0",
|
||||
@@ -45,7 +45,7 @@
|
||||
"@standardnotes/sncrypto-common": "^1.9.0",
|
||||
"@standardnotes/sncrypto-node": "workspace:*",
|
||||
"@standardnotes/time": "workspace:*",
|
||||
"aws-sdk": "^2.1253.0",
|
||||
"aws-sdk": "^2.1260.0",
|
||||
"axios": "^1.1.3",
|
||||
"bcryptjs": "2.4.3",
|
||||
"cors": "2.8.5",
|
||||
|
||||
@@ -230,13 +230,24 @@ export class ContainerConfigLoader {
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
if (env.get('SNS_AWS_REGION', true)) {
|
||||
container.bind<AWS.SNS>(TYPES.SNS).toConstantValue(
|
||||
new AWS.SNS({
|
||||
apiVersion: 'latest',
|
||||
region: env.get('SNS_AWS_REGION', true),
|
||||
}),
|
||||
)
|
||||
if (env.get('SNS_TOPIC_ARN', true)) {
|
||||
const snsConfig: AWS.SNS.Types.ClientConfiguration = {
|
||||
apiVersion: 'latest',
|
||||
region: env.get('SNS_AWS_REGION', true),
|
||||
}
|
||||
if (env.get('SNS_ENDPOINT', true)) {
|
||||
snsConfig.endpoint = env.get('SNS_ENDPOINT', true)
|
||||
}
|
||||
if (env.get('SNS_DISABLE_SSL', true) === 'true') {
|
||||
snsConfig.sslEnabled = false
|
||||
}
|
||||
if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) {
|
||||
snsConfig.credentials = {
|
||||
accessKeyId: env.get('SNS_ACCESS_KEY_ID', true),
|
||||
secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true),
|
||||
}
|
||||
}
|
||||
container.bind<AWS.SNS>(TYPES.SNS).toConstantValue(new AWS.SNS(snsConfig))
|
||||
}
|
||||
|
||||
if (env.get('SQS_QUEUE_URL', true)) {
|
||||
|
||||
@@ -1,406 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { EmailMessageIdentifier, ProtocolVersion, RoleName } from '@standardnotes/common'
|
||||
import { PredicateName, PredicateAuthority, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { DomainEventFactory } from './DomainEventFactory'
|
||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||
|
||||
describe('DomainEventFactory', () => {
|
||||
let timer: TimerInterface
|
||||
|
||||
const createFactory = () => new DomainEventFactory(timer)
|
||||
|
||||
beforeEach(() => {
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
|
||||
timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
|
||||
})
|
||||
|
||||
it('should create a EXIT_DISCOUNT_APPLY_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createExitDiscountApplyRequestedEvent({
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'exit-20',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userEmail: 'test@test.te',
|
||||
discountCode: 'exit-20',
|
||||
},
|
||||
type: 'EXIT_DISCOUNT_APPLY_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a WEB_SOCKET_MESSAGE_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createWebSocketMessageRequestedEvent({
|
||||
userUuid: '1-2-3',
|
||||
message: 'foobar',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
message: 'foobar',
|
||||
},
|
||||
type: 'WEB_SOCKET_MESSAGE_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a EMAIL_MESSAGE_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createEmailMessageRequestedEvent({
|
||||
userEmail: 'test@test.te',
|
||||
messageIdentifier: EmailMessageIdentifier.ENCOURAGE_EMAIL_BACKUPS,
|
||||
context: {
|
||||
foo: 'bar',
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
messageIdentifier: 'ENCOURAGE_EMAIL_BACKUPS',
|
||||
userEmail: 'test@test.te',
|
||||
context: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
type: 'EMAIL_MESSAGE_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a PREDICATE_VERIFIED event', () => {
|
||||
expect(
|
||||
createFactory().createPredicateVerifiedEvent({
|
||||
predicate: {
|
||||
authority: PredicateAuthority.Auth,
|
||||
jobUuid: '1-2-3',
|
||||
name: PredicateName.EmailBackupsEnabled,
|
||||
},
|
||||
predicateVerificationResult: PredicateVerificationResult.Affirmed,
|
||||
userUuid: '2-3-4',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '2-3-4',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
predicate: {
|
||||
authority: 'auth',
|
||||
jobUuid: '1-2-3',
|
||||
name: 'email-backups-enabled',
|
||||
},
|
||||
predicateVerificationResult: 'affirmed',
|
||||
},
|
||||
type: 'PREDICATE_VERIFIED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a SHARED_SUBSCRIPTION_INVITATION_CANCELED event', () => {
|
||||
expect(
|
||||
createFactory().createSharedSubscriptionInvitationCanceledEvent({
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterSubscriptionId: 1,
|
||||
inviterSubscriptionUuid: '2-3-4',
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviteeIdentifierType: InviteeIdentifierType.Email,
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterSubscriptionId: 1,
|
||||
inviterSubscriptionUuid: '2-3-4',
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviteeIdentifierType: InviteeIdentifierType.Email,
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
},
|
||||
type: 'SHARED_SUBSCRIPTION_INVITATION_CANCELED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a SHARED_SUBSCRIPTION_INVITATION_CREATED event', () => {
|
||||
expect(
|
||||
createFactory().createSharedSubscriptionInvitationCreatedEvent({
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterSubscriptionId: 1,
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviteeIdentifierType: InviteeIdentifierType.Email,
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterSubscriptionId: 1,
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviteeIdentifierType: InviteeIdentifierType.Email,
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
},
|
||||
type: 'SHARED_SUBSCRIPTION_INVITATION_CREATED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a USER_DISABLED_SESSION_USER_AGENT_LOGGING event', () => {
|
||||
expect(
|
||||
createFactory().createUserDisabledSessionUserAgentLoggingEvent({
|
||||
email: 'test@test.te',
|
||||
userUuid: '1-2-3',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
},
|
||||
type: 'USER_DISABLED_SESSION_USER_AGENT_LOGGING',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a USER_SIGNED_IN event', () => {
|
||||
expect(
|
||||
createFactory().createUserSignedInEvent({
|
||||
browser: 'Firefox 1',
|
||||
device: 'iOS 1',
|
||||
userEmail: 'test@test.te',
|
||||
userUuid: '1-2-3',
|
||||
signInAlertEnabled: true,
|
||||
muteSignInEmailsSettingUuid: '2-3-4',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
userEmail: 'test@test.te',
|
||||
browser: 'Firefox 1',
|
||||
device: 'iOS 1',
|
||||
signInAlertEnabled: true,
|
||||
muteSignInEmailsSettingUuid: '2-3-4',
|
||||
},
|
||||
type: 'USER_SIGNED_IN',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a LISTED_ACCOUNT_REQUESTED event', () => {
|
||||
expect(createFactory().createListedAccountRequestedEvent('1-2-3', 'test@test.te')).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
userEmail: 'test@test.te',
|
||||
},
|
||||
type: 'LISTED_ACCOUNT_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a USER_REGISTERED event', () => {
|
||||
expect(
|
||||
createFactory().createUserRegisteredEvent({
|
||||
userUuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
protocolVersion: ProtocolVersion.V004,
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
protocolVersion: '004',
|
||||
},
|
||||
type: 'USER_REGISTERED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a OFFLINE_SUBSCRIPTION_TOKEN_CREATED event', () => {
|
||||
expect(createFactory().createOfflineSubscriptionTokenCreatedEvent('1-2-3', 'test@test.te')).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: 'test@test.te',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
token: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
},
|
||||
type: 'OFFLINE_SUBSCRIPTION_TOKEN_CREATED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a USER_CHANGED_EMAIL event', () => {
|
||||
expect(createFactory().createUserEmailChangedEvent('1-2-3', 'test@test.te', 'test2@test.te')).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
fromEmail: 'test@test.te',
|
||||
toEmail: 'test2@test.te',
|
||||
},
|
||||
type: 'USER_EMAIL_CHANGED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a CLOUD_BACKUP_REQUESTED event', () => {
|
||||
expect(createFactory().createCloudBackupRequestedEvent('GOOGLE_DRIVE', 'test', '1-2-3', '2-3-4', true)).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
cloudProvider: 'GOOGLE_DRIVE',
|
||||
cloudProviderToken: 'test',
|
||||
userUuid: '1-2-3',
|
||||
muteEmailsSettingUuid: '2-3-4',
|
||||
userHasEmailsMuted: true,
|
||||
},
|
||||
type: 'CLOUD_BACKUP_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a EMAIL_BACKUP_REQUESTED event', () => {
|
||||
expect(createFactory().createEmailBackupRequestedEvent('1-2-3', '2-3-4', true)).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
muteEmailsSettingUuid: '2-3-4',
|
||||
userHasEmailsMuted: true,
|
||||
},
|
||||
type: 'EMAIL_BACKUP_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a ACCOUNT_DELETION_REQUESTED event', () => {
|
||||
expect(
|
||||
createFactory().createAccountDeletionRequestedEvent({
|
||||
userUuid: '1-2-3',
|
||||
userCreatedAtTimestamp: 123,
|
||||
regularSubscriptionUuid: '2-3-4',
|
||||
}),
|
||||
).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
userCreatedAtTimestamp: 123,
|
||||
regularSubscriptionUuid: '2-3-4',
|
||||
},
|
||||
type: 'ACCOUNT_DELETION_REQUESTED',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create a USER_ROLE_CHANGED event', () => {
|
||||
expect(createFactory().createUserRolesChangedEvent('1-2-3', 'test@test.com', [RoleName.ProUser])).toEqual({
|
||||
createdAt: expect.any(Date),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '1-2-3',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: 'auth',
|
||||
},
|
||||
payload: {
|
||||
userUuid: '1-2-3',
|
||||
email: 'test@test.com',
|
||||
currentRoles: [RoleName.ProUser],
|
||||
timestamp: expect.any(Number),
|
||||
},
|
||||
type: 'USER_ROLES_CHANGED',
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
/* istanbul ignore file */
|
||||
|
||||
import { EmailMessageIdentifier, JSONString, ProtocolVersion, RoleName, Uuid } from '@standardnotes/common'
|
||||
import {
|
||||
AccountDeletionRequestedEvent,
|
||||
@@ -17,6 +19,7 @@ import {
|
||||
EmailMessageRequestedEvent,
|
||||
WebSocketMessageRequestedEvent,
|
||||
ExitDiscountApplyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
@@ -29,6 +32,23 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
|
||||
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent {
|
||||
return {
|
||||
type: 'USER_CONTENT_SIZE_RECALCULATION_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.Auth,
|
||||
},
|
||||
payload: {
|
||||
userUuid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
createExitDiscountApplyRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
discountCode: string
|
||||
|
||||
@@ -17,10 +17,12 @@ import {
|
||||
EmailMessageRequestedEvent,
|
||||
WebSocketMessageRequestedEvent,
|
||||
ExitDiscountApplyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||
|
||||
export interface DomainEventFactoryInterface {
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent
|
||||
createWebSocketMessageRequestedEvent(dto: { userUuid: Uuid; message: JSONString }): WebSocketMessageRequestedEvent
|
||||
createEmailMessageRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.46.1](https://github.com/standardnotes/server/compare/@standardnotes/common@1.46.0...@standardnotes/common@1.46.1) (2022-11-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** add black friday 2022 reminder message identifier ([91b76ed](https://github.com/standardnotes/server/commit/91b76edce1c1abfa4e860932d98ce8cd369017c0))
|
||||
|
||||
# [1.46.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.45.0...@standardnotes/common@1.46.0) (2022-11-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **common:** add marketing campaign for black friday 2022 email message identifier ([d77eb7f](https://github.com/standardnotes/server/commit/d77eb7f5f11bcc7cd5c6fa6d20e891b466af7b45))
|
||||
|
||||
# [1.45.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.44.4...@standardnotes/common@1.45.0) (2022-11-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** extract domain core into a separate package ([0f94e2a](https://github.com/standardnotes/server/commit/0f94e2ad0c8927733eac31f130cbe649dce765f9))
|
||||
|
||||
## [1.44.4](https://github.com/standardnotes/server/compare/@standardnotes/common@1.44.1...@standardnotes/common@1.44.4) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/common",
|
||||
"version": "1.44.4",
|
||||
"version": "1.46.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -32,7 +32,6 @@
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ export enum EmailMessageIdentifier {
|
||||
STUDENT_DISCOUNT_REQUESTED = 'STUDENT_DISCOUNT_REQUESTED',
|
||||
STUDENT_DISCOUNT_APPROVED = 'STUDENT_DISCOUNT_APPROVED',
|
||||
MARKETING_CAMPAIGN_FILES = 'MARKETING_CAMPAIGN_FILES',
|
||||
MARKETING_BLACK_FRIDAY_2022 = 'MARKETING_BLACK_FRIDAY_2022',
|
||||
MARKETING_BLACK_FRIDAY_2022_REMINDER = 'MARKETING_BLACK_FRIDAY_2022_REMINDER',
|
||||
PAYMENT_FAILED = 'PAYMENT_FAILED',
|
||||
SEND_INVOICE = 'SEND_INVOICE',
|
||||
DISCOUNT_NOTICE = 'DISCOUNT_NOTICE',
|
||||
|
||||
1
packages/domain-core/.eslintignore
Normal file
1
packages/domain-core/.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
dist
|
||||
6
packages/domain-core/.eslintrc
Normal file
6
packages/domain-core/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
55
packages/domain-core/CHANGELOG.md
Normal file
55
packages/domain-core/CHANGELOG.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.5.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.5.0...@standardnotes/domain-core@1.5.1) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-core
|
||||
|
||||
# [1.5.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.4.0...@standardnotes/domain-core@1.5.0) (2022-11-24)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-core:** add methods to check role power ([9d90f27](https://github.com/standardnotes/server/commit/9d90f276de8915d91d009909154036ba128687e0))
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.3.0...@standardnotes/domain-core@1.4.0) (2022-11-24)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-core:** add role name collection value object ([ae2f8f0](https://github.com/standardnotes/server/commit/ae2f8f086b9f647bb98c59f32375b45243cb0af9))
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.2.2...@standardnotes/domain-core@1.3.0) (2022-11-24)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-core:** add role name value object ([748630e](https://github.com/standardnotes/server/commit/748630e1f1ed1dfae2e743cd2b3d3fd91967088c))
|
||||
|
||||
## [1.2.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.2.1...@standardnotes/domain-core@1.2.2) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-core
|
||||
|
||||
## [1.2.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.2.0...@standardnotes/domain-core@1.2.1) (2022-11-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain-core:** remove revisions related models to revisions microservice ([a6542dd](https://github.com/standardnotes/server/commit/a6542dd63870a8ada5fd8143d8e2133a570d9329))
|
||||
|
||||
# [1.2.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.1.1...@standardnotes/domain-core@1.2.0) (2022-11-18)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-core:** add revision definition to domain core ([c8f3a0c](https://github.com/standardnotes/server/commit/c8f3a0ce7b589a6fbc47941fc5d1a44b6cf04fe3))
|
||||
* **revisions:** add revisions microservice ([d5c06bf](https://github.com/standardnotes/server/commit/d5c06bfa58a987685fbd8fbab0d22df3fcff3377))
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.1.0...@standardnotes/domain-core@1.1.1) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** retrieving revisions ([50f7ae3](https://github.com/standardnotes/server/commit/50f7ae338ad66d3465fa16c31e7c47c57b1e0c3c))
|
||||
|
||||
# 1.1.0 (2022-11-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** extract domain core into a separate package ([0f94e2a](https://github.com/standardnotes/server/commit/0f94e2ad0c8927733eac31f130cbe649dce765f9))
|
||||
10
packages/domain-core/jest.config.js
Normal file
10
packages/domain-core/jest.config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const base = require('../../jest.config')
|
||||
const { defaults: tsjPreset } = require('ts-jest/presets')
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
transform: {
|
||||
...tsjPreset.transform,
|
||||
},
|
||||
}
|
||||
4
packages/domain-core/linter.tsconfig.json
Normal file
4
packages/domain-core/linter.tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
43
packages/domain-core/package.json
Normal file
43
packages/domain-core/package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-core",
|
||||
"version": "1.5.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
"description": "Domain Core SDK used in SN projects",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"files": [
|
||||
"dist/src/**/*.js",
|
||||
"dist/src/**/*.d.ts"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": "Standard Notes",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"build": "tsc --build",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test": "jest spec --coverage --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/features": "^1.52.1",
|
||||
"@standardnotes/predicates": "workspace:*",
|
||||
"@standardnotes/security": "workspace:*",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"shallow-equal-object": "^1.1.1",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.1.1",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "^29.1.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
36
packages/domain-core/src/Domain/Common/RoleName.spec.ts
Normal file
36
packages/domain-core/src/Domain/Common/RoleName.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { RoleName } from './RoleName'
|
||||
|
||||
describe('RoleName', () => {
|
||||
it('should create a value object', () => {
|
||||
const valueOrError = RoleName.create('PRO_USER')
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().value).toEqual('PRO_USER')
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
for (const value of ['', undefined, null, 0, 'SOME_USER']) {
|
||||
const valueOrError = RoleName.create(value as string)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
}
|
||||
})
|
||||
|
||||
it('should say if a role has more power or equal power to another role', () => {
|
||||
const proUserRole = RoleName.create('PRO_USER').getValue()
|
||||
const plusUserRole = RoleName.create('PLUS_USER').getValue()
|
||||
const coreUser = RoleName.create('CORE_USER').getValue()
|
||||
|
||||
expect(proUserRole.hasMoreOrEqualPowerTo(proUserRole)).toBeTruthy()
|
||||
expect(proUserRole.hasMoreOrEqualPowerTo(plusUserRole)).toBeTruthy()
|
||||
expect(proUserRole.hasMoreOrEqualPowerTo(coreUser)).toBeTruthy()
|
||||
|
||||
expect(plusUserRole.hasMoreOrEqualPowerTo(proUserRole)).toBeFalsy()
|
||||
expect(plusUserRole.hasMoreOrEqualPowerTo(plusUserRole)).toBeTruthy()
|
||||
expect(plusUserRole.hasMoreOrEqualPowerTo(coreUser)).toBeTruthy()
|
||||
|
||||
expect(coreUser.hasMoreOrEqualPowerTo(proUserRole)).toBeFalsy()
|
||||
expect(coreUser.hasMoreOrEqualPowerTo(plusUserRole)).toBeFalsy()
|
||||
expect(coreUser.hasMoreOrEqualPowerTo(coreUser)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
42
packages/domain-core/src/Domain/Common/RoleName.ts
Normal file
42
packages/domain-core/src/Domain/Common/RoleName.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RoleNameProps } from './RoleNameProps'
|
||||
|
||||
export class RoleName extends ValueObject<RoleNameProps> {
|
||||
private static readonly NAMES = {
|
||||
CoreUser: 'CORE_USER',
|
||||
PlusUser: 'PLUS_USER',
|
||||
ProUser: 'PRO_USER',
|
||||
FilesBetaUser: 'FILES_BETA_USER',
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this.props.value
|
||||
}
|
||||
|
||||
hasMoreOrEqualPowerTo(roleName: RoleName): boolean {
|
||||
switch (this.value) {
|
||||
case RoleName.NAMES.ProUser:
|
||||
return true
|
||||
case RoleName.NAMES.PlusUser:
|
||||
return [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser].includes(roleName.value)
|
||||
case RoleName.NAMES.CoreUser:
|
||||
return [RoleName.NAMES.CoreUser].includes(roleName.value)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private constructor(props: RoleNameProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(name: string): Result<RoleName> {
|
||||
const isValidName = Object.values(this.NAMES).includes(name)
|
||||
if (!isValidName) {
|
||||
return Result.fail<RoleName>(`Invalid role name: ${name}`)
|
||||
} else {
|
||||
return Result.ok<RoleName>(new RoleName({ value: name }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { RoleName } from './RoleName'
|
||||
import { RoleNameCollection } from './RoleNameCollection'
|
||||
|
||||
describe('RoleNameCollection', () => {
|
||||
it('should create a value object', () => {
|
||||
const role1 = RoleName.create('PRO_USER').getValue()
|
||||
|
||||
const valueOrError = RoleNameCollection.create([role1])
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().value).toEqual([role1])
|
||||
})
|
||||
|
||||
it('should tell if collections are not equal', () => {
|
||||
const roles1 = [RoleName.create('PRO_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
|
||||
const roles2 = RoleNameCollection.create([
|
||||
RoleName.create('PRO_USER').getValue(),
|
||||
RoleName.create('CORE_USER').getValue(),
|
||||
]).getValue()
|
||||
|
||||
const valueOrError = RoleNameCollection.create(roles1)
|
||||
expect(valueOrError.getValue().equals(roles2)).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should tell if collections are equal', () => {
|
||||
const roles1 = [RoleName.create('PRO_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
|
||||
const roles2 = RoleNameCollection.create([
|
||||
RoleName.create('PRO_USER').getValue(),
|
||||
RoleName.create('PLUS_USER').getValue(),
|
||||
]).getValue()
|
||||
|
||||
const valueOrError = RoleNameCollection.create(roles1)
|
||||
expect(valueOrError.getValue().equals(roles2)).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should tell if collection includes element', () => {
|
||||
const roles1 = [RoleName.create('PRO_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
|
||||
const valueOrError = RoleNameCollection.create(roles1)
|
||||
expect(valueOrError.getValue().includes(RoleName.create('PRO_USER').getValue())).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should tell if collection does not includes element', () => {
|
||||
const roles1 = [RoleName.create('PRO_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
|
||||
const valueOrError = RoleNameCollection.create(roles1)
|
||||
expect(valueOrError.getValue().includes(RoleName.create('CORE_USER').getValue())).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should tell if collection has a role with more or equal power to', () => {
|
||||
let roles = [RoleName.create('CORE_USER').getValue()]
|
||||
let valueOrError = RoleNameCollection.create(roles)
|
||||
let roleNames = valueOrError.getValue()
|
||||
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PLUS_USER').getValue())).toBeFalsy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PRO_USER').getValue())).toBeFalsy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('CORE_USER').getValue())).toBeTruthy()
|
||||
|
||||
roles = [RoleName.create('CORE_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
valueOrError = RoleNameCollection.create(roles)
|
||||
roleNames = valueOrError.getValue()
|
||||
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PLUS_USER').getValue())).toBeTruthy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PRO_USER').getValue())).toBeFalsy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('CORE_USER').getValue())).toBeTruthy()
|
||||
|
||||
roles = [RoleName.create('PRO_USER').getValue(), RoleName.create('PLUS_USER').getValue()]
|
||||
valueOrError = RoleNameCollection.create(roles)
|
||||
roleNames = valueOrError.getValue()
|
||||
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PLUS_USER').getValue())).toBeTruthy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('PRO_USER').getValue())).toBeTruthy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create('CORE_USER').getValue())).toBeTruthy()
|
||||
})
|
||||
})
|
||||
52
packages/domain-core/src/Domain/Common/RoleNameCollection.ts
Normal file
52
packages/domain-core/src/Domain/Common/RoleNameCollection.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { RoleNameCollectionProps } from './RoleNameCollectionProps'
|
||||
import { RoleName } from './RoleName'
|
||||
|
||||
export class RoleNameCollection extends ValueObject<RoleNameCollectionProps> {
|
||||
get value(): RoleName[] {
|
||||
return this.props.value
|
||||
}
|
||||
|
||||
includes(roleName: RoleName): boolean {
|
||||
for (const existingRoleName of this.props.value) {
|
||||
if (existingRoleName.equals(roleName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
hasARoleNameWithMoreOrEqualPowerTo(roleName: RoleName): boolean {
|
||||
for (const existingRoleName of this.props.value) {
|
||||
if (existingRoleName.hasMoreOrEqualPowerTo(roleName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override equals(roleNameCollection: RoleNameCollection): boolean {
|
||||
if (this.props.value.length !== roleNameCollection.value.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (const roleName of roleNameCollection.value) {
|
||||
if (!this.includes(roleName)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private constructor(props: RoleNameCollectionProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(roleName: RoleName[]): Result<RoleNameCollection> {
|
||||
return Result.ok<RoleNameCollection>(new RoleNameCollection({ value: roleName }))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { RoleName } from './RoleName'
|
||||
|
||||
export interface RoleNameCollectionProps {
|
||||
value: RoleName[]
|
||||
}
|
||||
3
packages/domain-core/src/Domain/Common/RoleNameProps.ts
Normal file
3
packages/domain-core/src/Domain/Common/RoleNameProps.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface RoleNameProps {
|
||||
value: string
|
||||
}
|
||||
21
packages/domain-core/src/Domain/Common/Timestamps.spec.ts
Normal file
21
packages/domain-core/src/Domain/Common/Timestamps.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Timestamps } from './Timestamps'
|
||||
|
||||
describe('Timestamps', () => {
|
||||
it('should create a value object', () => {
|
||||
const valueOrError = Timestamps.create(new Date(1), new Date(2))
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().createdAt).toEqual(new Date(1))
|
||||
expect(valueOrError.getValue().updatedAt).toEqual(new Date(2))
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
let valueOrError = Timestamps.create(null as unknown as Date, '2' as unknown as Date)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
|
||||
valueOrError = Timestamps.create(new Date(2), '2' as unknown as Date)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
32
packages/domain-core/src/Domain/Common/Timestamps.ts
Normal file
32
packages/domain-core/src/Domain/Common/Timestamps.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Result } from '../Core/Result'
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { TimestampsProps } from './TimestampsProps'
|
||||
|
||||
export class Timestamps extends ValueObject<TimestampsProps> {
|
||||
get createdAt(): Date {
|
||||
return this.props.createdAt
|
||||
}
|
||||
|
||||
get updatedAt(): Date {
|
||||
return this.props.updatedAt
|
||||
}
|
||||
|
||||
private constructor(props: TimestampsProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(createdAt: Date, updatedAt: Date): Result<Timestamps> {
|
||||
if (!(createdAt instanceof Date)) {
|
||||
return Result.fail<Timestamps>(
|
||||
`Could not create Timestamps. Creation date should be a date object, given: ${createdAt}`,
|
||||
)
|
||||
}
|
||||
if (!(updatedAt instanceof Date)) {
|
||||
return Result.fail<Timestamps>(
|
||||
`Could not create Timestamps. Update date should be a date object, given: ${createdAt}`,
|
||||
)
|
||||
}
|
||||
|
||||
return Result.ok<Timestamps>(new Timestamps({ createdAt, updatedAt }))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface TimestampsProps {
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
}
|
||||
@@ -2,14 +2,14 @@ import { Uuid } from './Uuid'
|
||||
|
||||
describe('Uuid', () => {
|
||||
it('should create a value object', () => {
|
||||
const valueOrError = Uuid.create('1-2-3')
|
||||
const valueOrError = Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d')
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().value).toEqual('1-2-3')
|
||||
expect(valueOrError.getValue().value).toEqual('84c0f8e8-544a-4c7e-9adf-26209303bc1d')
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
const valueOrError = Uuid.create('')
|
||||
const valueOrError = Uuid.create('1-2-3')
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
})
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { Result } from '../Core/Result'
|
||||
import { UuidProps } from './UuidProps'
|
||||
import { Validator } from '../Core/Validator'
|
||||
|
||||
export class Uuid extends ValueObject<UuidProps> {
|
||||
get value(): string {
|
||||
@@ -12,8 +13,9 @@ export class Uuid extends ValueObject<UuidProps> {
|
||||
}
|
||||
|
||||
static create(uuid: string): Result<Uuid> {
|
||||
if (!!uuid === false || uuid.length === 0) {
|
||||
return Result.fail<Uuid>('Uuid cannot be empty')
|
||||
const validUuidOrError = Validator.isValidUuid(uuid)
|
||||
if (validUuidOrError.isFailed()) {
|
||||
return Result.fail<Uuid>(validUuidOrError.getError())
|
||||
} else {
|
||||
return Result.ok<Uuid>(new Uuid({ value: uuid }))
|
||||
}
|
||||
32
packages/domain-core/src/Domain/Core/Validator.spec.ts
Normal file
32
packages/domain-core/src/Domain/Core/Validator.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Validator } from './Validator'
|
||||
|
||||
describe('Validator', () => {
|
||||
const validUuids = [
|
||||
'2221101c-1da9-4d2b-9b32-b8be2a8d1c82',
|
||||
'c08f2f29-a74b-42b4-aefd-98af9832391c',
|
||||
'b453fa64-1493-443b-b5bb-bca7b9c696c7',
|
||||
]
|
||||
|
||||
const invalidUuids = [
|
||||
123,
|
||||
'someone@127.0.0.1',
|
||||
'',
|
||||
null,
|
||||
'b453fa64-1493-443b-b5bb-ca7b9c696c7',
|
||||
'c08f*f29-a74b-42b4-aefd-98af9832391c',
|
||||
'c08f*f29-a74b-42b4-aefd-98af9832391c',
|
||||
'../../escaped.sh',
|
||||
]
|
||||
|
||||
it('should validate proper uuids', () => {
|
||||
for (const validUuid of validUuids) {
|
||||
expect(Validator.isValidUuid(validUuid).isFailed()).toBeFalsy()
|
||||
}
|
||||
})
|
||||
|
||||
it('should not validate invalid uuids', () => {
|
||||
for (const invalidUuid of invalidUuids) {
|
||||
expect(Validator.isValidUuid(invalidUuid as string).isFailed()).toBeTruthy()
|
||||
}
|
||||
})
|
||||
})
|
||||
14
packages/domain-core/src/Domain/Core/Validator.ts
Normal file
14
packages/domain-core/src/Domain/Core/Validator.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Result } from './Result'
|
||||
|
||||
export class Validator {
|
||||
private static readonly UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
||||
|
||||
static isValidUuid(value: string): Result<string> {
|
||||
const matchesUuidRegex = String(value).toLowerCase().match(Validator.UUID_REGEX) !== null
|
||||
if (matchesUuidRegex) {
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
return Result.fail(`Given value is not a valid uuid: ${value}`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface MapperInterface<T, U> {
|
||||
toDomain(projection: U): T
|
||||
toProjection(domain: T): U
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Result } from '../Core/Result'
|
||||
|
||||
export interface UseCaseInterface<T> {
|
||||
execute(...args: any[]): Promise<Result<T>>
|
||||
}
|
||||
23
packages/domain-core/src/Domain/index.ts
Normal file
23
packages/domain-core/src/Domain/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export * from './Common/Email'
|
||||
export * from './Common/EmailProps'
|
||||
export * from './Common/RoleName'
|
||||
export * from './Common/RoleNameProps'
|
||||
export * from './Common/RoleNameCollection'
|
||||
export * from './Common/RoleNameCollectionProps'
|
||||
export * from './Common/Timestamps'
|
||||
export * from './Common/TimestampsProps'
|
||||
export * from './Common/Uuid'
|
||||
export * from './Common/UuidProps'
|
||||
|
||||
export * from './Core/Aggregate'
|
||||
export * from './Core/Entity'
|
||||
export * from './Core/Id'
|
||||
export * from './Core/Result'
|
||||
export * from './Core/UniqueEntityId'
|
||||
export * from './Core/Validator'
|
||||
export * from './Core/ValueObject'
|
||||
export * from './Core/ValueObjectProps'
|
||||
|
||||
export * from './Mapping/MapperInterface'
|
||||
|
||||
export * from './UseCase/UseCaseInterface'
|
||||
1
packages/domain-core/src/index.ts
Normal file
1
packages/domain-core/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Domain'
|
||||
11
packages/domain-core/tsconfig.json
Normal file
11
packages/domain-core/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.9.34](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.33...@standardnotes/domain-events-infra@1.9.34) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.33](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.32...@standardnotes/domain-events-infra@1.9.33) (2022-11-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.32](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.31...@standardnotes/domain-events-infra@1.9.32) (2022-11-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.31](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.30...@standardnotes/domain-events-infra@1.9.31) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.30](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.29...@standardnotes/domain-events-infra@1.9.30) (2022-11-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.29](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.28...@standardnotes/domain-events-infra@1.9.29) (2022-11-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.28](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.27...@standardnotes/domain-events-infra@1.9.28) (2022-11-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.27](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.26...@standardnotes/domain-events-infra@1.9.27) (2022-11-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.26](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.23...@standardnotes/domain-events-infra@1.9.26) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.9.26",
|
||||
"version": "1.9.34",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -23,9 +23,8 @@
|
||||
"test": "jest spec --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "^9.0.0",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"aws-sdk": "^2.1253.0",
|
||||
"aws-sdk": "^2.1260.0",
|
||||
"ioredis": "^5.2.4",
|
||||
"newrelic": "^9.6.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.90.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.90.1...@standardnotes/domain-events@2.90.2) (2022-11-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
## [2.90.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.90.0...@standardnotes/domain-events@2.90.1) (2022-11-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
# [2.90.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.89.0...@standardnotes/domain-events@2.90.0) (2022-11-21)
|
||||
|
||||
### Features
|
||||
|
||||
* **syncing-server:** add creating item dumps for revision service ([8d152dd](https://github.com/standardnotes/server/commit/8d152ddfcb3c88cbbf9df04e3ed6e2c02571d821))
|
||||
|
||||
# [2.89.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.88.0...@standardnotes/domain-events@2.89.0) (2022-11-18)
|
||||
|
||||
### Features
|
||||
|
||||
* add item revision creation requested event ([5c9dff3](https://github.com/standardnotes/server/commit/5c9dff38c9006d39150ea95b2ca17c4ab7175ec2))
|
||||
|
||||
# [2.88.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.87.0...@standardnotes/domain-events@2.88.0) (2022-11-16)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add publishing churn calculation values in the report ([6c43a33](https://github.com/standardnotes/server/commit/6c43a331d09c2dcf1300742509da6a1d8ef2f5b7))
|
||||
|
||||
# [2.87.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.86.3...@standardnotes/domain-events@2.87.0) (2022-11-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** extract domain core into a separate package ([0f94e2a](https://github.com/standardnotes/server/commit/0f94e2ad0c8927733eac31f130cbe649dce765f9))
|
||||
|
||||
## [2.86.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.86.0...@standardnotes/domain-events@2.86.3) (2022-11-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user