Compare commits

...

25 Commits

Author SHA1 Message Date
standardci
b172177142 chore(release): publish new version
- @standardnotes/event-store@1.1.1
2022-07-11 10:17:12 +00:00
Karol Sójko
3fc11c5381 fix: optional migrations path 2022-07-11 12:15:40 +02:00
standardci
13cf896fe2 chore(release): publish new version
- @standardnotes/auth-server@1.11.0
 - @standardnotes/event-store@1.1.0
2022-07-11 10:00:23 +00:00
Karol Sójko
84ff915a56 feat: add event store package 2022-07-11 11:58:13 +02:00
Karol Sójko
74aedbccfe fix: publishing final image to docker hub 2022-07-08 12:45:12 +02:00
Karol Sójko
6e49298aea fix: add pre-deployment e2e tests 2022-07-08 12:18:20 +02:00
standardci
c1ba290e41 chore(release): publish new version
- @standardnotes/auth-server@1.10.0
 - @standardnotes/files-server@1.5.0
 - @standardnotes/sncrypto-node@1.10.0
2022-07-06 10:15:46 +00:00
Karol Sójko
60e8974580 feat: add sncryptio-node package 2022-07-06 12:14:05 +02:00
standardci
033eeda50a chore(release): publish new version
- @standardnotes/auth-server@1.9.0
 - @standardnotes/settings@1.17.0
 - @standardnotes/syncing-server@1.6.0
2022-07-06 10:07:30 +00:00
Karol Sójko
e7e34f3e16 feat: add settings package 2022-07-06 12:05:58 +02:00
standardci
7e1fcebdd8 chore(release): publish new version
- @standardnotes/api-gateway@1.6.1
 - @standardnotes/auth-server@1.8.0
 - @standardnotes/common@1.25.0
 - @standardnotes/domain-events-infra@1.7.5
 - @standardnotes/domain-events@2.39.0
 - @standardnotes/files-server@1.4.0
 - @standardnotes/predicates@1.2.0
 - @standardnotes/scheduler-server@1.5.0
 - @standardnotes/security@1.2.0
 - @standardnotes/syncing-server@1.5.0
2022-07-06 10:04:10 +00:00
Karol Sójko
fd4ee2123d feat: add common package 2022-07-06 12:02:39 +02:00
standardci
62caa840ef chore(release): publish new version
- @standardnotes/api-gateway@1.6.0
 - @standardnotes/auth-server@1.7.0
 - @standardnotes/files-server@1.3.0
 - @standardnotes/scheduler-server@1.4.0
 - @standardnotes/syncing-server@1.4.0
 - @standardnotes/time@1.9.0
2022-07-06 09:47:24 +00:00
Karol Sójko
565e890973 feat: add time package 2022-07-06 11:46:04 +02:00
standardci
84c4642ced chore(release): publish new version
- @standardnotes/api-gateway@1.5.0
 - @standardnotes/auth-server@1.6.0
 - @standardnotes/domain-events-infra@1.7.4
 - @standardnotes/domain-events@2.38.0
 - @standardnotes/files-server@1.2.0
 - @standardnotes/scheduler-server@1.3.2
 - @standardnotes/security@1.1.0
 - @standardnotes/syncing-server@1.3.0
2022-07-06 09:28:38 +00:00
Karol Sójko
699164eba5 fix: deps to @standarnotes/security 2022-07-06 11:27:19 +02:00
Karol Sójko
d86928f1b4 feat: add security package 2022-07-06 11:24:32 +02:00
standardci
06fc077f1b chore(release): publish new version
- @standardnotes/analytics@1.8.1
 - @standardnotes/api-gateway@1.4.2
 - @standardnotes/auth-server@1.5.1
 - @standardnotes/domain-events-infra@1.7.3
 - @standardnotes/domain-events@2.37.1
 - @standardnotes/files-server@1.1.14
 - @standardnotes/predicates@1.1.1
 - @standardnotes/scheduler-server@1.3.1
 - @standardnotes/syncing-server@1.2.2
2022-07-06 09:20:41 +00:00
Karol Sójko
97ba31f345 fix: files included in distributable packages 2022-07-06 11:19:05 +02:00
standardci
a8795defc1 chore(release): publish new version
- @standardnotes/api-gateway@1.4.1
 - @standardnotes/auth-server@1.5.0
 - @standardnotes/domain-events-infra@1.7.2
 - @standardnotes/domain-events@2.37.0
 - @standardnotes/files-server@1.1.13
 - @standardnotes/predicates@1.1.0
 - @standardnotes/scheduler-server@1.3.0
 - @standardnotes/syncing-server@1.2.1
2022-07-06 08:52:19 +00:00
Karol Sójko
1b35cf7a39 fix: scheduler to predicates imports 2022-07-06 10:51:02 +02:00
Karol Sójko
ed62ed516f feat: add predicates package 2022-07-06 10:49:22 +02:00
standardci
b4f1c6f7f8 chore(release): publish new version
- @standardnotes/analytics@1.8.0
 - @standardnotes/api-gateway@1.4.0
 - @standardnotes/auth-server@1.4.0
 - @standardnotes/domain-events-infra@1.7.1
 - @standardnotes/domain-events@2.36.0
 - @standardnotes/files-server@1.1.12
 - @standardnotes/scheduler-server@1.2.7
 - @standardnotes/syncing-server@1.2.0
2022-07-06 08:37:46 +00:00
Karol Sójko
14e4ca70b4 feat: add analytics package 2022-07-06 10:36:32 +02:00
Karol Sójko
12fa94539b fix: build process due to composite packages 2022-07-06 10:29:06 +02:00
247 changed files with 5508 additions and 538 deletions

View File

@@ -16,13 +16,42 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version-file: '.nvmrc'
- run: yarn build
- run: yarn lint:api-gateway
- name: Build
run: yarn build
- name: Lint
run: yarn lint:api-gateway
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish Docker image for E2E testing
run: |
yarn docker build @standardnotes/api-gateway -t standardnotes/api-gateway:${{ github.sha }}
docker push standardnotes/api-gateway:${{ github.sha }}
- name: Run E2E test suite
uses: convictional/trigger-workflow-and-wait@v1.6.1
with:
owner: standardnotes
repo: e2e
github_token: ${{ secrets.CI_PAT_TOKEN }}
workflow_file_name: testing-with-stable-client.yml
wait_interval: 30
client_payload: '{"api_gateway_image_tag": "${{ github.sha }}"}'
propagate_failure: true
trigger_workflow: true
wait_workflow: true
publish-aws-ecr:
needs: test
@@ -32,7 +61,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:api-gateway
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
@@ -62,17 +91,15 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:api-gateway
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build, tag, and push image to Docker Hub
- name: Publish Docker image as stable
run: |
yarn docker build @standardnotes/api-gateway -t standardnotes/api-gateway:${{ github.sha }}
docker push standardnotes/api-gateway:${{ github.sha }}
docker tag standardnotes/api-gateway:${{ github.sha }} standardnotes/api-gateway:latest
yarn docker build @standardnotes/api-gateway -t standardnotes/api-gateway:latest
docker push standardnotes/api-gateway:latest
deploy-web:

View File

@@ -16,14 +16,45 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version-file: '.nvmrc'
- run: yarn build
- run: yarn lint:auth
- run: yarn test:auth
- name: Build
run: yarn build
- name: Lint
run: yarn lint:auth
- name: Test
run: yarn test:auth
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish Docker image for E2E testing
run: |
yarn docker build @standardnotes/auth-server -t standardnotes/auth:${{ github.sha }}
docker push standardnotes/auth:${{ github.sha }}
- name: Run E2E test suite
uses: convictional/trigger-workflow-and-wait@v1.6.1
with:
owner: standardnotes
repo: e2e
github_token: ${{ secrets.CI_PAT_TOKEN }}
workflow_file_name: testing-with-stable-client.yml
wait_interval: 30
client_payload: '{"auth_image_tag": "${{ github.sha }}"}'
propagate_failure: true
trigger_workflow: true
wait_workflow: true
publish-aws-ecr:
needs: test
@@ -33,7 +64,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:auth
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
@@ -63,17 +94,15 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:auth
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build, tag, and push image to Docker Hub
- name: Publish Docker image as stable
run: |
yarn docker build @standardnotes/auth-server -t standardnotes/auth:${{ github.sha }}
docker push standardnotes/auth:${{ github.sha }}
docker tag standardnotes/auth:${{ github.sha }} standardnotes/auth:latest
yarn docker build @standardnotes/auth-server -t standardnotes/auth:latest
docker push standardnotes/auth:latest
deploy-web:

View File

@@ -0,0 +1,126 @@
name: Event Store
concurrency:
group: event-store
cancel-in-progress: true
on:
push:
tags:
- '*standardnotes/event-store*'
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version-file: '.nvmrc'
- run: yarn build
- run: yarn lint:event-store
- run: yarn test:event-store
publish-aws-ecr:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: event-store
IMAGE_TAG: ${{ github.sha }}
run: |
yarn docker build @standardnotes/event-store -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
publish-docker-hub:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build, tag, and push image to Docker Hub
run: |
yarn docker build @standardnotes/event-store -t standardnotes/event-store:${{ github.sha }}
docker push standardnotes/event-store:${{ github.sha }}
docker tag standardnotes/event-store:${{ github.sha }} standardnotes/event-store:latest
docker push standardnotes/event-store:latest
deploy-worker:
needs: publish-aws-ecr
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: PROD - Download task definition
run: |
aws ecs describe-task-definition --task-definition event-store-prod --query taskDefinition > task-definition.json
- name: PROD - Fill in the new version in the Amazon ECS task definition
run: |
jq '(.containerDefinitions[] | select(.name=="event-store-prod") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
- name: PROD - Fill in the new image ID in the Amazon ECS task definition
id: task-def-prod
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: event-store-prod
image: ${{ secrets.AWS_ECR_REGISTRY }}/event-store:${{ github.sha }}
- name: PROD - Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def-prod.outputs.task-definition }}
service: event-store-prod
cluster: prod
wait-for-service-stability: true
newrelic:
needs: [ deploy-worker ]
runs-on: ubuntu-latest
steps:
- 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_EVENT_STORE_PROD }}
revision: "${{ github.sha }}"
description: "Automated Deployment via Github Actions"
user: "${{ github.actor }}"

