mirror of
https://github.com/standardnotes/server
synced 2026-02-16 05:02:12 -05:00
Compare commits
45 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b57816bba4 | ||
|
|
b6db194a22 | ||
|
|
8f708164cd | ||
|
|
ff09ae0a47 | ||
|
|
d21d752029 | ||
|
|
2ea077a7cd | ||
|
|
0d67c55e12 | ||
|
|
8837dca039 | ||
|
|
c9ec846a3c | ||
|
|
786829f317 | ||
|
|
10891af33b | ||
|
|
3f091175e2 | ||
|
|
0e5d7c918b | ||
|
|
fd2358a4b8 | ||
|
|
dd36b1859c | ||
|
|
8c9a8a484f | ||
|
|
451ed1ae3a | ||
|
|
4ec30df2dc | ||
|
|
163b7ff2d8 | ||
|
|
6e136e98b3 | ||
|
|
100eef2cb8 | ||
|
|
1d8cf4b675 | ||
|
|
5a01517097 | ||
|
|
ca54d4e0a0 | ||
|
|
2bcc4a2254 | ||
|
|
afe5ff3e70 | ||
|
|
4d8b021284 | ||
|
|
281dd3d378 | ||
|
|
7efb48dd2a | ||
|
|
d7b68bcafb | ||
|
|
04d1dffe53 | ||
|
|
db492c3787 | ||
|
|
d04b04507a | ||
|
|
6c87d3614d | ||
|
|
dd6d409ebb | ||
|
|
9f75c2b601 | ||
|
|
9df87a0e3d | ||
|
|
628dcf1539 | ||
|
|
38b42dad62 | ||
|
|
90359d61d9 | ||
|
|
57c3b9c29e | ||
|
|
b25f2e8c54 | ||
|
|
5be40fa99c | ||
|
|
bc909dd3aa | ||
|
|
3110c20596 |
6
.env.sample
Normal file
6
.env.sample
Normal file
@@ -0,0 +1,6 @@
|
||||
DB_PORT=3306
|
||||
DB_USERNAME=std_notes_user
|
||||
DB_PASSWORD=changeme123
|
||||
DB_DATABASE=standard_notes_db
|
||||
|
||||
REDIS_PORT=6379
|
||||
141
.github/workflows/api-gateway.release.yml
vendored
Normal file
141
.github/workflows/api-gateway.release.yml
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
name: Api Gateway
|
||||
|
||||
concurrency:
|
||||
group: api_gateway
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*standardnotes/api-gateway*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '16.x'
|
||||
- run: yarn lint:api-gateway
|
||||
|
||||
publish-aws-ecr:
|
||||
needs: test
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build locally
|
||||
run: yarn build:api-gateway
|
||||
- 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: api-gateway
|
||||
IMAGE_TAG: ${{ github.sha }}
|
||||
run: |
|
||||
yarn docker build @standardnotes/api-gateway -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:api-gateway
|
||||
- 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/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
|
||||
docker push standardnotes/api-gateway:latest
|
||||
|
||||
deploy-web:
|
||||
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: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition api-gateway-dev --query taskDefinition > task-definition.json
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="api-gateway-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: api-gateway-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/api-gateway:${{ github.sha }}
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: api-gateway-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition api-gateway-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="api-gateway-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: api-gateway-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/api-gateway:${{ 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: api-gateway-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
newrelic:
|
||||
needs: deploy-web
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create New Relic deployment marker for Web
|
||||
uses: newrelic/deployment-marker-action@v1
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_API_GATEWAY_WEB_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
@@ -1,14 +1,13 @@
|
||||
name: Auth Server Dev
|
||||
name: Auth Server
|
||||
|
||||
concurrency:
|
||||
group: auth_dev_environment
|
||||
group: auth
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '@standardnotes/auth-server@[0-9]*.[0-9]*.[0-9]*-alpha.[0-9]*'
|
||||
- '@standardnotes/auth-server@[0-9]*.[0-9]*.[0-9]*-beta.[0-9]*'
|
||||
- '*standardnotes/auth-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -50,8 +49,8 @@ jobs:
|
||||
run: |
|
||||
yarn docker build @standardnotes/auth-server -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:dev
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev
|
||||
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
|
||||
@@ -71,8 +70,8 @@ jobs:
|
||||
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:dev
|
||||
docker push standardnotes/auth:dev
|
||||
docker tag standardnotes/auth:${{ github.sha }} standardnotes/auth:latest
|
||||
docker push standardnotes/auth:latest
|
||||
|
||||
deploy-web:
|
||||
needs: publish-aws-ecr
|
||||
@@ -86,26 +85,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition auth-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="auth-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: auth-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/auth:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: auth-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition auth-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="auth-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: auth-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/auth:${{ 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: auth-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
deploy-worker:
|
||||
needs: publish-aws-ecr
|
||||
@@ -119,26 +138,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition auth-worker-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="auth-worker-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: auth-worker-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/auth:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: auth-worker-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition auth-worker-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="auth-worker-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: auth-worker-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/auth:${{ 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: auth-worker-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
newrelic:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
@@ -150,7 +189,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_AUTH_WEB_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_AUTH_WEB_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
@@ -159,19 +198,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_AUTH_WORKER_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_AUTH_WORKER_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
|
||||
notify_discord:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Run Discord Webhook
|
||||
uses: johnnyhuy/actions-discord-git-webhook@main
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
name: Files Server Dev
|
||||
name: Files Server
|
||||
|
||||
concurrency:
|
||||
group: files_dev_environment
|
||||
group: files
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '@standardnotes/files-server@[0-9]*.[0-9]*.[0-9]*-alpha.[0-9]*'
|
||||
- '@standardnotes/files-server@[0-9]*.[0-9]*.[0-9]*-beta.[0-9]*'
|
||||
- '*standardnotes/files-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -29,8 +28,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: cp .env.sample .env
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build locally
|
||||
run: yarn build:files
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
@@ -47,10 +47,10 @@ jobs:
|
||||
ECR_REPOSITORY: files
|
||||
IMAGE_TAG: ${{ github.sha }}
|
||||
run: |
|
||||
yarn docker build @standardnotes/files -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
||||
yarn docker build @standardnotes/files-server -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:dev
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev
|
||||
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
|
||||
@@ -58,15 +58,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: cp .env.sample .env
|
||||
- name: Publish to Registry
|
||||
uses: elgohr/Publish-Docker-Github-Action@master
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build locally
|
||||
run: yarn build:files
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
name: standardnotes/files
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
tags: "dev,${{ github.sha }}"
|
||||
- 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
|
||||
docker push standardnotes/files:latest
|
||||
|
||||
deploy-web:
|
||||
needs: publish-aws-ecr
|
||||
@@ -80,26 +85,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition files-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="files-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: files-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/files:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: files-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition files-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="files-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: files-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/files:${{ 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: files-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
deploy-worker:
|
||||
needs: publish-aws-ecr
|
||||
@@ -113,26 +138,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition files-worker-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="files-worker-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: files-worker-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/files:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: files-worker-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition files-worker-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="files-worker-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: files-worker-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/files:${{ 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: files-worker-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
newrelic:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
@@ -144,7 +189,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_FILES_WEB_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_FILES_WEB_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
@@ -153,18 +198,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_FILES_WORKER_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_FILES_WORKER_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
|
||||
notify_discord:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Run Discord Webhook
|
||||
uses: johnnyhuy/actions-discord-git-webhook@main
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
@@ -1,14 +1,13 @@
|
||||
name: Scheduler Server Dev
|
||||
name: Scheduler Server
|
||||
|
||||
concurrency:
|
||||
group: scheduler_dev_environment
|
||||
group: scheduler
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '@standardnotes/scheduler-server@[0-9]*.[0-9]*.[0-9]*-alpha.[0-9]*'
|
||||
- '@standardnotes/scheduler-server@[0-9]*.[0-9]*.[0-9]*-beta.[0-9]*'
|
||||
- '*standardnotes/scheduler-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -50,8 +49,8 @@ jobs:
|
||||
run: |
|
||||
yarn docker build @standardnotes/scheduler-server -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:dev
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev
|
||||
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
|
||||
@@ -71,8 +70,8 @@ jobs:
|
||||
run: |
|
||||
yarn docker build @standardnotes/scheduler-server -t standardnotes/scheduler:${{ github.sha }}
|
||||
docker push standardnotes/scheduler:${{ github.sha }}
|
||||
docker tag standardnotes/scheduler:${{ github.sha }} standardnotes/scheduler:dev
|
||||
docker push standardnotes/scheduler:dev
|
||||
docker tag standardnotes/scheduler:${{ github.sha }} standardnotes/scheduler:latest
|
||||
docker push standardnotes/scheduler:latest
|
||||
|
||||
deploy-worker:
|
||||
needs: publish-aws-ecr
|
||||
@@ -86,26 +85,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition scheduler-worker-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="scheduler-worker-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: scheduler-worker-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/scheduler-worker:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: scheduler-worker-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition scheduler-worker-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="scheduler-worker-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: scheduler-worker-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/scheduler-worker:${{ 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: scheduler-worker-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
newrelic:
|
||||
needs: [ deploy-worker ]
|
||||
@@ -118,19 +137,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SCHEDULER_WORKER_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SCHEDULER_WORKER_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
|
||||
notify_discord:
|
||||
needs: [ deploy-worker ]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Run Discord Webhook
|
||||
uses: johnnyhuy/actions-discord-git-webhook@main
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
name: Syncing Server Dev
|
||||
name: Syncing Server
|
||||
|
||||
concurrency:
|
||||
group: syncing_server_dev_environment
|
||||
group: syncing_server
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '@standardnotes/syncing-server@[0-9]*.[0-9]*.[0-9]*-alpha.[0-9]*'
|
||||
- '@standardnotes/syncing-server@[0-9]*.[0-9]*.[0-9]*-beta.[0-9]*'
|
||||
- '*standardnotes/syncing-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -20,6 +19,7 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '16.x'
|
||||
- run: yarn install --immutable
|
||||
- run: yarn lint:syncing-server
|
||||
- run: yarn test:syncing-server
|
||||
|
||||
@@ -29,8 +29,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: cp .env.sample .env
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build locally
|
||||
run: yarn build:syncing-server
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
@@ -49,8 +50,8 @@ jobs:
|
||||
run: |
|
||||
yarn docker build @standardnotes/syncing-server -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:dev
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev
|
||||
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
|
||||
@@ -58,15 +59,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: cp .env.sample .env
|
||||
- name: Publish to Registry
|
||||
uses: elgohr/Publish-Docker-Github-Action@master
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build locally
|
||||
run: yarn build:syncing-server
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
name: standardnotes/syncing-server-js
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
tags: "dev,${{ github.sha }}"
|
||||
- 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
|
||||
docker push standardnotes/syncing-server-js:latest
|
||||
|
||||
deploy-web:
|
||||
needs: publish-aws-ecr
|
||||
@@ -80,26 +86,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition syncing-server-js-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="syncing-server-js-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: syncing-server-js-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/syncing-server-js:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: syncing-server-js-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition syncing-server-js-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="syncing-server-js-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: syncing-server-js-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/syncing-server-js:${{ 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: syncing-server-js-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
deploy-worker:
|
||||
needs: publish-aws-ecr
|
||||
@@ -113,26 +139,46 @@ jobs:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
- name: Download task definition
|
||||
- name: DEV - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition syncing-server-js-worker-dev --query taskDefinition > task-definition.json
|
||||
- name: Fill in the new version in the Amazon ECS task definition
|
||||
- name: DEV - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="syncing-server-js-worker-dev") | .environment[] | select(.name=="VERSION")).value = "${{ github.sha }}"' task-definition.json > tmp.json && mv tmp.json task-definition.json
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
- name: DEV - Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def-dev
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: syncing-server-js-worker-dev
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/syncing-server-js:${{ github.sha }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
- name: DEV - Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
task-definition: ${{ steps.task-def-dev.outputs.task-definition }}
|
||||
service: syncing-server-js-worker-dev
|
||||
cluster: dev
|
||||
wait-for-service-stability: true
|
||||
- name: PROD - Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition syncing-server-js-worker-prod --query taskDefinition > task-definition.json
|
||||
- name: PROD - Fill in the new version in the Amazon ECS task definition
|
||||
run: |
|
||||
jq '(.containerDefinitions[] | select(.name=="syncing-server-js-worker-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: syncing-server-js-worker-prod
|
||||
image: ${{ secrets.AWS_ECR_REGISTRY }}/syncing-server-js:${{ 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: syncing-server-js-worker-prod
|
||||
cluster: prod
|
||||
wait-for-service-stability: true
|
||||
|
||||
newrelic:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
@@ -144,7 +190,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SYNCING_SERVER_WEB_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SYNCING_SERVER_WEB_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
@@ -153,18 +199,7 @@ jobs:
|
||||
with:
|
||||
accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }}
|
||||
apiKey: ${{ secrets.NEW_RELIC_API_KEY }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SYNCING_SERVER_WORKER_DEV }}
|
||||
applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_SYNCING_SERVER_WORKER_PROD }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
|
||||
notify_discord:
|
||||
needs: [ deploy-web, deploy-worker ]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Run Discord Webhook
|
||||
uses: johnnyhuy/actions-discord-git-webhook@main
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
9
.github/workflows/version-bump.yml
vendored
9
.github/workflows/version-bump.yml
vendored
@@ -2,7 +2,7 @@ name: Version Bump
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ develop, main ]
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
@@ -35,10 +35,5 @@ jobs:
|
||||
- name: Install locally
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: Bump Prod Version
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
- name: Bump Version
|
||||
run: yarn release:prod
|
||||
|
||||
- name: Bump Beta Version
|
||||
if: ${{ github.ref == 'refs/heads/develop' }}
|
||||
run: yarn release:beta
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -18,3 +18,6 @@ newrelic_agent.log
|
||||
|
||||
packages/files/uploads/*
|
||||
!packages/files/uploads/.gitkeep
|
||||
|
||||
data/*
|
||||
!data/.gitkeep
|
||||
|
||||
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.
BIN
.yarn/cache/@sentry-core-npm-7.3.0-8e7d2a21e6-1768568404.zip
vendored
Normal file
BIN
.yarn/cache/@sentry-core-npm-7.3.0-8e7d2a21e6-1768568404.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@sentry-hub-npm-7.3.0-b5d4219eb3-a052a7c940.zip
vendored
Normal file
BIN
.yarn/cache/@sentry-hub-npm-7.3.0-b5d4219eb3-a052a7c940.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@sentry-node-npm-7.3.0-ae73eb5bb5-a92c2d2d1b.zip
vendored
Normal file
BIN
.yarn/cache/@sentry-node-npm-7.3.0-ae73eb5bb5-a92c2d2d1b.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@sentry-types-npm-7.3.0-4a455bc29c-3ddbc3c7eb.zip
vendored
Normal file
BIN
.yarn/cache/@sentry-types-npm-7.3.0-4a455bc29c-3ddbc3c7eb.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@sentry-utils-npm-7.3.0-a4b6fc94f0-2696b1bfad.zip
vendored
Normal file
BIN
.yarn/cache/@sentry-utils-npm-7.3.0-a4b6fc94f0-2696b1bfad.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-auth-npm-3.19.2-5289525e60-2e4b37b303.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-auth-npm-3.19.2-5289525e60-2e4b37b303.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-domain-events-infra-npm-1.4.127-18a82f2f72-54e37c296f.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-domain-events-infra-npm-1.4.127-18a82f2f72-54e37c296f.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-domain-events-npm-2.29.0-13bec3d9a7-1b68999e2a.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-domain-events-npm-2.29.0-13bec3d9a7-1b68999e2a.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-time-npm-1.7.1-e6859705d5-ccb9c4af73.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-time-npm-1.7.1-e6859705d5-ccb9c4af73.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/aws-sdk-npm-2.1160.0-1a3db600b7-b95647d4de.zip
vendored
Normal file
BIN
.yarn/cache/aws-sdk-npm-2.1160.0-1a3db600b7-b95647d4de.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/helmet-npm-4.4.1-286ac392ee-cfe385e185.zip
vendored
Normal file
BIN
.yarn/cache/helmet-npm-4.4.1-286ac392ee-cfe385e185.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
db:
|
||||
image: mysql:5.6
|
||||
environment:
|
||||
MYSQL_DATABASE: '${DB_DATABASE}'
|
||||
MYSQL_USER: '${DB_USERNAME}'
|
||||
MYSQL_PASSWORD: '${DB_PASSWORD}'
|
||||
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
|
||||
expose:
|
||||
- ${DB_PORT}:3306
|
||||
restart: unless-stopped
|
||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci
|
||||
volumes:
|
||||
- ./data/mysql:/var/lib/mysql
|
||||
- ./data/import:/docker-entrypoint-initdb.d
|
||||
|
||||
cache:
|
||||
image: redis:6.0-alpine
|
||||
volumes:
|
||||
- ./data/redis/:/data
|
||||
expose:
|
||||
- ${REDIS_PORT}:6379
|
||||
restart: unless-stopped
|
||||
16
package.json
16
package.json
@@ -16,18 +16,20 @@
|
||||
"lint:scheduler": "yarn workspace @standardnotes/scheduler-server lint",
|
||||
"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",
|
||||
"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",
|
||||
"clean": "yarn workspaces foreach -p --verbose run clean",
|
||||
"setup:env": "yarn workspaces foreach -p --verbose run setup:env",
|
||||
"setup:env": "cp .env.sample .env && yarn workspaces foreach -p --verbose run setup:env",
|
||||
"build": "yarn workspaces foreach -pt -j 10 --verbose run build",
|
||||
"build:auth": "yarn workspace @standardnotes/auth-server build",
|
||||
"build:scheduler": "yarn workspace @standardnotes/scheduler-server build",
|
||||
"build:syncing-server": "yarn workspace @standardnotes/syncing-server build",
|
||||
"build:files": "yarn workspace @standardnotes/files-server build",
|
||||
"build:api-gateway": "yarn workspace @standardnotes/api-gateway build",
|
||||
"start:auth": "yarn workspace @standardnotes/auth-server start",
|
||||
"start:auth-worker": "yarn workspace @standardnotes/auth-server worker",
|
||||
"start:scheduler": "yarn workspace @standardnotes/scheduler-server worker",
|
||||
@@ -35,7 +37,9 @@
|
||||
"start:syncing-server-worker": "yarn workspace @standardnotes/syncing-server worker",
|
||||
"start:files": "yarn workspace @standardnotes/files-server start",
|
||||
"start:files-worker": "yarn workspace @standardnotes/files-server worker",
|
||||
"release:beta": "lerna version --conventional-prerelease --conventional-commits --yes -m \"chore(release): publish\""
|
||||
"start:api-gateway": "yarn workspace @standardnotes/api-gateway start",
|
||||
"release:prod": "lerna version --conventional-graduate --conventional-commits --yes -m \"chore(release): publish new version\"",
|
||||
"postversion": "./scripts/push-tags-one-by-one.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.2",
|
||||
@@ -44,6 +48,8 @@
|
||||
"@lerna-lite/list": "^1.5.1",
|
||||
"@lerna-lite/run": "^1.5.1",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/parser": "^5.29.0",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
@@ -51,5 +57,9 @@
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"packageManager": "yarn@3.2.1"
|
||||
"packageManager": "yarn@3.2.1",
|
||||
"dependencies": {
|
||||
"@sentry/node": "^7.3.0",
|
||||
"newrelic": "^8.14.1"
|
||||
}
|
||||
}
|
||||
|
||||
33
packages/api-gateway/.env.sample
Normal file
33
packages/api-gateway/.env.sample
Normal file
@@ -0,0 +1,33 @@
|
||||
LOG_LEVEL=debug
|
||||
NODE_ENV=development
|
||||
VERSION=development
|
||||
|
||||
PORT=3000
|
||||
|
||||
SYNCING_SERVER_JS_URL=http://syncing_server_js:3000
|
||||
AUTH_SERVER_URL=http://auth:3000
|
||||
PAYMENTS_SERVER_URL=http://payments:3000
|
||||
FILES_SERVER_URL=http://files:3000
|
||||
|
||||
HTTP_CALL_TIMEOUT=60000
|
||||
|
||||
AUTH_JWT_SECRET=auth_jwt_secret
|
||||
|
||||
# (Optional) New Relic Setup
|
||||
NEW_RELIC_ENABLED=false
|
||||
NEW_RELIC_APP_NAME=API Gateway
|
||||
NEW_RELIC_LICENSE_KEY=
|
||||
NEW_RELIC_NO_CONFIG_FILE=true
|
||||
NEW_RELIC_DISTRIBUTED_TRACING_ENABLED=false
|
||||
NEW_RELIC_LOG_ENABLED=false
|
||||
NEW_RELIC_LOG_LEVEL=info
|
||||
|
||||
REDIS_URL=redis://cache
|
||||
REDIS_EVENTS_CHANNEL=events
|
||||
|
||||
# (Optional) SNS Setup
|
||||
SNS_TOPIC_ARN=
|
||||
SNS_AWS_REGION=
|
||||
|
||||
# (Optional) Caching Cross Service Tokens
|
||||
CROSS_SERVICE_TOKEN_CACHE_TTL=
|
||||
2
packages/api-gateway/.eslintignore
Normal file
2
packages/api-gateway/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
dist
|
||||
test-setup.ts
|
||||
6
packages/api-gateway/.eslintrc
Normal file
6
packages/api-gateway/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
58
packages/api-gateway/CHANGELOG.md
Normal file
58
packages/api-gateway/CHANGELOG.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.4...@standardnotes/api-gateway@1.1.5) (2022-06-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade sentry node sdk ([b6db194](https://github.com/standardnotes/api-gateway/commit/b6db194a22ff1d0afe96c291d545b408c0a5c373))
|
||||
|
||||
## [1.1.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.3...@standardnotes/api-gateway@1.1.4) (2022-06-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* newrelic deps and setup db and cache for local development purposes ([ff09ae0](https://github.com/standardnotes/api-gateway/commit/ff09ae0a47747eaf7977ce5d3937ad385101eaeb))
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.2...@standardnotes/api-gateway@1.1.3) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* curl in the final image ([0d67c55](https://github.com/standardnotes/api-gateway/commit/0d67c55e124eed08bca16824750152b895fceca7))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.1...@standardnotes/api-gateway@1.1.2) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0...@standardnotes/api-gateway@1.1.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.1.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0-alpha.4...@standardnotes/api-gateway@1.1.0) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.1.0-alpha.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0-alpha.3...@standardnotes/api-gateway@1.1.0-alpha.4) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.1.0-alpha.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0-alpha.2...@standardnotes/api-gateway@1.1.0-alpha.3) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.1.0-alpha.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0-alpha.1...@standardnotes/api-gateway@1.1.0-alpha.2) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing curl to docker image for healthcheck purposes ([7efb48d](https://github.com/standardnotes/api-gateway/commit/7efb48dd2a6066c29601d34bfcbfe6231f644c50))
|
||||
|
||||
# [1.1.0-alpha.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.1.0-alpha.0...@standardnotes/api-gateway@1.1.0-alpha.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# 1.1.0-alpha.0 (2022-06-23)
|
||||
|
||||
### Features
|
||||
|
||||
* add api-gateway package ([57c3b9c](https://github.com/standardnotes/api-gateway/commit/57c3b9c29e5b16449c864e59dbc1fd11689125f9))
|
||||
27
packages/api-gateway/Dockerfile
Normal file
27
packages/api-gateway/Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
||||
FROM node:16.15.1-alpine AS builder
|
||||
|
||||
# Install dependencies for building native libraries
|
||||
RUN apk add --update git openssh-client python3 alpine-sdk
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# docker-build plugin copies everything needed for `yarn install` to `manifests` folder.
|
||||
COPY manifests ./
|
||||
|
||||
RUN yarn install --immutable
|
||||
|
||||
FROM node:16.15.1-alpine
|
||||
|
||||
RUN apk add --update curl
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy the installed dependencies from the previous stage.
|
||||
COPY --from=builder /workspace ./
|
||||
|
||||
# docker-build plugin runs `yarn pack` in all workspace dependencies and copies them to `packs` folder.
|
||||
COPY packs ./
|
||||
|
||||
ENTRYPOINT [ "/workspace/packages/api-gateway/docker/entrypoint.sh" ]
|
||||
|
||||
CMD [ "start-web" ]
|
||||
75
packages/api-gateway/bin/report.ts
Normal file
75
packages/api-gateway/bin/report.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { DomainEventPublisherInterface, DailyAnalyticsReportGeneratedEvent } from '@standardnotes/domain-events'
|
||||
import { AnalyticsActivity, AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
const requestReport = async (
|
||||
analyticsStore: AnalyticsStoreInterface,
|
||||
statisticsStore: StatisticsStoreInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
): Promise<void> => {
|
||||
const event: DailyAnalyticsReportGeneratedEvent = {
|
||||
type: 'DAILY_ANALYTICS_REPORT_GENERATED',
|
||||
createdAt: new Date(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '',
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
},
|
||||
payload: {
|
||||
applicationStatistics: await statisticsStore.getYesterdayApplicationUsage(),
|
||||
snjsStatistics: await statisticsStore.getYesterdaySNJSUsage(),
|
||||
outOfSyncIncidents: await statisticsStore.getYesterdayOutOfSyncIncidents(),
|
||||
activityStatistics: [
|
||||
{
|
||||
name: AnalyticsActivity.EditingItems,
|
||||
retention: await analyticsStore.calculateActivityRetention(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.DayBeforeYesterday,
|
||||
Period.Yesterday,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
await domainEventPublisher.publish(event)
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Logger)
|
||||
|
||||
logger.info('Starting usage report generation...')
|
||||
|
||||
const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore)
|
||||
const statisticsStore: StatisticsStoreInterface = container.get(TYPES.StatisticsStore)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
|
||||
|
||||
Promise.resolve(requestReport(analyticsStore, statisticsStore, domainEventPublisher))
|
||||
.then(() => {
|
||||
logger.info('Usage report generation complete')
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not finish usage report generation: ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
113
packages/api-gateway/bin/server.ts
Normal file
113
packages/api-gateway/bin/server.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import * as Sentry from '@sentry/node'
|
||||
|
||||
import '../src/Controller/LegacyController'
|
||||
import '../src/Controller/HealthCheckController'
|
||||
|
||||
import '../src/Controller/v1/SessionsController'
|
||||
import '../src/Controller/v1/UsersController'
|
||||
import '../src/Controller/v1/ActionsController'
|
||||
import '../src/Controller/v1/InvoicesController'
|
||||
import '../src/Controller/v1/RevisionsController'
|
||||
import '../src/Controller/v1/ItemsController'
|
||||
import '../src/Controller/v1/PaymentsController'
|
||||
import '../src/Controller/v1/WebSocketsController'
|
||||
import '../src/Controller/v1/TokensController'
|
||||
import '../src/Controller/v1/OfflineController'
|
||||
import '../src/Controller/v1/FilesController'
|
||||
import '../src/Controller/v1/SubscriptionInvitesController'
|
||||
|
||||
import '../src/Controller/v2/PaymentsControllerV2'
|
||||
import '../src/Controller/v2/ActionsControllerV2'
|
||||
|
||||
import * as helmet from 'helmet'
|
||||
import * as cors from 'cors'
|
||||
import { text, json, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express'
|
||||
import * as winston from 'winston'
|
||||
|
||||
import { InversifyExpressServer } from 'inversify-express-utils'
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const server = new InversifyExpressServer(container)
|
||||
|
||||
server.setConfig((app) => {
|
||||
app.use((_request: Request, response: Response, next: NextFunction) => {
|
||||
response.setHeader('X-API-Gateway-Version', container.get(TYPES.VERSION))
|
||||
next()
|
||||
})
|
||||
/* eslint-disable */
|
||||
app.use(helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["https: 'self'"],
|
||||
baseUri: ["'self'"],
|
||||
childSrc: ["*", "blob:"],
|
||||
connectSrc: ["*"],
|
||||
fontSrc: ["*", "'self'"],
|
||||
formAction: ["'self'"],
|
||||
frameAncestors: ["*", "*.standardnotes.org", "*.standardnotes.com"],
|
||||
frameSrc: ["*", "blob:"],
|
||||
imgSrc: ["'self'", "*", "data:"],
|
||||
manifestSrc: ["'self'"],
|
||||
mediaSrc: ["'self'"],
|
||||
objectSrc: ["'self'"],
|
||||
scriptSrc: ["'self'"],
|
||||
styleSrc: ["'self'"]
|
||||
}
|
||||
}
|
||||
}))
|
||||
/* eslint-enable */
|
||||
app.use(json({ limit: '50mb' }))
|
||||
app.use(
|
||||
text({
|
||||
type: ['text/plain', 'application/x-www-form-urlencoded', 'application/x-www-form-urlencoded; charset=utf-8'],
|
||||
}),
|
||||
)
|
||||
app.use(cors())
|
||||
|
||||
if (env.get('SENTRY_DSN', true)) {
|
||||
Sentry.init({
|
||||
dsn: env.get('SENTRY_DSN'),
|
||||
integrations: [new Sentry.Integrations.Http({ tracing: false, breadcrumbs: true })],
|
||||
tracesSampleRate: 0,
|
||||
})
|
||||
|
||||
app.use(Sentry.Handlers.requestHandler() as RequestHandler)
|
||||
}
|
||||
})
|
||||
|
||||
const logger: winston.Logger = container.get(TYPES.Logger)
|
||||
|
||||
server.setErrorConfig((app) => {
|
||||
if (env.get('SENTRY_DSN', true)) {
|
||||
app.use(Sentry.Handlers.errorHandler() as ErrorRequestHandler)
|
||||
}
|
||||
|
||||
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
|
||||
logger.error(error.stack)
|
||||
|
||||
response.status(500).send({
|
||||
error: {
|
||||
message:
|
||||
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const serverInstance = server.build()
|
||||
|
||||
serverInstance.listen(env.get('PORT'))
|
||||
|
||||
logger.info(`Server started on port ${process.env.PORT}`)
|
||||
})
|
||||
29
packages/api-gateway/docker/entrypoint.sh
Executable file
29
packages/api-gateway/docker/entrypoint.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
COMMAND=$1 && shift 1
|
||||
|
||||
case "$COMMAND" in
|
||||
'start-local' )
|
||||
echo "Building the project..."
|
||||
yarn workspace @standardnotes/api-gateway build
|
||||
echo "Starting Web..."
|
||||
yarn workspace @standardnotes/api-gateway start
|
||||
;;
|
||||
|
||||
'start-web' )
|
||||
echo "Starting Web..."
|
||||
yarn workspace @standardnotes/api-gateway start
|
||||
;;
|
||||
|
||||
'report' )
|
||||
echo "Starting Usage Report Generation..."
|
||||
yarn workspace @standardnotes/api-gateway report
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "Unknown command"
|
||||
;;
|
||||
esac
|
||||
|
||||
exec "$@"
|
||||
18
packages/api-gateway/jest.config.js
Normal file
18
packages/api-gateway/jest.config.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const base = require('../../jest.config');
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: 'tsconfig.json',
|
||||
},
|
||||
},
|
||||
coveragePathIgnorePatterns: [
|
||||
'/Bootstrap/',
|
||||
'HealthCheckController'
|
||||
],
|
||||
setupFilesAfterEnv: [
|
||||
'./test-setup.ts'
|
||||
]
|
||||
};
|
||||
4
packages/api-gateway/linter.tsconfig.json
Normal file
4
packages/api-gateway/linter.tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist", "test-setup.ts"]
|
||||
}
|
||||
60
packages/api-gateway/package.json
Normal file
60
packages/api-gateway/package.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.1.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
"description": "API Gateway For Standard Notes Services",
|
||||
"main": "dist/src/index.js",
|
||||
"typings": "dist/src/index.d.ts",
|
||||
"repository": "git@github.com:standardnotes/api-gateway.git",
|
||||
"author": "Karol Sójko <karolsojko@standardnotes.com>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc --rootDir ./",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"setup:env": "cp .env.sample .env",
|
||||
"start": "yarn node dist/bin/server.js",
|
||||
"report": "yarn node dist/bin/report.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/winston-enricher": "^2.1.0",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/analytics": "^1.4.0",
|
||||
"@standardnotes/auth": "3.19.2",
|
||||
"@standardnotes/domain-events": "2.29.0",
|
||||
"@standardnotes/domain-events-infra": "1.4.127",
|
||||
"@standardnotes/time": "^1.7.0",
|
||||
"aws-sdk": "^2.1160.0",
|
||||
"axios": "0.24.0",
|
||||
"cors": "2.8.5",
|
||||
"dotenv": "8.2.0",
|
||||
"express": "4.17.1",
|
||||
"helmet": "4.4.1",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.0.6",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"newrelic": "^8.14.1",
|
||||
"prettyjson": "1.2.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"winston": "3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.9",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/prettyjson": "^0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.1",
|
||||
"nodemon": "^2.0.16",
|
||||
"ts-jest": "^28.0.1"
|
||||
}
|
||||
}
|
||||
117
packages/api-gateway/src/Bootstrap/Container.ts
Normal file
117
packages/api-gateway/src/Bootstrap/Container.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as winston from 'winston'
|
||||
import axios, { AxiosInstance } from 'axios'
|
||||
import Redis from 'ioredis'
|
||||
import { Container } from 'inversify'
|
||||
import * as AWS from 'aws-sdk'
|
||||
import {
|
||||
AnalyticsStoreInterface,
|
||||
PeriodKeyGenerator,
|
||||
RedisAnalyticsStore,
|
||||
RedisStatisticsStore,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
import { RedisDomainEventPublisher, SNSDomainEventPublisher } from '@standardnotes/domain-events-infra'
|
||||
import { Timer, TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { Env } from './Env'
|
||||
import TYPES from './Types'
|
||||
import { AuthMiddleware } from '../Controller/AuthMiddleware'
|
||||
import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
|
||||
import { HttpService } from '../Service/Http/HttpService'
|
||||
import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
|
||||
import { StatisticsMiddleware } from '../Controller/StatisticsMiddleware'
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicWinstonEnricher = require('@newrelic/winston-enricher')
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
async load(): Promise<Container> {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const container = new Container()
|
||||
|
||||
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||
if (env.get('NEW_RELIC_ENABLED', true) === 'true') {
|
||||
winstonFormatters.push(newrelicWinstonEnricher())
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: env.get('LOG_LEVEL') || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL') || 'info' })],
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
const redisUrl = env.get('REDIS_URL')
|
||||
const isRedisInClusterMode = redisUrl.indexOf(',') > 0
|
||||
let redis
|
||||
if (isRedisInClusterMode) {
|
||||
redis = new Redis.Cluster(redisUrl.split(','))
|
||||
} else {
|
||||
redis = new Redis(redisUrl)
|
||||
}
|
||||
container.bind(TYPES.Redis).toConstantValue(redis)
|
||||
|
||||
if (env.get('SNS_AWS_REGION', true)) {
|
||||
container.bind<AWS.SNS>(TYPES.SNS).toConstantValue(
|
||||
new AWS.SNS({
|
||||
apiVersion: 'latest',
|
||||
region: env.get('SNS_AWS_REGION', true),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
container.bind<AxiosInstance>(TYPES.HTTPClient).toConstantValue(axios.create())
|
||||
|
||||
// env vars
|
||||
container.bind(TYPES.SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL'))
|
||||
container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL'))
|
||||
container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
|
||||
container.bind(TYPES.FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true))
|
||||
container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
|
||||
container
|
||||
.bind(TYPES.HTTP_CALL_TIMEOUT)
|
||||
.toConstantValue(env.get('HTTP_CALL_TIMEOUT', true) ? +env.get('HTTP_CALL_TIMEOUT', true) : 60_000)
|
||||
container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION'))
|
||||
container.bind(TYPES.SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
|
||||
container.bind(TYPES.SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
|
||||
container.bind(TYPES.REDIS_EVENTS_CHANNEL).toConstantValue(env.get('REDIS_EVENTS_CHANNEL'))
|
||||
container.bind(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL).toConstantValue(+env.get('CROSS_SERVICE_TOKEN_CACHE_TTL', true))
|
||||
|
||||
// Middleware
|
||||
container.bind<AuthMiddleware>(TYPES.AuthMiddleware).to(AuthMiddleware)
|
||||
container
|
||||
.bind<SubscriptionTokenAuthMiddleware>(TYPES.SubscriptionTokenAuthMiddleware)
|
||||
.to(SubscriptionTokenAuthMiddleware)
|
||||
container.bind<StatisticsMiddleware>(TYPES.StatisticsMiddleware).to(StatisticsMiddleware)
|
||||
|
||||
// Services
|
||||
container.bind<HttpServiceInterface>(TYPES.HTTPService).to(HttpService)
|
||||
const periodKeyGenerator = new PeriodKeyGenerator()
|
||||
container
|
||||
.bind<AnalyticsStoreInterface>(TYPES.AnalyticsStore)
|
||||
.toConstantValue(new RedisAnalyticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
|
||||
container
|
||||
.bind<StatisticsStoreInterface>(TYPES.StatisticsStore)
|
||||
.toConstantValue(new RedisStatisticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
|
||||
container.bind<CrossServiceTokenCacheInterface>(TYPES.CrossServiceTokenCache).to(RedisCrossServiceTokenCache)
|
||||
container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
|
||||
|
||||
if (env.get('SNS_TOPIC_ARN', true)) {
|
||||
container
|
||||
.bind<SNSDomainEventPublisher>(TYPES.DomainEventPublisher)
|
||||
.toConstantValue(new SNSDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)))
|
||||
} else {
|
||||
container
|
||||
.bind<RedisDomainEventPublisher>(TYPES.DomainEventPublisher)
|
||||
.toConstantValue(
|
||||
new RedisDomainEventPublisher(container.get(TYPES.Redis), container.get(TYPES.REDIS_EVENTS_CHANNEL)),
|
||||
)
|
||||
}
|
||||
|
||||
return container
|
||||
}
|
||||
}
|
||||
24
packages/api-gateway/src/Bootstrap/Env.ts
Normal file
24
packages/api-gateway/src/Bootstrap/Env.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { config, DotenvParseOutput } from 'dotenv'
|
||||
import { injectable } from 'inversify'
|
||||
|
||||
@injectable()
|
||||
export class Env {
|
||||
private env?: DotenvParseOutput
|
||||
|
||||
public load(): void {
|
||||
const output = config()
|
||||
this.env = <DotenvParseOutput>output.parsed
|
||||
}
|
||||
|
||||
public get(key: string, optional = false): string {
|
||||
if (!this.env) {
|
||||
this.load()
|
||||
}
|
||||
|
||||
if (!process.env[key] && !optional) {
|
||||
throw new Error(`Environment variable ${key} not set`)
|
||||
}
|
||||
|
||||
return <string>process.env[key]
|
||||
}
|
||||
}
|
||||
31
packages/api-gateway/src/Bootstrap/Types.ts
Normal file
31
packages/api-gateway/src/Bootstrap/Types.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
const TYPES = {
|
||||
Logger: Symbol.for('Logger'),
|
||||
Redis: Symbol.for('Redis'),
|
||||
HTTPClient: Symbol.for('HTTPClient'),
|
||||
SNS: Symbol.for('SNS'),
|
||||
// env vars
|
||||
SYNCING_SERVER_JS_URL: Symbol.for('SYNCING_SERVER_JS_URL'),
|
||||
AUTH_SERVER_URL: Symbol.for('AUTH_SERVER_URL'),
|
||||
PAYMENTS_SERVER_URL: Symbol.for('PAYMENTS_SERVER_URL'),
|
||||
FILES_SERVER_URL: Symbol.for('FILES_SERVER_URL'),
|
||||
AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'),
|
||||
HTTP_CALL_TIMEOUT: Symbol.for('HTTP_CALL_TIMEOUT'),
|
||||
VERSION: Symbol.for('VERSION'),
|
||||
SNS_TOPIC_ARN: Symbol.for('SNS_TOPIC_ARN'),
|
||||
SNS_AWS_REGION: Symbol.for('SNS_AWS_REGION'),
|
||||
REDIS_EVENTS_CHANNEL: Symbol.for('REDIS_EVENTS_CHANNEL'),
|
||||
CROSS_SERVICE_TOKEN_CACHE_TTL: Symbol.for('CROSS_SERVICE_TOKEN_CACHE_TTL'),
|
||||
// Middleware
|
||||
StatisticsMiddleware: Symbol.for('StatisticsMiddleware'),
|
||||
AuthMiddleware: Symbol.for('AuthMiddleware'),
|
||||
SubscriptionTokenAuthMiddleware: Symbol.for('SubscriptionTokenAuthMiddleware'),
|
||||
// Services
|
||||
HTTPService: Symbol.for('HTTPService'),
|
||||
CrossServiceTokenCache: Symbol.for('CrossServiceTokenCache'),
|
||||
AnalyticsStore: Symbol.for('AnalyticsStore'),
|
||||
StatisticsStore: Symbol.for('StatisticsStore'),
|
||||
DomainEventPublisher: Symbol.for('DomainEventPublisher'),
|
||||
Timer: Symbol.for('Timer'),
|
||||
}
|
||||
|
||||
export default TYPES
|
||||
124
packages/api-gateway/src/Controller/AuthMiddleware.ts
Normal file
124
packages/api-gateway/src/Controller/AuthMiddleware.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { CrossServiceTokenData } from '@standardnotes/auth'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { BaseMiddleware } from 'inversify-express-utils'
|
||||
import { verify } from 'jsonwebtoken'
|
||||
import { AxiosError, AxiosInstance } from 'axios'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
|
||||
@injectable()
|
||||
export class AuthMiddleware extends BaseMiddleware {
|
||||
constructor(
|
||||
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
|
||||
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
|
||||
@inject(TYPES.AUTH_JWT_SECRET) private jwtSecret: string,
|
||||
@inject(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL) private crossServiceTokenCacheTTL: number,
|
||||
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||
@inject(TYPES.Timer) private timer: TimerInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async handler(request: Request, response: Response, next: NextFunction): Promise<void> {
|
||||
const authHeaderValue = request.headers.authorization as string
|
||||
|
||||
if (!authHeaderValue) {
|
||||
response.status(401).send({
|
||||
error: {
|
||||
tag: 'invalid-auth',
|
||||
message: 'Invalid login credentials.',
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
let crossServiceTokenFetchedFromCache = true
|
||||
let crossServiceToken = null
|
||||
if (this.crossServiceTokenCacheTTL) {
|
||||
crossServiceToken = await this.crossServiceTokenCache.get(authHeaderValue)
|
||||
}
|
||||
|
||||
if (crossServiceToken === null) {
|
||||
const authResponse = await this.httpClient.request({
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: authHeaderValue,
|
||||
Accept: 'application/json',
|
||||
},
|
||||
validateStatus: (status: number) => {
|
||||
return status >= 200 && status < 500
|
||||
},
|
||||
url: `${this.authServerUrl}/sessions/validate`,
|
||||
})
|
||||
|
||||
if (authResponse.status > 200) {
|
||||
response.setHeader('content-type', authResponse.headers['content-type'])
|
||||
response.status(authResponse.status).send(authResponse.data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
crossServiceToken = authResponse.data.authToken
|
||||
crossServiceTokenFetchedFromCache = false
|
||||
}
|
||||
|
||||
response.locals.authToken = crossServiceToken
|
||||
|
||||
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||
|
||||
if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
|
||||
await this.crossServiceTokenCache.set({
|
||||
authorizationHeaderValue: authHeaderValue,
|
||||
encodedCrossServiceToken: crossServiceToken,
|
||||
expiresAtInSeconds: this.getCrossServiceTokenCacheExpireTimestamp(decodedToken),
|
||||
userUuid: decodedToken.user.uuid,
|
||||
})
|
||||
}
|
||||
|
||||
response.locals.userUuid = decodedToken.user.uuid
|
||||
response.locals.roles = decodedToken.roles
|
||||
} catch (error) {
|
||||
const errorMessage = (error as AxiosError).isAxiosError
|
||||
? JSON.stringify((error as AxiosError).response?.data)
|
||||
: (error as Error).message
|
||||
|
||||
this.logger.error(
|
||||
`Could not pass the request to ${this.authServerUrl}/sessions/validate on underlying service: ${errorMessage}`,
|
||||
)
|
||||
|
||||
this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
|
||||
|
||||
if ((error as AxiosError).response?.headers['content-type']) {
|
||||
response.setHeader('content-type', (error as AxiosError).response?.headers['content-type'] as string)
|
||||
}
|
||||
|
||||
const errorCode = (error as AxiosError).isAxiosError ? +((error as AxiosError).code as string) : 500
|
||||
|
||||
response.status(errorCode).send(errorMessage)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
private getCrossServiceTokenCacheExpireTimestamp(token: CrossServiceTokenData): number {
|
||||
const crossServiceTokenDefaultCacheExpiration = this.timer.getTimestampInSeconds() + this.crossServiceTokenCacheTTL
|
||||
|
||||
if (token.session === undefined) {
|
||||
return crossServiceTokenDefaultCacheExpiration
|
||||
}
|
||||
|
||||
const sessionAccessExpiration = this.timer.convertStringDateToSeconds(token.session.access_expiration)
|
||||
const sessionRefreshExpiration = this.timer.convertStringDateToSeconds(token.session.refresh_expiration)
|
||||
|
||||
return Math.min(crossServiceTokenDefaultCacheExpiration, sessionAccessExpiration, sessionRefreshExpiration)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { controller, httpGet } from 'inversify-express-utils'
|
||||
|
||||
@controller('/healthcheck')
|
||||
export class HealthCheckController {
|
||||
@httpGet('/')
|
||||
public async get(): Promise<string> {
|
||||
return 'OK'
|
||||
}
|
||||
}
|
||||
124
packages/api-gateway/src/Controller/LegacyController.ts
Normal file
124
packages/api-gateway/src/Controller/LegacyController.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDelete } from 'inversify-express-utils'
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('', TYPES.StatisticsMiddleware)
|
||||
export class LegacyController extends BaseHttpController {
|
||||
private AUTH_ROUTES: Map<string, string>
|
||||
private PARAMETRIZED_AUTH_ROUTES: Map<string, string>
|
||||
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
|
||||
this.AUTH_ROUTES = new Map([
|
||||
['POST:/auth', 'POST:auth'],
|
||||
['POST:/auth/sign_out', 'POST:auth/sign_out'],
|
||||
['POST:/auth/change_pw', 'PUT:/users/legacy-endpoint-user/attributes/credentials'],
|
||||
['GET:/sessions', 'GET:sessions'],
|
||||
['DELETE:/session', 'DELETE:session'],
|
||||
['DELETE:/session/all', 'DELETE:session/all'],
|
||||
['POST:/session/refresh', 'POST:session/refresh'],
|
||||
['POST:/auth/sign_in', 'POST:auth/sign_in'],
|
||||
['GET:/auth/params', 'GET:auth/params'],
|
||||
])
|
||||
|
||||
this.PARAMETRIZED_AUTH_ROUTES = new Map([
|
||||
['PATCH:/users/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})', 'users/{uuid}'],
|
||||
])
|
||||
}
|
||||
|
||||
@httpPost('/items/sync', TYPES.AuthMiddleware)
|
||||
async legacyItemsSync(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
|
||||
}
|
||||
|
||||
@httpGet('/items/:item_id/revisions', TYPES.AuthMiddleware)
|
||||
async legacyGetRevisions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
|
||||
}
|
||||
|
||||
@httpGet('/items/:item_id/revisions/:id', TYPES.AuthMiddleware)
|
||||
async legacyGetRevision(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
|
||||
}
|
||||
|
||||
@httpGet('/items/mfa/:userUuid')
|
||||
async blockedMFARequest(): Promise<results.StatusCodeResult> {
|
||||
return this.statusCode(401)
|
||||
}
|
||||
|
||||
@httpDelete('/items/mfa/:userUuid')
|
||||
async blockedMFARemoveRequest(): Promise<results.StatusCodeResult> {
|
||||
return this.statusCode(401)
|
||||
}
|
||||
|
||||
@all('*')
|
||||
async legacyProxyToSyncingServer(request: Request, response: Response): Promise<void> {
|
||||
if (request.path === '/') {
|
||||
response.send('Welcome to the Standard Notes server infrastructure. Learn more at https://docs.standardnotes.com')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (this.shouldBeRedirectedToAuthService(request)) {
|
||||
const methodAndPath = this.getMethodAndPath(request)
|
||||
|
||||
request.method = methodAndPath.method
|
||||
await this.httpService.callAuthServerWithLegacyFormat(request, response, methodAndPath.path, request.body)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
|
||||
}
|
||||
|
||||
private getMethodAndPath(request: Request): { method: string; path: string } {
|
||||
const requestKey = `${request.method}:${request.path}`
|
||||
|
||||
if (this.AUTH_ROUTES.has(requestKey)) {
|
||||
const legacyRoute = this.AUTH_ROUTES.get(requestKey) as string
|
||||
const legacyRouteMethodAndPath = legacyRoute.split(':')
|
||||
|
||||
return {
|
||||
method: legacyRouteMethodAndPath[0],
|
||||
path: legacyRouteMethodAndPath[1],
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of this.AUTH_ROUTES.keys()) {
|
||||
const regExp = new RegExp(key)
|
||||
const matches = regExp.exec(requestKey)
|
||||
if (matches !== null) {
|
||||
const legacyRoute = (this.AUTH_ROUTES.get(key) as string).replace('{uuid}', matches[1])
|
||||
const legacyRouteMethodAndPath = legacyRoute.split(':')
|
||||
|
||||
return {
|
||||
method: legacyRouteMethodAndPath[0],
|
||||
path: legacyRouteMethodAndPath[1],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw Error('could not find path for key')
|
||||
}
|
||||
|
||||
private shouldBeRedirectedToAuthService(request: Request): boolean {
|
||||
const requestKey = `${request.method}:${request.path}`
|
||||
|
||||
if (this.AUTH_ROUTES.has(requestKey)) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (const key of this.PARAMETRIZED_AUTH_ROUTES.keys()) {
|
||||
const regExp = new RegExp(key)
|
||||
const matches = regExp.test(requestKey)
|
||||
if (matches) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
31
packages/api-gateway/src/Controller/StatisticsMiddleware.ts
Normal file
31
packages/api-gateway/src/Controller/StatisticsMiddleware.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { BaseMiddleware } from 'inversify-express-utils'
|
||||
import { Logger } from 'winston'
|
||||
import { StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
|
||||
@injectable()
|
||||
export class StatisticsMiddleware extends BaseMiddleware {
|
||||
constructor(
|
||||
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async handler(request: Request, _response: Response, next: NextFunction): Promise<void> {
|
||||
try {
|
||||
const snjsVersion = request.headers['x-snjs-version'] ?? 'unknown'
|
||||
await this.statisticsStore.incrementSNJSVersionUsage(snjsVersion as string)
|
||||
|
||||
const applicationVersion = request.headers['x-application-version'] ?? 'unknown'
|
||||
await this.statisticsStore.incrementApplicationVersionUsage(applicationVersion as string)
|
||||
} catch (error) {
|
||||
this.logger.error(`Could not store analytics data: ${(error as Error).message}`)
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { OfflineUserTokenData, CrossServiceTokenData } from '@standardnotes/auth'
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { BaseMiddleware } from 'inversify-express-utils'
|
||||
import { verify } from 'jsonwebtoken'
|
||||
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'
|
||||
import { Logger } from 'winston'
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
import { TokenAuthenticationMethod } from './TokenAuthenticationMethod'
|
||||
|
||||
@injectable()
|
||||
export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
||||
constructor(
|
||||
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
|
||||
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
|
||||
@inject(TYPES.AUTH_JWT_SECRET) private jwtSecret: string,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async handler(request: Request, response: Response, next: NextFunction): Promise<void> {
|
||||
const subscriptionToken = request.query.subscription_token
|
||||
const email = request.headers['x-offline-email']
|
||||
if (!subscriptionToken) {
|
||||
response.status(401).send({
|
||||
error: {
|
||||
tag: 'invalid-auth',
|
||||
message: 'Invalid login credentials.',
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
response.locals.tokenAuthenticationMethod = email
|
||||
? TokenAuthenticationMethod.OfflineSubscriptionToken
|
||||
: TokenAuthenticationMethod.SubscriptionToken
|
||||
|
||||
try {
|
||||
const url =
|
||||
response.locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken
|
||||
? `${this.authServerUrl}/offline/subscription-tokens/${subscriptionToken}/validate`
|
||||
: `${this.authServerUrl}/subscription-tokens/${subscriptionToken}/validate`
|
||||
|
||||
const authResponse = await this.httpClient.request({
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
data: {
|
||||
email,
|
||||
},
|
||||
validateStatus: (status: number) => {
|
||||
return status >= 200 && status < 500
|
||||
},
|
||||
url,
|
||||
})
|
||||
|
||||
if (authResponse.status > 200) {
|
||||
response.setHeader('content-type', authResponse.headers['content-type'])
|
||||
response.status(authResponse.status).send(authResponse.data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (response.locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
||||
this.handleOfflineAuthTokenValidationResponse(response, authResponse)
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
this.handleAuthTokenValidationResponse(response, authResponse)
|
||||
|
||||
return next()
|
||||
} catch (error) {
|
||||
const errorMessage = (error as AxiosError).isAxiosError
|
||||
? JSON.stringify((error as AxiosError).response?.data)
|
||||
: (error as Error).message
|
||||
|
||||
this.logger.error(
|
||||
`Could not pass the request to ${this.authServerUrl}/subscription-tokens/${subscriptionToken}/validate on underlying service: ${errorMessage}`,
|
||||
)
|
||||
|
||||
this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
|
||||
|
||||
if ((error as AxiosError).response?.headers['content-type']) {
|
||||
response.setHeader('content-type', (error as AxiosError).response?.headers['content-type'] as string)
|
||||
}
|
||||
|
||||
const errorCode = (error as AxiosError).isAxiosError ? +((error as AxiosError).code as string) : 500
|
||||
|
||||
response.status(errorCode).send(errorMessage)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private handleOfflineAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
||||
response.locals.offlineAuthToken = authResponse.data.authToken
|
||||
|
||||
const decodedToken = <OfflineUserTokenData>(
|
||||
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||
)
|
||||
|
||||
response.locals.offlineUserEmail = decodedToken.userEmail
|
||||
response.locals.offlineFeaturesToken = decodedToken.featuresToken
|
||||
}
|
||||
|
||||
private handleAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
||||
response.locals.authToken = authResponse.data.authToken
|
||||
|
||||
const decodedToken = <CrossServiceTokenData>(
|
||||
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||
)
|
||||
|
||||
response.locals.userUuid = decodedToken.user.uuid
|
||||
response.locals.roles = decodedToken.roles
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum TokenAuthenticationMethod {
|
||||
OfflineSubscriptionToken = 'OfflineSubscriptionToken',
|
||||
SubscriptionToken = 'SubscriptionToken',
|
||||
}
|
||||
52
packages/api-gateway/src/Controller/v1/ActionsController.ts
Normal file
52
packages/api-gateway/src/Controller/v1/ActionsController.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1', TYPES.StatisticsMiddleware)
|
||||
export class ActionsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/login')
|
||||
async login(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/sign_in', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/login-params')
|
||||
async loginParams(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/params', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/logout')
|
||||
async logout(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/sign_out', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/auth/methods')
|
||||
async methods(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/methods', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/failed-backups-emails/mute/:settingUuid')
|
||||
async muteFailedBackupsEmails(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`internal/settings/email_backup/${request.params.settingUuid}/mute`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/sign-in-emails/mute/:settingUuid')
|
||||
async muteSignInEmails(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`internal/settings/sign_in/${request.params.settingUuid}/mute`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
}
|
||||
18
packages/api-gateway/src/Controller/v1/FilesController.ts
Normal file
18
packages/api-gateway/src/Controller/v1/FilesController.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/files', TYPES.StatisticsMiddleware)
|
||||
export class FilesController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/valet-tokens', TYPES.AuthMiddleware)
|
||||
async createToken(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'valet-tokens', request.body)
|
||||
}
|
||||
}
|
||||
17
packages/api-gateway/src/Controller/v1/InvoicesController.ts
Normal file
17
packages/api-gateway/src/Controller/v1/InvoicesController.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
import { inject } from 'inversify'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1', TYPES.StatisticsMiddleware)
|
||||
export class InvoicesController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/invoices/send-latest', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async sendLatestInvoice(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-invoice', request.body)
|
||||
}
|
||||
}
|
||||
27
packages/api-gateway/src/Controller/v1/ItemsController.ts
Normal file
27
packages/api-gateway/src/Controller/v1/ItemsController.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/items', TYPES.StatisticsMiddleware, TYPES.AuthMiddleware)
|
||||
export class ItemsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/')
|
||||
async sync(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(request, response, 'items/sync', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/check-integrity')
|
||||
async checkIntegrity(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(request, response, 'items/check-integrity', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/:uuid')
|
||||
async getItem(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(request, response, `items/${request.params.uuid}`, request.body)
|
||||
}
|
||||
}
|
||||
33
packages/api-gateway/src/Controller/v1/OfflineController.ts
Normal file
33
packages/api-gateway/src/Controller/v1/OfflineController.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/offline', TYPES.StatisticsMiddleware)
|
||||
export class OfflineController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/features')
|
||||
async getOfflineFeatures(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'offline/features', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/subscription-tokens')
|
||||
async createOfflineSubscriptionToken(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'offline/subscription-tokens', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/payments/stripe-setup-intent')
|
||||
async createStripeSetupIntent(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
'api/pro_users/stripe-setup-intent/offline',
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
}
|
||||
162
packages/api-gateway/src/Controller/v1/PaymentsController.ts
Normal file
162
packages/api-gateway/src/Controller/v1/PaymentsController.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1', TYPES.StatisticsMiddleware)
|
||||
export class PaymentsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/downloads')
|
||||
async downloads(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/downloads', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/downloads/download-info')
|
||||
async downloadInfo(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/downloads/download-info', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/downloads/platforms')
|
||||
async platformDownloads(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/downloads/platforms', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/help/categories')
|
||||
async categoriesHelp(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/help/categories', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/knowledge/categories')
|
||||
async categoriesKnowledge(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/knowledge/categories', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/extensions')
|
||||
async extensions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/extensions', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/subscriptions/tiered', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async createTieredSubscription(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/tiered', request.body)
|
||||
}
|
||||
|
||||
@all('/subscriptions(/*)?')
|
||||
async subscriptions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, request.path.replace('v1', 'api'), request.body)
|
||||
}
|
||||
|
||||
@httpGet('/reset/validate')
|
||||
async validateReset(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/reset/validate', request.body)
|
||||
}
|
||||
|
||||
@httpDelete('/reset')
|
||||
async reset(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/reset', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/reset')
|
||||
async resetRequest(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/reset', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/user-registration')
|
||||
async userRegistration(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'admin/events/registration', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/admin/graphql')
|
||||
async adminGraphql(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'admin/graphql', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/admin/auth/login')
|
||||
async adminLogin(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'admin/auth/login', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/admin/auth/logout')
|
||||
async adminLogout(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'admin/auth/logout', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/students')
|
||||
async students(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/students', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/students/:token/approve')
|
||||
async studentsApprove(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/students/${request.params.token}/approve`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPost('/email_subscriptions/:token/less')
|
||||
async subscriptionsLess(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/email_subscriptions/${request.params.token}/less`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPost('/email_subscriptions/:token/more')
|
||||
async subscriptionsMore(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/email_subscriptions/${request.params.token}/more`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPost('/email_subscriptions/:token/mute/:campaignId')
|
||||
async subscriptionsMute(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/email_subscriptions/${request.params.token}/mute/${request.params.campaignId}`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPost('/email_subscriptions/:token/unsubscribe')
|
||||
async subscriptionsUnsubscribe(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/email_subscriptions/${request.params.token}/unsubscribe`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPost('/payments/stripe-setup-intent', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async createStripeSetupIntent(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/stripe-setup-intent', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/pro_users/cp-prepayment-info', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async coinpaymentsPrepaymentInfo(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/cp-prepayment-info', request.body)
|
||||
}
|
||||
|
||||
@all('/pro_users(/*)?')
|
||||
async proUsers(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, request.path.replace('v1', 'api'), request.body)
|
||||
}
|
||||
|
||||
@all('/refunds')
|
||||
async refunds(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/refunds', request.body)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/items/:item_id/revisions', TYPES.StatisticsMiddleware, TYPES.AuthMiddleware)
|
||||
export class RevisionsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/')
|
||||
async getRevisions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(request, response, `items/${request.params.item_id}/revisions`)
|
||||
}
|
||||
|
||||
@httpGet('/:id')
|
||||
async getRevision(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(
|
||||
request,
|
||||
response,
|
||||
`items/${request.params.item_id}/revisions/${request.params.id}`,
|
||||
)
|
||||
}
|
||||
|
||||
@httpDelete('/:id')
|
||||
async deleteRevision(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callSyncingServer(
|
||||
request,
|
||||
response,
|
||||
`items/${request.params.item_id}/revisions/${request.params.id}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
34
packages/api-gateway/src/Controller/v1/SessionsController.ts
Normal file
34
packages/api-gateway/src/Controller/v1/SessionsController.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/sessions', TYPES.StatisticsMiddleware)
|
||||
export class SessionsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/', TYPES.AuthMiddleware)
|
||||
async getSessions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'sessions')
|
||||
}
|
||||
|
||||
@httpDelete('/:uuid', TYPES.AuthMiddleware)
|
||||
async deleteSession(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'session', {
|
||||
uuid: request.params.uuid,
|
||||
})
|
||||
}
|
||||
|
||||
@httpDelete('/', TYPES.AuthMiddleware)
|
||||
async deleteSessions(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'session/all')
|
||||
}
|
||||
|
||||
@httpPost('/refresh')
|
||||
async refreshSession(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'session/refresh', request.body)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/subscription-invites', TYPES.StatisticsMiddleware)
|
||||
export class SubscriptionInvitesController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.AuthMiddleware)
|
||||
async inviteToSubscriptionSharing(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'subscription-invites', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/', TYPES.AuthMiddleware)
|
||||
async listInvites(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'subscription-invites', request.body)
|
||||
}
|
||||
|
||||
@httpDelete('/:inviteUuid', TYPES.AuthMiddleware)
|
||||
async cancelSubscriptionSharing(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `subscription-invites/${request.params.inviteUuid}`)
|
||||
}
|
||||
|
||||
@httpGet('/:inviteUuid/accept')
|
||||
async acceptInvite(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `subscription-invites/${request.params.inviteUuid}/accept`)
|
||||
}
|
||||
|
||||
@httpGet('/:inviteUuid/decline')
|
||||
async declineInvite(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`subscription-invites/${request.params.inviteUuid}/decline`,
|
||||
)
|
||||
}
|
||||
}
|
||||
18
packages/api-gateway/src/Controller/v1/TokensController.ts
Normal file
18
packages/api-gateway/src/Controller/v1/TokensController.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/subscription-tokens', TYPES.StatisticsMiddleware)
|
||||
export class TokensController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.AuthMiddleware)
|
||||
async createToken(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'subscription-tokens', request.body)
|
||||
}
|
||||
}
|
||||
150
packages/api-gateway/src/Controller/v1/UsersController.ts
Normal file
150
packages/api-gateway/src/Controller/v1/UsersController.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import {
|
||||
all,
|
||||
BaseHttpController,
|
||||
controller,
|
||||
httpDelete,
|
||||
httpGet,
|
||||
httpPatch,
|
||||
httpPost,
|
||||
httpPut,
|
||||
results,
|
||||
} from 'inversify-express-utils'
|
||||
import { Logger } from 'winston'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
||||
|
||||
@controller('/v1/users', TYPES.StatisticsMiddleware)
|
||||
export class UsersController extends BaseHttpController {
|
||||
constructor(
|
||||
@inject(TYPES.HTTPService) private httpService: HttpServiceInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/claim-account')
|
||||
async claimAccount(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/claim-account', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/send-activation-code', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async sendActivationCode(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-activation-code', request.body)
|
||||
}
|
||||
|
||||
@httpPatch('/:userId', TYPES.AuthMiddleware)
|
||||
async updateUser(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `users/${request.params.userId}`, request.body)
|
||||
}
|
||||
|
||||
@httpPut('/:userUuid/password', TYPES.AuthMiddleware)
|
||||
async changePassword(request: Request, response: Response): Promise<void> {
|
||||
this.logger.debug(
|
||||
'[DEPRECATED] use endpoint /v1/users/:userUuid/attributes/credentials instead of /v1/users/:userUuid/password',
|
||||
)
|
||||
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`users/${request.params.userUuid}/attributes/credentials`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPut('/:userUuid/attributes/credentials', TYPES.AuthMiddleware)
|
||||
async changeCredentials(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`users/${request.params.userUuid}/attributes/credentials`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/:userId/params', TYPES.AuthMiddleware)
|
||||
async getKeyParams(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/params')
|
||||
}
|
||||
|
||||
@all('/:userId/mfa', TYPES.AuthMiddleware)
|
||||
async blockMFA(): Promise<results.StatusCodeResult> {
|
||||
return this.statusCode(401)
|
||||
}
|
||||
|
||||
@httpPost('/:userUuid/integrations/listed', TYPES.AuthMiddleware)
|
||||
async createListedAccount(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'listed', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/')
|
||||
async register(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/:userUuid/settings', TYPES.AuthMiddleware)
|
||||
async listSettings(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/settings`)
|
||||
}
|
||||
|
||||
@httpPut('/:userUuid/settings', TYPES.AuthMiddleware)
|
||||
async putSetting(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/settings`, request.body)
|
||||
}
|
||||
|
||||
@httpGet('/:userUuid/settings/:settingName', TYPES.AuthMiddleware)
|
||||
async getSetting(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`users/${request.params.userUuid}/settings/${request.params.settingName}`,
|
||||
)
|
||||
}
|
||||
|
||||
@httpDelete('/:userUuid/settings/:settingName', TYPES.AuthMiddleware)
|
||||
async deleteSetting(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`users/${request.params.userUuid}/settings/${request.params.settingName}`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/:userUuid/subscription-settings/:subscriptionSettingName', TYPES.AuthMiddleware)
|
||||
async getSubscriptionSetting(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
`users/${request.params.userUuid}/subscription-settings/${request.params.subscriptionSettingName}`,
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/:userUuid/features', TYPES.AuthMiddleware)
|
||||
async getFeatures(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/features`)
|
||||
}
|
||||
|
||||
@httpGet('/:userUuid/subscription', TYPES.AuthMiddleware)
|
||||
async getSubscription(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/subscription`)
|
||||
}
|
||||
|
||||
@httpGet('/subscription', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async getSubscriptionBySubscriptionToken(request: Request, response: Response): Promise<void> {
|
||||
if (response.locals.tokenAuthenticationMethod === TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
||||
await this.httpService.callAuthServer(request, response, 'offline/users/subscription')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.httpService.callAuthServer(request, response, `users/${response.locals.userUuid}/subscription`)
|
||||
}
|
||||
|
||||
@httpDelete('/:userUuid', TYPES.AuthMiddleware)
|
||||
async deleteUser(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/account', request.body)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpPost } from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/sockets')
|
||||
export class WebSocketsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.AuthMiddleware)
|
||||
async createWebSocketConnection(request: Request, response: Response): Promise<void> {
|
||||
if (!request.headers.connectionid) {
|
||||
response.status(400).send('Missing connection id in the request')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.httpService.callAuthServer(request, response, `sockets/${request.headers.connectionid}`, request.body)
|
||||
}
|
||||
|
||||
@httpDelete('/')
|
||||
async deleteWebSocketConnection(request: Request, response: Response): Promise<void> {
|
||||
if (!request.headers.connectionid) {
|
||||
response.status(400).send('Missing connection id in the request')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.httpService.callAuthServer(request, response, `sockets/${request.headers.connectionid}`, request.body)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v2', TYPES.StatisticsMiddleware)
|
||||
export class ActionsControllerV2 extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/login')
|
||||
async login(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/pkce_sign_in', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/login-params')
|
||||
async loginParams(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(request, response, 'auth/pkce_params', request.body)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
||||
import { inject } from 'inversify'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v2', TYPES.StatisticsMiddleware)
|
||||
export class PaymentsControllerV2 extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/subscriptions')
|
||||
async getSubscriptionsWithFeatures(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/features', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/subscriptions/tailored', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async getTailoredSubscriptionsWithFeatures(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/features', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/subscriptions/deltas', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async getSubscriptionDeltasForChangingPlan(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/deltas', request.body)
|
||||
}
|
||||
|
||||
@httpPost('/subscriptions/deltas/apply', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async applySubscriptionDelta(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/deltas/apply', request.body)
|
||||
}
|
||||
|
||||
@httpGet('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async getSubscription(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/subscriptions/${request.params.subscriptionId}`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpDelete('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async cancelSubscription(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/subscriptions/${request.params.subscriptionId}`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
|
||||
@httpPatch('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
|
||||
async updateSubscription(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callPaymentsServer(
|
||||
request,
|
||||
response,
|
||||
`api/subscriptions/${request.params.subscriptionId}`,
|
||||
request.body,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
import * as IORedis from 'ioredis'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
|
||||
import { CrossServiceTokenCacheInterface } from '../../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
|
||||
@injectable()
|
||||
export class RedisCrossServiceTokenCache implements CrossServiceTokenCacheInterface {
|
||||
private readonly PREFIX = 'cst'
|
||||
private readonly USER_CST_PREFIX = 'user-cst'
|
||||
|
||||
constructor(@inject(TYPES.Redis) private redisClient: IORedis.Redis) {}
|
||||
|
||||
async set(dto: {
|
||||
authorizationHeaderValue: string
|
||||
encodedCrossServiceToken: string
|
||||
expiresAtInSeconds: number
|
||||
userUuid: string
|
||||
}): Promise<void> {
|
||||
const pipeline = this.redisClient.pipeline()
|
||||
|
||||
pipeline.sadd(`${this.USER_CST_PREFIX}:${dto.userUuid}`, dto.authorizationHeaderValue)
|
||||
pipeline.expireat(`${this.USER_CST_PREFIX}:${dto.userUuid}`, dto.expiresAtInSeconds)
|
||||
|
||||
pipeline.set(`${this.PREFIX}:${dto.authorizationHeaderValue}`, dto.encodedCrossServiceToken)
|
||||
pipeline.expireat(`${this.PREFIX}:${dto.authorizationHeaderValue}`, dto.expiresAtInSeconds)
|
||||
|
||||
await pipeline.exec()
|
||||
}
|
||||
|
||||
async get(authorizationHeaderValue: string): Promise<string | null> {
|
||||
return this.redisClient.get(`${this.PREFIX}:${authorizationHeaderValue}`)
|
||||
}
|
||||
|
||||
async invalidate(userUuid: string): Promise<void> {
|
||||
const userAuthorizationHeaderValues = await this.redisClient.smembers(`${this.USER_CST_PREFIX}:${userUuid}`)
|
||||
|
||||
const pipeline = this.redisClient.pipeline()
|
||||
for (const authorizationHeaderValue of userAuthorizationHeaderValues) {
|
||||
pipeline.del(`${this.PREFIX}:${authorizationHeaderValue}`)
|
||||
}
|
||||
pipeline.del(`${this.USER_CST_PREFIX}:${userUuid}`)
|
||||
|
||||
await pipeline.exec()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface CrossServiceTokenCacheInterface {
|
||||
set(dto: {
|
||||
authorizationHeaderValue: string
|
||||
encodedCrossServiceToken: string
|
||||
expiresAtInSeconds: number
|
||||
userUuid: string
|
||||
}): Promise<void>
|
||||
get(authorizationHeaderValue: string): Promise<string | null>
|
||||
invalidate(userUuid: string): Promise<void>
|
||||
}
|
||||
231
packages/api-gateway/src/Service/Http/HttpService.ts
Normal file
231
packages/api-gateway/src/Service/Http/HttpService.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { AxiosInstance, AxiosError, AxiosResponse, Method } from 'axios'
|
||||
import { Request, Response } from 'express'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||
import { HttpServiceInterface } from './HttpServiceInterface'
|
||||
|
||||
@injectable()
|
||||
export class HttpService implements HttpServiceInterface {
|
||||
constructor(
|
||||
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
|
||||
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
|
||||
@inject(TYPES.SYNCING_SERVER_JS_URL) private syncingServerJsUrl: string,
|
||||
@inject(TYPES.PAYMENTS_SERVER_URL) private paymentsServerUrl: string,
|
||||
@inject(TYPES.FILES_SERVER_URL) private filesServerUrl: string,
|
||||
@inject(TYPES.HTTP_CALL_TIMEOUT) private httpCallTimeout: number,
|
||||
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
|
||||
async callSyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callLegacySyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServerWithLegacyFormat(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callAuthServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServer(this.authServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callPaymentsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
if (!this.paymentsServerUrl) {
|
||||
this.logger.debug('Payments Server URL not defined. Skipped request to Payments API.')
|
||||
|
||||
return
|
||||
}
|
||||
await this.callServerWithLegacyFormat(this.paymentsServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callAuthServerWithLegacyFormat(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
private async getServerResponse(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<AxiosResponse | undefined> {
|
||||
try {
|
||||
const headers: Record<string, string> = {}
|
||||
for (const headerName of Object.keys(request.headers)) {
|
||||
headers[headerName] = request.headers[headerName] as string
|
||||
}
|
||||
|
||||
delete headers.host
|
||||
delete headers['content-length']
|
||||
|
||||
if (response.locals.authToken) {
|
||||
headers['X-Auth-Token'] = response.locals.authToken
|
||||
}
|
||||
|
||||
if (response.locals.offlineAuthToken) {
|
||||
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
||||
}
|
||||
|
||||
this.logger.debug(`Calling [${request.method}] ${serverUrl}/${endpoint},
|
||||
headers: ${JSON.stringify(headers)},
|
||||
query: ${JSON.stringify(request.query)},
|
||||
payload: ${JSON.stringify(payload)}`)
|
||||
|
||||
const serviceResponse = await this.httpClient.request({
|
||||
method: request.method as Method,
|
||||
headers,
|
||||
url: `${serverUrl}/${endpoint}`,
|
||||
data: this.getRequestData(payload),
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
params: request.query,
|
||||
timeout: this.httpCallTimeout,
|
||||
validateStatus: (status: number) => {
|
||||
return status >= 200 && status < 500
|
||||
},
|
||||
})
|
||||
|
||||
if (serviceResponse.headers['x-invalidate-cache']) {
|
||||
const userUuid = serviceResponse.headers['x-invalidate-cache']
|
||||
await this.crossServiceTokenCache.invalidate(userUuid)
|
||||
}
|
||||
|
||||
return serviceResponse
|
||||
} catch (error) {
|
||||
const errorMessage = (error as AxiosError).isAxiosError
|
||||
? JSON.stringify((error as AxiosError).response?.data)
|
||||
: (error as Error).message
|
||||
|
||||
this.logger.error(`Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${errorMessage}`)
|
||||
|
||||
this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
|
||||
|
||||
if ((error as AxiosError).response?.headers['content-type']) {
|
||||
response.setHeader('content-type', (error as AxiosError).response?.headers['content-type'] as string)
|
||||
}
|
||||
|
||||
const errorCode = (error as AxiosError).isAxiosError ? +((error as AxiosError).code as string) : 500
|
||||
|
||||
response.status(errorCode).send(errorMessage)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
private async callServer(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||
|
||||
this.logger.debug(`Response from underlying server: ${JSON.stringify(serviceResponse?.data)},
|
||||
headers: ${JSON.stringify(serviceResponse?.headers)}`)
|
||||
|
||||
if (!serviceResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
this.applyResponseHeaders(serviceResponse, response)
|
||||
|
||||
response.status(serviceResponse.status).send({
|
||||
meta: {
|
||||
auth: {
|
||||
userUuid: response.locals.userUuid,
|
||||
roles: response.locals.roles,
|
||||
},
|
||||
server: {
|
||||
filesServerUrl: this.filesServerUrl,
|
||||
},
|
||||
},
|
||||
data: serviceResponse.data,
|
||||
})
|
||||
}
|
||||
|
||||
private async callServerWithLegacyFormat(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||
|
||||
if (!serviceResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
this.applyResponseHeaders(serviceResponse, response)
|
||||
|
||||
if (serviceResponse.request._redirectable._redirectCount > 0) {
|
||||
response.status(302).redirect(serviceResponse.request.res.responseUrl)
|
||||
} else {
|
||||
response.status(serviceResponse.status).send(serviceResponse.data)
|
||||
}
|
||||
}
|
||||
|
||||
private getRequestData(
|
||||
payload: Record<string, unknown> | string | undefined,
|
||||
): Record<string, unknown> | string | undefined {
|
||||
if (
|
||||
payload === '' ||
|
||||
payload === null ||
|
||||
payload === undefined ||
|
||||
(typeof payload === 'object' && Object.keys(payload).length === 0)
|
||||
) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
||||
const returnedHeadersFromUnderlyingService = [
|
||||
'access-control-allow-methods',
|
||||
'access-control-allow-origin',
|
||||
'access-control-expose-headers',
|
||||
'authorization',
|
||||
'content-type',
|
||||
'x-ssjs-version',
|
||||
'x-auth-version',
|
||||
]
|
||||
|
||||
returnedHeadersFromUnderlyingService.map((headerName) => {
|
||||
const headerValue = serviceResponse.headers[headerName]
|
||||
if (headerValue) {
|
||||
response.setHeader(headerName, headerValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
export interface HttpServiceInterface {
|
||||
callAuthServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callAuthServerWithLegacyFormat(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callSyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callLegacySyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callPaymentsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
}
|
||||
0
packages/api-gateway/test-setup.ts
Normal file
0
packages/api-gateway/test-setup.ts
Normal file
12
packages/api-gateway/tsconfig.json
Normal file
12
packages/api-gateway/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"bin/**/*",
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
17
packages/api-gateway/wait-for.sh
Executable file
17
packages/api-gateway/wait-for.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
host="$1"
|
||||
shift
|
||||
port="$1"
|
||||
shift
|
||||
cmd="$@"
|
||||
|
||||
while ! nc -vz $host $port; do
|
||||
>&2 echo "$host:$port is unavailable yet - waiting for it to start"
|
||||
sleep 10
|
||||
done
|
||||
|
||||
>&2 echo "$host:$port is up - executing command"
|
||||
exec $cmd
|
||||
@@ -3,6 +3,56 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.4...@standardnotes/auth-server@1.1.5) (2022-06-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade sentry node sdk ([b6db194](https://github.com/standardnotes/auth/commit/b6db194a22ff1d0afe96c291d545b408c0a5c373))
|
||||
|
||||
## [1.1.4](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.3...@standardnotes/auth-server@1.1.4) (2022-06-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* newrelic deps and setup db and cache for local development purposes ([ff09ae0](https://github.com/standardnotes/auth/commit/ff09ae0a47747eaf7977ce5d3937ad385101eaeb))
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.2...@standardnotes/auth-server@1.1.3) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* curl in the final image ([0d67c55](https://github.com/standardnotes/auth/commit/0d67c55e124eed08bca16824750152b895fceca7))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.1...@standardnotes/auth-server@1.1.2) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0...@standardnotes/auth-server@1.1.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.1.0](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.8...@standardnotes/auth-server@1.1.0) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.1.0-alpha.8](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.7...@standardnotes/auth-server@1.1.0-alpha.8) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.1.0-alpha.7](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.6...@standardnotes/auth-server@1.1.0-alpha.7) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.1.0-alpha.6](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.5...@standardnotes/auth-server@1.1.0-alpha.6) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing curl to docker image for healthcheck purposes ([7efb48d](https://github.com/standardnotes/auth/commit/7efb48dd2a6066c29601d34bfcbfe6231f644c50))
|
||||
|
||||
# [1.1.0-alpha.5](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.4...@standardnotes/auth-server@1.1.0-alpha.5) (2022-06-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* make DISABLE_USER_REGISTRATION env var optional ([3110c20](https://github.com/standardnotes/auth/commit/3110c20596b52da8a43551432cfef94e68046385))
|
||||
|
||||
# [1.1.0-alpha.4](https://github.com/standardnotes/auth/compare/@standardnotes/auth-server@1.1.0-alpha.3...@standardnotes/auth-server@1.1.0-alpha.4) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -12,6 +12,8 @@ RUN yarn install --immutable
|
||||
|
||||
FROM node:16.15.1-alpine
|
||||
|
||||
RUN apk add --update curl
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy the installed dependencies from the previous stage.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.1.0-alpha.4",
|
||||
"version": "1.1.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -12,6 +12,7 @@
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"setup:env": "cp .env.sample .env",
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc --rootDir ./",
|
||||
"lint": "eslint . --ext .ts",
|
||||
@@ -27,9 +28,8 @@
|
||||
"typeorm": "typeorm-ts-node-commonjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "7.0.2",
|
||||
"@newrelic/winston-enricher": "^2.1.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/analytics": "^1.6.0",
|
||||
"@standardnotes/api": "^1.1.13",
|
||||
"@standardnotes/auth": "^3.19.2",
|
||||
@@ -55,7 +55,7 @@
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.0.6",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "8.6.0",
|
||||
"newrelic": "^8.14.1",
|
||||
"otplib": "12.0.1",
|
||||
"prettyjson": "1.2.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -70,7 +70,7 @@
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/newrelic": "^7.0.2",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/otplib": "^10.0.0",
|
||||
"@types/prettyjson": "^0.0.29",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
|
||||
@@ -357,7 +357,9 @@ export class ContainerConfigLoader {
|
||||
container.bind(TYPES.PSEUDO_KEY_PARAMS_KEY).toConstantValue(env.get('PSEUDO_KEY_PARAMS_KEY'))
|
||||
container.bind(TYPES.EPHEMERAL_SESSION_AGE).toConstantValue(env.get('EPHEMERAL_SESSION_AGE'))
|
||||
container.bind(TYPES.REDIS_URL).toConstantValue(env.get('REDIS_URL'))
|
||||
container.bind(TYPES.DISABLE_USER_REGISTRATION).toConstantValue(env.get('DISABLE_USER_REGISTRATION') === 'true')
|
||||
container
|
||||
.bind(TYPES.DISABLE_USER_REGISTRATION)
|
||||
.toConstantValue(env.get('DISABLE_USER_REGISTRATION', true) === 'true')
|
||||
container.bind(TYPES.ANALYTICS_ENABLED).toConstantValue(env.get('ANALYTICS_ENABLED', true) === 'true')
|
||||
container.bind(TYPES.SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
|
||||
container.bind(TYPES.SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
|
||||
|
||||
@@ -3,6 +3,64 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.4...@standardnotes/files-server@1.1.5) (2022-06-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade sentry node sdk ([b6db194](https://github.com/standardnotes/files/commit/b6db194a22ff1d0afe96c291d545b408c0a5c373))
|
||||
|
||||
## [1.1.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.3...@standardnotes/files-server@1.1.4) (2022-06-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* newrelic deps and setup db and cache for local development purposes ([ff09ae0](https://github.com/standardnotes/files/commit/ff09ae0a47747eaf7977ce5d3937ad385101eaeb))
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.2...@standardnotes/files-server@1.1.3) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* curl in the final image ([0d67c55](https://github.com/standardnotes/files/commit/0d67c55e124eed08bca16824750152b895fceca7))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.1...@standardnotes/files-server@1.1.2) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0...@standardnotes/files-server@1.1.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# [1.1.0](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.6...@standardnotes/files-server@1.1.0) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# [1.1.0-alpha.6](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.5...@standardnotes/files-server@1.1.0-alpha.6) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# [1.1.0-alpha.5](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.4...@standardnotes/files-server@1.1.0-alpha.5) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# [1.1.0-alpha.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.3...@standardnotes/files-server@1.1.0-alpha.4) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing curl to docker image for healthcheck purposes ([7efb48d](https://github.com/standardnotes/files/commit/7efb48dd2a6066c29601d34bfcbfe6231f644c50))
|
||||
|
||||
# [1.1.0-alpha.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.2...@standardnotes/files-server@1.1.0-alpha.3) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# [1.1.0-alpha.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.1...@standardnotes/files-server@1.1.0-alpha.2) (2022-06-23)
|
||||
|
||||
### Features
|
||||
|
||||
* add api-gateway package ([57c3b9c](https://github.com/standardnotes/files/commit/57c3b9c29e5b16449c864e59dbc1fd11689125f9))
|
||||
|
||||
# [1.1.0-alpha.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.1.0-alpha.0...@standardnotes/files-server@1.1.0-alpha.1) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
# 1.1.0-alpha.0 (2022-06-22)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -12,6 +12,8 @@ RUN yarn install --immutable
|
||||
|
||||
FROM node:16.15.1-alpine
|
||||
|
||||
RUN apk add --update curl
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy the installed dependencies from the previous stage.
|
||||
@@ -20,6 +22,6 @@ COPY --from=builder /workspace ./
|
||||
# docker-build plugin runs `yarn pack` in all workspace dependencies and copies them to `packs` folder.
|
||||
COPY packs ./
|
||||
|
||||
ENTRYPOINT [ "/workspace/packages/auth/docker/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/workspace/packages/files/docker/entrypoint.sh" ]
|
||||
|
||||
CMD [ "start-web" ]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.1.0-alpha.0",
|
||||
"version": "1.1.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -14,6 +14,7 @@
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"setup:env": "cp .env.sample .env",
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc --rootDir ./",
|
||||
"lint": "eslint . --ext .ts",
|
||||
@@ -23,8 +24,7 @@
|
||||
"worker": "yarn node dist/bin/worker.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "7.0.2",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/auth": "^3.18.9",
|
||||
"@standardnotes/common": "^1.19.4",
|
||||
"@standardnotes/domain-events": "^2.27.6",
|
||||
@@ -44,7 +44,7 @@
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"ioredis": "^5.0.6",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"newrelic": "^7.3.1",
|
||||
"newrelic": "^8.14.1",
|
||||
"nodemon": "^2.0.15",
|
||||
"prettyjson": "^1.2.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
@@ -59,7 +59,7 @@
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/newrelic": "^7.0.1",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/prettyjson": "^0.0.29",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
|
||||
@@ -3,6 +3,54 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.4...@standardnotes/scheduler-server@1.1.5) (2022-06-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade sentry node sdk ([b6db194](https://github.com/standardnotes/server/commit/b6db194a22ff1d0afe96c291d545b408c0a5c373))
|
||||
|
||||
## [1.1.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.3...@standardnotes/scheduler-server@1.1.4) (2022-06-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* newrelic deps and setup db and cache for local development purposes ([ff09ae0](https://github.com/standardnotes/server/commit/ff09ae0a47747eaf7977ce5d3937ad385101eaeb))
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.2...@standardnotes/scheduler-server@1.1.3) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* curl in the final image ([0d67c55](https://github.com/standardnotes/server/commit/0d67c55e124eed08bca16824750152b895fceca7))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.1...@standardnotes/scheduler-server@1.1.2) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0...@standardnotes/scheduler-server@1.1.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.1.0](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.16...@standardnotes/scheduler-server@1.1.0) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.1.0-alpha.16](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.15...@standardnotes/scheduler-server@1.1.0-alpha.16) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.1.0-alpha.15](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.14...@standardnotes/scheduler-server@1.1.0-alpha.15) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.1.0-alpha.14](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.13...@standardnotes/scheduler-server@1.1.0-alpha.14) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing curl to docker image for healthcheck purposes ([7efb48d](https://github.com/standardnotes/server/commit/7efb48dd2a6066c29601d34bfcbfe6231f644c50))
|
||||
|
||||
# [1.1.0-alpha.13](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.12...@standardnotes/scheduler-server@1.1.0-alpha.13) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
# [1.1.0-alpha.12](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.1.0-alpha.11...@standardnotes/scheduler-server@1.1.0-alpha.12) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -12,6 +12,8 @@ RUN yarn install --immutable
|
||||
|
||||
FROM node:16.15.1-alpine
|
||||
|
||||
RUN apk add --update curl
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy the installed dependencies from the previous stage.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.1.0-alpha.12",
|
||||
"version": "1.1.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -22,8 +22,8 @@
|
||||
"typeorm": "typeorm-ts-node-commonjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "7.0.2",
|
||||
"@newrelic/winston-enricher": "^2.1.0",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/common": "^1.23.0",
|
||||
"@standardnotes/domain-events": "^2.32.0",
|
||||
"@standardnotes/domain-events-infra": "^1.5.0",
|
||||
@@ -35,7 +35,7 @@
|
||||
"inversify": "5.0.5",
|
||||
"ioredis": "^5.0.6",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "8.6.0",
|
||||
"newrelic": "^8.14.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"typeorm": "^0.3.6",
|
||||
"winston": "3.3.3"
|
||||
@@ -43,7 +43,7 @@
|
||||
"devDependencies": {
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/newrelic": "^7.0.2",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
|
||||
@@ -3,6 +3,74 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.5](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.4...@standardnotes/syncing-server@1.1.5) (2022-06-27)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade sentry node sdk ([b6db194](https://github.com/standardnotes/syncing-server-js/commit/b6db194a22ff1d0afe96c291d545b408c0a5c373))
|
||||
|
||||
## [1.1.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.3...@standardnotes/syncing-server@1.1.4) (2022-06-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* newrelic deps and setup db and cache for local development purposes ([ff09ae0](https://github.com/standardnotes/syncing-server-js/commit/ff09ae0a47747eaf7977ce5d3937ad385101eaeb))
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.2...@standardnotes/syncing-server@1.1.3) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* curl in the final image ([0d67c55](https://github.com/standardnotes/syncing-server-js/commit/0d67c55e124eed08bca16824750152b895fceca7))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.1...@standardnotes/syncing-server@1.1.2) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0...@standardnotes/syncing-server@1.1.1) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.10...@standardnotes/syncing-server@1.1.0) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.10](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.9...@standardnotes/syncing-server@1.1.0-alpha.10) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.9](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.8...@standardnotes/syncing-server@1.1.0-alpha.9) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.8](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.7...@standardnotes/syncing-server@1.1.0-alpha.8) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add missing curl to docker image for healthcheck purposes ([7efb48d](https://github.com/standardnotes/syncing-server-js/commit/7efb48dd2a6066c29601d34bfcbfe6231f644c50))
|
||||
|
||||
# [1.1.0-alpha.7](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.6...@standardnotes/syncing-server@1.1.0-alpha.7) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.6](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.5...@standardnotes/syncing-server@1.1.0-alpha.6) (2022-06-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade time lib for syncing-server ([6c87d36](https://github.com/standardnotes/syncing-server-js/commit/6c87d3614dfb77f6d1cb02d3d4c1884f2164693f))
|
||||
|
||||
# [1.1.0-alpha.5](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.4...@standardnotes/syncing-server@1.1.0-alpha.5) (2022-06-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.3...@standardnotes/syncing-server@1.1.0-alpha.4) (2022-06-23)
|
||||
|
||||
### Features
|
||||
|
||||
* add api-gateway package ([57c3b9c](https://github.com/standardnotes/syncing-server-js/commit/57c3b9c29e5b16449c864e59dbc1fd11689125f9))
|
||||
|
||||
# [1.1.0-alpha.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.2...@standardnotes/syncing-server@1.1.0-alpha.3) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
# [1.1.0-alpha.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.1.0-alpha.1...@standardnotes/syncing-server@1.1.0-alpha.2) (2022-06-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -12,6 +12,8 @@ RUN yarn install --immutable
|
||||
|
||||
FROM node:16.15.1-alpine
|
||||
|
||||
RUN apk add --update curl
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy the installed dependencies from the previous stage.
|
||||
@@ -20,6 +22,6 @@ COPY --from=builder /workspace ./
|
||||
# docker-build plugin runs `yarn pack` in all workspace dependencies and copies them to `packs` folder.
|
||||
COPY packs ./
|
||||
|
||||
ENTRYPOINT [ "/workspace/packages/auth/docker/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/workspace/packages/syncing-server/docker/entrypoint.sh" ]
|
||||
|
||||
CMD [ "start-web" ]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.1.0-alpha.2",
|
||||
"version": "1.1.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -12,6 +12,7 @@
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"setup:env": "cp .env.sample .env",
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc --rootDir ./",
|
||||
"lint": "eslint . --ext .ts",
|
||||
@@ -21,9 +22,8 @@
|
||||
"worker": "yarn node dist/bin/worker.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "7.0.2",
|
||||
"@newrelic/winston-enricher": "^2.1.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/analytics": "^1.6.0",
|
||||
"@standardnotes/auth": "^3.19.2",
|
||||
"@standardnotes/common": "^1.22.0",
|
||||
@@ -32,7 +32,7 @@
|
||||
"@standardnotes/payloads": "^1.5.1",
|
||||
"@standardnotes/responses": "^1.6.15",
|
||||
"@standardnotes/settings": "1.14.3",
|
||||
"@standardnotes/time": "^1.7.0",
|
||||
"@standardnotes/time": "^1.7.1",
|
||||
"aws-sdk": "^2.1159.0",
|
||||
"axios": "0.24.0",
|
||||
"cors": "2.8.5",
|
||||
@@ -44,7 +44,7 @@
|
||||
"ioredis": "^5.0.6",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"mysql2": "^2.3.3",
|
||||
"newrelic": "8.6.0",
|
||||
"newrelic": "^8.14.1",
|
||||
"nodemon": "2.0.7",
|
||||
"prettyjson": "1.2.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -61,7 +61,7 @@
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/jsonwebtoken": "^8.5.0",
|
||||
"@types/newrelic": "^7.0.2",
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/prettyjson": "^0.0.29",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/uuid": "^8.3.0",
|
||||
|
||||
16
scripts/push-tags-one-by-one.sh
Executable file
16
scripts/push-tags-one-by-one.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
# source: https://github.com/lerna/lerna/issues/2218#issuecomment-771876933
|
||||
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
|
||||
# > "Note: An event will not be created when you create more than three tags at once."
|
||||
# GitHub workflows will not run if a commit includes more than 3 tags at once. This
|
||||
# fix pushes tags up one by one.
|
||||
|
||||
# get all tags on this commit
|
||||
TAGS=$(git tag --points-at HEAD | cat)
|
||||
|
||||
# only push tags one by one if there are more than 3
|
||||
if (($(echo "$TAGS"| wc -l) > 3))
|
||||
then
|
||||
echo "Pushing tags one by one to avoid GitHub webhook limit of 3"
|
||||
echo "$TAGS" | while read line ; do git push origin --no-follow-tags $line; done
|
||||
fi
|
||||
@@ -33,6 +33,9 @@
|
||||
},
|
||||
{
|
||||
"path": "./packages/files"
|
||||
},
|
||||
{
|
||||
"path": "./packages/api-gateway"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
388
yarn.lock
388
yarn.lock
@@ -629,7 +629,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/grpc-js@npm:^1.2.11, @grpc/grpc-js@npm:^1.5.5":
|
||||
"@grpc/grpc-js@npm:^1.5.5":
|
||||
version: 1.6.7
|
||||
resolution: "@grpc/grpc-js@npm:1.6.7"
|
||||
dependencies:
|
||||
@@ -639,16 +639,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/proto-loader@npm:^0.5.6":
|
||||
version: 0.5.6
|
||||
resolution: "@grpc/proto-loader@npm:0.5.6"
|
||||
dependencies:
|
||||
lodash.camelcase: ^4.3.0
|
||||
protobufjs: ^6.8.6
|
||||
checksum: 13fe76d84ab1a516f3dc47d06df4dd682f6f1515a7a4aa3f8cddcc8f8256f33cbf529bd0b6729946f548f7459acfcd9b5b026c10572e21d40213a358115658b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/proto-loader@npm:^0.6.13, @grpc/proto-loader@npm:^0.6.4":
|
||||
version: 0.6.13
|
||||
resolution: "@grpc/proto-loader@npm:0.6.13"
|
||||
@@ -1218,16 +1208,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/aws-sdk@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "@newrelic/aws-sdk@npm:3.1.0"
|
||||
peerDependencies:
|
||||
newrelic: ">=6.11.0"
|
||||
checksum: 5601d90c78f82d3216d9cacb664c7a74c1b06acfff44471e758a878a36345ac46449896f9ea4a0b44673b7a72308ee7717d999c184e6e87f3478d5b2d3a14d0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/aws-sdk@npm:^4.0.1, @newrelic/aws-sdk@npm:^4.1.1":
|
||||
"@newrelic/aws-sdk@npm:^4.1.1":
|
||||
version: 4.1.2
|
||||
resolution: "@newrelic/aws-sdk@npm:4.1.2"
|
||||
dependencies:
|
||||
@@ -1238,18 +1219,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/koa@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "@newrelic/koa@npm:5.0.0"
|
||||
dependencies:
|
||||
methods: ^1.1.2
|
||||
peerDependencies:
|
||||
newrelic: ">=6.11.0"
|
||||
checksum: e98d921b96d043817b623bf83752bdae4e8ca9e594e47ad23109cb516d9a8715ca4b79e4949c5fc5e76ca806d99b2e46e2b7afa2861e0af408f6d647b18f292f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/koa@npm:^6.0.1, @newrelic/koa@npm:^6.1.1":
|
||||
"@newrelic/koa@npm:^6.1.1":
|
||||
version: 6.1.2
|
||||
resolution: "@newrelic/koa@npm:6.1.2"
|
||||
peerDependencies:
|
||||
@@ -1258,40 +1228,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/native-metrics@npm:7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "@newrelic/native-metrics@npm:7.0.2"
|
||||
dependencies:
|
||||
nan: ^2.14.2
|
||||
node-gyp: latest
|
||||
semver: ^5.5.1
|
||||
checksum: 501805d29fc5be83a34b5f9b78f9e9b9ccc7ba047ad8dc77a3da90d7606e260607536795b0c75c242880bdd8bb40464f870f82fe4b2cd6b1503576a01aca5269
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/native-metrics@npm:^6.0.0":
|
||||
version: 6.0.2
|
||||
resolution: "@newrelic/native-metrics@npm:6.0.2"
|
||||
dependencies:
|
||||
nan: ^2.14.2
|
||||
node-gyp: latest
|
||||
semver: ^5.5.1
|
||||
checksum: 78f92bbe7feb662699b1a148a869b3d963653a16d3c6ffc63159c4b8bea7905e26140e55631444e167dbd4291e6b7c2261bcd3ce4b8917852fe1d92ffb3936f9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/native-metrics@npm:^7.0.1":
|
||||
version: 7.1.2
|
||||
resolution: "@newrelic/native-metrics@npm:7.1.2"
|
||||
dependencies:
|
||||
https-proxy-agent: ^5.0.0
|
||||
nan: ^2.15.0
|
||||
node-gyp: latest
|
||||
semver: ^5.5.1
|
||||
checksum: c8358b5e6170ed2a32cf14b557f0a2c0d1d836c82a80e1be23e2b2f427a54104fc8a99c59c8d4ebf13fb057eca20ddf5ba3f49657d53d51f1afb846b390fbf91
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/native-metrics@npm:^8.0.0":
|
||||
version: 8.0.0
|
||||
resolution: "@newrelic/native-metrics@npm:8.0.0"
|
||||
@@ -1304,18 +1240,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/superagent@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "@newrelic/superagent@npm:4.0.0"
|
||||
dependencies:
|
||||
methods: ^1.1.2
|
||||
peerDependencies:
|
||||
newrelic: ">=6.11.0"
|
||||
checksum: 5fb257ac0530f91bae58265678500c96c28f164bd6fcec5c0dff51958c8e72bc721dd04d1d2c48bace9e077b57b233c47efb8af61f2a005b71d4636e29ae9728
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@newrelic/superagent@npm:^5.0.1, @newrelic/superagent@npm:^5.1.0":
|
||||
"@newrelic/superagent@npm:^5.1.0":
|
||||
version: 5.1.1
|
||||
resolution: "@newrelic/superagent@npm:5.1.1"
|
||||
peerDependencies:
|
||||
@@ -1729,71 +1654,59 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/core@npm:6.19.7":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/core@npm:6.19.7"
|
||||
"@sentry/core@npm:7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "@sentry/core@npm:7.3.0"
|
||||
dependencies:
|
||||
"@sentry/hub": 6.19.7
|
||||
"@sentry/minimal": 6.19.7
|
||||
"@sentry/types": 6.19.7
|
||||
"@sentry/utils": 6.19.7
|
||||
"@sentry/hub": 7.3.0
|
||||
"@sentry/types": 7.3.0
|
||||
"@sentry/utils": 7.3.0
|
||||
tslib: ^1.9.3
|
||||
checksum: d212e8ef07114549de4a93b81f8bfa217ca1550ca7a5eeaa611e5629faef78ff72663ce561ffa2cff48f3dc556745ef65177044f9965cdd3cbccf617cf3bf675
|
||||
checksum: 176856840462c881c9a2ea30c5af209b64516201e5d7978e3960473fead6fc10547c556185e3636a2eade6856b293d190212825f9e8ff6fe4331fcdb0f6c213a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/hub@npm:6.19.7":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/hub@npm:6.19.7"
|
||||
"@sentry/hub@npm:7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "@sentry/hub@npm:7.3.0"
|
||||
dependencies:
|
||||
"@sentry/types": 6.19.7
|
||||
"@sentry/utils": 6.19.7
|
||||
"@sentry/types": 7.3.0
|
||||
"@sentry/utils": 7.3.0
|
||||
tslib: ^1.9.3
|
||||
checksum: 10bb1c5cba1b0f1e27a3dd0a186c22f94aeaf11c4662890ab07b2774f46f46af78d61e3ba71d76edc750a7b45af86edd032f35efecdb4efa2eaf551080ccdcb1
|
||||
checksum: a052a7c940e1f6af16ca2c61f1e184eaf0d7874598ec4eae3a28c8b5ea6a19cf3b89106768aaeea19deb9816bdd316ec0218764c2e66cc92a87e2e404d6e0dd6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/minimal@npm:6.19.7":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/minimal@npm:6.19.7"
|
||||
"@sentry/node@npm:^7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "@sentry/node@npm:7.3.0"
|
||||
dependencies:
|
||||
"@sentry/hub": 6.19.7
|
||||
"@sentry/types": 6.19.7
|
||||
tslib: ^1.9.3
|
||||
checksum: 9153ac426ee056fc34c5be898f83d74ec08f559d69f544c5944ec05e584b62ed356b92d1a9b08993a7022ad42b5661c3d72881221adc19bee5fc1af3ad3864a8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/node@npm:^6.16.1":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/node@npm:6.19.7"
|
||||
dependencies:
|
||||
"@sentry/core": 6.19.7
|
||||
"@sentry/hub": 6.19.7
|
||||
"@sentry/types": 6.19.7
|
||||
"@sentry/utils": 6.19.7
|
||||
"@sentry/core": 7.3.0
|
||||
"@sentry/hub": 7.3.0
|
||||
"@sentry/types": 7.3.0
|
||||
"@sentry/utils": 7.3.0
|
||||
cookie: ^0.4.1
|
||||
https-proxy-agent: ^5.0.0
|
||||
lru_map: ^0.3.3
|
||||
tslib: ^1.9.3
|
||||
checksum: 2293b0d1d1f9fac3a451eb94f820bc27721c8edddd1f373064666ddd6272f0a4c70dbe58c6c4b3d3ccaf4578aab8f466d71ee69f6f6ff93521bbb02dfe829ce5
|
||||
checksum: a92c2d2d1b05136b3c04f39cb87bf459519619c7e4f548f4e2a34145e868edd1ccdd505bcf5d3ff56872ea994530c263deb7ce4c498e9f4e39111c5fcacd342f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/types@npm:6.19.7":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/types@npm:6.19.7"
|
||||
checksum: f46ef74a33376ad6ea9b128115515c58eb9369d89293c60aa67abca26b5d5d519aa4d0a736db56ae0d75ffd816643d62187018298523cbc2e6c2fb3a6b2a9035
|
||||
"@sentry/types@npm:7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "@sentry/types@npm:7.3.0"
|
||||
checksum: 3ddbc3c7ebf2caad2d97a4c7a25f14791f642f7baadfa3c02857e433c0377ca7e6df4d3fc7e197717f2d6f8fca876178d01c827b5c1b42adba92115c62e18daf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sentry/utils@npm:6.19.7":
|
||||
version: 6.19.7
|
||||
resolution: "@sentry/utils@npm:6.19.7"
|
||||
"@sentry/utils@npm:7.3.0":
|
||||
version: 7.3.0
|
||||
resolution: "@sentry/utils@npm:7.3.0"
|
||||
dependencies:
|
||||
"@sentry/types": 6.19.7
|
||||
"@sentry/types": 7.3.0
|
||||
tslib: ^1.9.3
|
||||
checksum: a000223b9c646c64e3565e79cace1eeb75114342b768367c4dddd646476c215eb1bddfb70c63f05e2352d3bce2d7d415344e4757a001605d0e01ac74da5dd306
|
||||
checksum: 2696b1bfad1ad2e8e2aa7dd822fb0546d680b06aa302c3a8e8c8da0577fb9938da094f3eda589b2a1c216e1c84a81a5119b30136fd013de9c3a4513aece55d05
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1836,13 +1749,54 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/analytics@npm:^1.6.0":
|
||||
"@standardnotes/analytics@npm:^1.4.0, @standardnotes/analytics@npm:^1.6.0":
|
||||
version: 1.6.0
|
||||
resolution: "@standardnotes/analytics@npm:1.6.0"
|
||||
checksum: 6a5e86152673ce9ddce43c52b5f699a1b3ba5141e58a944bda8eaa88fc2f4169df27239f82633226752bf3f10f9804f426721b9c919d10fbfbb51f952430eb1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/api-gateway@workspace:packages/api-gateway":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway"
|
||||
dependencies:
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": ^1.4.0
|
||||
"@standardnotes/auth": 3.19.2
|
||||
"@standardnotes/domain-events": 2.29.0
|
||||
"@standardnotes/domain-events-infra": 1.4.127
|
||||
"@standardnotes/time": ^1.7.0
|
||||
"@types/cors": ^2.8.9
|
||||
"@types/express": ^4.17.11
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.3
|
||||
"@types/jsonwebtoken": ^8.5.0
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/prettyjson": ^0.0.29
|
||||
"@typescript-eslint/eslint-plugin": ^5.29.0
|
||||
aws-sdk: ^2.1160.0
|
||||
axios: 0.24.0
|
||||
cors: 2.8.5
|
||||
dotenv: 8.2.0
|
||||
eslint: ^8.14.0
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
express: 4.17.1
|
||||
helmet: 4.4.1
|
||||
inversify: ^6.0.1
|
||||
inversify-express-utils: ^6.4.3
|
||||
ioredis: ^5.0.6
|
||||
jest: ^28.1.1
|
||||
jsonwebtoken: 8.5.1
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.16
|
||||
prettyjson: 1.2.1
|
||||
reflect-metadata: 0.1.13
|
||||
ts-jest: ^28.0.1
|
||||
winston: 3.3.3
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/api@npm:^1.1.13":
|
||||
version: 1.1.13
|
||||
resolution: "@standardnotes/api@npm:1.1.13"
|
||||
@@ -1861,9 +1815,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/auth-server@workspace:packages/auth"
|
||||
dependencies:
|
||||
"@newrelic/native-metrics": 7.0.2
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@sentry/node": ^6.16.1
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": ^1.6.0
|
||||
"@standardnotes/api": ^1.1.13
|
||||
"@standardnotes/auth": ^3.19.2
|
||||
@@ -1882,7 +1835,7 @@ __metadata:
|
||||
"@types/express": ^4.17.11
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.3
|
||||
"@types/newrelic": ^7.0.2
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/otplib": ^10.0.0
|
||||
"@types/prettyjson": ^0.0.29
|
||||
"@types/ua-parser-js": ^0.7.36
|
||||
@@ -1903,7 +1856,7 @@ __metadata:
|
||||
ioredis: ^5.0.6
|
||||
jest: ^28.1.1
|
||||
mysql2: ^2.3.3
|
||||
newrelic: 8.6.0
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.16
|
||||
otplib: 12.0.1
|
||||
prettyjson: 1.2.1
|
||||
@@ -1916,6 +1869,16 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/auth@npm:3.19.2":
|
||||
version: 3.19.2
|
||||
resolution: "@standardnotes/auth@npm:3.19.2"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.22.0
|
||||
jsonwebtoken: ^8.5.1
|
||||
checksum: 2e4b37b3034ca561e42525313c5ddf66249d27da4c423738241fb3f59f8ea990eafb60b113e648fa6904c171e3c86e93abffb7e72a52bb17b0eb6c9025427678
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/auth@npm:^3.18.9, @standardnotes/auth@npm:^3.19.2, @standardnotes/auth@npm:^3.19.3":
|
||||
version: 3.19.3
|
||||
resolution: "@standardnotes/auth@npm:3.19.3"
|
||||
@@ -1943,6 +1906,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/domain-events-infra@npm:1.4.127":
|
||||
version: 1.4.127
|
||||
resolution: "@standardnotes/domain-events-infra@npm:1.4.127"
|
||||
dependencies:
|
||||
"@standardnotes/domain-events": ^2.29.0
|
||||
aws-sdk: ^2.1082.0
|
||||
ioredis: ^4.28.5
|
||||
newrelic: ^8.8.0
|
||||
reflect-metadata: ^0.1.13
|
||||
sqs-consumer: ^5.6.0
|
||||
winston: ^3.6.0
|
||||
checksum: 54e37c296ff3b44adc8d425f89fd56eb42d435dded6b04a952ff77ebb867022585bb472635f488863c9f9b6493a04592593f7a0f2bfa1d86bb9354ba341d350f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/domain-events-infra@npm:^1.4.135, @standardnotes/domain-events-infra@npm:^1.4.93, @standardnotes/domain-events-infra@npm:^1.5.0, @standardnotes/domain-events-infra@npm:^1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@standardnotes/domain-events-infra@npm:1.5.2"
|
||||
@@ -1958,7 +1936,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/domain-events@npm:^2.27.6, @standardnotes/domain-events@npm:^2.31.1, @standardnotes/domain-events@npm:^2.32.0, @standardnotes/domain-events@npm:^2.32.2":
|
||||
"@standardnotes/domain-events@npm:2.29.0":
|
||||
version: 2.29.0
|
||||
resolution: "@standardnotes/domain-events@npm:2.29.0"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.2
|
||||
"@standardnotes/features": ^1.44.6
|
||||
checksum: 1b68999e2a7a6a26a9ecd27638cbb878bd4abb987a1a3b254136af0bec5619d4f5f99ede1b27cf93561fd6d6453f645310b5decfe468c8dd644363caed48aeb9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/domain-events@npm:^2.27.6, @standardnotes/domain-events@npm:^2.29.0, @standardnotes/domain-events@npm:^2.31.1, @standardnotes/domain-events@npm:^2.32.0, @standardnotes/domain-events@npm:^2.32.2":
|
||||
version: 2.32.2
|
||||
resolution: "@standardnotes/domain-events@npm:2.32.2"
|
||||
dependencies:
|
||||
@@ -1980,7 +1968,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/features@npm:^1.36.3, @standardnotes/features@npm:^1.45.2, @standardnotes/features@npm:^1.45.5":
|
||||
"@standardnotes/features@npm:^1.36.3, @standardnotes/features@npm:^1.44.6, @standardnotes/features@npm:^1.45.2, @standardnotes/features@npm:^1.45.5":
|
||||
version: 1.45.5
|
||||
resolution: "@standardnotes/features@npm:1.45.5"
|
||||
dependencies:
|
||||
@@ -1994,8 +1982,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/files-server@workspace:packages/files"
|
||||
dependencies:
|
||||
"@newrelic/native-metrics": 7.0.2
|
||||
"@sentry/node": ^6.16.1
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/auth": ^3.18.9
|
||||
"@standardnotes/common": ^1.19.4
|
||||
"@standardnotes/config": 2.0.1
|
||||
@@ -2010,7 +1997,7 @@ __metadata:
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.3
|
||||
"@types/jsonwebtoken": ^8.5.0
|
||||
"@types/newrelic": ^7.0.1
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/prettyjson": ^0.0.29
|
||||
"@types/uuid": ^8.3.0
|
||||
"@typescript-eslint/eslint-plugin": ^5.29.0
|
||||
@@ -2029,7 +2016,7 @@ __metadata:
|
||||
ioredis: ^5.0.6
|
||||
jest: ^28.1.1
|
||||
jsonwebtoken: ^8.5.1
|
||||
newrelic: ^7.3.1
|
||||
newrelic: ^8.14.1
|
||||
nodemon: ^2.0.16
|
||||
prettyjson: ^1.2.1
|
||||
reflect-metadata: ^0.1.13
|
||||
@@ -2077,8 +2064,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/scheduler-server@workspace:packages/scheduler"
|
||||
dependencies:
|
||||
"@newrelic/native-metrics": 7.0.2
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/common": ^1.23.0
|
||||
"@standardnotes/domain-events": ^2.32.0
|
||||
"@standardnotes/domain-events-infra": ^1.5.0
|
||||
@@ -2086,7 +2073,7 @@ __metadata:
|
||||
"@standardnotes/time": ^1.7.0
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.2
|
||||
"@types/newrelic": ^7.0.2
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/node": ^18.0.0
|
||||
"@typescript-eslint/eslint-plugin": ^5.29.0
|
||||
aws-sdk: ^2.1158.0
|
||||
@@ -2097,7 +2084,7 @@ __metadata:
|
||||
ioredis: ^5.0.6
|
||||
jest: ^28.1.1
|
||||
mysql2: ^2.3.3
|
||||
newrelic: 8.6.0
|
||||
newrelic: ^8.14.1
|
||||
reflect-metadata: ^0.1.13
|
||||
ts-jest: ^28.0.5
|
||||
typeorm: ^0.3.6
|
||||
@@ -2123,10 +2110,14 @@ __metadata:
|
||||
"@lerna-lite/cli": ^1.5.1
|
||||
"@lerna-lite/list": ^1.5.1
|
||||
"@lerna-lite/run": ^1.5.1
|
||||
"@sentry/node": ^7.3.0
|
||||
"@types/jest": ^28.1.3
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/node": ^18.0.0
|
||||
"@typescript-eslint/parser": ^5.29.0
|
||||
eslint: ^8.17.0
|
||||
eslint-config-prettier: ^8.5.0
|
||||
newrelic: ^8.14.1
|
||||
prettier: ^2.7.1
|
||||
ts-node: ^10.8.1
|
||||
typescript: ^4.7.4
|
||||
@@ -2173,9 +2164,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/syncing-server@workspace:packages/syncing-server"
|
||||
dependencies:
|
||||
"@newrelic/native-metrics": 7.0.2
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@sentry/node": ^6.16.1
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": ^1.6.0
|
||||
"@standardnotes/auth": ^3.19.2
|
||||
"@standardnotes/common": ^1.22.0
|
||||
@@ -2184,7 +2174,7 @@ __metadata:
|
||||
"@standardnotes/payloads": ^1.5.1
|
||||
"@standardnotes/responses": ^1.6.15
|
||||
"@standardnotes/settings": 1.14.3
|
||||
"@standardnotes/time": ^1.7.0
|
||||
"@standardnotes/time": ^1.7.1
|
||||
"@types/cors": ^2.8.9
|
||||
"@types/dotenv": ^8.2.0
|
||||
"@types/express": ^4.17.9
|
||||
@@ -2192,7 +2182,7 @@ __metadata:
|
||||
"@types/ioredis": ^4.28.10
|
||||
"@types/jest": ^28.1.3
|
||||
"@types/jsonwebtoken": ^8.5.0
|
||||
"@types/newrelic": ^7.0.2
|
||||
"@types/newrelic": ^7.0.3
|
||||
"@types/prettyjson": ^0.0.29
|
||||
"@types/ua-parser-js": ^0.7.36
|
||||
"@types/uuid": ^8.3.0
|
||||
@@ -2211,7 +2201,7 @@ __metadata:
|
||||
jest: ^28.1.1
|
||||
jsonwebtoken: 8.5.1
|
||||
mysql2: ^2.3.3
|
||||
newrelic: 8.6.0
|
||||
newrelic: ^8.14.1
|
||||
nodemon: 2.0.7
|
||||
prettyjson: 1.2.1
|
||||
reflect-metadata: 0.1.13
|
||||
@@ -2234,6 +2224,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/time@npm:^1.7.1":
|
||||
version: 1.7.1
|
||||
resolution: "@standardnotes/time@npm:1.7.1"
|
||||
dependencies:
|
||||
dayjs: ^1.10.8
|
||||
microtime: ^3.1.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: ccb9c4af73d2c77d5b1cfea480930e3a30e87fb426eee3c60eb0ce0f259fa5c1f9b1b29fdc52c72d321821791e3bdc141e4af0bfc668662863012743332c5407
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/utils@npm:^1.4.6, @standardnotes/utils@npm:^1.6.11":
|
||||
version: 1.6.11
|
||||
resolution: "@standardnotes/utils@npm:1.6.11"
|
||||
@@ -2547,7 +2548,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/newrelic@npm:^7.0.1, @types/newrelic@npm:^7.0.2":
|
||||
"@types/newrelic@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "@types/newrelic@npm:7.0.3"
|
||||
checksum: 31156f61c5cf6c22e3cd227966499d758e4af278a2b0097194578feee9579339473f7a08b07556530046a2f64ba449656a220a553116b475c4bbd8cca177dfd3
|
||||
@@ -2953,13 +2954,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"agent-base@npm:5":
|
||||
version: 5.1.1
|
||||
resolution: "agent-base@npm:5.1.1"
|
||||
checksum: 61ae789f3019f1dc10e8cba6d3ae9826949299a4e54aaa1cfa2fa37c95a108e70e95423b963bb987d7891a703fd9a5c383a506f4901819f3ee56f3147c0aa8ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"agent-base@npm:6, agent-base@npm:^6.0.2":
|
||||
version: 6.0.2
|
||||
resolution: "agent-base@npm:6.0.2"
|
||||
@@ -3158,7 +3152,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"async@npm:^3.1.0, async@npm:^3.2.0, async@npm:^3.2.3, async@npm:^3.2.4":
|
||||
"async@npm:^3.1.0, async@npm:^3.2.3, async@npm:^3.2.4":
|
||||
version: 3.2.4
|
||||
resolution: "async@npm:3.2.4"
|
||||
checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89
|
||||
@@ -3216,6 +3210,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aws-sdk@npm:^2.1160.0":
|
||||
version: 2.1160.0
|
||||
resolution: "aws-sdk@npm:2.1160.0"
|
||||
dependencies:
|
||||
buffer: 4.9.2
|
||||
events: 1.1.1
|
||||
ieee754: 1.1.13
|
||||
jmespath: 0.16.0
|
||||
querystring: 0.2.0
|
||||
sax: 1.2.1
|
||||
url: 0.10.3
|
||||
uuid: 8.0.0
|
||||
xml2js: 0.4.19
|
||||
checksum: b95647d4de6d07fc7b62ef409d1dd4a915f3711163a4da4057a3451d62b56818f4ea3d7970c2735af376c44a97d603190f2d85c2a11911eb6f97334ad0ace4a7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"axios@npm:0.24.0":
|
||||
version: 0.24.0
|
||||
resolution: "axios@npm:0.24.0"
|
||||
@@ -5696,6 +5707,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"helmet@npm:4.4.1":
|
||||
version: 4.4.1
|
||||
resolution: "helmet@npm:4.4.1"
|
||||
checksum: cfe385e185e1ef6e4cd2ade4c54e160b05dd0454f270a663c528a8666402cbcad14e0ff0df09567fa62b0b4ac3371bbd1c8a253f6e7af37656a22339fe98c869
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"helmet@npm:^4.3.1":
|
||||
version: 4.6.0
|
||||
resolution: "helmet@npm:4.6.0"
|
||||
@@ -5817,16 +5835,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-proxy-agent@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "https-proxy-agent@npm:4.0.0"
|
||||
dependencies:
|
||||
agent-base: 5
|
||||
debug: 4
|
||||
checksum: 19471d5aae3e747b1c98b17556647e2a1362e68220c6b19585a8527498f32e62e03c41d2872d059d8720d56846bd7460a80ac06f876bccfa786468ff40dd5eef
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-proxy-agent@npm:^5.0.0":
|
||||
version: 5.0.1
|
||||
resolution: "https-proxy-agent@npm:5.0.1"
|
||||
@@ -7471,7 +7479,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"methods@npm:^1.1.2, methods@npm:~1.1.2":
|
||||
"methods@npm:~1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "methods@npm:1.1.2"
|
||||
checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a
|
||||
@@ -7488,7 +7496,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"microtime@npm:^3.0.0":
|
||||
"microtime@npm:^3.0.0, microtime@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "microtime@npm:3.1.0"
|
||||
dependencies:
|
||||
@@ -7776,7 +7784,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nan@npm:^2.14.2, nan@npm:^2.15.0":
|
||||
"nan@npm:^2.15.0":
|
||||
version: 2.16.0
|
||||
resolution: "nan@npm:2.16.0"
|
||||
dependencies:
|
||||
@@ -7806,59 +7814,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"newrelic@npm:8.6.0":
|
||||
version: 8.6.0
|
||||
resolution: "newrelic@npm:8.6.0"
|
||||
dependencies:
|
||||
"@grpc/grpc-js": ^1.2.11
|
||||
"@grpc/proto-loader": ^0.5.6
|
||||
"@newrelic/aws-sdk": ^4.0.1
|
||||
"@newrelic/koa": ^6.0.1
|
||||
"@newrelic/native-metrics": ^7.0.1
|
||||
"@newrelic/superagent": ^5.0.1
|
||||
"@tyriar/fibonacci-heap": ^2.0.7
|
||||
async: ^3.2.0
|
||||
concat-stream: ^2.0.0
|
||||
https-proxy-agent: ^5.0.0
|
||||
json-stringify-safe: ^5.0.0
|
||||
readable-stream: ^3.6.0
|
||||
semver: ^5.3.0
|
||||
dependenciesMeta:
|
||||
"@newrelic/native-metrics":
|
||||
optional: true
|
||||
bin:
|
||||
newrelic-naming-rules: bin/test-naming-rules.js
|
||||
checksum: 083b65ce8b01b365e901ca3fe989d55fad10157af9df62f3b8b6d2204bedc5b08abde9c1aec4cb8bc0682b60083b1cdc03febd8d95d5f6ee4199aaca4cad24be
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"newrelic@npm:^7.3.1":
|
||||
version: 7.5.2
|
||||
resolution: "newrelic@npm:7.5.2"
|
||||
dependencies:
|
||||
"@grpc/grpc-js": ^1.2.11
|
||||
"@grpc/proto-loader": ^0.5.6
|
||||
"@newrelic/aws-sdk": ^3.1.0
|
||||
"@newrelic/koa": ^5.0.0
|
||||
"@newrelic/native-metrics": ^6.0.0
|
||||
"@newrelic/superagent": ^4.0.0
|
||||
"@tyriar/fibonacci-heap": ^2.0.7
|
||||
async: ^3.2.0
|
||||
concat-stream: ^2.0.0
|
||||
https-proxy-agent: ^4.0.0
|
||||
json-stringify-safe: ^5.0.0
|
||||
readable-stream: ^3.6.0
|
||||
semver: ^5.3.0
|
||||
dependenciesMeta:
|
||||
"@newrelic/native-metrics":
|
||||
optional: true
|
||||
bin:
|
||||
newrelic-naming-rules: bin/test-naming-rules.js
|
||||
checksum: f6c67dbb7dfc265eaf46ece7bb5fc0fdab4cdb84010be724f52e5d903474d1c108a35f743a801c0f9ef2a3fa9d1c1c17a1b32bf091f3d4f1fcd323d8130a1e36
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"newrelic@npm:^8.8.0":
|
||||
"newrelic@npm:^8.14.1, newrelic@npm:^8.8.0":
|
||||
version: 8.14.1
|
||||
resolution: "newrelic@npm:8.14.1"
|
||||
dependencies:
|
||||
@@ -8813,7 +8769,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"protobufjs@npm:^6.11.3, protobufjs@npm:^6.8.6":
|
||||
"protobufjs@npm:^6.11.3":
|
||||
version: 6.11.3
|
||||
resolution: "protobufjs@npm:6.11.3"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user