mirror of
https://github.com/standardnotes/server
synced 2026-06-02 05:38:53 -04:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1b22415c3 | |||
| b4fae4b800 | |||
| b172177142 | |||
| 3fc11c5381 | |||
| 13cf896fe2 | |||
| 84ff915a56 | |||
| 74aedbccfe | |||
| 6e49298aea | |||
| c1ba290e41 | |||
| 60e8974580 | |||
| 033eeda50a | |||
| e7e34f3e16 | |||
| 7e1fcebdd8 | |||
| fd4ee2123d | |||
| 62caa840ef | |||
| 565e890973 | |||
| 84c4642ced | |||
| 699164eba5 | |||
| d86928f1b4 | |||
| 06fc077f1b | |||
| 97ba31f345 | |||
| a8795defc1 | |||
| 1b35cf7a39 | |||
| ed62ed516f | |||
| b4f1c6f7f8 | |||
| 14e4ca70b4 | |||
| 12fa94539b |
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 }}"
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum AnalyticsActivity {
|
||||
EditingItems = 'editing-items',
|
||||
Login = 'login',
|
||||
EmailUnbackedUpData = 'email-unbacked-up-data',
|
||||
EmailBackup = 'email-backup',
|
||||
}
|
||||
@@ -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>
|
||||
}
|
||||
@@ -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>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export enum Period {
|
||||
Today,
|
||||
Yesterday,
|
||||
DayBeforeYesterday,
|
||||
ThisWeek,
|
||||
LastWeek,
|
||||
WeekBeforeLastWeek,
|
||||
ThisMonth,
|
||||
LastMonth,
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Period } from './Period'
|
||||
|
||||
export interface PeriodKeyGeneratorInterface {
|
||||
getPeriodKey(period: Period): string
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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()
|
||||
})
|
||||
})
|
||||
@@ -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)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './Redis/RedisAnalyticsStore'
|
||||
export * from './Redis/RedisStatisticsStore'
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './Domain'
|
||||
export * from './Infra'
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
@@ -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.6.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.6.1...@standardnotes/api-gateway@1.6.2) (2022-07-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.3.5",
|
||||
"version": "1.6.2",
|
||||
"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",
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.11.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.11.0...@standardnotes/auth-server@1.11.1) (2022-07-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.3.14",
|
||||
"version": "1.11.1",
|
||||
"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",
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Role } from '@standardnotes/auth'
|
||||
import { Role } from '@standardnotes/security'
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import {
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/auth'
|
||||
import { SessionTokenData, TokenEncoderInterface } from '@standardnotes/security'
|
||||
import 'reflect-metadata'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { Predicate } from '@standardnotes/scheduler'
|
||||
import { Predicate } from '@standardnotes/predicates'
|
||||
|
||||
export type VerifyPredicateDTO = {
|
||||
predicate: Predicate
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PredicateVerificationResult } from '@standardnotes/scheduler'
|
||||
import { PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
|
||||
export type VerifyPredicateResponse = {
|
||||
predicateVerificationResult: PredicateVerificationResult
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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({})
|
||||
})
|
||||
})
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface ContentDecoderInterface {
|
||||
decode(content: string, leftPaddingLength?: number): Record<string, unknown>
|
||||
encode(content: Record<string, unknown>, leftPaddingLength?: number): string | undefined
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type AnyRecord = Partial<Record<string, any>>
|
||||
@@ -0,0 +1 @@
|
||||
export type ApplicationIdentifier = string
|
||||
@@ -0,0 +1 @@
|
||||
export type MicrosecondsTimestamp = number
|
||||
@@ -0,0 +1 @@
|
||||
export type Uuid = string
|
||||
@@ -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',
|
||||
}
|
||||
@@ -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',
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user