View File

@@ -16,14 +16,45 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version-file: '.nvmrc'
- run: yarn build
- run: yarn lint:files
- run: yarn test:files
- name: Build
run: yarn build
- name: Lint
run: yarn lint:files
- name: Test
run: yarn test:files
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish Docker image for E2E testing
run: |
yarn docker build @standardnotes/files-server -t standardnotes/files:${{ github.sha }}
docker push standardnotes/files:${{ github.sha }}
- name: Run E2E test suite
uses: convictional/trigger-workflow-and-wait@v1.6.1
with:
owner: standardnotes
repo: e2e
github_token: ${{ secrets.CI_PAT_TOKEN }}
workflow_file_name: testing-with-stable-client.yml
wait_interval: 30
client_payload: '{"files_image_tag": "${{ github.sha }}"}'
propagate_failure: true
trigger_workflow: true
wait_workflow: true
publish-aws-ecr:
needs: test
@@ -33,7 +64,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:files
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
@@ -63,7 +94,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:files
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
@@ -71,9 +102,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build, tag, and push image to Docker Hub
run: |
yarn docker build @standardnotes/files-server -t standardnotes/files:${{ github.sha }}
docker push standardnotes/files:${{ github.sha }}
docker tag standardnotes/files:${{ github.sha }} standardnotes/files:latest
yarn docker build @standardnotes/files-server -t standardnotes/files:latest
docker push standardnotes/files:latest
deploy-web:

View File

@@ -33,7 +33,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:scheduler
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
@@ -63,7 +63,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:scheduler
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:

View File

@@ -16,14 +16,45 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version-file: '.nvmrc'
- run: yarn build
- run: yarn lint:syncing-server
- run: yarn test:syncing-server
- name: Build
run: yarn build
- name: Lint
run: yarn lint:syncing-server
- name: Test
run: yarn test:syncing-server
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish Docker image for E2E testing
run: |
yarn docker build @standardnotes/syncing-server -t standardnotes/syncing-server-js:${{ github.sha }}
docker push standardnotes/syncing-server-js:${{ github.sha }}
- name: Run E2E test suite
uses: convictional/trigger-workflow-and-wait@v1.6.1
with:
owner: standardnotes
repo: e2e
github_token: ${{ secrets.CI_PAT_TOKEN }}
workflow_file_name: testing-with-stable-client.yml
wait_interval: 30
client_payload: '{"syncing_server_js_image_tag": "${{ github.sha }}"}'
propagate_failure: true
trigger_workflow: true
wait_workflow: true
publish-aws-ecr:
needs: test
@@ -33,7 +64,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:syncing-server
run: yarn build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
@@ -63,7 +94,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build locally
run: yarn build:syncing-server
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
@@ -71,9 +102,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build, tag, and push image to Docker Hub
run: |
yarn docker build @standardnotes/syncing-server -t standardnotes/syncing-server-js:${{ github.sha }}
docker push standardnotes/syncing-server-js:${{ github.sha }}
docker tag standardnotes/syncing-server-js:${{ github.sha }} standardnotes/syncing-server-js:latest
yarn docker build @standardnotes/syncing-server -t standardnotes/syncing-server-js:latest
docker push standardnotes/syncing-server-js:latest
deploy-web:

893
.pnp.cjs generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,11 +17,13 @@
"lint:syncing-server": "yarn workspace @standardnotes/syncing-server lint",
"lint:files": "yarn workspace @standardnotes/files-server lint",
"lint:api-gateway": "yarn workspace @standardnotes/api-gateway lint",
"lint:event-store": "yarn workspace @standardnotes/event-store lint",
"test": "yarn workspaces foreach -p -j 10 --verbose run test",
"test:auth": "yarn workspace @standardnotes/auth-server test",
"test:scheduler": "yarn workspace @standardnotes/scheduler-server test",
"test:syncing-server": "yarn workspace @standardnotes/syncing-server test",
"test:files": "yarn workspace @standardnotes/files-server test",
"test:event-store": "yarn workspace @standardnotes/event-store test",
"clean": "yarn workspaces foreach -p --verbose run clean",
"setup:env": "cp .env.sample .env && yarn workspaces foreach -p --verbose run setup:env",
"build": "yarn workspaces foreach -pt -j 10 --verbose run build",

View File

@@ -0,0 +1 @@
dist

View File

@@ -0,0 +1,6 @@
{
"extends": "../../.eslintrc",
"parserOptions": {
"project": "./linter.tsconfig.json"
}
}

View File

