feat: add api-gateway package
This commit is contained in:
parent
b25f2e8c54
commit
57c3b9c29e
53 changed files with 2537 additions and 195 deletions
125
.github/workflows/api-gateway.release.dev.yml
vendored
Normal file
125
.github/workflows/api-gateway.release.dev.yml
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
name: Api Gateway Dev
|
||||
|
||||
concurrency:
|
||||
group: api_gateway_dev_environment
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '@standardnotes/api-gateway@[0-9]*.[0-9]*.[0-9]*-alpha.[0-9]*'
|
||||
- '@standardnotes/api-gateway@[0-9]*.[0-9]*.[0-9]*-beta.[0-9]*'
|
||||
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@v2
|
||||
- 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:dev
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:dev
|
||||
|
||||
publish-docker-hub:
|
||||
needs: test
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Publish to Registry
|
||||
uses: elgohr/Publish-Docker-Github-Action@master
|
||||
with:
|
||||
name: standardnotes/api-gateway
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
tags: "dev,${{ github.sha }}"
|
||||
|
||||
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: Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition api-gateway-dev --query taskDefinition > task-definition.json
|
||||
- name: 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: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
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: Deploy Amazon ECS task definition
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
service: api-gateway-dev
|
||||
cluster: dev
|
||||
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_DEV }}
|
||||
revision: "${{ github.sha }}"
|
||||
description: "Automated Deployment via Github Actions"
|
||||
user: "${{ github.actor }}"
|
||||
|
||||
notify_discord:
|
||||
needs: deploy-web
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Run Discord Webhook
|
||||
uses: johnnyhuy/actions-discord-git-webhook@main
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
2
.github/workflows/files.release.dev.yml
vendored
2
.github/workflows/files.release.dev.yml
vendored
|
@ -46,7 +46,7 @@ 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
|
||||
|
|
482
.pnp.cjs
generated
482
.pnp.cjs
generated
|
@ -20,6 +20,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"name": "@standardnotes/server-monorepo",\
|
||||
"reference": "workspace:."\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/api-gateway",\
|
||||
"reference": "workspace:packages/api-gateway"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/auth-server",\
|
||||
"reference": "workspace:packages/auth"\
|
||||
|
@ -40,6 +44,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"enableTopLevelFallback": true,\
|
||||
"ignorePatternData": "(^(?:\\\\.yarn\\\\/sdks(?:\\\\/(?!\\\\.{1,2}(?:\\\\/|$))(?:(?:(?!(?:^|\\\\/)\\\\.{1,2}(?:\\\\/|$)).)*?)|$))$)",\
|
||||
"fallbackExclusionList": [\
|
||||
["@standardnotes/api-gateway", ["workspace:packages/api-gateway"]],\
|
||||
["@standardnotes/auth-server", ["workspace:packages/auth"]],\
|
||||
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
||||
["@standardnotes/scheduler-server", ["workspace:packages/scheduler"]],\
|
||||
|
@ -307,10 +312,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-async-generators-virtual-1c91e87c25/0/cache/@babel-plugin-syntax-async-generators-npm-7.8.4-d10cf993c9-7ed1c1d9b9.zip/node_modules/@babel/plugin-syntax-async-generators/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-async-generators-virtual-20dc503383/0/cache/@babel-plugin-syntax-async-generators-npm-7.8.4-d10cf993c9-7ed1c1d9b9.zip/node_modules/@babel/plugin-syntax-async-generators/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-async-generators", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.4"],\
|
||||
["@babel/plugin-syntax-async-generators", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.4"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -344,10 +349,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-bigint-virtual-62067a9335/0/cache/@babel-plugin-syntax-bigint-npm-7.8.3-b05d971e6c-3a10849d83.zip/node_modules/@babel/plugin-syntax-bigint/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-bigint-virtual-f9f6a1f31a/0/cache/@babel-plugin-syntax-bigint-npm-7.8.3-b05d971e6c-3a10849d83.zip/node_modules/@babel/plugin-syntax-bigint/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-bigint", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-bigint", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -381,10 +386,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.12.13", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-class-properties-virtual-c73477fb62/0/cache/@babel-plugin-syntax-class-properties-npm-7.12.13-002ee9d930-24f34b196d.zip/node_modules/@babel/plugin-syntax-class-properties/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.12.13", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-class-properties-virtual-d36699afc2/0/cache/@babel-plugin-syntax-class-properties-npm-7.12.13-002ee9d930-24f34b196d.zip/node_modules/@babel/plugin-syntax-class-properties/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-class-properties", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.12.13"],\
|
||||
["@babel/plugin-syntax-class-properties", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.12.13"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -418,10 +423,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-import-meta-virtual-f94e1adec9/0/cache/@babel-plugin-syntax-import-meta-npm-7.10.4-4a0a0158bc-166ac1125d.zip/node_modules/@babel/plugin-syntax-import-meta/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-import-meta-virtual-f872deb0c7/0/cache/@babel-plugin-syntax-import-meta-npm-7.10.4-4a0a0158bc-166ac1125d.zip/node_modules/@babel/plugin-syntax-import-meta/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-import-meta", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-import-meta", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -455,10 +460,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-json-strings-virtual-b788fe66a9/0/cache/@babel-plugin-syntax-json-strings-npm-7.8.3-6dc7848179-bf5aea1f31.zip/node_modules/@babel/plugin-syntax-json-strings/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-json-strings-virtual-b38277fec2/0/cache/@babel-plugin-syntax-json-strings-npm-7.8.3-6dc7848179-bf5aea1f31.zip/node_modules/@babel/plugin-syntax-json-strings/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-json-strings", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-json-strings", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -492,10 +497,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-logical-assignment-operators-virtual-00106656c0/0/cache/@babel-plugin-syntax-logical-assignment-operators-npm-7.10.4-72ae00fdf6-aff3357703.zip/node_modules/@babel/plugin-syntax-logical-assignment-operators/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-logical-assignment-operators-virtual-f4f5745024/0/cache/@babel-plugin-syntax-logical-assignment-operators-npm-7.10.4-72ae00fdf6-aff3357703.zip/node_modules/@babel/plugin-syntax-logical-assignment-operators/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-logical-assignment-operators", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-logical-assignment-operators", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -529,10 +534,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-nullish-coalescing-operator-virtual-0e94aeb633/0/cache/@babel-plugin-syntax-nullish-coalescing-operator-npm-7.8.3-8a723173b5-87aca49189.zip/node_modules/@babel/plugin-syntax-nullish-coalescing-operator/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-nullish-coalescing-operator-virtual-7cd00d383d/0/cache/@babel-plugin-syntax-nullish-coalescing-operator-npm-7.8.3-8a723173b5-87aca49189.zip/node_modules/@babel/plugin-syntax-nullish-coalescing-operator/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-nullish-coalescing-operator", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-nullish-coalescing-operator", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -566,10 +571,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-numeric-separator-virtual-ae7862c24d/0/cache/@babel-plugin-syntax-numeric-separator-npm-7.10.4-81444be605-01ec5547bd.zip/node_modules/@babel/plugin-syntax-numeric-separator/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-numeric-separator-virtual-1f39443676/0/cache/@babel-plugin-syntax-numeric-separator-npm-7.10.4-81444be605-01ec5547bd.zip/node_modules/@babel/plugin-syntax-numeric-separator/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-numeric-separator", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-numeric-separator", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -603,10 +608,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-object-rest-spread-virtual-70d6d17cdf/0/cache/@babel-plugin-syntax-object-rest-spread-npm-7.8.3-60bd05b6ae-fddcf581a5.zip/node_modules/@babel/plugin-syntax-object-rest-spread/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-object-rest-spread-virtual-e635fc53df/0/cache/@babel-plugin-syntax-object-rest-spread-npm-7.8.3-60bd05b6ae-fddcf581a5.zip/node_modules/@babel/plugin-syntax-object-rest-spread/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-object-rest-spread", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-object-rest-spread", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -640,10 +645,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-optional-catch-binding-virtual-19cae39d4e/0/cache/@babel-plugin-syntax-optional-catch-binding-npm-7.8.3-ce337427d8-910d90e72b.zip/node_modules/@babel/plugin-syntax-optional-catch-binding/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-optional-catch-binding-virtual-7faf06b837/0/cache/@babel-plugin-syntax-optional-catch-binding-npm-7.8.3-ce337427d8-910d90e72b.zip/node_modules/@babel/plugin-syntax-optional-catch-binding/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-optional-catch-binding", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-catch-binding", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -677,10 +682,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-optional-chaining-virtual-0faf2c8e15/0/cache/@babel-plugin-syntax-optional-chaining-npm-7.8.3-f3f3c79579-eef94d53a1.zip/node_modules/@babel/plugin-syntax-optional-chaining/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-optional-chaining-virtual-cd0a3a9619/0/cache/@babel-plugin-syntax-optional-chaining-npm-7.8.3-f3f3c79579-eef94d53a1.zip/node_modules/@babel/plugin-syntax-optional-chaining/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-optional-chaining", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-chaining", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -714,10 +719,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.14.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-top-level-await-virtual-4f23029d05/0/cache/@babel-plugin-syntax-top-level-await-npm-7.14.5-60a0a2e83b-bbd1a56b09.zip/node_modules/@babel/plugin-syntax-top-level-await/",\
|
||||
["virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.14.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@babel-plugin-syntax-top-level-await-virtual-ea96b657a7/0/cache/@babel-plugin-syntax-top-level-await-npm-7.14.5-60a0a2e83b-bbd1a56b09.zip/node_modules/@babel/plugin-syntax-top-level-await/",\
|
||||
"packageDependencies": [\
|
||||
["@babel/plugin-syntax-top-level-await", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.14.5"],\
|
||||
["@babel/plugin-syntax-top-level-await", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.14.5"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/helper-plugin-utils", "npm:7.17.12"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
|
@ -1201,12 +1206,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@jest-core-virtual-4b45c3242e/0/cache/@jest-core-npm-28.1.1-fb910fbf90-fd4361f77b.zip/node_modules/@jest/core/",\
|
||||
["virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@jest-core-virtual-c650136efc/0/cache/@jest-core-npm-28.1.1-fb910fbf90-fd4361f77b.zip/node_modules/@jest/core/",\
|
||||
"packageDependencies": [\
|
||||
["@jest/core", "virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1"],\
|
||||
["@jest/core", "virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1"],\
|
||||
["@jest/console", "npm:28.1.1"],\
|
||||
["@jest/reporters", "virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1"],\
|
||||
["@jest/reporters", "virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1"],\
|
||||
["@jest/test-result", "npm:28.1.1"],\
|
||||
["@jest/transform", "npm:28.1.1"],\
|
||||
["@jest/types", "npm:28.1.1"],\
|
||||
|
@ -1218,7 +1223,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["exit", "npm:0.1.2"],\
|
||||
["graceful-fs", "npm:4.2.10"],\
|
||||
["jest-changed-files", "npm:28.0.2"],\
|
||||
["jest-config", "virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1"],\
|
||||
["jest-config", "virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1"],\
|
||||
["jest-haste-map", "npm:28.1.1"],\
|
||||
["jest-message-util", "npm:28.1.1"],\
|
||||
["jest-regex-util", "npm:28.0.2"],\
|
||||
|
@ -1313,10 +1318,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@jest-reporters-virtual-ea52091ed4/0/cache/@jest-reporters-npm-28.1.1-21fe131d02-8ad68d4a93.zip/node_modules/@jest/reporters/",\
|
||||
["virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@jest-reporters-virtual-4b439ab9a1/0/cache/@jest-reporters-npm-28.1.1-21fe131d02-8ad68d4a93.zip/node_modules/@jest/reporters/",\
|
||||
"packageDependencies": [\
|
||||
["@jest/reporters", "virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1"],\
|
||||
["@jest/reporters", "virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1"],\
|
||||
["@bcoe/v8-coverage", "npm:0.2.3"],\
|
||||
["@jest/console", "npm:28.1.1"],\
|
||||
["@jest/test-result", "npm:28.1.1"],\
|
||||
|
@ -1944,10 +1949,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:2.1.2", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@newrelic-winston-enricher-virtual-30a09b12b4/0/cache/@newrelic-winston-enricher-npm-2.1.2-732878a1b2-d001c13166.zip/node_modules/@newrelic/winston-enricher/",\
|
||||
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@newrelic-winston-enricher-virtual-193127fbcd/0/cache/@newrelic-winston-enricher-npm-2.1.2-732878a1b2-d001c13166.zip/node_modules/@newrelic/winston-enricher/",\
|
||||
"packageDependencies": [\
|
||||
["@newrelic/winston-enricher", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:2.1.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
|
||||
["@types/newrelic", "npm:7.0.3"],\
|
||||
["@types/winston", null],\
|
||||
["newrelic", "npm:8.6.0"],\
|
||||
|
@ -2584,7 +2589,60 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/api-gateway", [\
|
||||
["workspace:packages/api-gateway", {\
|
||||
"packageLocation": "./packages/api-gateway/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
||||
["@newrelic/native-metrics", "npm:7.0.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
|
||||
["@sentry/node", "npm:6.19.7"],\
|
||||
["@standardnotes/analytics", "npm:1.6.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.2"],\
|
||||
["@standardnotes/domain-events", "npm:2.29.0"],\
|
||||
["@standardnotes/domain-events-infra", "npm:1.4.127"],\
|
||||
["@standardnotes/time", "npm:1.7.0"],\
|
||||
["@types/cors", "npm:2.8.12"],\
|
||||
["@types/express", "npm:4.17.13"],\
|
||||
["@types/ioredis", "npm:4.28.10"],\
|
||||
["@types/jest", "npm:28.1.3"],\
|
||||
["@types/jsonwebtoken", "npm:8.5.8"],\
|
||||
["@types/newrelic", "npm:7.0.3"],\
|
||||
["@types/prettyjson", "npm:0.0.29"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0"],\
|
||||
["aws-sdk", "npm:2.1160.0"],\
|
||||
["axios", "npm:0.24.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:8.2.0"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["express", "npm:4.17.1"],\
|
||||
["helmet", "npm:4.4.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.0.6"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["newrelic", "npm:8.6.0"],\
|
||||
["nodemon", "npm:2.0.16"],\
|
||||
["prettyjson", "npm:1.2.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5"],\
|
||||
["winston", "npm:3.3.3"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/auth", [\
|
||||
["npm:3.19.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-auth-npm-3.19.2-5289525e60-2e4b37b303.zip/node_modules/@standardnotes/auth/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/auth", "npm:3.19.2"],\
|
||||
["@standardnotes/common", "npm:1.23.0"],\
|
||||
["jsonwebtoken", "npm:8.5.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.19.3", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-auth-npm-3.19.3-c77ec60e52-7e421b5eaf.zip/node_modules/@standardnotes/auth/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -2601,7 +2659,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"packageDependencies": [\
|
||||
["@standardnotes/auth-server", "workspace:packages/auth"],\
|
||||
["@newrelic/native-metrics", "npm:7.0.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:2.1.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
|
||||
["@sentry/node", "npm:6.19.7"],\
|
||||
["@standardnotes/analytics", "npm:1.6.0"],\
|
||||
["@standardnotes/api", "npm:1.1.13"],\
|
||||
|
@ -2626,7 +2684,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@types/prettyjson", "npm:0.0.29"],\
|
||||
["@types/ua-parser-js", "npm:0.7.36"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.29.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0"],\
|
||||
["aws-sdk", "npm:2.1159.0"],\
|
||||
["axios", "npm:0.24.0"],\
|
||||
["bcryptjs", "npm:2.4.3"],\
|
||||
|
@ -2635,19 +2693,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["dayjs", "npm:1.11.3"],\
|
||||
["dotenv", "npm:8.2.0"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-plugin-prettier", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:4.0.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["express", "npm:4.17.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.0.6"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.6.0"],\
|
||||
["nodemon", "npm:2.0.16"],\
|
||||
["otplib", "npm:12.0.1"],\
|
||||
["prettyjson", "npm:1.2.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.0.5"],\
|
||||
["ts-jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.6"],\
|
||||
["ua-parser-js", "npm:1.0.2"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
|
@ -2677,6 +2735,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["@standardnotes/domain-events", [\
|
||||
["npm:2.29.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-domain-events-npm-2.29.0-13bec3d9a7-1b68999e2a.zip/node_modules/@standardnotes/domain-events/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/domain-events", "npm:2.29.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.3"],\
|
||||
["@standardnotes/features", "npm:1.45.5"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.32.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-domain-events-npm-2.32.2-73adf7a999-54da5fc885.zip/node_modules/@standardnotes/domain-events/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -2689,6 +2756,20 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["@standardnotes/domain-events-infra", [\
|
||||
["npm:1.4.127", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-domain-events-infra-npm-1.4.127-18a82f2f72-54e37c296f.zip/node_modules/@standardnotes/domain-events-infra/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/domain-events-infra", "npm:1.4.127"],\
|
||||
["@standardnotes/domain-events", "npm:2.32.2"],\
|
||||
["aws-sdk", "npm:2.1157.0"],\
|
||||
["ioredis", "npm:4.28.5"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["sqs-consumer", "virtual:18a82f2f722cf47811304317f79c07fee6ecd8a887f3af2b42c72227f3b982ee05bf525aa8a7d2d20252ed23a1ed39ca99b430ed432b264a8bad79965c0cae5e#npm:5.7.0"],\
|
||||
["winston", "npm:3.7.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.5.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-domain-events-infra-npm-1.5.2-948d77a715-b027dfd329.zip/node_modules/@standardnotes/domain-events-infra/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -2698,7 +2779,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["ioredis", "npm:4.28.5"],\
|
||||
["newrelic", "npm:8.14.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["sqs-consumer", "virtual:948d77a715c2182e00f2764d231af7afb02bf7f3164cf05b0248dc116c0a54912c77c570591f08b5b0dbb55984329e93f5f5704931076ba8f07fc46d4a69d072#npm:5.7.0"],\
|
||||
["sqs-consumer", "virtual:18a82f2f722cf47811304317f79c07fee6ecd8a887f3af2b42c72227f3b982ee05bf525aa8a7d2d20252ed23a1ed39ca99b430ed432b264a8bad79965c0cae5e#npm:5.7.0"],\
|
||||
["winston", "npm:3.7.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
@ -2751,27 +2832,27 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@types/newrelic", "npm:7.0.3"],\
|
||||
["@types/prettyjson", "npm:0.0.29"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.29.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0"],\
|
||||
["aws-sdk", "npm:2.1158.0"],\
|
||||
["connect-busboy", "npm:1.0.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dayjs", "npm:1.11.3"],\
|
||||
["dotenv", "npm:8.6.0"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-plugin-prettier", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:4.0.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["express", "npm:4.18.1"],\
|
||||
["express-winston", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:4.2.0"],\
|
||||
["helmet", "npm:4.6.0"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.0.6"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["newrelic", "npm:7.5.2"],\
|
||||
["nodemon", "npm:2.0.16"],\
|
||||
["prettyjson", "npm:1.2.5"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.0.5"],\
|
||||
["ts-jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5"],\
|
||||
["ts-node", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.8.1"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
["winston", "npm:3.7.2"]\
|
||||
|
@ -2831,7 +2912,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"packageDependencies": [\
|
||||
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
|
||||
["@newrelic/native-metrics", "npm:7.0.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:2.1.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
|
||||
["@standardnotes/common", "npm:1.23.0"],\
|
||||
["@standardnotes/domain-events", "npm:2.32.2"],\
|
||||
["@standardnotes/domain-events-infra", "npm:1.5.2"],\
|
||||
|
@ -2848,7 +2929,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["eslint-plugin-prettier", "virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:4.0.0"],\
|
||||
["inversify", "npm:5.0.5"],\
|
||||
["ioredis", "npm:5.0.6"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.6.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
|
@ -2928,7 +3009,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"packageDependencies": [\
|
||||
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
|
||||
["@newrelic/native-metrics", "npm:7.0.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:2.1.2"],\
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:2.1.2"],\
|
||||
["@sentry/node", "npm:6.19.7"],\
|
||||
["@standardnotes/analytics", "npm:1.6.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.3"],\
|
||||
|
@ -2950,26 +3031,26 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@types/prettyjson", "npm:0.0.29"],\
|
||||
["@types/ua-parser-js", "npm:0.7.36"],\
|
||||
["@types/uuid", "npm:8.3.4"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.29.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0"],\
|
||||
["aws-sdk", "npm:2.1159.0"],\
|
||||
["axios", "npm:0.24.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
["dotenv", "npm:8.2.0"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-plugin-prettier", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:4.0.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["express", "npm:4.17.1"],\
|
||||
["helmet", "npm:4.3.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["ioredis", "npm:5.0.6"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["jsonwebtoken", "npm:8.5.1"],\
|
||||
["mysql2", "npm:2.3.3"],\
|
||||
["newrelic", "npm:8.6.0"],\
|
||||
["nodemon", "npm:2.0.7"],\
|
||||
["prettyjson", "npm:1.2.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.0.5"],\
|
||||
["ts-jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.6"],\
|
||||
["ua-parser-js", "npm:1.0.2"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
|
@ -3513,6 +3594,36 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-eslint-plugin-virtual-d2330b8caf/0/cache/@typescript-eslint-eslint-plugin-npm-5.29.0-d7e482bb3e-b1022a640f.zip/node_modules/@typescript-eslint/eslint-plugin/",\
|
||||
"packageDependencies": [\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.29.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/typescript", null],\
|
||||
["@types/typescript-eslint__parser", null],\
|
||||
["@typescript-eslint/parser", null],\
|
||||
["@typescript-eslint/scope-manager", "npm:5.29.0"],\
|
||||
["@typescript-eslint/type-utils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0"],\
|
||||
["@typescript-eslint/utils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["functional-red-black-tree", "npm:1.0.1"],\
|
||||
["ignore", "npm:5.2.0"],\
|
||||
["regexpp", "npm:3.2.0"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/eslint",\
|
||||
"@types/typescript-eslint__parser",\
|
||||
"@types/typescript",\
|
||||
"@typescript-eslint/parser",\
|
||||
"eslint",\
|
||||
"typescript"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-eslint-plugin-virtual-f8d5e1f46d/0/cache/@typescript-eslint-eslint-plugin-npm-5.29.0-d7e482bb3e-b1022a640f.zip/node_modules/@typescript-eslint/eslint-plugin/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -3530,37 +3641,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["ignore", "npm:5.2.0"],\
|
||||
["regexpp", "npm:3.2.0"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/eslint",\
|
||||
"@types/typescript-eslint__parser",\
|
||||
"@types/typescript",\
|
||||
"@typescript-eslint/parser",\
|
||||
"eslint",\
|
||||
"typescript"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-eslint-plugin-virtual-e64d284169/0/cache/@typescript-eslint-eslint-plugin-npm-5.29.0-d7e482bb3e-b1022a640f.zip/node_modules/@typescript-eslint/eslint-plugin/",\
|
||||
"packageDependencies": [\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.29.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/typescript", null],\
|
||||
["@types/typescript-eslint__parser", null],\
|
||||
["@typescript-eslint/parser", null],\
|
||||
["@typescript-eslint/scope-manager", "npm:5.29.0"],\
|
||||
["@typescript-eslint/type-utils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0"],\
|
||||
["@typescript-eslint/utils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["functional-red-black-tree", "npm:1.0.1"],\
|
||||
["ignore", "npm:5.2.0"],\
|
||||
["regexpp", "npm:3.2.0"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3589,7 +3670,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["ignore", "npm:5.2.0"],\
|
||||
["regexpp", "npm:3.2.0"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3717,16 +3798,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-type-utils-virtual-96dd1bc160/0/cache/@typescript-eslint-type-utils-npm-5.29.0-063d15676f-686b8ff05a.zip/node_modules/@typescript-eslint/type-utils/",\
|
||||
["virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-type-utils-virtual-2a27889b50/0/cache/@typescript-eslint-type-utils-npm-5.29.0-063d15676f-686b8ff05a.zip/node_modules/@typescript-eslint/type-utils/",\
|
||||
"packageDependencies": [\
|
||||
["@typescript-eslint/type-utils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0"],\
|
||||
["@typescript-eslint/type-utils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/typescript", null],\
|
||||
["@typescript-eslint/utils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0"],\
|
||||
["@typescript-eslint/utils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3746,7 +3827,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@typescript-eslint/utils", "virtual:f8d5e1f46dbb2f1fb352e8d15f1237589f03161f87569a6446ffa325c842024c20e3b7f196872650fbbdc62125c711d99dd1c2ba271f15e9b316292a2dec51bc#npm:5.29.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
|
||||
["eslint", null],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3800,7 +3881,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["globby", "npm:11.1.0"],\
|
||||
["is-glob", "npm:4.0.3"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3829,10 +3910,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:4ec458b53cfcb38d153394fe4d0300908a12ce721ae6026f1e2d7bbe8409ed98079b29d9688a9eb93463ace5dbaac7d454b12c4582b1cd0b1d8210588cf0cb1c#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-typescript-estree-virtual-8de7b9cb0d/0/cache/@typescript-eslint-typescript-estree-npm-5.29.0-f23de2ab5c-b91107a9fc.zip/node_modules/@typescript-eslint/typescript-estree/",\
|
||||
["virtual:5355269a141f9a806d08de8974384aa45476d01ec51fc7301c8384e52bbf36be0eab945f0602a4df4c7737fa267f81331777eaeb3d1de352f83549caee258ae1#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-typescript-estree-virtual-76f89dbc29/0/cache/@typescript-eslint-typescript-estree-npm-5.29.0-f23de2ab5c-b91107a9fc.zip/node_modules/@typescript-eslint/typescript-estree/",\
|
||||
"packageDependencies": [\
|
||||
["@typescript-eslint/typescript-estree", "virtual:4ec458b53cfcb38d153394fe4d0300908a12ce721ae6026f1e2d7bbe8409ed98079b29d9688a9eb93463ace5dbaac7d454b12c4582b1cd0b1d8210588cf0cb1c#npm:5.29.0"],\
|
||||
["@typescript-eslint/typescript-estree", "virtual:5355269a141f9a806d08de8974384aa45476d01ec51fc7301c8384e52bbf36be0eab945f0602a4df4c7737fa267f81331777eaeb3d1de352f83549caee258ae1#npm:5.29.0"],\
|
||||
["@types/typescript", null],\
|
||||
["@typescript-eslint/types", "npm:5.29.0"],\
|
||||
["@typescript-eslint/visitor-keys", "npm:5.29.0"],\
|
||||
|
@ -3840,7 +3921,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["globby", "npm:11.1.0"],\
|
||||
["is-glob", "npm:4.0.3"],\
|
||||
["semver", "npm:7.3.7"],\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["typescript", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -3858,15 +3939,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-utils-virtual-4ec458b53c/0/cache/@typescript-eslint-utils-npm-5.29.0-f3bfc5f3f3-216f51fb9c.zip/node_modules/@typescript-eslint/utils/",\
|
||||
["virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@typescript-eslint-utils-virtual-5355269a14/0/cache/@typescript-eslint-utils-npm-5.29.0-f3bfc5f3f3-216f51fb9c.zip/node_modules/@typescript-eslint/utils/",\
|
||||
"packageDependencies": [\
|
||||
["@typescript-eslint/utils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:5.29.0"],\
|
||||
["@typescript-eslint/utils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:5.29.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/json-schema", "npm:7.0.11"],\
|
||||
["@typescript-eslint/scope-manager", "npm:5.29.0"],\
|
||||
["@typescript-eslint/types", "npm:5.29.0"],\
|
||||
["@typescript-eslint/typescript-estree", "virtual:4ec458b53cfcb38d153394fe4d0300908a12ce721ae6026f1e2d7bbe8409ed98079b29d9688a9eb93463ace5dbaac7d454b12c4582b1cd0b1d8210588cf0cb1c#npm:5.29.0"],\
|
||||
["@typescript-eslint/typescript-estree", "virtual:5355269a141f9a806d08de8974384aa45476d01ec51fc7301c8384e52bbf36be0eab945f0602a4df4c7737fa267f81331777eaeb3d1de352f83549caee258ae1#npm:5.29.0"],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-scope", "npm:5.1.1"],\
|
||||
["eslint-utils", "virtual:3b3bfb190f25ed01591b1d51c8e6a15e818ab97d9cabea5c63912afc819a8f6e3ad395aaf338cd170314411b04e35eec5c8cff33dfa644476d292dcf2c5354d1#npm:3.0.0"]\
|
||||
|
@ -3885,7 +3966,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@types/json-schema", "npm:7.0.11"],\
|
||||
["@typescript-eslint/scope-manager", "npm:5.29.0"],\
|
||||
["@typescript-eslint/types", "npm:5.29.0"],\
|
||||
["@typescript-eslint/typescript-estree", "virtual:4ec458b53cfcb38d153394fe4d0300908a12ce721ae6026f1e2d7bbe8409ed98079b29d9688a9eb93463ace5dbaac7d454b12c4582b1cd0b1d8210588cf0cb1c#npm:5.29.0"],\
|
||||
["@typescript-eslint/typescript-estree", "virtual:5355269a141f9a806d08de8974384aa45476d01ec51fc7301c8384e52bbf36be0eab945f0602a4df4c7737fa267f81331777eaeb3d1de352f83549caee258ae1#npm:5.29.0"],\
|
||||
["eslint", null],\
|
||||
["eslint-scope", "npm:5.1.1"],\
|
||||
["eslint-utils", "virtual:3b1d487b65ac14c3c2f5d6292c3e4b93bf25216a88a2d253428f98942e01532ac4933ee30564874cec0a0bb5aea3ee613d7494705e42eed4a2106f8ac0a03f97#npm:3.0.0"]\
|
||||
|
@ -4297,6 +4378,22 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["xml2js", "npm:0.4.19"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.1160.0", {\
|
||||
"packageLocation": "./.yarn/cache/aws-sdk-npm-2.1160.0-1a3db600b7-b95647d4de.zip/node_modules/aws-sdk/",\
|
||||
"packageDependencies": [\
|
||||
["aws-sdk", "npm:2.1160.0"],\
|
||||
["buffer", "npm:4.9.2"],\
|
||||
["events", "npm:1.1.1"],\
|
||||
["ieee754", "npm:1.1.13"],\
|
||||
["jmespath", "npm:0.16.0"],\
|
||||
["querystring", "npm:0.2.0"],\
|
||||
["sax", "npm:1.2.1"],\
|
||||
["url", "npm:0.10.3"],\
|
||||
["uuid", "npm:8.0.0"],\
|
||||
["xml2js", "npm:0.4.19"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["axios", [\
|
||||
|
@ -4317,15 +4414,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:805c813b6f046618cef5c7d6c026d202467ce267579e0c7a252be4f063439bc6f090ab5b924f50d7ae022b220d8e89e00ef15869e26244774ec68ef480e4e54d#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-jest-virtual-419439314f/0/cache/babel-jest-npm-28.1.1-a0706ab037-9c7c7f6006.zip/node_modules/babel-jest/",\
|
||||
["virtual:32b5269fd2e54a6fa7239e0777f3768bd33c5a094884dd5492350113f2bec8947944fe0156c37c044965c85742064fae363a3a7138decb195966e011bb7f7d4f#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-jest-virtual-08d3591870/0/cache/babel-jest-npm-28.1.1-a0706ab037-9c7c7f6006.zip/node_modules/babel-jest/",\
|
||||
"packageDependencies": [\
|
||||
["babel-jest", "virtual:805c813b6f046618cef5c7d6c026d202467ce267579e0c7a252be4f063439bc6f090ab5b924f50d7ae022b220d8e89e00ef15869e26244774ec68ef480e4e54d#npm:28.1.1"],\
|
||||
["babel-jest", "virtual:32b5269fd2e54a6fa7239e0777f3768bd33c5a094884dd5492350113f2bec8947944fe0156c37c044965c85742064fae363a3a7138decb195966e011bb7f7d4f#npm:28.1.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@jest/transform", "npm:28.1.1"],\
|
||||
["@types/babel__core", "npm:7.1.19"],\
|
||||
["babel-plugin-istanbul", "npm:6.1.1"],\
|
||||
["babel-preset-jest", "virtual:419439314f6ac7e6aeb104f74d9bd1fb754b552a3112b86e2807390519b56dbd6a88f32cff6e239d59a2670b389ec32d1afc7812be06ebe4cb1eeb9c2c58cf9e#npm:28.1.1"],\
|
||||
["babel-preset-jest", "virtual:08d35918703ec0bc2fb72b89407cc8430c63eb749ffe2bff641418cce72be4aab0afe750c610e41ee52e9bd2c8d7e721847c3791d36317060f0620130926424e#npm:28.1.1"],\
|
||||
["chalk", "npm:4.1.2"],\
|
||||
["graceful-fs", "npm:4.2.10"],\
|
||||
["slash", "npm:3.0.0"]\
|
||||
|
@ -4371,6 +4468,31 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:081cd5e09087a97f33e6c2157b2f04624b270420cbd295805f8d59379d1fdc60eb969f610d8b11a66179e64b76fb08cb87d36cb6f67d17466aa40dc8ab796225#npm:1.0.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-preset-current-node-syntax-virtual-c373874e1b/0/cache/babel-preset-current-node-syntax-npm-1.0.1-849ec71e32-d118c27424.zip/node_modules/babel-preset-current-node-syntax/",\
|
||||
"packageDependencies": [\
|
||||
["babel-preset-current-node-syntax", "virtual:081cd5e09087a97f33e6c2157b2f04624b270420cbd295805f8d59379d1fdc60eb969f610d8b11a66179e64b76fb08cb87d36cb6f67d17466aa40dc8ab796225#npm:1.0.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/plugin-syntax-async-generators", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.4"],\
|
||||
["@babel/plugin-syntax-bigint", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-class-properties", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.12.13"],\
|
||||
["@babel/plugin-syntax-import-meta", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-json-strings", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-logical-assignment-operators", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-nullish-coalescing-operator", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-numeric-separator", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-object-rest-spread", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-catch-binding", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-chaining", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-top-level-await", "virtual:c373874e1baa9d76ffb6ce2109646b13db6b2b433728eac72e69f1da2ca3718a077c7549e49925b0fa06952690278e6a36ceca4ebe492de934ac9dea98343dd7#npm:7.14.5"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@babel/core",\
|
||||
"@types/babel__core"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:7ff9a9a22630d18bc8c20eec37b86b4c191fbcee5349c62dbf8ba14d95b3502ae4cb63cce8e26089a0dd1b269b70fad4ce808ff97d3255679417f5177f7bef0e#npm:1.0.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-preset-current-node-syntax-virtual-fcabcac42b/0/cache/babel-preset-current-node-syntax-npm-1.0.1-849ec71e32-d118c27424.zip/node_modules/babel-preset-current-node-syntax/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -4395,31 +4517,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"@types/babel__core"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:a21946f32fecc6d2a4f39c804bc6851b8c98cf267db2bb0a25b0f443fe3cf1ff67012036ab014b3ec1309cc1f0a5678c35acb443e7d8c8a0d3c29071288e53d7#npm:1.0.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-preset-current-node-syntax-virtual-511f18ec47/0/cache/babel-preset-current-node-syntax-npm-1.0.1-849ec71e32-d118c27424.zip/node_modules/babel-preset-current-node-syntax/",\
|
||||
"packageDependencies": [\
|
||||
["babel-preset-current-node-syntax", "virtual:a21946f32fecc6d2a4f39c804bc6851b8c98cf267db2bb0a25b0f443fe3cf1ff67012036ab014b3ec1309cc1f0a5678c35acb443e7d8c8a0d3c29071288e53d7#npm:1.0.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@babel/plugin-syntax-async-generators", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.4"],\
|
||||
["@babel/plugin-syntax-bigint", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-class-properties", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.12.13"],\
|
||||
["@babel/plugin-syntax-import-meta", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-json-strings", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-logical-assignment-operators", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-nullish-coalescing-operator", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-numeric-separator", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.10.4"],\
|
||||
["@babel/plugin-syntax-object-rest-spread", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-catch-binding", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-optional-chaining", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.8.3"],\
|
||||
["@babel/plugin-syntax-top-level-await", "virtual:511f18ec4797ab42da93993c808942012470709446ef400bc600a66a60e5e382e8081da234db4fe66d41d38d9212735169fb3c604c828d1ff8dc854506ed7b48#npm:7.14.5"],\
|
||||
["@types/babel__core", "npm:7.1.19"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@babel/core",\
|
||||
"@types/babel__core"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["babel-preset-jest", [\
|
||||
|
@ -4430,14 +4527,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:419439314f6ac7e6aeb104f74d9bd1fb754b552a3112b86e2807390519b56dbd6a88f32cff6e239d59a2670b389ec32d1afc7812be06ebe4cb1eeb9c2c58cf9e#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-preset-jest-virtual-a21946f32f/0/cache/babel-preset-jest-npm-28.1.1-05a1e38dd1-c581a81967.zip/node_modules/babel-preset-jest/",\
|
||||
["virtual:08d35918703ec0bc2fb72b89407cc8430c63eb749ffe2bff641418cce72be4aab0afe750c610e41ee52e9bd2c8d7e721847c3791d36317060f0620130926424e#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/babel-preset-jest-virtual-081cd5e090/0/cache/babel-preset-jest-npm-28.1.1-05a1e38dd1-c581a81967.zip/node_modules/babel-preset-jest/",\
|
||||
"packageDependencies": [\
|
||||
["babel-preset-jest", "virtual:419439314f6ac7e6aeb104f74d9bd1fb754b552a3112b86e2807390519b56dbd6a88f32cff6e239d59a2670b389ec32d1afc7812be06ebe4cb1eeb9c2c58cf9e#npm:28.1.1"],\
|
||||
["babel-preset-jest", "virtual:08d35918703ec0bc2fb72b89407cc8430c63eb749ffe2bff641418cce72be4aab0afe750c610e41ee52e9bd2c8d7e721847c3791d36317060f0620130926424e#npm:28.1.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@types/babel__core", "npm:7.1.19"],\
|
||||
["babel-plugin-jest-hoist", "npm:28.1.1"],\
|
||||
["babel-preset-current-node-syntax", "virtual:a21946f32fecc6d2a4f39c804bc6851b8c98cf267db2bb0a25b0f443fe3cf1ff67012036ab014b3ec1309cc1f0a5678c35acb443e7d8c8a0d3c29071288e53d7#npm:1.0.1"]\
|
||||
["babel-preset-current-node-syntax", "virtual:081cd5e09087a97f33e6c2157b2f04624b270420cbd295805f8d59379d1fdc60eb969f610d8b11a66179e64b76fb08cb87d36cb6f67d17466aa40dc8ab796225#npm:1.0.1"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@babel/core",\
|
||||
|
@ -6173,14 +6270,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/eslint-plugin-prettier-virtual-7e331f4408/0/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\
|
||||
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/eslint-plugin-prettier-virtual-eaf1b54b4e/0/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\
|
||||
"packageDependencies": [\
|
||||
["eslint-plugin-prettier", "virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:4.0.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/eslint-config-prettier", null],\
|
||||
["@types/prettier", null],\
|
||||
["eslint", null],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint-config-prettier", null],\
|
||||
["prettier", null],\
|
||||
["prettier-linter-helpers", "npm:1.0.0"]\
|
||||
|
@ -6195,14 +6292,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/eslint-plugin-prettier-virtual-5c96b2a218/0/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\
|
||||
["virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/eslint-plugin-prettier-virtual-7e331f4408/0/cache/eslint-plugin-prettier-npm-4.0.0-e632552861-03d69177a3.zip/node_modules/eslint-plugin-prettier/",\
|
||||
"packageDependencies": [\
|
||||
["eslint-plugin-prettier", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:4.0.0"],\
|
||||
["eslint-plugin-prettier", "virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:4.0.0"],\
|
||||
["@types/eslint", null],\
|
||||
["@types/eslint-config-prettier", null],\
|
||||
["@types/prettier", null],\
|
||||
["eslint", "npm:8.18.0"],\
|
||||
["eslint", null],\
|
||||
["eslint-config-prettier", null],\
|
||||
["prettier", null],\
|
||||
["prettier-linter-helpers", "npm:1.0.0"]\
|
||||
|
@ -7231,6 +7328,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:4.4.1", {\
|
||||
"packageLocation": "./.yarn/cache/helmet-npm-4.4.1-286ac392ee-cfe385e185.zip/node_modules/helmet/",\
|
||||
"packageDependencies": [\
|
||||
["helmet", "npm:4.4.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:4.6.0", {\
|
||||
"packageLocation": "./.yarn/cache/helmet-npm-4.6.0-f244fd965c-139ad678d1.zip/node_modules/helmet/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -8038,15 +8142,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-virtual-6e20fd2eaa/0/cache/jest-npm-28.1.1-a4158efd82-398a143d9e.zip/node_modules/jest/",\
|
||||
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-virtual-c6df9164d8/0/cache/jest-npm-28.1.1-a4158efd82-398a143d9e.zip/node_modules/jest/",\
|
||||
"packageDependencies": [\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["@jest/core", "virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["@jest/core", "virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1"],\
|
||||
["@jest/types", "npm:28.1.1"],\
|
||||
["@types/node-notifier", null],\
|
||||
["import-local", "npm:3.1.0"],\
|
||||
["jest-cli", "virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1"],\
|
||||
["jest-cli", "virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1"],\
|
||||
["node-notifier", null]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -8103,11 +8207,11 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-cli-virtual-18fea92b00/0/cache/jest-cli-npm-28.1.1-7fb5826ae7-fce96f2f0c.zip/node_modules/jest-cli/",\
|
||||
["virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-cli-virtual-ffe7948780/0/cache/jest-cli-npm-28.1.1-7fb5826ae7-fce96f2f0c.zip/node_modules/jest-cli/",\
|
||||
"packageDependencies": [\
|
||||
["jest-cli", "virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1"],\
|
||||
["@jest/core", "virtual:6e20fd2eaaa940ccda315da6252a82baa2918f5ea3c40e2d7cb4d97f01b503d35a5076b4b63a33762fb1174e73a3313072cadf65e4a26d1b33660f964eda7880#npm:28.1.1"],\
|
||||
["jest-cli", "virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1"],\
|
||||
["@jest/core", "virtual:c6df9164d8eb22b719e1cd2b32bc24b485c129a3b28db796c6f3a6c22ad9410bc922a7f59cbbfe78d6492c9ee9f75de8ed7c2ec2f694d58e500097e2a2b74028#npm:28.1.1"],\
|
||||
["@jest/test-result", "npm:28.1.1"],\
|
||||
["@jest/types", "npm:28.1.1"],\
|
||||
["@types/node-notifier", null],\
|
||||
|
@ -8115,7 +8219,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["exit", "npm:0.1.2"],\
|
||||
["graceful-fs", "npm:4.2.10"],\
|
||||
["import-local", "npm:3.1.0"],\
|
||||
["jest-config", "virtual:18fea92b00a9a17809e3136cba934f07b76b6365d781cde6e4e8ad39518603c42b210c61bd96fbdefd3c18ea76e15da85ec1d250fdb153b485bb120f2884a87d#npm:28.1.1"],\
|
||||
["jest-config", "virtual:ffe7948780650e103d113b366bd00aa5fddf83f2645b1950ace5412f68838bb229734eeb6f43c5cf8e80750f2112707820eb53dac9ef0db7f3ad9a040066aa3b#npm:28.1.1"],\
|
||||
["jest-util", "npm:28.1.1"],\
|
||||
["jest-validate", "npm:28.1.1"],\
|
||||
["node-notifier", null],\
|
||||
|
@ -8137,16 +8241,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:18fea92b00a9a17809e3136cba934f07b76b6365d781cde6e4e8ad39518603c42b210c61bd96fbdefd3c18ea76e15da85ec1d250fdb153b485bb120f2884a87d#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-config-virtual-56145f3e40/0/cache/jest-config-npm-28.1.1-8c4e855059-8ce9f6b8f6.zip/node_modules/jest-config/",\
|
||||
["virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-config-virtual-32b5269fd2/0/cache/jest-config-npm-28.1.1-8c4e855059-8ce9f6b8f6.zip/node_modules/jest-config/",\
|
||||
"packageDependencies": [\
|
||||
["jest-config", "virtual:18fea92b00a9a17809e3136cba934f07b76b6365d781cde6e4e8ad39518603c42b210c61bd96fbdefd3c18ea76e15da85ec1d250fdb153b485bb120f2884a87d#npm:28.1.1"],\
|
||||
["jest-config", "virtual:c650136efccbbb479cf2d5b8062777752af30a07867b5d5c0bde3cbc6a5c6f054afdfcc433e9ded24592d8fb0664ba4983e4f355a06678d9210b9c9e34f577b9#npm:28.1.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@jest/test-sequencer", "npm:28.1.1"],\
|
||||
["@jest/types", "npm:28.1.1"],\
|
||||
["@types/node", null],\
|
||||
["@types/node", "npm:18.0.0"],\
|
||||
["@types/ts-node", null],\
|
||||
["babel-jest", "virtual:805c813b6f046618cef5c7d6c026d202467ce267579e0c7a252be4f063439bc6f090ab5b924f50d7ae022b220d8e89e00ef15869e26244774ec68ef480e4e54d#npm:28.1.1"],\
|
||||
["babel-jest", "virtual:32b5269fd2e54a6fa7239e0777f3768bd33c5a094884dd5492350113f2bec8947944fe0156c37c044965c85742064fae363a3a7138decb195966e011bb7f7d4f#npm:28.1.1"],\
|
||||
["chalk", "npm:4.1.2"],\
|
||||
["ci-info", "npm:3.3.2"],\
|
||||
["deepmerge", "npm:4.2.2"],\
|
||||
|
@ -8174,16 +8278,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-config-virtual-805c813b6f/0/cache/jest-config-npm-28.1.1-8c4e855059-8ce9f6b8f6.zip/node_modules/jest-config/",\
|
||||
["virtual:ffe7948780650e103d113b366bd00aa5fddf83f2645b1950ace5412f68838bb229734eeb6f43c5cf8e80750f2112707820eb53dac9ef0db7f3ad9a040066aa3b#npm:28.1.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/jest-config-virtual-588b409452/0/cache/jest-config-npm-28.1.1-8c4e855059-8ce9f6b8f6.zip/node_modules/jest-config/",\
|
||||
"packageDependencies": [\
|
||||
["jest-config", "virtual:4b45c3242ed36b84511b3946081e5d3b347e0463d6e39ebfdee2ad8392eb4bd7a5761a69e4fccf0d230c488b171720ddcf381e7c249fe8f4fcdf9d4afc493b87#npm:28.1.1"],\
|
||||
["jest-config", "virtual:ffe7948780650e103d113b366bd00aa5fddf83f2645b1950ace5412f68838bb229734eeb6f43c5cf8e80750f2112707820eb53dac9ef0db7f3ad9a040066aa3b#npm:28.1.1"],\
|
||||
["@babel/core", "npm:7.18.5"],\
|
||||
["@jest/test-sequencer", "npm:28.1.1"],\
|
||||
["@jest/types", "npm:28.1.1"],\
|
||||
["@types/node", "npm:18.0.0"],\
|
||||
["@types/node", null],\
|
||||
["@types/ts-node", null],\
|
||||
["babel-jest", "virtual:805c813b6f046618cef5c7d6c026d202467ce267579e0c7a252be4f063439bc6f090ab5b924f50d7ae022b220d8e89e00ef15869e26244774ec68ef480e4e54d#npm:28.1.1"],\
|
||||
["babel-jest", "virtual:32b5269fd2e54a6fa7239e0777f3768bd33c5a094884dd5492350113f2bec8947944fe0156c37c044965c85742064fae363a3a7138decb195966e011bb7f7d4f#npm:28.1.1"],\
|
||||
["chalk", "npm:4.1.2"],\
|
||||
["ci-info", "npm:3.3.2"],\
|
||||
["deepmerge", "npm:4.2.2"],\
|
||||
|
@ -11713,10 +11817,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:948d77a715c2182e00f2764d231af7afb02bf7f3164cf05b0248dc116c0a54912c77c570591f08b5b0dbb55984329e93f5f5704931076ba8f07fc46d4a69d072#npm:5.7.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/sqs-consumer-virtual-b5ed97f086/0/cache/sqs-consumer-npm-5.7.0-09231a3791-d1eb00cbc5.zip/node_modules/sqs-consumer/",\
|
||||
["virtual:18a82f2f722cf47811304317f79c07fee6ecd8a887f3af2b42c72227f3b982ee05bf525aa8a7d2d20252ed23a1ed39ca99b430ed432b264a8bad79965c0cae5e#npm:5.7.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/sqs-consumer-virtual-cbacaabf93/0/cache/sqs-consumer-npm-5.7.0-09231a3791-d1eb00cbc5.zip/node_modules/sqs-consumer/",\
|
||||
"packageDependencies": [\
|
||||
["sqs-consumer", "virtual:948d77a715c2182e00f2764d231af7afb02bf7f3164cf05b0248dc116c0a54912c77c570591f08b5b0dbb55984329e93f5f5704931076ba8f07fc46d4a69d072#npm:5.7.0"],\
|
||||
["sqs-consumer", "virtual:18a82f2f722cf47811304317f79c07fee6ecd8a887f3af2b42c72227f3b982ee05bf525aa8a7d2d20252ed23a1ed39ca99b430ed432b264a8bad79965c0cae5e#npm:5.7.0"],\
|
||||
["@types/aws-sdk", null],\
|
||||
["aws-sdk", "npm:2.1157.0"],\
|
||||
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"]\
|
||||
|
@ -12233,21 +12337,21 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:28.0.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-jest-virtual-c9b832d80c/0/cache/ts-jest-npm-28.0.5-8c44d8b86f-53e05db5b7.zip/node_modules/ts-jest/",\
|
||||
["virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-jest-virtual-45e1f3673c/0/cache/ts-jest-npm-28.0.5-8c44d8b86f-53e05db5b7.zip/node_modules/ts-jest/",\
|
||||
"packageDependencies": [\
|
||||
["ts-jest", "virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:28.0.5"],\
|
||||
["ts-jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.0.5"],\
|
||||
["@babel/core", null],\
|
||||
["@types/babel-jest", null],\
|
||||
["@types/babel__core", null],\
|
||||
["@types/esbuild", null],\
|
||||
["@types/jest", "npm:28.1.2"],\
|
||||
["@types/jest", "npm:28.1.3"],\
|
||||
["@types/typescript", null],\
|
||||
["babel-jest", null],\
|
||||
["bs-logger", "npm:0.2.6"],\
|
||||
["esbuild", null],\
|
||||
["fast-json-stable-stringify", "npm:2.1.0"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["jest-util", "npm:28.1.1"],\
|
||||
["json5", "npm:2.2.1"],\
|
||||
["lodash.memoize", "npm:4.1.2"],\
|
||||
|
@ -12270,21 +12374,21 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.0.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-jest-virtual-21163ab03c/0/cache/ts-jest-npm-28.0.5-8c44d8b86f-53e05db5b7.zip/node_modules/ts-jest/",\
|
||||
["virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:28.0.5", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-jest-virtual-c9b832d80c/0/cache/ts-jest-npm-28.0.5-8c44d8b86f-53e05db5b7.zip/node_modules/ts-jest/",\
|
||||
"packageDependencies": [\
|
||||
["ts-jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.0.5"],\
|
||||
["ts-jest", "virtual:16bfd8597041deb71e4581ea0755edd4dcd1b09b8ab14bfbbf5e4d5ca6b5d47ed7fbe2a25cdf57fcbb8e092c30b6beb93d2e7533f9e31c5dc62f7f0e487d1e4b#npm:28.0.5"],\
|
||||
["@babel/core", null],\
|
||||
["@types/babel-jest", null],\
|
||||
["@types/babel__core", null],\
|
||||
["@types/esbuild", null],\
|
||||
["@types/jest", "npm:28.1.3"],\
|
||||
["@types/jest", "npm:28.1.2"],\
|
||||
["@types/typescript", null],\
|
||||
["babel-jest", null],\
|
||||
["bs-logger", "npm:0.2.6"],\
|
||||
["esbuild", null],\
|
||||
["fast-json-stable-stringify", "npm:2.1.0"],\
|
||||
["jest", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:28.1.1"],\
|
||||
["jest", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:28.1.1"],\
|
||||
["jest-util", "npm:28.1.1"],\
|
||||
["json5", "npm:2.2.1"],\
|
||||
["lodash.memoize", "npm:4.1.2"],\
|
||||
|
@ -12463,10 +12567,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/tsutils-virtual-cd74663c37/0/cache/tsutils-npm-3.21.0-347e6636c5-1843f4c1b2.zip/node_modules/tsutils/",\
|
||||
["virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/tsutils-virtual-f8ae8a51d8/0/cache/tsutils-npm-3.21.0-347e6636c5-1843f4c1b2.zip/node_modules/tsutils/",\
|
||||
"packageDependencies": [\
|
||||
["tsutils", "virtual:e64d2841693653abb2dee666d19406912f5e913a8081a709c081d9877d2f39987ff853b7cd736901a2df59af98328f7249f3db0da01abf060cf1d858d4d4e43b#npm:3.21.0"],\
|
||||
["tsutils", "virtual:d2330b8caf9d1ed905d5d037b08afe5d2dcb2220d795f2d96b3dd514824e8aefae721c334dbd0cd8d53c639ff2c9ad893d3d83b1092b2db05593aa9dc8e59994#npm:3.21.0"],\
|
||||
["@types/typescript", null],\
|
||||
["tslib", "npm:1.14.1"],\
|
||||
["typescript", null]\
|
||||
|
|
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/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.
|
@ -16,6 +16,7 @@
|
|||
"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",
|
||||
|
@ -28,6 +29,7 @@
|
|||
"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,6 +37,7 @@
|
|||
"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",
|
||||
"start:api-gateway": "yarn workspace @standardnotes/api-gateway start",
|
||||
"release:beta": "lerna version --conventional-prerelease --conventional-commits --yes -m \"chore(release): publish\""
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
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"
|
||||
}
|
||||
}
|
25
packages/api-gateway/Dockerfile
Normal file
25
packages/api-gateway/Dockerfile
Normal file
|
@ -0,0 +1,25 @@
|
|||
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
|
||||
|
||||
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.0.0",
|
||||
"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",
|
||||
"start": "yarn node dist/bin/server.js",
|
||||
"report": "yarn node dist/bin/report.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@newrelic/native-metrics": "7.0.2",
|
||||
"@newrelic/winston-enricher": "^2.1.0",
|
||||
"@sentry/node": "^6.16.1",
|
||||
"@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.6.0",
|
||||
"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.1",
|
||||
"@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
|
|
@ -20,6 +20,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" ]
|
||||
|
|
|
@ -20,6 +20,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" ]
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
},
|
||||
{
|
||||
"path": "./packages/files"
|
||||
},
|
||||
{
|
||||
"path": "./packages/api-gateway"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
107
yarn.lock
107
yarn.lock
|
@ -1836,13 +1836,55 @@ __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/native-metrics": 7.0.2
|
||||
"@newrelic/winston-enricher": ^2.1.0
|
||||
"@sentry/node": ^6.16.1
|
||||
"@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.1
|
||||
"@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.6.0
|
||||
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"
|
||||
|
@ -1916,6 +1958,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 +1995,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 +2025,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 +2057,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:
|
||||
|
@ -3216,6 +3293,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 +5790,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"
|
||||
|
|
Loading…
Reference in a new issue