@@ -0,0 +1,98 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.8.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.8.0...@standardnotes/analytics@1.8.1) (2022-07-06)
### Bug Fixes
* files included in distributable packages ([97ba31f](https://github.com/standardnotes/server/commit/97ba31f345fc95df0c15a348f0461fb9e5bcb923))
# 1.8.0 (2022-07-06)
### Features
* add analytics package ([14e4ca7](https://github.com/standardnotes/server/commit/14e4ca70b438dd3eaaa404bc0ca31d22a62b45be))
## [1.6.1](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.6.0...@standardnotes/analytics@1.6.1) (2022-07-04)
### Bug Fixes
* add missing reflect-metadata package to all packages ([ce3a5bb](https://github.com/standardnotes/snjs/commit/ce3a5bbf3f1d2276ac4abc3eec3c6a44c8c3ba9b))
# [1.6.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.5.0...@standardnotes/analytics@1.6.0) (2022-06-02)
### Features
* refactor analytics store to handle different periods of time ([00d4f3f](https://github.com/standardnotes/snjs/commit/00d4f3f2f742b0deb5ef4cd415c672574cb3a911))
# [1.5.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.4.1...@standardnotes/analytics@1.5.0) (2022-06-01)
### Features
* add unmarking activities ([09cea1d](https://github.com/standardnotes/snjs/commit/09cea1d8e97dd83f2eaafaef5ff680aef8c5c3ff))
## [1.4.1](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.4.0...@standardnotes/analytics@1.4.1) (2022-06-01)
### Bug Fixes
* rename analytics activity backup to email backup ([30d2db6](https://github.com/standardnotes/snjs/commit/30d2db63e5dec05b3f0976211c661d8aa0e04139))
# [1.4.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.3.1...@standardnotes/analytics@1.4.0) (2022-06-01)
### Features
* add calculating total counts of activites in analytics ([6ed659a](https://github.com/standardnotes/snjs/commit/6ed659a7c4411ce2555e4af96dc5473c3d03fd41))
## [1.3.1](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.3.0...@standardnotes/analytics@1.3.1) (2022-05-26)
### Bug Fixes
* add backup analytics activity ([cf7ae68](https://github.com/standardnotes/snjs/commit/cf7ae68e13aa9403702340da8a3bca35e9273784))
# [1.3.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.2.0...@standardnotes/analytics@1.3.0) (2022-05-26)
### Features
* add calculating activity retention in analytics ([bc2f26d](https://github.com/standardnotes/snjs/commit/bc2f26d63a8ff0e2750b37bc1ee56297f6a8c98d))
# [1.2.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.1.0...@standardnotes/analytics@1.2.0) (2022-05-26)
### Features
* add activity indicators in analytics ([e6f5b5a](https://github.com/standardnotes/snjs/commit/e6f5b5afbff1f5f96adfcba42f4708fa74ac7f80))
# [1.1.0](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.7...@standardnotes/analytics@1.1.0) (2022-05-24)
### Features
* add marking activity in analytics ([#750](https://github.com/standardnotes/snjs/issues/750)) ([2a68fa6](https://github.com/standardnotes/snjs/commit/2a68fa6636c24e79443359d31a8427d50ca87cca))
## [1.0.7](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.5...@standardnotes/analytics@1.0.7) (2022-05-04)
**Note:** Version bump only for package @standardnotes/analytics
## [1.0.6](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.5...@standardnotes/analytics@1.0.6) (2022-05-04)
**Note:** Version bump only for package @standardnotes/analytics
## [1.0.5](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.4...@standardnotes/analytics@1.0.5) (2022-04-22)
**Note:** Version bump only for package @standardnotes/analytics
## [1.0.4](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.3...@standardnotes/analytics@1.0.4) (2022-04-15)
**Note:** Version bump only for package @standardnotes/analytics
## [1.0.3](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.2...@standardnotes/analytics@1.0.3) (2022-04-11)
**Note:** Version bump only for package @standardnotes/analytics
## [1.0.2](https://github.com/standardnotes/snjs/compare/@standardnotes/analytics@1.0.1...@standardnotes/analytics@1.0.2) (2022-03-31)
**Note:** Version bump only for package @standardnotes/analytics
## 1.0.1 (2022-03-10)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -0,0 +1,11 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const base = require('../../jest.config');
module.exports = {
...base,
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json',
},
},
};

View File

@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["dist"]
}

View File

@@ -0,0 +1,40 @@
{
"name": "@standardnotes/analytics",
"version": "1.8.1",
"engines": {
"node": ">=14.0.0 <17.0.0"
},
"description": "Analytics tools for Standard Notes projects",
"main": "dist/src/index.js",
"author": "Standard Notes",
"types": "dist/src/index.d.ts",
"files": [
"dist/src/**/*.js",
"dist/src/**/*.d.ts"
],
"publishConfig": {
"access": "public"
},
"license": "AGPL-3.0-or-later",
"scripts": {
"clean": "rm -fr dist",
"prestart": "yarn clean",
"start": "tsc -p tsconfig.json --watch",
"prebuild": "yarn clean",
"build": "tsc -p tsconfig.json",
"lint": "eslint . --ext .ts",
"test:unit": "jest spec --coverage"
},
"devDependencies": {
"@types/ioredis": "^4.28.8",
"@types/jest": "^27.4.1",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"eslint-plugin-prettier": "^4.2.1",
"ioredis": "^4.28.5",
"jest": "^27.5.1",
"ts-jest": "^27.1.3"
},
"dependencies": {
"reflect-metadata": "^0.1.13"
}
}

View File

@@ -0,0 +1,6 @@
export enum AnalyticsActivity {
EditingItems = 'editing-items',
Login = 'login',
EmailUnbackedUpData = 'email-unbacked-up-data',
EmailBackup = 'email-backup',
}

View File

@@ -0,0 +1,10 @@
import { Period } from '../Time/Period'
import { AnalyticsActivity } from './AnalyticsActivity'
export interface AnalyticsStoreInterface {
unmarkActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void>
markActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void>
wasActivityDone(activity: AnalyticsActivity, analyticsId: number, period: Period): Promise<boolean>
calculateActivityRetention(activity: AnalyticsActivity, firstPeriod: Period, secondPeriod: Period): Promise<number>
calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number>
}

View File

@@ -0,0 +1,8 @@
export interface StatisticsStoreInterface {
incrementSNJSVersionUsage(snjsVersion: string): Promise<void>
incrementApplicationVersionUsage(applicationVersion: string): Promise<void>
incrementOutOfSyncIncidents(): Promise<void>
getYesterdaySNJSUsage(): Promise<Array<{ version: string; count: number }>>
getYesterdayApplicationUsage(): Promise<Array<{ version: string; count: number }>>
getYesterdayOutOfSyncIncidents(): Promise<number>
}

View File

@@ -0,0 +1,10 @@
export enum Period {
Today,
Yesterday,
DayBeforeYesterday,
ThisWeek,
LastWeek,
WeekBeforeLastWeek,
ThisMonth,
LastMonth,
}

View File

@@ -0,0 +1,58 @@
import { Period } from './Period'
import { PeriodKeyGenerator } from './PeriodKeyGenerator'
describe('PeriodKeyGenerator', () => {
const createGenerator = () => new PeriodKeyGenerator()
beforeEach(() => {
jest.useFakeTimers('modern')
jest.setSystemTime(1653395155000)
})
afterEach(() => {
jest.useRealTimers()
})
it('should generate a period key for today', () => {
expect(createGenerator().getPeriodKey(Period.Today)).toEqual('2022-5-24')
})
it('should generate a period key for yesterday', () => {
expect(createGenerator().getPeriodKey(Period.Yesterday)).toEqual('2022-5-23')
})
it('should generate a period key for the day before yesterday', () => {
expect(createGenerator().getPeriodKey(Period.DayBeforeYesterday)).toEqual('2022-5-22')
})
it('should generate a period key for this week', () => {
expect(createGenerator().getPeriodKey(Period.ThisWeek)).toEqual('2022-week-21')
})
it('should generate a period key for last week', () => {
expect(createGenerator().getPeriodKey(Period.LastWeek)).toEqual('2022-week-20')
})
it('should generate a period key for the week before last week', () => {
expect(createGenerator().getPeriodKey(Period.WeekBeforeLastWeek)).toEqual('2022-week-19')
})
it('should generate a period key for this month', () => {
expect(createGenerator().getPeriodKey(Period.ThisMonth)).toEqual('2022-5')
})
it('should generate a period key for last month', () => {
expect(createGenerator().getPeriodKey(Period.LastMonth)).toEqual('2022-4')
})
it('should throw error on unsupported period', () => {
let error = null
try {
createGenerator().getPeriodKey(42 as Period)
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
})

View File

@@ -0,0 +1,99 @@
import { Period } from './Period'
import { PeriodKeyGeneratorInterface } from './PeriodKeyGeneratorInterface'
export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
getPeriodKey(period: Period): string {
switch (period) {
case Period.Today:
return this.getDailyKey()
case Period.Yesterday:
return this.getDailyKey(this.getYesterdayDate())
case Period.DayBeforeYesterday:
return this.getDailyKey(this.getDayBeforeYesterdayDate())
case Period.ThisWeek:
return this.getWeeklyKey()
case Period.LastWeek:
return this.getWeeklyKey(this.getLastWeekDate())
case Period.WeekBeforeLastWeek:
return this.getWeeklyKey(this.getWeekBeforeLastWeekDate())
case Period.ThisMonth:
return this.getMonthlyKey()
case Period.LastMonth:
return this.getMonthlyKey(this.getLastMonthDate())
default:
throw new Error(`Unsuporrted period: ${period}`)
}
}
private getMonthlyKey(date?: Date): string {
date = date ?? new Date()
return `${this.getYear(date)}-${this.getMonth(date)}`
}
private getDailyKey(date?: Date): string {
date = date ?? new Date()
return `${this.getYear(date)}-${this.getMonth(date)}-${this.getDayOfTheMonth(date)}`
}
private getWeeklyKey(date?: Date): string {
date = date ?? new Date()
const firstJanuary = new Date(date.getFullYear(), 0, 1)
const numberOfDaysPassed = Math.floor((date.getTime() - firstJanuary.getTime()) / (24 * 60 * 60 * 1000))
const weekNumber = Math.ceil((date.getDay() + 1 + numberOfDaysPassed) / 7)
return `${this.getYear(date)}-week-${weekNumber}`
}
private getYear(date: Date): string {
return date.getFullYear().toString()
}
private getMonth(date: Date): string {
return (date.getMonth() + 1).toString()
}
private getDayOfTheMonth(date: Date): string {
return date.getDate().toString()
}
private getYesterdayDate(): Date {
const yesterday = new Date()
yesterday.setDate(new Date().getDate() - 1)
return yesterday
}
private getDayBeforeYesterdayDate(): Date {
const dayBeforeYesterday = new Date()
dayBeforeYesterday.setDate(new Date().getDate() - 2)
return dayBeforeYesterday
}
private getLastWeekDate(): Date {
const yesterday = new Date()
yesterday.setDate(new Date().getDate() - 7)
return yesterday
}
private getLastMonthDate(): Date {
const lastMonth = new Date()
lastMonth.setDate(1)
lastMonth.setMonth(lastMonth.getMonth() - 1)
return lastMonth
}
private getWeekBeforeLastWeekDate(): Date {
const yesterday = new Date()
yesterday.setDate(new Date().getDate() - 14)
return yesterday
}
}

View File

@@ -0,0 +1,5 @@
import { Period } from './Period'
export interface PeriodKeyGeneratorInterface {
getPeriodKey(period: Period): string
}

View File

@@ -0,0 +1,6 @@
export * from './Analytics/AnalyticsActivity'
export * from './Analytics/AnalyticsStoreInterface'
export * from './Statistics/StatisticsStoreInterface'
export * from './Time/Period'
export * from './Time/PeriodKeyGenerator'
export * from './Time/PeriodKeyGeneratorInterface'

View File

@@ -0,0 +1,131 @@
import * as IORedis from 'ioredis'
import { Period } from '../../Domain'
import { AnalyticsActivity } from '../../Domain/Analytics/AnalyticsActivity'
import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'
import { RedisAnalyticsStore } from './RedisAnalyticsStore'
describe('RedisAnalyticsStore', () => {
let redisClient: IORedis.Redis
let pipeline: IORedis.Pipeline
let periodKeyGenerator: PeriodKeyGeneratorInterface
const createStore = () => new RedisAnalyticsStore(periodKeyGenerator, redisClient)
beforeEach(() => {
pipeline = {} as jest.Mocked<IORedis.Pipeline>
pipeline.incr = jest.fn()
pipeline.setbit = jest.fn()
pipeline.exec = jest.fn()
redisClient = {} as jest.Mocked<IORedis.Redis>
redisClient.pipeline = jest.fn().mockReturnValue(pipeline)
redisClient.incr = jest.fn()
redisClient.setbit = jest.fn()
redisClient.getbit = jest.fn().mockReturnValue(1)
redisClient.send_command = jest.fn()
periodKeyGenerator = {} as jest.Mocked<PeriodKeyGeneratorInterface>
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
})
it('should calculate total count of activities', async () => {
redisClient.bitcount = jest.fn().mockReturnValue(70)
expect(await createStore().calculateActivityTotalCount(AnalyticsActivity.EditingItems, Period.Yesterday)).toEqual(
70,
)
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key')
})
it('should calculate activity retention', async () => {
redisClient.bitcount = jest.fn().mockReturnValueOnce(7).mockReturnValueOnce(10)
expect(
await createStore().calculateActivityRetention(
AnalyticsActivity.EditingItems,
Period.DayBeforeYesterday,
Period.Yesterday,
),
).toEqual(70)
expect(redisClient.send_command).toHaveBeenCalledWith(
'BITOP',
'AND',
'bitmap:action:editing-items:timespan:period-key-period-key',
'bitmap:action:editing-items:timespan:period-key',
'bitmap:action:editing-items:timespan:period-key',
)
})
it('shoud tell if activity was done', async () => {
await createStore().wasActivityDone(AnalyticsActivity.EditingItems, 123, Period.Yesterday)
expect(redisClient.getbit).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:period-key', 123)
})
it('should mark activity as done', async () => {
await createStore().markActivity([AnalyticsActivity.EditingItems], 123, [Period.Today])
expect(pipeline.setbit).toBeCalledTimes(1)
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
expect(pipeline.exec).toHaveBeenCalled()
})
it('should mark activities as done', async () => {
await createStore().markActivity([AnalyticsActivity.EditingItems, AnalyticsActivity.EmailUnbackedUpData], 123, [
Period.Today,
Period.ThisWeek,
])
expect(pipeline.setbit).toBeCalledTimes(4)
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 1)
expect(pipeline.setbit).toHaveBeenNthCalledWith(
3,
'bitmap:action:email-unbacked-up-data:timespan:period-key',
123,
1,
)
expect(pipeline.setbit).toHaveBeenNthCalledWith(
4,
'bitmap:action:email-unbacked-up-data:timespan:period-key',
123,
1,
)
expect(pipeline.exec).toHaveBeenCalled()
})
it('should unmark activity as done', async () => {
await createStore().unmarkActivity([AnalyticsActivity.EditingItems], 123, [Period.Today])
expect(pipeline.setbit).toBeCalledTimes(1)
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
expect(pipeline.exec).toHaveBeenCalled()
})
it('should unmark activities as done', async () => {
await createStore().unmarkActivity([AnalyticsActivity.EditingItems, AnalyticsActivity.EmailUnbackedUpData], 123, [
Period.Today,
Period.ThisWeek,
])
expect(pipeline.setbit).toBeCalledTimes(4)
expect(pipeline.setbit).toHaveBeenNthCalledWith(1, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
expect(pipeline.setbit).toHaveBeenNthCalledWith(2, 'bitmap:action:editing-items:timespan:period-key', 123, 0)
expect(pipeline.setbit).toHaveBeenNthCalledWith(
3,
'bitmap:action:email-unbacked-up-data:timespan:period-key',
123,
0,
)
expect(pipeline.setbit).toHaveBeenNthCalledWith(
4,
'bitmap:action:email-unbacked-up-data:timespan:period-key',
123,
0,
)
expect(pipeline.exec).toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,84 @@
import * as IORedis from 'ioredis'
import { Period } from '../../Domain/Time/Period'
import { PeriodKeyGeneratorInterface } from '../../Domain/Time/PeriodKeyGeneratorInterface'
import { AnalyticsActivity } from '../../Domain/Analytics/AnalyticsActivity'
import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreInterface'
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
async markActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void> {
const pipeline = this.redisClient.pipeline()
for (const activity of activities) {
for (const period of periods) {
pipeline.setbit(
`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
analyticsId,
1,
)
}
}
await pipeline.exec()
}
async unmarkActivity(activities: AnalyticsActivity[], analyticsId: number, periods: Period[]): Promise<void> {
const pipeline = this.redisClient.pipeline()
for (const activity of activities) {
for (const period of periods) {
pipeline.setbit(
`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
analyticsId,
0,
)
}
}
await pipeline.exec()
}
async wasActivityDone(activity: AnalyticsActivity, analyticsId: number, period: Period): Promise<boolean> {
const bitValue = await this.redisClient.getbit(
`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
analyticsId,
)
return bitValue === 1
}
async calculateActivityRetention(
activity: AnalyticsActivity,
firstPeriod: Period,
secondPeriod: Period,
): Promise<number> {
const initialPeriodKey = this.periodKeyGenerator.getPeriodKey(firstPeriod)
const subsequentPeriodKey = this.periodKeyGenerator.getPeriodKey(secondPeriod)
const diffKey = `bitmap:action:${activity}:timespan:${initialPeriodKey}-${subsequentPeriodKey}`
await this.redisClient.send_command(
'BITOP',
'AND',
diffKey,
`bitmap:action:${activity}:timespan:${initialPeriodKey}`,
`bitmap:action:${activity}:timespan:${subsequentPeriodKey}`,
)
const retainedTotalInActivity = await this.redisClient.bitcount(diffKey)
const initialTotalInActivity = await this.redisClient.bitcount(
`bitmap:action:${activity}:timespan:${initialPeriodKey}`,
)
return Math.ceil((retainedTotalInActivity * 100) / initialTotalInActivity)
}
async calculateActivityTotalCount(activity: AnalyticsActivity, period: Period): Promise<number> {
return this.redisClient.bitcount(
`bitmap:action:${activity}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
)
}
}

View File

@@ -0,0 +1,92 @@
import * as IORedis from 'ioredis'
import { PeriodKeyGeneratorInterface } from '../../Domain'
import { RedisStatisticsStore } from './RedisStatisticsStore'
describe('RedisStatisticsStore', () => {
let redisClient: IORedis.Redis
let periodKeyGenerator: PeriodKeyGeneratorInterface
let pipeline: IORedis.Pipeline
const createStore = () => new RedisStatisticsStore(periodKeyGenerator, redisClient)
beforeEach(() => {
pipeline = {} as jest.Mocked<IORedis.Pipeline>
pipeline.incr = jest.fn()
pipeline.setbit = jest.fn()
pipeline.exec = jest.fn()
redisClient = {} as jest.Mocked<IORedis.Redis>
redisClient.pipeline = jest.fn().mockReturnValue(pipeline)
redisClient.incr = jest.fn()
redisClient.setbit = jest.fn()
redisClient.getbit = jest.fn().mockReturnValue(1)
redisClient.send_command = jest.fn()
periodKeyGenerator = {} as jest.Mocked<PeriodKeyGeneratorInterface>
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
})
it('should get yesterday out of sync incidents', async () => {
redisClient.get = jest.fn().mockReturnValue(1)
expect(await createStore().getYesterdayOutOfSyncIncidents()).toEqual(1)
})
it('should default to 0 yesterday out of sync incidents', async () => {
redisClient.get = jest.fn().mockReturnValue(null)
expect(await createStore().getYesterdayOutOfSyncIncidents()).toEqual(0)
})
it('should get yesterday application version usage', async () => {
redisClient.keys = jest
.fn()
.mockReturnValue([
'count:action:application-request:1.2.3:timespan:2022-3-10',
'count:action:application-request:2.3.4:timespan:2022-3-10',
])
redisClient.get = jest.fn().mockReturnValueOnce(3).mockReturnValueOnce(4)
expect(await createStore().getYesterdayApplicationUsage()).toEqual([
{ count: 3, version: '1.2.3' },
{ count: 4, version: '2.3.4' },
])
})
it('should get yesterday snjs version usage', async () => {
redisClient.keys = jest
.fn()
.mockReturnValue([
'count:action:snjs-request:1.2.3:timespan:2022-3-10',
'count:action:snjs-request:2.3.4:timespan:2022-3-10',
])
redisClient.get = jest.fn().mockReturnValueOnce(3).mockReturnValueOnce(4)
expect(await createStore().getYesterdaySNJSUsage()).toEqual([
{ count: 3, version: '1.2.3' },
{ count: 4, version: '2.3.4' },
])
})
it('should increment application version usage', async () => {
await createStore().incrementApplicationVersionUsage('1.2.3')
expect(pipeline.incr).toHaveBeenCalled()
expect(pipeline.exec).toHaveBeenCalled()
})
it('should increment snjs version usage', async () => {
await createStore().incrementSNJSVersionUsage('1.2.3')
expect(pipeline.incr).toHaveBeenCalled()
expect(pipeline.exec).toHaveBeenCalled()
})
it('should increment out of sync incedent count', async () => {
await createStore().incrementOutOfSyncIncidents()
expect(pipeline.incr).toHaveBeenCalled()
expect(pipeline.exec).toHaveBeenCalled()
})
})

View File

@@ -0,0 +1,99 @@
import * as IORedis from 'ioredis'
import { Period, PeriodKeyGeneratorInterface } from '../../Domain'
import { StatisticsStoreInterface } from '../../Domain/Statistics/StatisticsStoreInterface'
export class RedisStatisticsStore implements StatisticsStoreInterface {
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
async getYesterdayOutOfSyncIncidents(): Promise<number> {
const count = await this.redisClient.get(
`count:action:out-of-sync:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Yesterday)}`,
)
if (count === null) {
return 0
}
return +count
}
async incrementOutOfSyncIncidents(): Promise<void> {
const pipeline = this.redisClient.pipeline()
pipeline.incr(`count:action:out-of-sync:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Today)}`)
pipeline.incr(`count:action:out-of-sync:timespan:${this.periodKeyGenerator.getPeriodKey(Period.ThisWeek)}`)
pipeline.incr(`count:action:out-of-sync:timespan:${this.periodKeyGenerator.getPeriodKey(Period.ThisMonth)}`)
await pipeline.exec()
}
async getYesterdaySNJSUsage(): Promise<{ version: string; count: number }[]> {
const keys = await this.redisClient.keys(
`count:action:snjs-request:*:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Yesterday)}`,
)
return this.getRequestCountPerVersion(keys)
}
async getYesterdayApplicationUsage(): Promise<{ version: string; count: number }[]> {
const keys = await this.redisClient.keys(
`count:action:application-request:*:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Yesterday)}`,
)
return this.getRequestCountPerVersion(keys)
}
async incrementApplicationVersionUsage(applicationVersion: string): Promise<void> {
const pipeline = this.redisClient.pipeline()
pipeline.incr(
`count:action:application-request:${applicationVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(
Period.Today,
)}`,
)
pipeline.incr(
`count:action:application-request:${applicationVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(
Period.ThisWeek,
)}`,
)
pipeline.incr(
`count:action:application-request:${applicationVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(
Period.ThisMonth,
)}`,
)
await pipeline.exec()
}
async incrementSNJSVersionUsage(snjsVersion: string): Promise<void> {
const pipeline = this.redisClient.pipeline()
pipeline.incr(
`count:action:snjs-request:${snjsVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Today)}`,
)
pipeline.incr(
`count:action:snjs-request:${snjsVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(Period.ThisWeek)}`,
)
pipeline.incr(
`count:action:snjs-request:${snjsVersion}:timespan:${this.periodKeyGenerator.getPeriodKey(Period.ThisMonth)}`,
)
await pipeline.exec()
}
private async getRequestCountPerVersion(keys: string[]): Promise<{ version: string; count: number }[]> {
const statistics = []
for (const key of keys) {
const count = await this.redisClient.get(key)
const version = key.split(':')[3]
statistics.push({
version,
count: +(count as string),
})
}
return statistics
}
}

View File

@@ -0,0 +1,2 @@
export * from './Redis/RedisAnalyticsStore'
export * from './Redis/RedisStatisticsStore'

View File

@@ -0,0 +1,2 @@
export * from './Domain'
export * from './Infra'

View File

@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist",
},
"include": [
"src/**/*"
],
"references": []
}

View File

@@ -3,6 +3,40 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.6.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.0...@standardnotes/api-gateway@1.6.1) (2022-07-06)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.6.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.5.0...@standardnotes/api-gateway@1.6.0) (2022-07-06)
### Features
* add time package ([565e890](https://github.com/standardnotes/api-gateway/commit/565e890973b1d96544bb750fdd700d58f8dad088))
# [1.5.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.4.2...@standardnotes/api-gateway@1.5.0) (2022-07-06)
### Bug Fixes
* deps to @standarnotes/security ([699164e](https://github.com/standardnotes/api-gateway/commit/699164eba553cd07fb50f7a06ae8991028167603))
### Features
* add security package ([d86928f](https://github.com/standardnotes/api-gateway/commit/d86928f1b4b5feda8c330ed8ee0bf9de0fc12ae7))
## [1.4.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.4.1...@standardnotes/api-gateway@1.4.2) (2022-07-06)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.4.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.4.0...@standardnotes/api-gateway@1.4.1) (2022-07-06)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.4.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.3.5...@standardnotes/api-gateway@1.4.0) (2022-07-06)
### Features
* add analytics package ([14e4ca7](https://github.com/standardnotes/api-gateway/commit/14e4ca70b438dd3eaaa404bc0ca31d22a62b45be))
## [1.3.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.3.4...@standardnotes/api-gateway@1.3.5) (2022-07-06)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.3.5",
"version": "1.6.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -24,11 +24,11 @@
"dependencies": {
"@newrelic/winston-enricher": "^2.1.0",
"@sentry/node": "^7.3.0",
"@standardnotes/analytics": "^1.6.0",
"@standardnotes/auth": "3.19.4",
"@standardnotes/analytics": "workspace:*",
"@standardnotes/domain-events": "workspace:*",
"@standardnotes/domain-events-infra": "workspace:*",
"@standardnotes/time": "^1.7.1",
"@standardnotes/security": "workspace:*",
"@standardnotes/time": "workspace:*",
"aws-sdk": "^2.1160.0",
"axios": "0.24.0",
"cors": "2.8.5",

View File

@@ -1,4 +1,4 @@
import { CrossServiceTokenData } from '@standardnotes/auth'
import { CrossServiceTokenData } from '@standardnotes/security'
import { TimerInterface } from '@standardnotes/time'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'

View File

@@ -1,4 +1,4 @@
import { OfflineUserTokenData, CrossServiceTokenData } from '@standardnotes/auth'
import { OfflineUserTokenData, CrossServiceTokenData } from '@standardnotes/security'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'
import { BaseMiddleware } from 'inversify-express-utils'

View File

@@ -3,6 +3,66 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.11.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.10.0...@standardnotes/auth-server@1.11.0) (2022-07-11)
### Features
* add event store package ([84ff915](https://github.com/standardnotes/server/commit/84ff915a565e8e64410c4bf97a30d359649825c7))
# [1.10.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.9.0...@standardnotes/auth-server@1.10.0) (2022-07-06)
### Features
* add sncryptio-node package ([60e8974](https://github.com/standardnotes/auth/commit/60e8974580d498e7edf80813c32268a8bf7eda39))
# [1.9.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.8.0...@standardnotes/auth-server@1.9.0) (2022-07-06)
### Features
* add settings package ([e7e34f3](https://github.com/standardnotes/auth/commit/e7e34f3e16eb865f083b7b49b2f8f83fd8af8de0))
# [1.8.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.7.0...@standardnotes/auth-server@1.8.0) (2022-07-06)
### Features
* add common package ([fd4ee21](https://github.com/standardnotes/auth/commit/fd4ee2123dc72b4d8755504d57bced608c1ab928))
# [1.7.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.6.0...@standardnotes/auth-server@1.7.0) (2022-07-06)
### Features
* add time package ([565e890](https://github.com/standardnotes/auth/commit/565e890973b1d96544bb750fdd700d58f8dad088))
# [1.6.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.5.1...@standardnotes/auth-server@1.6.0) (2022-07-06)
### Bug Fixes
* deps to @standarnotes/security ([699164e](https://github.com/standardnotes/auth/commit/699164eba553cd07fb50f7a06ae8991028167603))
### Features
* add security package ([d86928f](https://github.com/standardnotes/auth/commit/d86928f1b4b5feda8c330ed8ee0bf9de0fc12ae7))
## [1.5.1](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.5.0...@standardnotes/auth-server@1.5.1) (2022-07-06)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.5.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.4.0...@standardnotes/auth-server@1.5.0) (2022-07-06)
### Bug Fixes
* scheduler to predicates imports ([1b35cf7](https://github.com/standardnotes/auth/commit/1b35cf7a392fbe6c4b49889f92ffab6ddd7bb181))
### Features
* add predicates package ([ed62ed5](https://github.com/standardnotes/auth/commit/ed62ed516f5cf8784975f41680366bf0518ce491))
# [1.4.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.3.14...@standardnotes/auth-server@1.4.0) (2022-07-06)
### Features
* add analytics package ([14e4ca7](https://github.com/standardnotes/auth/commit/14e4ca70b438dd3eaaa404bc0ca31d22a62b45be))
## [1.3.14](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.3.13...@standardnotes/auth-server@1.3.14) (2022-07-06)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.3.14",
"version": "1.11.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -8,7 +8,6 @@
"description": "Auth Server",
"main": "dist/src/index.js",
"typings": "dist/src/index.d.ts",
"repository": "git@github.com:standardnotes/auth.git",
"author": "Karol Sójko <karolsojko@standardnotes.com>",
"license": "AGPL-3.0-or-later",
"scripts": {
@@ -33,19 +32,19 @@
"dependencies": {
"@newrelic/winston-enricher": "^2.1.0",
"@sentry/node": "^7.3.0",
"@standardnotes/analytics": "^1.6.0",
"@standardnotes/analytics": "workspace:*",
"@standardnotes/api": "^1.1.19",
"@standardnotes/auth": "^3.19.4",
"@standardnotes/common": "^1.23.1",
"@standardnotes/common": "workspace:*",
"@standardnotes/domain-events": "workspace:*",
"@standardnotes/domain-events-infra": "workspace:*",
"@standardnotes/features": "^1.47.0",
"@standardnotes/predicates": "workspace:*",
"@standardnotes/responses": "^1.6.39",
"@standardnotes/scheduler": "^1.1.2",
"@standardnotes/settings": "^1.15.0",
"@standardnotes/security": "workspace:*",
"@standardnotes/settings": "workspace:*",
"@standardnotes/sncrypto-common": "^1.9.0",
"@standardnotes/sncrypto-node": "^1.8.3",
"@standardnotes/time": "^1.7.1",
"@standardnotes/sncrypto-node": "workspace:*",
"@standardnotes/time": "workspace:*",
"aws-sdk": "^2.1159.0",
"axios": "0.24.0",
"bcryptjs": "2.4.3",

View File

@@ -143,7 +143,7 @@ import {
TokenEncoder,
TokenEncoderInterface,
ValetTokenData,
} from '@standardnotes/auth'
} from '@standardnotes/security'
import { FileUploadedEventHandler } from '../Domain/Handler/FileUploadedEventHandler'
import { CreateValetToken } from '../Domain/UseCase/CreateValetToken/CreateValetToken'
import { CreateListedAccount } from '../Domain/UseCase/CreateListedAccount/CreateListedAccount'

View File

@@ -3,7 +3,7 @@ import 'reflect-metadata'
import { ApiGatewayAuthMiddleware } from './ApiGatewayAuthMiddleware'
import { NextFunction, Request, Response } from 'express'
import { Logger } from 'winston'
import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/security'
import { RoleName } from '@standardnotes/common'
describe('ApiGatewayAuthMiddleware', () => {

View File

@@ -1,4 +1,4 @@
import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/security'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'
import { BaseMiddleware } from 'inversify-express-utils'

View File

@@ -3,7 +3,7 @@ import 'reflect-metadata'
import { ApiGatewayOfflineAuthMiddleware } from './ApiGatewayOfflineAuthMiddleware'
import { NextFunction, Request, Response } from 'express'
import { Logger } from 'winston'
import { OfflineUserTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { OfflineUserTokenData, TokenDecoderInterface } from '@standardnotes/security'
describe('ApiGatewayOfflineAuthMiddleware', () => {
let tokenDecoder: TokenDecoderInterface<OfflineUserTokenData>

View File

@@ -1,4 +1,4 @@
import { OfflineUserTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { OfflineUserTokenData, TokenDecoderInterface } from '@standardnotes/security'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'
import { BaseMiddleware } from 'inversify-express-utils'

View File

@@ -11,7 +11,7 @@ import { CreateOfflineSubscriptionTokenResponse } from '../Domain/UseCase/Create
import { AuthenticateOfflineSubscriptionToken } from '../Domain/UseCase/AuthenticateOfflineSubscriptionToken/AuthenticateOfflineSubscriptionToken'
import { OfflineUserSubscription } from '../Domain/Subscription/OfflineUserSubscription'
import { GetUserOfflineSubscription } from '../Domain/UseCase/GetUserOfflineSubscription/GetUserOfflineSubscription'
import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { SubscriptionName } from '@standardnotes/common'
import { Logger } from 'winston'

View File

@@ -14,7 +14,7 @@ import { AuthenticateOfflineSubscriptionToken } from '../Domain/UseCase/Authenti
import { CreateOfflineSubscriptionToken } from '../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionToken'
import { GetUserOfflineSubscription } from '../Domain/UseCase/GetUserOfflineSubscription/GetUserOfflineSubscription'
import { Logger } from 'winston'
import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/security'
@controller('/offline')
export class OfflineController extends BaseHttpController {

View File

@@ -10,7 +10,7 @@ import { GetActiveSessionsForUser } from '../Domain/UseCase/GetActiveSessionsFor
import { AuthenticateRequest } from '../Domain/UseCase/AuthenticateRequest'
import { User } from '../Domain/User/User'
import { Role } from '../Domain/Role/Role'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
describe('SessionsController', () => {

View File

@@ -16,7 +16,7 @@ import { Role } from '../Domain/Role/Role'
import { User } from '../Domain/User/User'
import { ProjectorInterface } from '../Projection/ProjectorInterface'
import { SessionProjector } from '../Projection/SessionProjector'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { RoleName } from '@standardnotes/common'
import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'

View File

@@ -1,4 +1,4 @@
import { Role } from '@standardnotes/auth'
import { Role } from '@standardnotes/security'
import { Request, Response } from 'express'
import { inject } from 'inversify'
import {

View File

@@ -12,7 +12,7 @@ import { ProjectorInterface } from '../Projection/ProjectorInterface'
import { Role } from '../Domain/Role/Role'
import { SettingServiceInterface } from '../Domain/Setting/SettingServiceInterface'
import { Setting } from '../Domain/Setting/Setting'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { GetUserAnalyticsId } from '../Domain/UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
describe('SubscriptionTokensController', () => {

View File

@@ -1,4 +1,4 @@
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { ErrorTag, RoleName } from '@standardnotes/common'
import { SettingName } from '@standardnotes/settings'
import { Request, Response } from 'express'

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { Logger } from 'winston'
import { ProjectorInterface } from '../../Projection/ProjectorInterface'

View File

@@ -1,4 +1,4 @@
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { Uuid } from '@standardnotes/common'
import * as crypto from 'crypto'

View File

@@ -1,4 +1,4 @@
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/security'
import 'reflect-metadata'
import { Logger } from 'winston'

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/security'
import { SessionBody } from '@standardnotes/responses'
import { Logger } from 'winston'

View File

@@ -2,7 +2,7 @@ import {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
SessionTokenData,
TokenEncoderInterface,
} from '@standardnotes/auth'
} from '@standardnotes/security'
import { Uuid } from '@standardnotes/common'
import { SessionBody } from '@standardnotes/responses'
import { inject, injectable } from 'inversify'

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { SessionTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenDecoderInterface } from '@standardnotes/security'
import { RevokedSession } from '../Session/RevokedSession'
import { Session } from '../Session/Session'

View File

@@ -1,4 +1,4 @@
import { SessionTokenData, TokenDecoderInterface } from '@standardnotes/auth'
import { SessionTokenData, TokenDecoderInterface } from '@standardnotes/security'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { SessionServiceInterface } from '../Session/SessionServiceInterface'

View File

@@ -1,7 +1,7 @@
import 'reflect-metadata'
import { EmailMessageIdentifier, RoleName } from '@standardnotes/common'
import { PredicateName, PredicateAuthority, PredicateVerificationResult } from '@standardnotes/scheduler'
import { PredicateName, PredicateAuthority, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
import { DomainEventFactory } from './DomainEventFactory'

View File

@@ -16,7 +16,7 @@ import {
DomainEventService,
EmailMessageRequestedEvent,
} from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/scheduler'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'

View File

@@ -1,5 +1,5 @@
import { Uuid, RoleName, EmailMessageIdentifier } from '@standardnotes/common'
import { Predicate, PredicateVerificationResult } from '@standardnotes/scheduler'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import {
AccountDeletionRequestedEvent,
CloudBackupRequestedEvent,

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { Role } from '@standardnotes/auth'
import { Role } from '@standardnotes/security'
import { RoleName, SubscriptionName } from '@standardnotes/common'
import { RoleToSubscriptionMapInterface } from '../Role/RoleToSubscriptionMapInterface'

View File

@@ -1,6 +1,6 @@
import { DomainEventHandlerInterface, ExtensionKeyGrantedEvent } from '@standardnotes/domain-events'
import { SettingName } from '@standardnotes/settings'
import { OfflineFeaturesTokenData } from '@standardnotes/auth'
import { OfflineFeaturesTokenData } from '@standardnotes/security'
import { ContentDecoderInterface } from '@standardnotes/common'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'

View File

@@ -7,7 +7,7 @@ import {
PredicateVerificationRequestedEventPayload,
PredicateVerifiedEvent,
} from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/scheduler'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { Logger } from 'winston'
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'

View File

@@ -1,4 +1,4 @@
import { OfflineFeaturesTokenData } from '@standardnotes/auth'
import { OfflineFeaturesTokenData } from '@standardnotes/security'
import { DomainEventHandlerInterface, SubscriptionSyncRequestedEvent } from '@standardnotes/domain-events'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { TokenEncoderInterface, ValetTokenData } from '@standardnotes/auth'
import { TokenEncoderInterface, ValetTokenData } from '@standardnotes/security'
import { CreateValetToken } from './CreateValetToken'
import { TimerInterface } from '@standardnotes/time'
import { UserSubscription } from '../../Subscription/UserSubscription'

View File

@@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify'
import { SubscriptionName } from '@standardnotes/common'
import { TimerInterface } from '@standardnotes/time'
import { TokenEncoderInterface, ValetTokenData } from '@standardnotes/auth'
import { TokenEncoderInterface, ValetTokenData } from '@standardnotes/security'
import { CreateValetTokenPayload, CreateValetTokenResponseData } from '@standardnotes/responses'
import { SubscriptionSettingName } from '@standardnotes/settings'

View File

@@ -7,7 +7,7 @@ import { VerifyMFA } from './VerifyMFA'
import { Setting } from '../Setting/Setting'
import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
import { SettingName } from '@standardnotes/settings'
import { SelectorInterface } from '@standardnotes/auth'
import { SelectorInterface } from '@standardnotes/security'
import { LockRepositoryInterface } from '../User/LockRepositoryInterface'
describe('VerifyMFA', () => {

View File

@@ -12,7 +12,7 @@ import { UseCaseInterface } from './UseCaseInterface'
import { VerifyMFADTO } from './VerifyMFADTO'
import { VerifyMFAResponse } from './VerifyMFAResponse'
import { SettingServiceInterface } from '../Setting/SettingServiceInterface'
import { SelectorInterface } from '@standardnotes/auth'
import { SelectorInterface } from '@standardnotes/security'
import { LockRepositoryInterface } from '../User/LockRepositoryInterface'
@injectable()

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { PredicateName, PredicateVerificationResult, PredicateAuthority } from '@standardnotes/scheduler'
import { PredicateName, PredicateVerificationResult, PredicateAuthority } from '@standardnotes/predicates'
import { Setting } from '../../Setting/Setting'
import { SettingRepositoryInterface } from '../../Setting/SettingRepositoryInterface'

View File

@@ -1,5 +1,5 @@
import { Uuid } from '@standardnotes/common'
import { PredicateName, PredicateVerificationResult } from '@standardnotes/scheduler'
import { PredicateName, PredicateVerificationResult } from '@standardnotes/predicates'
import { EmailBackupFrequency, SettingName } from '@standardnotes/settings'
import { inject, injectable } from 'inversify'

View File

@@ -1,5 +1,5 @@
import { Uuid } from '@standardnotes/common'
import { Predicate } from '@standardnotes/scheduler'
import { Predicate } from '@standardnotes/predicates'
export type VerifyPredicateDTO = {
predicate: Predicate

View File

@@ -1,4 +1,4 @@
import { PredicateVerificationResult } from '@standardnotes/scheduler'
import { PredicateVerificationResult } from '@standardnotes/predicates'
export type VerifyPredicateResponse = {
predicateVerificationResult: PredicateVerificationResult

View File

@@ -1,6 +1,6 @@
import 'reflect-metadata'
import { SelectorInterface } from '@standardnotes/auth'
import { SelectorInterface } from '@standardnotes/security'
import { ProtocolVersion } from '@standardnotes/common'
import { KeyParamsFactory } from './KeyParamsFactory'

View File

@@ -6,7 +6,7 @@ import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { KeyParamsFactoryInterface } from './KeyParamsFactoryInterface'
import { User } from './User'
import { SelectorInterface } from '@standardnotes/auth'
import { SelectorInterface } from '@standardnotes/security'
@injectable()
export class KeyParamsFactory implements KeyParamsFactoryInterface {

View File

@@ -0,0 +1 @@
dist

View File

@@ -0,0 +1,6 @@
{
"extends": "../../.eslintrc",
"parserOptions": {
"project": "./linter.tsconfig.json"
}
}

View File

@@ -0,0 +1,264 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# 1.25.0 (2022-07-06)
### Features
* add common package ([fd4ee21](https://github.com/standardnotes/server/commit/fd4ee2123dc72b4d8755504d57bced608c1ab928))
## [1.23.2](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.23.1...@standardnotes/common@1.23.2) (2022-07-04)
### Bug Fixes
* add missing reflect-metadata package ([70aa494](https://github.com/standardnotes/snjs/commit/70aa4943a3fde70d4360055db22cb5388fc3f76e))
## [1.23.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.23.0...@standardnotes/common@1.23.1) (2022-06-27)
### Bug Fixes
* add email message identifier for files email campaign ([affa300](https://github.com/standardnotes/snjs/commit/affa3005b6933165e262227282198310f0a65cb3))
# [1.23.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.22.0...@standardnotes/common@1.23.0) (2022-06-15)
### Features
* add email requested events ([4d501fa](https://github.com/standardnotes/snjs/commit/4d501faedad44ff23782db1704956a6c19365fb6))
# [1.22.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.21.0...@standardnotes/common@1.22.0) (2022-05-22)
### Features
* optional files navigation ([#745](https://github.com/standardnotes/snjs/issues/745)) ([8512166](https://github.com/standardnotes/snjs/commit/851216615478b57b11a570173f94ee598bec31c0))
# [1.21.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.20.1...@standardnotes/common@1.21.0) (2022-05-17)
### Features
* remove basic user role and core subscription plan ([#741](https://github.com/standardnotes/snjs/issues/741)) ([7800ecd](https://github.com/standardnotes/snjs/commit/7800ecd119e7bbb5872d48bd7806b5d0f5522c0e))
## [1.20.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.20.0...@standardnotes/common@1.20.1) (2022-05-16)
**Note:** Version bump only for package @standardnotes/common
# [1.20.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.8...@standardnotes/common@1.20.0) (2022-05-16)
### Features
* remove basic user role and core subscription plan names ([304e232](https://github.com/standardnotes/snjs/commit/304e232e738456a93374de869117b5579e8a8f57))
## [1.19.8](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.6...@standardnotes/common@1.19.8) (2022-05-04)
**Note:** Version bump only for package @standardnotes/common
## [1.19.7](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.6...@standardnotes/common@1.19.7) (2022-05-04)
**Note:** Version bump only for package @standardnotes/common
## [1.19.6](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.5...@standardnotes/common@1.19.6) (2022-04-22)
**Note:** Version bump only for package @standardnotes/common
## [1.19.5](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.4...@standardnotes/common@1.19.5) (2022-04-21)
### Bug Fixes
* abort key recovery after aborted challenge ([#703](https://github.com/standardnotes/snjs/issues/703)) ([a67fb7e](https://github.com/standardnotes/snjs/commit/a67fb7e8cde41a5c9fadf545933e35d525faeaf0))
## [1.19.4](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.3...@standardnotes/common@1.19.4) (2022-04-15)
**Note:** Version bump only for package @standardnotes/common
## [1.19.3](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.2...@standardnotes/common@1.19.3) (2022-04-11)
**Note:** Version bump only for package @standardnotes/common
## [1.19.2](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.1...@standardnotes/common@1.19.2) (2022-04-01)
**Note:** Version bump only for package @standardnotes/common
## [1.19.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.19.0...@standardnotes/common@1.19.1) (2022-03-31)
**Note:** Version bump only for package @standardnotes/common
# [1.19.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.18.0...@standardnotes/common@1.19.0) (2022-03-31)
### Features
* encryption and models packages ([#679](https://github.com/standardnotes/snjs/issues/679)) ([5e03d48](https://github.com/standardnotes/snjs/commit/5e03d48aba7e3dd266117201139ab869b1f70cc9))
# [1.18.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.17.0...@standardnotes/common@1.18.0) (2022-03-30)
### Features
* files-beta role ([#678](https://github.com/standardnotes/snjs/issues/678)) ([f1ae62f](https://github.com/standardnotes/snjs/commit/f1ae62ff05e361dc551f1a0d047feabd129d0f76))
# [1.17.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.16.2...@standardnotes/common@1.17.0) (2022-03-22)
### Features
* add read only access error tag ([c3c7b4c](https://github.com/standardnotes/snjs/commit/c3c7b4c12f9b23dfc8e4bf1d4af43f6307f64190))
## [1.16.2](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.16.1...@standardnotes/common@1.16.2) (2022-03-21)
**Note:** Version bump only for package @standardnotes/common
## [1.16.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.16.0...@standardnotes/common@1.16.1) (2022-03-18)
### Bug Fixes
* add demo user role ([aa7ebc8](https://github.com/standardnotes/snjs/commit/aa7ebc84ef1160688d2767b86a32719ce68a257b))
# [1.16.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.15.3...@standardnotes/common@1.16.0) (2022-03-16)
### Features
* delete file functionality ([#657](https://github.com/standardnotes/snjs/issues/657)) ([edec4f7](https://github.com/standardnotes/snjs/commit/edec4f7a65ef557ed5f47be4dddcf2b659ee28b4))
## [1.15.4](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.15.3...@standardnotes/common@1.15.4) (2022-03-16)
**Note:** Version bump only for package @standardnotes/common
## [1.15.3](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.15.1...@standardnotes/common@1.15.3) (2022-02-28)
### Bug Fixes
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
## [1.15.2](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.15.1...@standardnotes/common@1.15.2) (2022-02-28)
### Bug Fixes
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
## [1.15.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.15.0...@standardnotes/common@1.15.1) (2022-02-27)
**Note:** Version bump only for package @standardnotes/common
# [1.15.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.14.1...@standardnotes/common@1.15.0) (2022-02-25)
### Features
* extract core functionalities to separate packages ([#610](https://github.com/standardnotes/snjs/issues/610)) ([801547a](https://github.com/standardnotes/snjs/commit/801547a71614ad51a92fb249eaa184ed46a44aac))
## [1.14.1](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.14.0...@standardnotes/common@1.14.1) (2022-02-24)
**Note:** Version bump only for package @standardnotes/common
# [1.14.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.13.0...@standardnotes/common@1.14.0) (2022-02-22)
### Features
* extract services package ([#605](https://github.com/standardnotes/snjs/issues/605)) ([3966b10](https://github.com/standardnotes/snjs/commit/3966b10745c10ef5bb92871abb13ceb4ea631362))
# [1.13.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.12.0...@standardnotes/common@1.13.0) (2022-02-22)
### Features
* extract SNJS utils as a separate package ([#604](https://github.com/standardnotes/snjs/issues/604)) ([b28195c](https://github.com/standardnotes/snjs/commit/b28195c20be788eec8dabc44c5aff518f074cdd9))
# [1.12.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.11.0...@standardnotes/common@1.12.0) (2022-02-18)
### Features
* add item integrity hash model ([975474a](https://github.com/standardnotes/snjs/commit/975474a04c4b11edea381235fe38273db59fa770))
# [1.11.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.10.0...@standardnotes/common@1.11.0) (2022-02-16)
### Features
* add paid roles definition ([3432608](https://github.com/standardnotes/snjs/commit/34326086c16000397d994054e807dd3589b536db))
# [1.10.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.9.0...@standardnotes/common@1.10.0) (2022-02-10)
### Features
* move role names and suscription names from auth to common package ([5358c03](https://github.com/standardnotes/snjs/commit/5358c03ef113597bcdcf7b0f3e730c8014885a0f))
# [1.9.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.8.0...@standardnotes/common@1.9.0) (2022-02-07)
### Features
* dynamic features based on runtime env ([#590](https://github.com/standardnotes/snjs/issues/590)) ([060861a](https://github.com/standardnotes/snjs/commit/060861a6c5bc179e3e1987c2b63490888e153bbb))
# [1.8.0](https://github.com/standardnotes/snjs/compare/@standardnotes/common@1.7.0...@standardnotes/common@1.8.0) (2022-01-15)
### Bug Fixes
* correct gitignore paths ([cefc0cf](https://github.com/standardnotes/snjs/commit/cefc0cfcf98e3e5378e055b8c46931b53b23195e))
* include dist in static components ([d17ce0f](https://github.com/standardnotes/snjs/commit/d17ce0f67045c6e4c97bf4577709aa58794e72e6))
### Features
* remove server extension type ([#552](https://github.com/standardnotes/snjs/issues/552)) ([aa542f3](https://github.com/standardnotes/snjs/commit/aa542f3124c60fa81a0b271030b3c35415c54a62))
# 1.7.0 (2021-12-23)
### Features
* rename email backup setting to email backup frequency ([25e7b46](https://github.com/standardnotes/snjs/commit/25e7b4620834711ac7f513ae893898c5eab1af53))
## 1.6.3 (2021-12-23)
### Bug Fixes
* lock package versions ([8aa2ce6](https://github.com/standardnotes/snjs/commit/8aa2ce676b57598ab72840adf851869d8e769022))
## 1.6.2 (2021-12-23)
### Bug Fixes
* add publishing from package version by lerna ([80433d0](https://github.com/standardnotes/snjs/commit/80433d044f258095753482b8322d73aba3d9a9e4))
## 1.6.1 (2021-12-23)
### Bug Fixes
* remove the ammend commit from lerna versioning ([f0400d9](https://github.com/standardnotes/snjs/commit/f0400d9a2f5a04eaece2e4c16da71166a2ddb251))
# 1.6.0 (2021-12-23)
### Features
* add one drive backup frequency setting ([#522](https://github.com/standardnotes/snjs/issues/522)) ([c27827f](https://github.com/standardnotes/snjs/commit/c27827f8c7969dd32511c9c75122ece372132c83))
## 1.5.4 (2021-12-23)
### Bug Fixes
* remove running tests upon deployment - ensured on PR status checks ([#523](https://github.com/standardnotes/snjs/issues/523)) ([5c795d1](https://github.com/standardnotes/snjs/commit/5c795d17b583d02955773576384e622c3ef7f418))
## 1.5.3 (2021-12-23)
### Bug Fixes
* pr template ([#518](https://github.com/standardnotes/snjs/issues/518)) ([b445bb6](https://github.com/standardnotes/snjs/commit/b445bb64841217ae27c2514887629235be95d2a3))
## 1.5.2 (2021-12-23)
### Bug Fixes
* checkout with personal access token ([773c1ef](https://github.com/standardnotes/snjs/commit/773c1ef91c4452ad411e928342060dcb59428e3c))
## 1.5.1 (2021-12-22)
### Bug Fixes
* gpg signing with CI StandardNotes user ([d72f61c](https://github.com/standardnotes/snjs/commit/d72f61c23cd15b31d37340cc756d16526634b9ee))
# 1.5.0 (2021-12-22)
### Bug Fixes
* versioning and package dependencies ([#509](https://github.com/standardnotes/snjs/issues/509)) ([fe1df94](https://github.com/standardnotes/snjs/commit/fe1df94eff3e90bcf9ba0cf45bdc44ac49204c71))
### Features
* add content decoder to common package ([504cf10](https://github.com/standardnotes/snjs/commit/504cf10d83c9cba6e8ee79ce138847a293a2f9e0))
* add ContentType to common package ([#401](https://github.com/standardnotes/snjs/issues/401)) ([1152c02](https://github.com/standardnotes/snjs/commit/1152c020e30e60996b4830b66e07ec4183bbac24))
* add SN|Privileges to content types ([#444](https://github.com/standardnotes/snjs/issues/444)) ([0eee358](https://github.com/standardnotes/snjs/commit/0eee3581e5f9f41f227c824adc92a0e15b8fa4b4))
* extract settings and common package ([#372](https://github.com/standardnotes/snjs/issues/372)) ([4f89688](https://github.com/standardnotes/snjs/commit/4f89688054cdae88c001287c9fb3431debd0136c))
* remove legacy mfa ([#495](https://github.com/standardnotes/snjs/issues/495)) ([b0498f4](https://github.com/standardnotes/snjs/commit/b0498f4fad85367e1b57c6deacb5d313331bf8db))
* upgrade node engine versions to latest active LTS ([#462](https://github.com/standardnotes/snjs/issues/462)) ([686fc15](https://github.com/standardnotes/snjs/commit/686fc15030d302b474ebb7ef1cd4dcc48ec42359))

View File

@@ -0,0 +1,19 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const base = require('../../jest.config');
module.exports = {
...base,
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json',
},
},
coverageThreshold: {
global: {
branches: 14,
functions: 13,
lines: 14,
statements: 14
}
}
};

View File

@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["dist"]
}

View File

@@ -0,0 +1,39 @@
{
"name": "@standardnotes/common",
"version": "1.25.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
"description": "Common types and utilities for Standard Notes projects",
"main": "dist/src/index.js",
"author": "Standard Notes",
"types": "dist/src/index.d.ts",
"files": [
"dist/src/**/*.js",
"dist/src/**/*.d.ts"
],
"publishConfig": {
"access": "public"
},
"license": "AGPL-3.0-or-later",
"scripts": {
"clean": "rm -fr dist",
"prestart": "yarn clean",
"start": "tsc -p tsconfig.json --watch",
"prebuild": "yarn clean",
"build": "tsc -p tsconfig.json",
"lint": "eslint . --ext .ts",
"test:unit": "jest spec --coverage"
},
"devDependencies": {
"@types/jest": "^27.4.1",
"@types/node": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^27.5.1",
"ts-jest": "^27.1.3"
},
"dependencies": {
"reflect-metadata": "^0.1.13"
}
}

View File

@@ -0,0 +1,37 @@
import 'reflect-metadata'
import { ContentDecoder } from './ContentDecoder'
describe('ContentDecoder', () => {
const createDecoder = () => new ContentDecoder()
it('should decode content', () => {
const content = '000eyJmb28iOiJiYXIifQ=='
expect(createDecoder().decode(content)).toEqual({
foo: 'bar',
})
})
it('should decode content without padding', () => {
const content = 'eyJmb28iOiJiYXIifQ=='
expect(createDecoder().decode(content, 0)).toEqual({
foo: 'bar',
})
})
it('should encode content', () => {
expect(
createDecoder().encode({
foo: 'bar',
}),
).toEqual('000eyJmb28iOiJiYXIifQ==')
})
it('should return empty object on decoding failure', () => {
const content = '032400eyJmb28iOiJiYXIifQ=='
expect(createDecoder().decode(content)).toEqual({})
})
})

View File

@@ -0,0 +1,23 @@
import { ContentDecoderInterface } from './ContentDecoderInterface'
export class ContentDecoder implements ContentDecoderInterface {
decode(content: string, leftPaddingLength = 3): Record<string, unknown> {
try {
const contentToDecode = leftPaddingLength > 0 ? content.substring(leftPaddingLength) : content
const contentBuffer = Buffer.from(contentToDecode, 'base64')
const decodedContent = contentBuffer.toString()
return JSON.parse(decodedContent)
} catch (error) {
return {}
}
}
encode(content: Record<string, unknown>, leftPaddingLength = 3): string | undefined {
const stringifiedContent = JSON.stringify(content)
const encodedContent = Buffer.from(stringifiedContent).toString('base64')
return encodedContent.padStart(encodedContent.length + leftPaddingLength, '0')
}
}

View File

@@ -0,0 +1,4 @@
export interface ContentDecoderInterface {
decode(content: string, leftPaddingLength?: number): Record<string, unknown>
encode(content: Record<string, unknown>, leftPaddingLength?: number): string | undefined
}

View File

@@ -0,0 +1,44 @@
/* istanbul ignore file */
export enum ContentType {
Any = '*',
Item = 'SF|Item',
RootKey = 'SN|RootKey|NoSync',
ItemsKey = 'SN|ItemsKey',
EncryptedStorage = 'SN|EncryptedStorage',
Privileges = 'SN|Privileges',
Note = 'Note',
Tag = 'Tag',
SmartView = 'SN|SmartTag',
Component = 'SN|Component',
Editor = 'SN|Editor',
ActionsExtension = 'Extension',
UserPrefs = 'SN|UserPreferences',
HistorySession = 'SN|HistorySession',
Theme = 'SN|Theme',
File = 'SN|File',
FilesafeCredentials = 'SN|FileSafe|Credentials',
FilesafeFileMetadata = 'SN|FileSafe|FileMetadata',
FilesafeIntegration = 'SN|FileSafe|Integration',
ExtensionRepo = 'SN|ExtensionRepo',
Unknown = 'Unknown',
}
export function DisplayStringForContentType(contentType: ContentType): string | undefined {
const map: Partial<Record<ContentType, string>> = {
[ContentType.ActionsExtension]: 'action-based extension',
[ContentType.Component]: 'component',
[ContentType.Editor]: 'editor',
[ContentType.File]: 'file',
[ContentType.FilesafeCredentials]: 'FileSafe credential',
[ContentType.FilesafeFileMetadata]: 'FileSafe file',
[ContentType.FilesafeIntegration]: 'FileSafe integration',
[ContentType.ItemsKey]: 'encryption key',
[ContentType.Note]: 'note',
[ContentType.SmartView]: 'smart view',
[ContentType.Tag]: 'tag',
[ContentType.Theme]: 'theme',
[ContentType.UserPrefs]: 'user preferences',
}
return map[contentType]
}

View File

@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AnyRecord = Partial<Record<string, any>>

View File

@@ -0,0 +1 @@
export type ApplicationIdentifier = string

View File

@@ -0,0 +1 @@
export type MicrosecondsTimestamp = number

View File

@@ -0,0 +1 @@
export type Uuid = string

View File

@@ -0,0 +1,18 @@
export enum EmailMessageIdentifier {
WELCOME_EMAIL = 'WELCOME_EMAIL',
ACCOUNT_CLAIM = 'ACCOUNT_CLAIM',
ACTIVATION_CODE = 'ACTIVATION_CODE',
VERSION_ADOPTION_REPORT = 'VERSION_ADOPTION_REPORT',
FAILED_DROPBOX_BACKUP = 'FAILED_DROPBOX_BACKUP',
FAILED_GOOGLE_DRIVE_BACKUP = 'FAILED_GOOGLE_DRIVE_BACKUP',
FAILED_ONE_DRIVE_BACKUP = 'FAILED_ONE_DRIVE_BACKUP',
DATA_BACKUP = 'DATA_BACKUP',
FAILED_BACKUP_ATTACHMENT_TOO_BIG = 'FAILED_BACKUP_ATTACHMENT_TOO_BIG',
OFFLINE_SUBSCRIPTION_ACCESS = 'OFFLINE_SUBSCRIPTION_ACCESS',
SIGN_IN = 'SIGN_IN',
SHARED_SUBSCRIPTION_INVITATION = 'SHARED_SUBSCRIPTION_INVITATION',
ENCOURAGE_EMAIL_BACKUPS = 'ENCOURAGE_EMAIL_BACKUPS',
ENCOURAGE_SUBSCRIPTION_PURCHASING = 'ENCOURAGE_SUBSCRIPTION_PURCHASING',
EXIT_INTERVIEW = 'EXIT_INTERVIEW',
MARKETING_CAMPAIGN_FILES = 'MARKETING_CAMPAIGN_FILES',
}

View File

@@ -0,0 +1,12 @@
/* istanbul ignore file */
export enum ErrorTag {
MfaInvalid = 'mfa-invalid',
MfaRequired = 'mfa-required',
RefreshTokenInvalid = 'invalid-refresh-token',
RefreshTokenExpired = 'expired-refresh-token',
AccessTokenExpired = 'expired-access-token',
ParametersInvalid = 'invalid-parameters',
RevokedSession = 'revoked-session',
AuthInvalid = 'invalid-auth',
ReadOnlyAccess = 'read-only-access',
}

View File

@@ -0,0 +1,6 @@
import { KeyParamsContent001 } from './KeyParamsContent001'
import { KeyParamsContent002 } from './KeyParamsContent002'
import { KeyParamsContent003 } from './KeyParamsContent003'
import { KeyParamsContent004 } from './KeyParamsContent004'
export type AnyKeyParamsContent = KeyParamsContent001 | KeyParamsContent002 | KeyParamsContent003 | KeyParamsContent004

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