mirror of
https://github.com/standardnotes/server
synced 2026-05-15 06:57:35 -04:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1665779b5 | |||
| a82192db42 | |||
| 589b740f49 | |||
| 3c10de3e5d | |||
| 41a04062c9 | |||
| db9d10c302 | |||
| 5596d04040 | |||
| 341f69e301 | |||
| ef0464690b | |||
| 199ebeb4ea | |||
| c949670d4c | |||
| 9dcd583b58 | |||
| 097e320490 | |||
| c9bfda91f4 | |||
| 2d6a3ebf45 | |||
| d0d4bd23fb | |||
| edb0a768d0 | |||
| 4cc647ac07 | |||
| bcd1d830e6 | |||
| 2597324876 | |||
| 69b404f5d4 | |||
| e94b0d0b02 | |||
| ed1bf37287 | |||
| 3946f56261 | |||
| fc53dab007 | |||
| e836abdef7 | |||
| 826482b1f0 | |||
| 45bd00919c | |||
| 4e1bae6daf | |||
| 8f23c8ab3f | |||
| 4d32f26631 | |||
| c11abe1bd3 | |||
| 4d12566b0d | |||
| 2200dca69d | |||
| d41dd3bdda | |||
| c5c24b3ac9 | |||
| 462ade2145 | |||
| bfef16ce37 | |||
| aa4351c8e9 | |||
| 2dff6a2ed3 | |||
| 7808cc8ed2 | |||
| 5b84f078c6 | |||
| cf5f44a4a5 | |||
| ed05ea553f | |||
| 4418c38878 | |||
| 6391a01b57 | |||
| 9dbcec198d | |||
| 78fbeb595f | |||
| d894a87e87 | |||
| 4f62cac213 | |||
| ce081274da | |||
| fd997f4849 | |||
| 3ddd671c47 | |||
| c19de13cac | |||
| f65809ef30 | |||
| 2823ed8612 | |||
| 420bf9ec54 | |||
| 5f67e5efda | |||
| daed1a77a0 | |||
| b39eb09d91 | |||
| f6ec8626e5 | |||
| 97b12f2131 | |||
| 8e4e36513a | |||
| c8bf4ab3a0 | |||
| 3fa01a328b | |||
| 60686dcdbd | |||
| fddd17e531 | |||
| f99750169f | |||
| daad76d0dd | |||
| b3542e2fab | |||
| a9b1543e20 | |||
| e6d8e5c5f2 | |||
| c24353cc24 | |||
| 4855e1d5f5 | |||
| 5d3fb9a537 | |||
| b55d80a7cd | |||
| 16f92bdc99 | |||
| 4c5738416a | |||
| 45d4920e0f |
@@ -61,13 +61,6 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: "direct"
|
- dependency-type: "direct"
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/packages/event-store"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
allow:
|
|
||||||
- dependency-type: "direct"
|
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/packages/files"
|
directory: "/packages/files"
|
||||||
schedule:
|
schedule:
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ jobs:
|
|||||||
name: (Self Hosting) E2E Test Suite
|
name: (Self Hosting) E2E Test Suite
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
service_proxy_type: [http, grpc]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -42,6 +44,14 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DB_TYPE: mysql
|
DB_TYPE: mysql
|
||||||
CACHE_TYPE: redis
|
CACHE_TYPE: redis
|
||||||
|
SERVICE_PROXY_TYPE: ${{ matrix.service_proxy_type }}
|
||||||
|
|
||||||
|
- name: Output Server Logs to File
|
||||||
|
run: docker compose -f docker-compose.ci.yml logs -f > logs/docker-compose.log 2>&1 &
|
||||||
|
env:
|
||||||
|
DB_TYPE: mysql
|
||||||
|
CACHE_TYPE: redis
|
||||||
|
SERVICE_PROXY_TYPE: ${{ matrix.service_proxy_type }}
|
||||||
|
|
||||||
- name: Wait for server to start
|
- name: Wait for server to start
|
||||||
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: contains(github.event.head_commit.message, 'chore(release)') == false
|
if: contains(github.event.head_commit.message, 'chore(release)') == false
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ const RAW_RUNTIME_STATE =
|
|||||||
"name": "@standardnotes/domain-events-infra",\
|
"name": "@standardnotes/domain-events-infra",\
|
||||||
"reference": "workspace:packages/domain-events-infra"\
|
"reference": "workspace:packages/domain-events-infra"\
|
||||||
},\
|
},\
|
||||||
{\
|
|
||||||
"name": "@standardnotes/event-store",\
|
|
||||||
"reference": "workspace:packages/event-store"\
|
|
||||||
},\
|
|
||||||
{\
|
{\
|
||||||
"name": "@standardnotes/files-server",\
|
"name": "@standardnotes/files-server",\
|
||||||
"reference": "workspace:packages/files"\
|
"reference": "workspace:packages/files"\
|
||||||
},\
|
},\
|
||||||
|
{\
|
||||||
|
"name": "@standardnotes/grpc",\
|
||||||
|
"reference": "workspace:packages/grpc"\
|
||||||
|
},\
|
||||||
{\
|
{\
|
||||||
"name": "@standardnotes/home-server",\
|
"name": "@standardnotes/home-server",\
|
||||||
"reference": "workspace:packages/home-server"\
|
"reference": "workspace:packages/home-server"\
|
||||||
@@ -100,8 +100,8 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/domain-core", ["workspace:packages/domain-core"]],\
|
["@standardnotes/domain-core", ["workspace:packages/domain-core"]],\
|
||||||
["@standardnotes/domain-events", ["workspace:packages/domain-events"]],\
|
["@standardnotes/domain-events", ["workspace:packages/domain-events"]],\
|
||||||
["@standardnotes/domain-events-infra", ["workspace:packages/domain-events-infra"]],\
|
["@standardnotes/domain-events-infra", ["workspace:packages/domain-events-infra"]],\
|
||||||
["@standardnotes/event-store", ["workspace:packages/event-store"]],\
|
|
||||||
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
||||||
|
["@standardnotes/grpc", ["workspace:packages/grpc"]],\
|
||||||
["@standardnotes/home-server", ["workspace:packages/home-server"]],\
|
["@standardnotes/home-server", ["workspace:packages/home-server"]],\
|
||||||
["@standardnotes/predicates", ["workspace:packages/predicates"]],\
|
["@standardnotes/predicates", ["workspace:packages/predicates"]],\
|
||||||
["@standardnotes/revisions-server", ["workspace:packages/revisions"]],\
|
["@standardnotes/revisions-server", ["workspace:packages/revisions"]],\
|
||||||
@@ -2674,6 +2674,15 @@ const RAW_RUNTIME_STATE =
|
|||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["@grpc/grpc-js", [\
|
["@grpc/grpc-js", [\
|
||||||
|
["npm:1.9.11", {\
|
||||||
|
"packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.11-5bb7febd65-71b8517b4f.zip/node_modules/@grpc/grpc-js/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["@grpc/grpc-js", "npm:1.9.11"],\
|
||||||
|
["@grpc/proto-loader", "npm:0.7.10"],\
|
||||||
|
["@types/node", "npm:20.2.5"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
["npm:1.9.5", {\
|
["npm:1.9.5", {\
|
||||||
"packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.5-9b0cd6b5ed-5499d964d2.zip/node_modules/@grpc/grpc-js/",\
|
"packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.5-9b0cd6b5ed-5499d964d2.zip/node_modules/@grpc/grpc-js/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
@@ -3575,6 +3584,22 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tar", "npm:6.1.15"]\
|
["tar", "npm:6.1.15"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
|
["npm:1.0.11", {\
|
||||||
|
"packageLocation": "./.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.11-5547f15a2b-59529a2444.zip/node_modules/@mapbox/node-pre-gyp/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["@mapbox/node-pre-gyp", "npm:1.0.11"],\
|
||||||
|
["detect-libc", "npm:2.0.1"],\
|
||||||
|
["https-proxy-agent", "npm:5.0.1"],\
|
||||||
|
["make-dir", "npm:3.1.0"],\
|
||||||
|
["node-fetch", "virtual:0f92dfe7f9dc4fd492639d4a5b7805c2b27442bf599fd4f370b22a7966ba078f5d4525e2a8e8af29369f20e1833ed084bd52be59679efaa6c1c6c10cdbcd8baa#npm:2.6.11"],\
|
||||||
|
["nopt", "npm:5.0.0"],\
|
||||||
|
["npmlog", "npm:5.0.1"],\
|
||||||
|
["rimraf", "npm:3.0.2"],\
|
||||||
|
["semver", "npm:7.5.1"],\
|
||||||
|
["tar", "npm:6.1.15"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["@nodelib/fs.scandir", [\
|
["@nodelib/fs.scandir", [\
|
||||||
@@ -6376,9 +6401,11 @@ const RAW_RUNTIME_STATE =
|
|||||||
"packageLocation": "./packages/api-gateway/",\
|
"packageLocation": "./packages/api-gateway/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
||||||
|
["@grpc/grpc-js", "npm:1.9.11"],\
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||||
|
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||||
["@standardnotes/security", "workspace:packages/security"],\
|
["@standardnotes/security", "workspace:packages/security"],\
|
||||||
["@standardnotes/time", "workspace:packages/time"],\
|
["@standardnotes/time", "workspace:packages/time"],\
|
||||||
["@types/cors", "npm:2.8.13"],\
|
["@types/cors", "npm:2.8.13"],\
|
||||||
@@ -6390,7 +6417,8 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@types/prettyjson", "npm:0.0.30"],\
|
["@types/prettyjson", "npm:0.0.30"],\
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["axios", "npm:1.4.0"],\
|
["agentkeepalive", "npm:4.5.0"],\
|
||||||
|
["axios", "npm:1.6.1"],\
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
["eslint", "npm:8.41.0"],\
|
["eslint", "npm:8.41.0"],\
|
||||||
@@ -6423,6 +6451,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
||||||
["@cbor-extract/cbor-extract-linux-arm64", "npm:2.1.1"],\
|
["@cbor-extract/cbor-extract-linux-arm64", "npm:2.1.1"],\
|
||||||
["@cbor-extract/cbor-extract-linux-x64", "npm:2.1.1"],\
|
["@cbor-extract/cbor-extract-linux-x64", "npm:2.1.1"],\
|
||||||
|
["@grpc/grpc-js", "npm:1.9.11"],\
|
||||||
["@simplewebauthn/server", "npm:8.1.1"],\
|
["@simplewebauthn/server", "npm:8.1.1"],\
|
||||||
["@simplewebauthn/typescript-types", "npm:8.0.0"],\
|
["@simplewebauthn/typescript-types", "npm:8.0.0"],\
|
||||||
["@standardnotes/api", "npm:1.26.26"],\
|
["@standardnotes/api", "npm:1.26.26"],\
|
||||||
@@ -6431,6 +6460,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||||
["@standardnotes/features", "npm:1.59.7"],\
|
["@standardnotes/features", "npm:1.59.7"],\
|
||||||
|
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||||
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
||||||
["@standardnotes/responses", "npm:1.13.27"],\
|
["@standardnotes/responses", "npm:1.13.27"],\
|
||||||
["@standardnotes/security", "workspace:packages/security"],\
|
["@standardnotes/security", "workspace:packages/security"],\
|
||||||
@@ -6578,38 +6608,6 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "SOFT"\
|
"linkType": "SOFT"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["@standardnotes/event-store", [\
|
|
||||||
["workspace:packages/event-store", {\
|
|
||||||
"packageLocation": "./packages/event-store/",\
|
|
||||||
"packageDependencies": [\
|
|
||||||
["@standardnotes/event-store", "workspace:packages/event-store"],\
|
|
||||||
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
|
||||||
["@standardnotes/time", "workspace:packages/time"],\
|
|
||||||
["@types/ioredis", "npm:5.0.0"],\
|
|
||||||
["@types/jest", "npm:29.5.2"],\
|
|
||||||
["@types/nodemailer", "npm:6.4.8"],\
|
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
|
||||||
["dotenv", "npm:16.1.3"],\
|
|
||||||
["eslint", "npm:8.41.0"],\
|
|
||||||
["eslint-plugin-prettier", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.0.0"],\
|
|
||||||
["inversify", "npm:6.0.1"],\
|
|
||||||
["ioredis", "npm:5.3.2"],\
|
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
|
||||||
["mysql2", "npm:3.3.3"],\
|
|
||||||
["prettier", "npm:3.0.3"],\
|
|
||||||
["reflect-metadata", "npm:0.1.13"],\
|
|
||||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
|
||||||
["typeorm", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:0.3.17"],\
|
|
||||||
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
|
|
||||||
["winston", "npm:3.9.0"]\
|
|
||||||
],\
|
|
||||||
"linkType": "SOFT"\
|
|
||||||
}]\
|
|
||||||
]],\
|
|
||||||
["@standardnotes/features", [\
|
["@standardnotes/features", [\
|
||||||
["npm:1.59.7", {\
|
["npm:1.59.7", {\
|
||||||
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.59.7-27c3e5296e-421af62d1e.zip/node_modules/@standardnotes/features/",\
|
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.59.7-27c3e5296e-421af62d1e.zip/node_modules/@standardnotes/features/",\
|
||||||
@@ -6675,6 +6673,21 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "SOFT"\
|
"linkType": "SOFT"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["@standardnotes/grpc", [\
|
||||||
|
["workspace:packages/grpc", {\
|
||||||
|
"packageLocation": "./packages/grpc/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||||
|
["@grpc/grpc-js", "npm:1.9.11"],\
|
||||||
|
["@types/google-protobuf", "npm:3.15.10"],\
|
||||||
|
["google-protobuf", "npm:3.21.2"],\
|
||||||
|
["grpc-tools", "npm:1.12.4"],\
|
||||||
|
["grpc_tools_node_protoc_ts", "npm:5.3.3"],\
|
||||||
|
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"]\
|
||||||
|
],\
|
||||||
|
"linkType": "SOFT"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["@standardnotes/home-server", [\
|
["@standardnotes/home-server", [\
|
||||||
["workspace:packages/home-server", {\
|
["workspace:packages/home-server", {\
|
||||||
"packageLocation": "./packages/home-server/",\
|
"packageLocation": "./packages/home-server/",\
|
||||||
@@ -6938,11 +6951,13 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@aws-sdk/client-s3", "npm:3.427.0"],\
|
["@aws-sdk/client-s3", "npm:3.427.0"],\
|
||||||
["@aws-sdk/client-sns", "npm:3.427.0"],\
|
["@aws-sdk/client-sns", "npm:3.427.0"],\
|
||||||
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
||||||
|
["@grpc/grpc-js", "npm:1.9.11"],\
|
||||||
["@standardnotes/api", "npm:1.26.26"],\
|
["@standardnotes/api", "npm:1.26.26"],\
|
||||||
["@standardnotes/common", "workspace:packages/common"],\
|
["@standardnotes/common", "workspace:packages/common"],\
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||||
|
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||||
["@standardnotes/responses", "npm:1.13.27"],\
|
["@standardnotes/responses", "npm:1.13.27"],\
|
||||||
["@standardnotes/security", "workspace:packages/security"],\
|
["@standardnotes/security", "workspace:packages/security"],\
|
||||||
["@standardnotes/settings", "workspace:packages/settings"],\
|
["@standardnotes/settings", "workspace:packages/settings"],\
|
||||||
@@ -6961,7 +6976,6 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@types/uuid", "npm:9.0.3"],\
|
["@types/uuid", "npm:9.0.3"],\
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["axios", "npm:1.4.0"],\
|
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
["eslint", "npm:8.41.0"],\
|
["eslint", "npm:8.41.0"],\
|
||||||
@@ -7031,20 +7045,19 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/websockets-server", "workspace:packages/websockets"],\
|
["@standardnotes/websockets-server", "workspace:packages/websockets"],\
|
||||||
["@aws-sdk/client-apigatewaymanagementapi", "npm:3.427.0"],\
|
["@aws-sdk/client-apigatewaymanagementapi", "npm:3.427.0"],\
|
||||||
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
||||||
["@standardnotes/api", "npm:1.26.26"],\
|
|
||||||
["@standardnotes/common", "workspace:packages/common"],\
|
["@standardnotes/common", "workspace:packages/common"],\
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||||
["@standardnotes/responses", "npm:1.13.27"],\
|
["@standardnotes/responses", "npm:1.13.27"],\
|
||||||
["@standardnotes/security", "workspace:packages/security"],\
|
["@standardnotes/security", "workspace:packages/security"],\
|
||||||
|
["@standardnotes/time", "workspace:packages/time"],\
|
||||||
["@types/cors", "npm:2.8.13"],\
|
["@types/cors", "npm:2.8.13"],\
|
||||||
["@types/express", "npm:4.17.17"],\
|
["@types/express", "npm:4.17.17"],\
|
||||||
["@types/ioredis", "npm:5.0.0"],\
|
["@types/ioredis", "npm:5.0.0"],\
|
||||||
["@types/jest", "npm:29.5.2"],\
|
["@types/jest", "npm:29.5.2"],\
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["axios", "npm:1.4.0"],\
|
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
["eslint", "npm:8.41.0"],\
|
["eslint", "npm:8.41.0"],\
|
||||||
@@ -7322,6 +7335,15 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["@types/google-protobuf", [\
|
||||||
|
["npm:3.15.10", {\
|
||||||
|
"packageLocation": "./.yarn/cache/@types-google-protobuf-npm-3.15.10-cbaa6c3e6c-29efde966f.zip/node_modules/@types/google-protobuf/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["@types/google-protobuf", "npm:3.15.10"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["@types/graceful-fs", [\
|
["@types/graceful-fs", [\
|
||||||
["npm:4.1.6", {\
|
["npm:4.1.6", {\
|
||||||
"packageLocation": "./.yarn/cache/@types-graceful-fs-npm-4.1.6-1eadcf742d-c3070ccdc9.zip/node_modules/@types/graceful-fs/",\
|
"packageLocation": "./.yarn/cache/@types-graceful-fs-npm-4.1.6-1eadcf742d-c3070ccdc9.zip/node_modules/@types/graceful-fs/",\
|
||||||
@@ -7477,16 +7499,6 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["@types/nodemailer", [\
|
|
||||||
["npm:6.4.8", {\
|
|
||||||
"packageLocation": "./.yarn/cache/@types-nodemailer-npm-6.4.8-04975b93f9-d5afdd77ef.zip/node_modules/@types/nodemailer/",\
|
|
||||||
"packageDependencies": [\
|
|
||||||
["@types/nodemailer", "npm:6.4.8"],\
|
|
||||||
["@types/node", "npm:20.2.5"]\
|
|
||||||
],\
|
|
||||||
"linkType": "HARD"\
|
|
||||||
}]\
|
|
||||||
]],\
|
|
||||||
["@types/normalize-package-data", [\
|
["@types/normalize-package-data", [\
|
||||||
["npm:2.4.1", {\
|
["npm:2.4.1", {\
|
||||||
"packageLocation": "./.yarn/cache/@types-normalize-package-data-npm-2.4.1-c31c56ae6a-e87bccbf11.zip/node_modules/@types/normalize-package-data/",\
|
"packageLocation": "./.yarn/cache/@types-normalize-package-data-npm-2.4.1-c31c56ae6a-e87bccbf11.zip/node_modules/@types/normalize-package-data/",\
|
||||||
@@ -8196,6 +8208,14 @@ const RAW_RUNTIME_STATE =
|
|||||||
["humanize-ms", "npm:1.2.1"]\
|
["humanize-ms", "npm:1.2.1"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
|
["npm:4.5.0", {\
|
||||||
|
"packageLocation": "./.yarn/cache/agentkeepalive-npm-4.5.0-f237b580b2-dd210ba2a2.zip/node_modules/agentkeepalive/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["agentkeepalive", "npm:4.5.0"],\
|
||||||
|
["humanize-ms", "npm:1.2.1"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["aggregate-error", [\
|
["aggregate-error", [\
|
||||||
@@ -8498,11 +8518,11 @@ const RAW_RUNTIME_STATE =
|
|||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["axios", [\
|
["axios", [\
|
||||||
["npm:1.4.0", {\
|
["npm:1.6.1", {\
|
||||||
"packageLocation": "./.yarn/cache/axios-npm-1.4.0-4d7ce8ca3e-b987e4259e.zip/node_modules/axios/",\
|
"packageLocation": "./.yarn/cache/axios-npm-1.6.1-ffaff76449-fb091af3ad.zip/node_modules/axios/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
["axios", "npm:1.4.0"],\
|
["axios", "npm:1.6.1"],\
|
||||||
["follow-redirects", "virtual:4d7ce8ca3e1e44d82523fba2ad95e1be18c4e9f8dec6d551377587540da3ed75bd8bd3e812280309a3b90cfdb0560f076f3552a20839f7f15665207a4fbd588a#npm:1.15.2"],\
|
["follow-redirects", "virtual:ffaff76449f02e83712a7d24e03c564489516739c78ebeffb0fbcdb3893ad9a0e48504f9acfa70fe6f16debe9c8dabde3679d63bf648278ea98a5ff38cf77a9e#npm:1.15.2"],\
|
||||||
["form-data", "npm:4.0.0"],\
|
["form-data", "npm:4.0.0"],\
|
||||||
["proxy-from-env", "npm:1.1.0"]\
|
["proxy-from-env", "npm:1.1.0"]\
|
||||||
],\
|
],\
|
||||||
@@ -10906,10 +10926,10 @@ const RAW_RUNTIME_STATE =
|
|||||||
],\
|
],\
|
||||||
"linkType": "SOFT"\
|
"linkType": "SOFT"\
|
||||||
}],\
|
}],\
|
||||||
["virtual:4d7ce8ca3e1e44d82523fba2ad95e1be18c4e9f8dec6d551377587540da3ed75bd8bd3e812280309a3b90cfdb0560f076f3552a20839f7f15665207a4fbd588a#npm:1.15.2", {\
|
["virtual:ffaff76449f02e83712a7d24e03c564489516739c78ebeffb0fbcdb3893ad9a0e48504f9acfa70fe6f16debe9c8dabde3679d63bf648278ea98a5ff38cf77a9e#npm:1.15.2", {\
|
||||||
"packageLocation": "./.yarn/__virtual__/follow-redirects-virtual-359bc4c55c/0/cache/follow-redirects-npm-1.15.2-1ec1dd82be-8be0d39919.zip/node_modules/follow-redirects/",\
|
"packageLocation": "./.yarn/__virtual__/follow-redirects-virtual-c2d5794c26/0/cache/follow-redirects-npm-1.15.2-1ec1dd82be-8be0d39919.zip/node_modules/follow-redirects/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
["follow-redirects", "virtual:4d7ce8ca3e1e44d82523fba2ad95e1be18c4e9f8dec6d551377587540da3ed75bd8bd3e812280309a3b90cfdb0560f076f3552a20839f7f15665207a4fbd588a#npm:1.15.2"],\
|
["follow-redirects", "virtual:ffaff76449f02e83712a7d24e03c564489516739c78ebeffb0fbcdb3893ad9a0e48504f9acfa70fe6f16debe9c8dabde3679d63bf648278ea98a5ff38cf77a9e#npm:1.15.2"],\
|
||||||
["@types/debug", null],\
|
["@types/debug", null],\
|
||||||
["debug", null]\
|
["debug", null]\
|
||||||
],\
|
],\
|
||||||
@@ -11336,6 +11356,22 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["google-protobuf", [\
|
||||||
|
["npm:3.15.8", {\
|
||||||
|
"packageLocation": "./.yarn/cache/google-protobuf-npm-3.15.8-75df975b6c-0b1ea24a55.zip/node_modules/google-protobuf/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["google-protobuf", "npm:3.15.8"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
|
["npm:3.21.2", {\
|
||||||
|
"packageLocation": "./.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-b376c2e47f.zip/node_modules/google-protobuf/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["google-protobuf", "npm:3.21.2"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["graceful-fs", [\
|
["graceful-fs", [\
|
||||||
["npm:4.2.11", {\
|
["npm:4.2.11", {\
|
||||||
"packageLocation": "./.yarn/cache/graceful-fs-npm-4.2.11-24bb648a68-bf152d0ed1.zip/node_modules/graceful-fs/",\
|
"packageLocation": "./.yarn/cache/graceful-fs-npm-4.2.11-24bb648a68-bf152d0ed1.zip/node_modules/graceful-fs/",\
|
||||||
@@ -11354,6 +11390,27 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["grpc-tools", [\
|
||||||
|
["npm:1.12.4", {\
|
||||||
|
"packageLocation": "./.yarn/unplugged/grpc-tools-npm-1.12.4-956df6794d/node_modules/grpc-tools/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["grpc-tools", "npm:1.12.4"],\
|
||||||
|
["@mapbox/node-pre-gyp", "npm:1.0.11"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
|
["grpc_tools_node_protoc_ts", [\
|
||||||
|
["npm:5.3.3", {\
|
||||||
|
"packageLocation": "./.yarn/unplugged/grpc_tools_node_protoc_ts-npm-5.3.3-297a345c26/node_modules/grpc_tools_node_protoc_ts/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["grpc_tools_node_protoc_ts", "npm:5.3.3"],\
|
||||||
|
["google-protobuf", "npm:3.15.8"],\
|
||||||
|
["handlebars", "npm:4.7.7"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["handlebars", [\
|
["handlebars", [\
|
||||||
["npm:4.7.7", {\
|
["npm:4.7.7", {\
|
||||||
"packageLocation": "./.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip/node_modules/handlebars/",\
|
"packageLocation": "./.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip/node_modules/handlebars/",\
|
||||||
@@ -17991,14 +18048,16 @@ const Filename = {
|
|||||||
const npath = Object.create(path__default.default);
|
const npath = Object.create(path__default.default);
|
||||||
const ppath = Object.create(path__default.default.posix);
|
const ppath = Object.create(path__default.default.posix);
|
||||||
npath.cwd = () => process.cwd();
|
npath.cwd = () => process.cwd();
|
||||||
ppath.cwd = () => toPortablePath(process.cwd());
|
ppath.cwd = process.platform === `win32` ? () => toPortablePath(process.cwd()) : process.cwd;
|
||||||
ppath.resolve = (...segments) => {
|
if (process.platform === `win32`) {
|
||||||
if (segments.length > 0 && ppath.isAbsolute(segments[0])) {
|
ppath.resolve = (...segments) => {
|
||||||
return path__default.default.posix.resolve(...segments);
|
if (segments.length > 0 && ppath.isAbsolute(segments[0])) {
|
||||||
} else {
|
return path__default.default.posix.resolve(...segments);
|
||||||
return path__default.default.posix.resolve(ppath.cwd(), ...segments);
|
} else {
|
||||||
}
|
return path__default.default.posix.resolve(ppath.cwd(), ...segments);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
const contains = function(pathUtils, from, to) {
|
const contains = function(pathUtils, from, to) {
|
||||||
from = pathUtils.normalize(from);
|
from = pathUtils.normalize(from);
|
||||||
to = pathUtils.normalize(to);
|
to = pathUtils.normalize(to);
|
||||||
@@ -18012,17 +18071,13 @@ const contains = function(pathUtils, from, to) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
npath.fromPortablePath = fromPortablePath;
|
|
||||||
npath.toPortablePath = toPortablePath;
|
|
||||||
npath.contains = (from, to) => contains(npath, from, to);
|
npath.contains = (from, to) => contains(npath, from, to);
|
||||||
ppath.contains = (from, to) => contains(ppath, from, to);
|
ppath.contains = (from, to) => contains(ppath, from, to);
|
||||||
const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/;
|
const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/;
|
||||||
const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/;
|
const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/;
|
||||||
const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/;
|
const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/;
|
||||||
const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/;
|
const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/;
|
||||||
function fromPortablePath(p) {
|
function fromPortablePathWin32(p) {
|
||||||
if (process.platform !== `win32`)
|
|
||||||
return p;
|
|
||||||
let portablePathMatch, uncPortablePathMatch;
|
let portablePathMatch, uncPortablePathMatch;
|
||||||
if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP))
|
if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP))
|
||||||
p = portablePathMatch[1];
|
p = portablePathMatch[1];
|
||||||
@@ -18032,9 +18087,7 @@ function fromPortablePath(p) {
|
|||||||
return p;
|
return p;
|
||||||
return p.replace(/\//g, `\\`);
|
return p.replace(/\//g, `\\`);
|
||||||
}
|
}
|
||||||
function toPortablePath(p) {
|
function toPortablePathWin32(p) {
|
||||||
if (process.platform !== `win32`)
|
|
||||||
return p;
|
|
||||||
p = p.replace(/\\/g, `/`);
|
p = p.replace(/\\/g, `/`);
|
||||||
let windowsPathMatch, uncWindowsPathMatch;
|
let windowsPathMatch, uncWindowsPathMatch;
|
||||||
if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP))
|
if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP))
|
||||||
@@ -18043,6 +18096,10 @@ function toPortablePath(p) {
|
|||||||
p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`;
|
p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
const toPortablePath = process.platform === `win32` ? toPortablePathWin32 : (p) => p;
|
||||||
|
const fromPortablePath = process.platform === `win32` ? fromPortablePathWin32 : (p) => p;
|
||||||
|
npath.fromPortablePath = fromPortablePath;
|
||||||
|
npath.toPortablePath = toPortablePath;
|
||||||
function convertPath(targetPathUtils, sourcePath) {
|
function convertPath(targetPathUtils, sourcePath) {
|
||||||
return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath);
|
return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath);
|
||||||
}
|
}
|
||||||
@@ -19087,6 +19144,12 @@ class ProxiedFS extends FakeFS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function direntToPortable(dirent) {
|
||||||
|
const portableDirent = dirent;
|
||||||
|
if (typeof dirent.path === `string`)
|
||||||
|
portableDirent.path = npath.toPortablePath(dirent.path);
|
||||||
|
return portableDirent;
|
||||||
|
}
|
||||||
class NodeFS extends BasePortableFakeFS {
|
class NodeFS extends BasePortableFakeFS {
|
||||||
constructor(realFs = fs__default.default) {
|
constructor(realFs = fs__default.default) {
|
||||||
super();
|
super();
|
||||||
@@ -19413,15 +19476,31 @@ class NodeFS extends BasePortableFakeFS {
|
|||||||
async readdirPromise(p, opts) {
|
async readdirPromise(p, opts) {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
if (opts) {
|
if (opts) {
|
||||||
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
|
if (opts.recursive && process.platform === `win32`) {
|
||||||
|
if (opts.withFileTypes) {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(direntToPortable)), reject));
|
||||||
|
} else {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(npath.toPortablePath)), reject));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject));
|
this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
readdirSync(p, opts) {
|
readdirSync(p, opts) {
|
||||||
if (opts) {
|
if (opts) {
|
||||||
return this.realFs.readdirSync(npath.fromPortablePath(p), opts);
|
if (opts.recursive && process.platform === `win32`) {
|
||||||
|
if (opts.withFileTypes) {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(direntToPortable);
|
||||||
|
} else {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(npath.toPortablePath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return this.realFs.readdirSync(npath.fromPortablePath(p));
|
return this.realFs.readdirSync(npath.fromPortablePath(p));
|
||||||
}
|
}
|
||||||
@@ -22975,8 +23054,6 @@ function getPathForDisplay(p) {
|
|||||||
const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
|
const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
|
||||||
const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
|
const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
|
||||||
|
|
||||||
const builtinModules = new Set(require$$0.Module.builtinModules || Object.keys(process.binding(`natives`)));
|
|
||||||
const isBuiltinModule = (request) => request.startsWith(`node:`) || builtinModules.has(request);
|
|
||||||
function readPackageScope(checkPath) {
|
function readPackageScope(checkPath) {
|
||||||
const rootSeparatorIndex = checkPath.indexOf(npath.sep);
|
const rootSeparatorIndex = checkPath.indexOf(npath.sep);
|
||||||
let separatorIndex;
|
let separatorIndex;
|
||||||
@@ -23085,7 +23162,7 @@ function applyPatch(pnpapi, opts) {
|
|||||||
const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:@[^/]+\/)?[^/]+)\/*(.*|)$/;
|
const pathRegExp = /^(?![a-zA-Z]:[\\/]|\\\\|\.{0,2}(?:\/|$))((?:@[^/]+\/)?[^/]+)\/*(.*|)$/;
|
||||||
const originalModuleResolveFilename = require$$0.Module._resolveFilename;
|
const originalModuleResolveFilename = require$$0.Module._resolveFilename;
|
||||||
require$$0.Module._resolveFilename = function(request, parent, isMain, options) {
|
require$$0.Module._resolveFilename = function(request, parent, isMain, options) {
|
||||||
if (isBuiltinModule(request))
|
if (require$$0.isBuiltin(request))
|
||||||
return request;
|
return request;
|
||||||
if (!enableNativeHooks)
|
if (!enableNativeHooks)
|
||||||
return originalModuleResolveFilename.call(require$$0.Module, request, parent, isMain, options);
|
return originalModuleResolveFilename.call(require$$0.Module, request, parent, isMain, options);
|
||||||
@@ -24447,7 +24524,7 @@ function makeApi(runtimeState, opts) {
|
|||||||
throw new Error(`resolveToUnqualified can not handle private import mappings`);
|
throw new Error(`resolveToUnqualified can not handle private import mappings`);
|
||||||
if (request === `pnpapi`)
|
if (request === `pnpapi`)
|
||||||
return npath.toPortablePath(opts.pnpapiResolution);
|
return npath.toPortablePath(opts.pnpapiResolution);
|
||||||
if (considerBuiltins && isBuiltinModule(request))
|
if (considerBuiltins && require$$0.isBuiltin(request))
|
||||||
return null;
|
return null;
|
||||||
const requestForDisplay = getPathForDisplay(request);
|
const requestForDisplay = getPathForDisplay(request);
|
||||||
const issuerForDisplay = issuer && getPathForDisplay(issuer);
|
const issuerForDisplay = issuer && getPathForDisplay(issuer);
|
||||||
@@ -24585,7 +24662,7 @@ ${brokenAncestors.map((ancestorLocator) => `Ancestor breaking the chain: ${ances
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (dependencyReference === void 0) {
|
} else if (dependencyReference === void 0) {
|
||||||
if (!considerBuiltins && isBuiltinModule(request)) {
|
if (!considerBuiltins && require$$0.isBuiltin(request)) {
|
||||||
if (isDependencyTreeRoot(issuerLocator)) {
|
if (isDependencyTreeRoot(issuerLocator)) {
|
||||||
error = makeError(
|
error = makeError(
|
||||||
ErrorCode.UNDECLARED_DEPENDENCY,
|
ErrorCode.UNDECLARED_DEPENDENCY,
|
||||||
@@ -24752,7 +24829,7 @@ ${candidates.map((candidate) => `Not found: ${getPathForDisplay(candidate)}
|
|||||||
if (unqualifiedPath === null)
|
if (unqualifiedPath === null)
|
||||||
return null;
|
return null;
|
||||||
const isIssuerIgnored = () => issuer !== null ? isPathIgnored(issuer) : false;
|
const isIssuerIgnored = () => issuer !== null ? isPathIgnored(issuer) : false;
|
||||||
const remappedPath = (!considerBuiltins || !isBuiltinModule(request)) && !isIssuerIgnored() ? resolveUnqualifiedExport(request, unqualifiedPath, conditions, issuer) : unqualifiedPath;
|
const remappedPath = (!considerBuiltins || !require$$0.isBuiltin(request)) && !isIssuerIgnored() ? resolveUnqualifiedExport(request, unqualifiedPath, conditions, issuer) : unqualifiedPath;
|
||||||
return resolveUnqualified(remappedPath, { extensions });
|
return resolveUnqualified(remappedPath, { extensions });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (Object.hasOwn(error, `pnpCode`))
|
if (Object.hasOwn(error, `pnpCode`))
|
||||||
|
|||||||
Generated
+81
-46
@@ -1,9 +1,9 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url';
|
import { URL as URL$1, fileURLToPath, pathToFileURL } from 'url';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import moduleExports, { Module } from 'module';
|
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import { EOL } from 'os';
|
import { EOL } from 'os';
|
||||||
|
import moduleExports, { isBuiltin } from 'module';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
const SAFE_TIME = 456789e3;
|
const SAFE_TIME = 456789e3;
|
||||||
@@ -16,14 +16,16 @@ const PortablePath = {
|
|||||||
const npath = Object.create(path);
|
const npath = Object.create(path);
|
||||||
const ppath = Object.create(path.posix);
|
const ppath = Object.create(path.posix);
|
||||||
npath.cwd = () => process.cwd();
|
npath.cwd = () => process.cwd();
|
||||||
ppath.cwd = () => toPortablePath(process.cwd());
|
ppath.cwd = process.platform === `win32` ? () => toPortablePath(process.cwd()) : process.cwd;
|
||||||
ppath.resolve = (...segments) => {
|
if (process.platform === `win32`) {
|
||||||
if (segments.length > 0 && ppath.isAbsolute(segments[0])) {
|
ppath.resolve = (...segments) => {
|
||||||
return path.posix.resolve(...segments);
|
if (segments.length > 0 && ppath.isAbsolute(segments[0])) {
|
||||||
} else {
|
return path.posix.resolve(...segments);
|
||||||
return path.posix.resolve(ppath.cwd(), ...segments);
|
} else {
|
||||||
}
|
return path.posix.resolve(ppath.cwd(), ...segments);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
const contains = function(pathUtils, from, to) {
|
const contains = function(pathUtils, from, to) {
|
||||||
from = pathUtils.normalize(from);
|
from = pathUtils.normalize(from);
|
||||||
to = pathUtils.normalize(to);
|
to = pathUtils.normalize(to);
|
||||||
@@ -37,17 +39,13 @@ const contains = function(pathUtils, from, to) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
npath.fromPortablePath = fromPortablePath;
|
|
||||||
npath.toPortablePath = toPortablePath;
|
|
||||||
npath.contains = (from, to) => contains(npath, from, to);
|
npath.contains = (from, to) => contains(npath, from, to);
|
||||||
ppath.contains = (from, to) => contains(ppath, from, to);
|
ppath.contains = (from, to) => contains(ppath, from, to);
|
||||||
const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/;
|
const WINDOWS_PATH_REGEXP = /^([a-zA-Z]:.*)$/;
|
||||||
const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/;
|
const UNC_WINDOWS_PATH_REGEXP = /^\/\/(\.\/)?(.*)$/;
|
||||||
const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/;
|
const PORTABLE_PATH_REGEXP = /^\/([a-zA-Z]:.*)$/;
|
||||||
const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/;
|
const UNC_PORTABLE_PATH_REGEXP = /^\/unc\/(\.dot\/)?(.*)$/;
|
||||||
function fromPortablePath(p) {
|
function fromPortablePathWin32(p) {
|
||||||
if (process.platform !== `win32`)
|
|
||||||
return p;
|
|
||||||
let portablePathMatch, uncPortablePathMatch;
|
let portablePathMatch, uncPortablePathMatch;
|
||||||
if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP))
|
if (portablePathMatch = p.match(PORTABLE_PATH_REGEXP))
|
||||||
p = portablePathMatch[1];
|
p = portablePathMatch[1];
|
||||||
@@ -57,9 +55,7 @@ function fromPortablePath(p) {
|
|||||||
return p;
|
return p;
|
||||||
return p.replace(/\//g, `\\`);
|
return p.replace(/\//g, `\\`);
|
||||||
}
|
}
|
||||||
function toPortablePath(p) {
|
function toPortablePathWin32(p) {
|
||||||
if (process.platform !== `win32`)
|
|
||||||
return p;
|
|
||||||
p = p.replace(/\\/g, `/`);
|
p = p.replace(/\\/g, `/`);
|
||||||
let windowsPathMatch, uncWindowsPathMatch;
|
let windowsPathMatch, uncWindowsPathMatch;
|
||||||
if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP))
|
if (windowsPathMatch = p.match(WINDOWS_PATH_REGEXP))
|
||||||
@@ -68,6 +64,10 @@ function toPortablePath(p) {
|
|||||||
p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`;
|
p = `/unc/${uncWindowsPathMatch[1] ? `.dot/` : ``}${uncWindowsPathMatch[2]}`;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
const toPortablePath = process.platform === `win32` ? toPortablePathWin32 : (p) => p;
|
||||||
|
const fromPortablePath = process.platform === `win32` ? fromPortablePathWin32 : (p) => p;
|
||||||
|
npath.fromPortablePath = fromPortablePath;
|
||||||
|
npath.toPortablePath = toPortablePath;
|
||||||
function convertPath(targetPathUtils, sourcePath) {
|
function convertPath(targetPathUtils, sourcePath) {
|
||||||
return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath);
|
return targetPathUtils === npath ? fromPortablePath(sourcePath) : toPortablePath(sourcePath);
|
||||||
}
|
}
|
||||||
@@ -902,6 +902,12 @@ class ProxiedFS extends FakeFS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function direntToPortable(dirent) {
|
||||||
|
const portableDirent = dirent;
|
||||||
|
if (typeof dirent.path === `string`)
|
||||||
|
portableDirent.path = npath.toPortablePath(dirent.path);
|
||||||
|
return portableDirent;
|
||||||
|
}
|
||||||
class NodeFS extends BasePortableFakeFS {
|
class NodeFS extends BasePortableFakeFS {
|
||||||
constructor(realFs = fs) {
|
constructor(realFs = fs) {
|
||||||
super();
|
super();
|
||||||
@@ -1228,15 +1234,31 @@ class NodeFS extends BasePortableFakeFS {
|
|||||||
async readdirPromise(p, opts) {
|
async readdirPromise(p, opts) {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
if (opts) {
|
if (opts) {
|
||||||
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
|
if (opts.recursive && process.platform === `win32`) {
|
||||||
|
if (opts.withFileTypes) {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(direntToPortable)), reject));
|
||||||
|
} else {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback((results) => resolve(results.map(npath.toPortablePath)), reject));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.realFs.readdir(npath.fromPortablePath(p), opts, this.makeCallback(resolve, reject));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback((value) => resolve(value), reject));
|
this.realFs.readdir(npath.fromPortablePath(p), this.makeCallback(resolve, reject));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
readdirSync(p, opts) {
|
readdirSync(p, opts) {
|
||||||
if (opts) {
|
if (opts) {
|
||||||
return this.realFs.readdirSync(npath.fromPortablePath(p), opts);
|
if (opts.recursive && process.platform === `win32`) {
|
||||||
|
if (opts.withFileTypes) {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(direntToPortable);
|
||||||
|
} else {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts).map(npath.toPortablePath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.realFs.readdirSync(npath.fromPortablePath(p), opts);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return this.realFs.readdirSync(npath.fromPortablePath(p));
|
return this.realFs.readdirSync(npath.fromPortablePath(p));
|
||||||
}
|
}
|
||||||
@@ -1372,10 +1394,8 @@ class VirtualFS extends ProxiedFS {
|
|||||||
|
|
||||||
const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
|
const [major, minor] = process.versions.node.split(`.`).map((value) => parseInt(value, 10));
|
||||||
const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
|
const WATCH_MODE_MESSAGE_USES_ARRAYS = major > 19 || major === 19 && minor >= 2 || major === 18 && minor >= 13;
|
||||||
const HAS_LAZY_LOADED_TRANSLATORS = major > 19 || major === 19 && minor >= 3;
|
const HAS_LAZY_LOADED_TRANSLATORS = major === 20 && minor < 6 || major === 19 && minor >= 3;
|
||||||
|
|
||||||
const builtinModules = new Set(Module.builtinModules || Object.keys(process.binding(`natives`)));
|
|
||||||
const isBuiltinModule = (request) => request.startsWith(`node:`) || builtinModules.has(request);
|
|
||||||
function readPackageScope(checkPath) {
|
function readPackageScope(checkPath) {
|
||||||
const rootSeparatorIndex = checkPath.indexOf(npath.sep);
|
const rootSeparatorIndex = checkPath.indexOf(npath.sep);
|
||||||
let separatorIndex;
|
let separatorIndex;
|
||||||
@@ -1963,7 +1983,7 @@ async function resolvePrivateRequest(specifier, issuer, context, nextResolve) {
|
|||||||
}
|
}
|
||||||
async function resolve$1(originalSpecifier, context, nextResolve) {
|
async function resolve$1(originalSpecifier, context, nextResolve) {
|
||||||
const { findPnpApi } = moduleExports;
|
const { findPnpApi } = moduleExports;
|
||||||
if (!findPnpApi || isBuiltinModule(originalSpecifier))
|
if (!findPnpApi || isBuiltin(originalSpecifier))
|
||||||
return nextResolve(originalSpecifier, context, nextResolve);
|
return nextResolve(originalSpecifier, context, nextResolve);
|
||||||
let specifier = originalSpecifier;
|
let specifier = originalSpecifier;
|
||||||
const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0);
|
const url = tryParseURL(specifier, isRelativeRegexp.test(specifier) ? context.parentURL : void 0);
|
||||||
@@ -2022,31 +2042,46 @@ async function resolve$1(originalSpecifier, context, nextResolve) {
|
|||||||
|
|
||||||
if (!HAS_LAZY_LOADED_TRANSLATORS) {
|
if (!HAS_LAZY_LOADED_TRANSLATORS) {
|
||||||
const binding = process.binding(`fs`);
|
const binding = process.binding(`fs`);
|
||||||
const originalfstat = binding.fstat;
|
const originalReadFile = binding.readFileUtf8 || binding.readFileSync;
|
||||||
const ZIP_MASK = 4278190080;
|
if (originalReadFile) {
|
||||||
const ZIP_MAGIC = 704643072;
|
binding[originalReadFile.name] = function(...args) {
|
||||||
binding.fstat = function(...args) {
|
|
||||||
const [fd, useBigint, req] = args;
|
|
||||||
if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) {
|
|
||||||
try {
|
try {
|
||||||
const stats = fs.fstatSync(fd);
|
return fs.readFileSync(args[0], {
|
||||||
return new Float64Array([
|
encoding: `utf8`,
|
||||||
stats.dev,
|
flag: args[1]
|
||||||
stats.mode,
|
});
|
||||||
stats.nlink,
|
|
||||||
stats.uid,
|
|
||||||
stats.gid,
|
|
||||||
stats.rdev,
|
|
||||||
stats.blksize,
|
|
||||||
stats.ino,
|
|
||||||
stats.size,
|
|
||||||
stats.blocks
|
|
||||||
]);
|
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
}
|
return originalReadFile.apply(this, args);
|
||||||
return originalfstat.apply(this, args);
|
};
|
||||||
};
|
} else {
|
||||||
|
const binding2 = process.binding(`fs`);
|
||||||
|
const originalfstat = binding2.fstat;
|
||||||
|
const ZIP_MASK = 4278190080;
|
||||||
|
const ZIP_MAGIC = 704643072;
|
||||||
|
binding2.fstat = function(...args) {
|
||||||
|
const [fd, useBigint, req] = args;
|
||||||
|
if ((fd & ZIP_MASK) === ZIP_MAGIC && useBigint === false && req === void 0) {
|
||||||
|
try {
|
||||||
|
const stats = fs.fstatSync(fd);
|
||||||
|
return new Float64Array([
|
||||||
|
stats.dev,
|
||||||
|
stats.mode,
|
||||||
|
stats.nlink,
|
||||||
|
stats.uid,
|
||||||
|
stats.gid,
|
||||||
|
stats.rdev,
|
||||||
|
stats.blksize,
|
||||||
|
stats.ino,
|
||||||
|
stats.size,
|
||||||
|
stats.blocks
|
||||||
|
]);
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return originalfstat.apply(this, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolve = resolve$1;
|
const resolve = resolve$1;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
-891
File diff suppressed because one or more lines are too long
+893
File diff suppressed because one or more lines are too long
+1
-1
@@ -2,4 +2,4 @@ compressionLevel: mixed
|
|||||||
|
|
||||||
enableGlobalCache: false
|
enableGlobalCache: false
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.0.0-rc.51.cjs
|
yarnPath: .yarn/releases/yarn-4.0.2.cjs
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DB_TYPE: "${DB_TYPE}"
|
DB_TYPE: "${DB_TYPE}"
|
||||||
CACHE_TYPE: "${CACHE_TYPE}"
|
CACHE_TYPE: "${CACHE_TYPE}"
|
||||||
|
SERVICE_PROXY_TYPE: "${SERVICE_PROXY_TYPE}"
|
||||||
container_name: server-ci
|
container_name: server-ci
|
||||||
ports:
|
ports:
|
||||||
- 3123:3000
|
- 3123:3000
|
||||||
@@ -32,7 +33,7 @@ services:
|
|||||||
- standardnotes_self_hosted
|
- standardnotes_self_hosted
|
||||||
|
|
||||||
localstack:
|
localstack:
|
||||||
image: localstack/localstack:1.4
|
image: localstack/localstack:3.0
|
||||||
container_name: localstack-ci
|
container_name: localstack-ci
|
||||||
expose:
|
expose:
|
||||||
- 4566
|
- 4566
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
- standardnotes_self_hosted
|
- standardnotes_self_hosted
|
||||||
|
|
||||||
localstack:
|
localstack:
|
||||||
image: localstack/localstack:1.3
|
image: localstack/localstack:3.0
|
||||||
container_name: localstack_self_hosted
|
container_name: localstack_self_hosted
|
||||||
expose:
|
expose:
|
||||||
- 4566
|
- 4566
|
||||||
|
|||||||
@@ -14,10 +14,18 @@ if [ -z "$SYNCING_SERVER_PORT" ]; then
|
|||||||
export SYNCING_SERVER_PORT=3101
|
export SYNCING_SERVER_PORT=3101
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "$SYNCING_SERVER_GRPC_PORT" ]; then
|
||||||
|
export SYNCING_SERVER_GRPC_PORT=50052
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$AUTH_SERVER_PORT" ]; then
|
if [ -z "$AUTH_SERVER_PORT" ]; then
|
||||||
export AUTH_SERVER_PORT=3103
|
export AUTH_SERVER_PORT=3103
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AUTH_SERVER_GRPC_PORT" ]; then
|
||||||
|
export AUTH_SERVER_GRPC_PORT=50051
|
||||||
|
fi
|
||||||
|
|
||||||
export FILES_SERVER_PORT=3104
|
export FILES_SERVER_PORT=3104
|
||||||
|
|
||||||
if [ -z "$REVISIONS_SERVER_PORT" ]; then
|
if [ -z "$REVISIONS_SERVER_PORT" ]; then
|
||||||
@@ -352,7 +360,9 @@ export API_GATEWAY_NODE_ENV=production
|
|||||||
export API_GATEWAY_VERSION=local
|
export API_GATEWAY_VERSION=local
|
||||||
|
|
||||||
export API_GATEWAY_SYNCING_SERVER_JS_URL=http://localhost:$SYNCING_SERVER_PORT
|
export API_GATEWAY_SYNCING_SERVER_JS_URL=http://localhost:$SYNCING_SERVER_PORT
|
||||||
|
export API_GATEWAY_SYNCING_SERVER_GRPC_URL=0.0.0.0:$SYNCING_SERVER_GRPC_PORT
|
||||||
export API_GATEWAY_AUTH_SERVER_URL=http://localhost:$AUTH_SERVER_PORT
|
export API_GATEWAY_AUTH_SERVER_URL=http://localhost:$AUTH_SERVER_PORT
|
||||||
|
export API_GATEWAY_AUTH_SERVER_GRPC_URL=0.0.0.0:$AUTH_SERVER_GRPC_PORT
|
||||||
export API_GATEWAY_REVISIONS_SERVER_URL=http://localhost:$REVISIONS_SERVER_PORT
|
export API_GATEWAY_REVISIONS_SERVER_URL=http://localhost:$REVISIONS_SERVER_PORT
|
||||||
if [ -z "$PUBLIC_FILES_SERVER_URL" ]; then
|
if [ -z "$PUBLIC_FILES_SERVER_URL" ]; then
|
||||||
export PUBLIC_FILES_SERVER_URL=http://localhost:3125
|
export PUBLIC_FILES_SERVER_URL=http://localhost:3125
|
||||||
|
|||||||
+9
-1
@@ -39,5 +39,13 @@
|
|||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.0.0-rc.51"
|
"packageManager": "yarn@4.0.2",
|
||||||
|
"dependenciesMeta": {
|
||||||
|
"grpc-tools@1.12.4": {
|
||||||
|
"unplugged": true
|
||||||
|
},
|
||||||
|
"grpc_tools_node_protoc_ts@5.3.3": {
|
||||||
|
"unplugged": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,48 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.34.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.2...@standardnotes/analytics@2.34.3) (2023-11-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.34.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.1...@standardnotes/analytics@2.34.2) (2023-11-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.34.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.0...@standardnotes/analytics@2.34.1) (2023-11-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* repository config in package.json files ([ed1bf37](https://github.com/standardnotes/server/commit/ed1bf37287af23a25b8388ada95f0acdec8f71ea))
|
||||||
|
|
||||||
|
# [2.34.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.4...@standardnotes/analytics@2.34.0) (2023-11-27)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add npm provenance to published packages ([e836abd](https://github.com/standardnotes/server/commit/e836abdef73d246940d8fffd9e65e17c64cd35c8))
|
||||||
|
|
||||||
|
## [2.33.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.3...@standardnotes/analytics@2.33.4) (2023-11-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.33.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.2...@standardnotes/analytics@2.33.3) (2023-11-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.33.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.1...@standardnotes/analytics@2.33.2) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.33.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.0...@standardnotes/analytics@2.33.1) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
# [2.33.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.6...@standardnotes/analytics@2.33.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/server/issues/923)) ([c24353c](https://github.com/standardnotes/server/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
## [2.32.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.5...@standardnotes/analytics@2.32.6) (2023-11-07)
|
## [2.32.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.5...@standardnotes/analytics@2.32.6) (2023-11-07)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/analytics
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|||||||
@@ -22,5 +22,11 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
|
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM received. Stopping worker...')
|
||||||
|
subscriber.stop()
|
||||||
|
logger.info('Worker stopped.')
|
||||||
|
})
|
||||||
|
|
||||||
subscriber.start()
|
subscriber.start()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-worker' )
|
'start-worker' )
|
||||||
echo "[Docker] Starting Worker..."
|
echo "[Docker] Starting Worker..."
|
||||||
node docker/entrypoint-worker.js
|
exec node docker/entrypoint-worker.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'report' )
|
'report' )
|
||||||
echo "[Docker] Starting Usage Report Generation..."
|
echo "[Docker] Starting Usage Report Generation..."
|
||||||
node docker/entrypoint-report.js
|
exec node docker/entrypoint-report.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/analytics",
|
"name": "@standardnotes/analytics",
|
||||||
"version": "2.32.6",
|
"version": "2.34.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -10,7 +10,13 @@
|
|||||||
"author": "Standard Notes",
|
"author": "Standard Notes",
|
||||||
"types": "dist/src/index.d.ts",
|
"types": "dist/src/index.d.ts",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"provenance": true
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:standardnotes/server.git",
|
||||||
|
"directory": "packages/analytics"
|
||||||
},
|
},
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ VERSION=development
|
|||||||
PORT=3000
|
PORT=3000
|
||||||
|
|
||||||
SYNCING_SERVER_JS_URL=http://syncing_server_js:3000
|
SYNCING_SERVER_JS_URL=http://syncing_server_js:3000
|
||||||
|
SYNCING_SERVER_GRPC_URL=http://syncing_server_js:50052
|
||||||
AUTH_SERVER_URL=http://auth:3000
|
AUTH_SERVER_URL=http://auth:3000
|
||||||
|
AUTH_SERVER_GRPC_URL=http://auth:50051
|
||||||
WEB_SOCKET_SERVER_URL=http://websockets:3000
|
WEB_SOCKET_SERVER_URL=http://websockets:3000
|
||||||
PAYMENTS_SERVER_URL=http://payments:3000
|
PAYMENTS_SERVER_URL=http://payments:3000
|
||||||
FILES_SERVER_URL=http://files:3000
|
FILES_SERVER_URL=http://files:3000
|
||||||
|
|||||||
@@ -3,6 +3,164 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.87.4](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.87.3...@standardnotes/api-gateway@1.87.4) (2023-12-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** home server home page ([#949](https://github.com/standardnotes/server/issues/949)) ([a82192d](https://github.com/standardnotes/server/commit/a82192db42dfbb3eea4ac6af40ef2b3d6126e5a3))
|
||||||
|
|
||||||
|
## [1.87.3](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.87.2...@standardnotes/api-gateway@1.87.3) (2023-11-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add session to response locals from web socket middleware ([4cc647a](https://github.com/standardnotes/server/commit/4cc647ac07b2471d6616a913bcdca431c506fd0e))
|
||||||
|
|
||||||
|
## [1.87.2](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.87.1...@standardnotes/api-gateway@1.87.2) (2023-11-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||||
|
|
||||||
|
## [1.87.1](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.87.0...@standardnotes/api-gateway@1.87.1) (2023-11-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* repository config in package.json files ([ed1bf37](https://github.com/standardnotes/server/commit/ed1bf37287af23a25b8388ada95f0acdec8f71ea))
|
||||||
|
|
||||||
|
# [1.87.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.6...@standardnotes/api-gateway@1.87.0) (2023-11-27)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add npm provenance to published packages ([e836abd](https://github.com/standardnotes/api-gateway/commit/e836abdef73d246940d8fffd9e65e17c64cd35c8))
|
||||||
|
|
||||||
|
## [1.86.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.5...@standardnotes/api-gateway@1.86.6) (2023-11-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||||
|
|
||||||
|
## [1.86.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.4...@standardnotes/api-gateway@1.86.5) (2023-11-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* error handling on gRPC ([#937](https://github.com/standardnotes/api-gateway/issues/937)) ([8f23c8a](https://github.com/standardnotes/api-gateway/commit/8f23c8ab3f03e9c23adfb31a33c5805492bc2f5b))
|
||||||
|
|
||||||
|
## [1.86.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.3...@standardnotes/api-gateway@1.86.4) (2023-11-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||||
|
|
||||||
|
## [1.86.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.2...@standardnotes/api-gateway@1.86.3) (2023-11-21)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add meta field to grpc sync calls ([#934](https://github.com/standardnotes/api-gateway/issues/934)) ([c5c24b3](https://github.com/standardnotes/api-gateway/commit/c5c24b3ac9dbd559d96adc56270d724a3156ebd4))
|
||||||
|
|
||||||
|
## [1.86.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.1...@standardnotes/api-gateway@1.86.2) (2023-11-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* define grpc max message size ([bfef16c](https://github.com/standardnotes/api-gateway/commit/bfef16ce3757b57ea1cb0cb7417d6bc935a52321))
|
||||||
|
|
||||||
|
## [1.86.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.86.0...@standardnotes/api-gateway@1.86.1) (2023-11-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* setting gzip as default compression on grpc calls ([#933](https://github.com/standardnotes/api-gateway/issues/933)) ([2dff6a2](https://github.com/standardnotes/api-gateway/commit/2dff6a2ed3d105ca65996d47321a811e22e25099))
|
||||||
|
|
||||||
|
# [1.86.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.85.1...@standardnotes/api-gateway@1.86.0) (2023-11-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **grpc:** add syncing protocol buffers ([#930](https://github.com/standardnotes/api-gateway/issues/930)) ([5b84f07](https://github.com/standardnotes/api-gateway/commit/5b84f078c6ae6330706895f7c57b67ff8c8d18ae))
|
||||||
|
|
||||||
|
## [1.85.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.85.0...@standardnotes/api-gateway@1.85.1) (2023-11-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** remove overly verbose debug messages ([ed05ea5](https://github.com/standardnotes/api-gateway/commit/ed05ea553f605234cd8803e633f3c07429877dbb))
|
||||||
|
|
||||||
|
# [1.85.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.84.1...@standardnotes/api-gateway@1.85.0) (2023-11-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add debug logs for grpc communication ([6391a01](https://github.com/standardnotes/api-gateway/commit/6391a01b5703db23b566710d0520c1197c46144b))
|
||||||
|
|
||||||
|
## [1.84.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.84.0...@standardnotes/api-gateway@1.84.1) (2023-11-16)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** bindings ([78fbeb5](https://github.com/standardnotes/api-gateway/commit/78fbeb595f9e213688bcb2a031fba2aa3974cc6a))
|
||||||
|
|
||||||
|
# [1.84.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.5...@standardnotes/api-gateway@1.84.0) (2023-11-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add grpc sessions validation server ([#928](https://github.com/standardnotes/api-gateway/issues/928)) ([4f62cac](https://github.com/standardnotes/api-gateway/commit/4f62cac213a6b5f503040ef6319e5198967974ce))
|
||||||
|
|
||||||
|
## [1.83.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.4...@standardnotes/api-gateway@1.83.5) (2023-11-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** remove the verify body function ([3ddd671](https://github.com/standardnotes/api-gateway/commit/3ddd671c4797482a396844e804b4b45b82dbff2d))
|
||||||
|
* **api-gateway:** remove unused imports ([fd997f4](https://github.com/standardnotes/api-gateway/commit/fd997f4849ed01ef3ae4baf52b5895012fa711d4))
|
||||||
|
|
||||||
|
## [1.83.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.3...@standardnotes/api-gateway@1.83.4) (2023-11-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add verification if json is valid on request ([420bf9e](https://github.com/standardnotes/api-gateway/commit/420bf9ec5460a9693cc382e9164b4bdbb9b769a1))
|
||||||
|
* **api-gateway:** buffer encoding ([2823ed8](https://github.com/standardnotes/api-gateway/commit/2823ed8612cb9797d43e847edac5e2bdc0fe7426))
|
||||||
|
* **api-gateway:** checking for buffer length ([f65809e](https://github.com/standardnotes/api-gateway/commit/f65809ef3052d05df2e3f012a9b6340d18a6deae))
|
||||||
|
|
||||||
|
## [1.83.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.2...@standardnotes/api-gateway@1.83.3) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add application version to the error logs ([daed1a7](https://github.com/standardnotes/api-gateway/commit/daed1a77a02559a8487896b6fb8299befe8a2d96))
|
||||||
|
* **api-gateway:** add request method to the debug logs ([b39eb09](https://github.com/standardnotes/api-gateway/commit/b39eb09d91f0ea9482d27578faecdf57ed2ea48e))
|
||||||
|
|
||||||
|
## [1.83.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.1...@standardnotes/api-gateway@1.83.2) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** debug log on error thrown body representation ([c8bf4ab](https://github.com/standardnotes/api-gateway/commit/c8bf4ab3a0ab757092077fc594e3ca7e090116b4))
|
||||||
|
|
||||||
|
## [1.83.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.0...@standardnotes/api-gateway@1.83.1) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add debug logs for errors on parsing ([60686dc](https://github.com/standardnotes/api-gateway/commit/60686dcdbd59c0d99cd1857a82ad62baed088b25))
|
||||||
|
|
||||||
|
# [1.83.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.82.1...@standardnotes/api-gateway@1.83.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add more info on error logs ([f997501](https://github.com/standardnotes/api-gateway/commit/f99750169f4d24cdc7530184af2230c687f3e166))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add keep-alive connections to subservices ([#924](https://github.com/standardnotes/api-gateway/issues/924)) ([daad76d](https://github.com/standardnotes/api-gateway/commit/daad76d0ddae34c59dce45eedc4a055c4a11456d))
|
||||||
|
|
||||||
|
## [1.82.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.82.0...@standardnotes/api-gateway@1.82.1) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** websockets calls logs severity ([a9b1543](https://github.com/standardnotes/api-gateway/commit/a9b1543e204afeab1fa2e008327c39cf306a247c))
|
||||||
|
|
||||||
|
# [1.82.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.14...@standardnotes/api-gateway@1.82.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/api-gateway/issues/923)) ([c24353c](https://github.com/standardnotes/api-gateway/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
|
## [1.81.14](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.13...@standardnotes/api-gateway@1.81.14) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add logs about calling web sockets with minimal format ([5d3fb9a](https://github.com/standardnotes/api-gateway/commit/5d3fb9a537f6971cfe8ae3c5ea449806cc4de8a0))
|
||||||
|
|
||||||
|
## [1.81.13](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.12...@standardnotes/api-gateway@1.81.13) (2023-11-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add possibility to configure keep-alive timeout ([#920](https://github.com/standardnotes/api-gateway/issues/920)) ([16f92bd](https://github.com/standardnotes/api-gateway/commit/16f92bdc990ded5c3f1fe5af1e6e4a113a9954de))
|
||||||
|
|
||||||
## [1.81.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.11...@standardnotes/api-gateway@1.81.12) (2023-11-09)
|
## [1.81.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.11...@standardnotes/api-gateway@1.81.12) (2023-11-09)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -90,8 +90,15 @@ void container.load().then((container) => {
|
|||||||
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
||||||
|
|
||||||
server.setErrorConfig((app) => {
|
server.setErrorConfig((app) => {
|
||||||
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
|
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
||||||
logger.error(error.stack)
|
logger.error(
|
||||||
|
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${request.headers['x-application-version']}] Error thrown: ${error.stack}`,
|
||||||
|
)
|
||||||
|
logger.debug(
|
||||||
|
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${
|
||||||
|
request.headers['x-application-version']
|
||||||
|
}] Request body: ${JSON.stringify(request.body)}`,
|
||||||
|
)
|
||||||
|
|
||||||
response.status(500).send({
|
response.status(500).send({
|
||||||
error: {
|
error: {
|
||||||
@@ -102,9 +109,18 @@ void container.load().then((container) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverInstance = server.build()
|
const serverInstance = server.build().listen(env.get('PORT'))
|
||||||
|
|
||||||
serverInstance.listen(env.get('PORT'))
|
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||||
|
|
||||||
|
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM signal received: closing HTTP server')
|
||||||
|
serverInstance.close(() => {
|
||||||
|
logger.info('HTTP server closed')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
logger.info(`Server started on port ${process.env.PORT}`)
|
logger.info(`Server started on port ${process.env.PORT}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-web' )
|
'start-web' )
|
||||||
echo "Starting Web..."
|
echo "Starting Web..."
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/api-gateway",
|
"name": "@standardnotes/api-gateway",
|
||||||
"version": "1.81.12",
|
"version": "1.87.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -11,11 +11,16 @@
|
|||||||
"dist/src/**/*.js",
|
"dist/src/**/*.js",
|
||||||
"dist/src/**/*.d.ts"
|
"dist/src/**/*.d.ts"
|
||||||
],
|
],
|
||||||
"repository": "git@github.com:standardnotes/api-gateway.git",
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:standardnotes/server.git",
|
||||||
|
"directory": "packages/api-gateway"
|
||||||
|
},
|
||||||
"author": "Karol Sójko <karol@standardnotes.com>",
|
"author": "Karol Sójko <karol@standardnotes.com>",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"provenance": true
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -fr dist",
|
"clean": "rm -fr dist",
|
||||||
@@ -26,12 +31,15 @@
|
|||||||
"start": "yarn node dist/bin/server.js"
|
"start": "yarn node dist/bin/server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@grpc/grpc-js": "^1.9.11",
|
||||||
"@standardnotes/domain-core": "workspace:^",
|
"@standardnotes/domain-core": "workspace:^",
|
||||||
"@standardnotes/domain-events": "workspace:*",
|
"@standardnotes/domain-events": "workspace:*",
|
||||||
"@standardnotes/domain-events-infra": "workspace:*",
|
"@standardnotes/domain-events-infra": "workspace:*",
|
||||||
|
"@standardnotes/grpc": "workspace:^",
|
||||||
"@standardnotes/security": "workspace:*",
|
"@standardnotes/security": "workspace:*",
|
||||||
"@standardnotes/time": "workspace:*",
|
"@standardnotes/time": "workspace:*",
|
||||||
"axios": "^1.1.3",
|
"agentkeepalive": "^4.5.0",
|
||||||
|
"axios": "^1.6.1",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
|||||||
@@ -1,27 +1,40 @@
|
|||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
import * as AgentKeepAlive from 'agentkeepalive'
|
||||||
const axios = require('axios')
|
import * as grpc from '@grpc/grpc-js'
|
||||||
import { AxiosInstance } from 'axios'
|
import axios, { AxiosInstance } from 'axios'
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
import { Timer, TimerInterface } from '@standardnotes/time'
|
import { Timer, TimerInterface } from '@standardnotes/time'
|
||||||
|
|
||||||
import { Env } from './Env'
|
import { Env } from './Env'
|
||||||
import { TYPES } from './Types'
|
import { TYPES } from './Types'
|
||||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
import { HttpServiceProxy } from '../Service/Http/HttpServiceProxy'
|
import { HttpServiceProxy } from '../Service/Http/HttpServiceProxy'
|
||||||
import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
|
import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
|
||||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
|
import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
|
||||||
import { WebSocketAuthMiddleware } from '../Controller/WebSocketAuthMiddleware'
|
import { WebSocketAuthMiddleware } from '../Controller/WebSocketAuthMiddleware'
|
||||||
import { InMemoryCrossServiceTokenCache } from '../Infra/InMemory/InMemoryCrossServiceTokenCache'
|
import { InMemoryCrossServiceTokenCache } from '../Infra/InMemory/InMemoryCrossServiceTokenCache'
|
||||||
import { DirectCallServiceProxy } from '../Service/Proxy/DirectCallServiceProxy'
|
import { DirectCallServiceProxy } from '../Service/DirectCall/DirectCallServiceProxy'
|
||||||
import { ServiceContainerInterface } from '@standardnotes/domain-core'
|
import { MapperInterface, ServiceContainerInterface } from '@standardnotes/domain-core'
|
||||||
import { EndpointResolverInterface } from '../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../Service/Resolver/EndpointResolverInterface'
|
||||||
import { EndpointResolver } from '../Service/Resolver/EndpointResolver'
|
import { EndpointResolver } from '../Service/Resolver/EndpointResolver'
|
||||||
import { RequiredCrossServiceTokenMiddleware } from '../Controller/RequiredCrossServiceTokenMiddleware'
|
import { RequiredCrossServiceTokenMiddleware } from '../Controller/RequiredCrossServiceTokenMiddleware'
|
||||||
import { OptionalCrossServiceTokenMiddleware } from '../Controller/OptionalCrossServiceTokenMiddleware'
|
import { OptionalCrossServiceTokenMiddleware } from '../Controller/OptionalCrossServiceTokenMiddleware'
|
||||||
import { Transform } from 'stream'
|
import { Transform } from 'stream'
|
||||||
|
import {
|
||||||
|
ISessionsClient,
|
||||||
|
ISyncingClient,
|
||||||
|
SessionsClient,
|
||||||
|
SyncRequest,
|
||||||
|
SyncResponse,
|
||||||
|
SyncingClient,
|
||||||
|
} from '@standardnotes/grpc'
|
||||||
|
import { GRPCServiceProxy } from '../Service/gRPC/GRPCServiceProxy'
|
||||||
|
import { GRPCSyncingServerServiceProxy } from '../Service/gRPC/GRPCSyncingServerServiceProxy'
|
||||||
|
import { SyncResponseHttpRepresentation } from '../Mapping/Sync/Http/SyncResponseHttpRepresentation'
|
||||||
|
import { SyncRequestGRPCMapper } from '../Mapping/Sync/GRPC/SyncRequestGRPCMapper'
|
||||||
|
import { SyncResponseGRPCMapper } from '../Mapping/Sync/GRPC/SyncResponseGRPCMapper'
|
||||||
|
|
||||||
export class ContainerConfigLoader {
|
export class ContainerConfigLoader {
|
||||||
async load(configuration?: {
|
async load(configuration?: {
|
||||||
@@ -70,7 +83,19 @@ export class ContainerConfigLoader {
|
|||||||
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
|
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
|
||||||
}
|
}
|
||||||
|
|
||||||
container.bind<AxiosInstance>(TYPES.ApiGateway_HTTPClient).toConstantValue(axios.create())
|
const httpAgentKeepAliveTimeout = env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
? +env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
: 4_000
|
||||||
|
|
||||||
|
container.bind<AxiosInstance>(TYPES.ApiGateway_HTTPClient).toConstantValue(
|
||||||
|
axios.create({
|
||||||
|
httpAgent: new AgentKeepAlive({
|
||||||
|
keepAlive: true,
|
||||||
|
timeout: 2 * httpAgentKeepAliveTimeout,
|
||||||
|
freeSocketTimeout: httpAgentKeepAliveTimeout,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
// env vars
|
// env vars
|
||||||
container.bind(TYPES.ApiGateway_SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
|
container.bind(TYPES.ApiGateway_SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
|
||||||
@@ -105,19 +130,6 @@ export class ContainerConfigLoader {
|
|||||||
// Services
|
// Services
|
||||||
container.bind<TimerInterface>(TYPES.ApiGateway_Timer).toConstantValue(new Timer())
|
container.bind<TimerInterface>(TYPES.ApiGateway_Timer).toConstantValue(new Timer())
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
|
||||||
if (!configuration?.serviceContainer) {
|
|
||||||
throw new Error('Service container is required when configured for home server')
|
|
||||||
}
|
|
||||||
container
|
|
||||||
.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy)
|
|
||||||
.toConstantValue(
|
|
||||||
new DirectCallServiceProxy(configuration.serviceContainer, container.get(TYPES.ApiGateway_FILES_SERVER_URL)),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
container.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy).to(HttpServiceProxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForHomeServer) {
|
||||||
container
|
container
|
||||||
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
||||||
@@ -131,6 +143,100 @@ export class ContainerConfigLoader {
|
|||||||
.bind<EndpointResolverInterface>(TYPES.ApiGateway_EndpointResolver)
|
.bind<EndpointResolverInterface>(TYPES.ApiGateway_EndpointResolver)
|
||||||
.toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
|
.toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
|
||||||
|
|
||||||
|
if (isConfiguredForHomeServer) {
|
||||||
|
if (!configuration?.serviceContainer) {
|
||||||
|
throw new Error('Service container is required when configured for home server')
|
||||||
|
}
|
||||||
|
container
|
||||||
|
.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy)
|
||||||
|
.toConstantValue(
|
||||||
|
new DirectCallServiceProxy(configuration.serviceContainer, container.get(TYPES.ApiGateway_FILES_SERVER_URL)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const isConfiguredForGRPCProxy = env.get('SERVICE_PROXY_TYPE', true) === 'grpc'
|
||||||
|
if (isConfiguredForGRPCProxy) {
|
||||||
|
container.bind(TYPES.ApiGateway_AUTH_SERVER_GRPC_URL).toConstantValue(env.get('AUTH_SERVER_GRPC_URL'))
|
||||||
|
container.bind(TYPES.ApiGateway_SYNCING_SERVER_GRPC_URL).toConstantValue(env.get('SYNCING_SERVER_GRPC_URL'))
|
||||||
|
const grpcAgentKeepAliveTimeout = env.get('GRPC_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
? +env.get('GRPC_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
: 8_000
|
||||||
|
|
||||||
|
const grpcMaxMessageSize = env.get('GRPC_MAX_MESSAGE_SIZE', true)
|
||||||
|
? +env.get('GRPC_MAX_MESSAGE_SIZE', true)
|
||||||
|
: 1024 * 1024 * 50
|
||||||
|
|
||||||
|
container.bind<ISessionsClient>(TYPES.ApiGateway_GRPCSessionsClient).toConstantValue(
|
||||||
|
new SessionsClient(
|
||||||
|
container.get<string>(TYPES.ApiGateway_AUTH_SERVER_GRPC_URL),
|
||||||
|
grpc.credentials.createInsecure(),
|
||||||
|
{
|
||||||
|
'grpc.keepalive_time_ms': grpcAgentKeepAliveTimeout * 2,
|
||||||
|
'grpc.keepalive_timeout_ms': grpcAgentKeepAliveTimeout,
|
||||||
|
'grpc.default_compression_algorithm': grpc.compressionAlgorithms.gzip,
|
||||||
|
'grpc.default_compression_level': 2,
|
||||||
|
'grpc.max_receive_message_length': grpcMaxMessageSize,
|
||||||
|
'grpc.max_send_message_length': grpcMaxMessageSize,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container.bind<ISyncingClient>(TYPES.ApiGateway_GRPCSyncingClient).toConstantValue(
|
||||||
|
new SyncingClient(
|
||||||
|
container.get<string>(TYPES.ApiGateway_SYNCING_SERVER_GRPC_URL),
|
||||||
|
grpc.credentials.createInsecure(),
|
||||||
|
{
|
||||||
|
'grpc.keepalive_time_ms': grpcAgentKeepAliveTimeout * 2,
|
||||||
|
'grpc.keepalive_timeout_ms': grpcAgentKeepAliveTimeout,
|
||||||
|
'grpc.default_compression_algorithm': grpc.compressionAlgorithms.gzip,
|
||||||
|
'grpc.default_compression_level': 2,
|
||||||
|
'grpc.max_receive_message_length': grpcMaxMessageSize,
|
||||||
|
'grpc.max_send_message_length': grpcMaxMessageSize,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<MapperInterface<Record<string, unknown>, SyncRequest>>(TYPES.Mapper_SyncRequestGRPCMapper)
|
||||||
|
.toConstantValue(new SyncRequestGRPCMapper())
|
||||||
|
container
|
||||||
|
.bind<MapperInterface<SyncResponse, SyncResponseHttpRepresentation>>(TYPES.Mapper_SyncResponseGRPCMapper)
|
||||||
|
.toConstantValue(new SyncResponseGRPCMapper())
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<GRPCSyncingServerServiceProxy>(TYPES.ApiGateway_GRPCSyncingServerServiceProxy)
|
||||||
|
.toConstantValue(
|
||||||
|
new GRPCSyncingServerServiceProxy(
|
||||||
|
container.get<ISyncingClient>(TYPES.ApiGateway_GRPCSyncingClient),
|
||||||
|
container.get<MapperInterface<Record<string, unknown>, SyncRequest>>(TYPES.Mapper_SyncRequestGRPCMapper),
|
||||||
|
container.get<MapperInterface<SyncResponse, SyncResponseHttpRepresentation>>(
|
||||||
|
TYPES.Mapper_SyncResponseGRPCMapper,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy)
|
||||||
|
.toConstantValue(
|
||||||
|
new GRPCServiceProxy(
|
||||||
|
container.get<AxiosInstance>(TYPES.ApiGateway_HTTPClient),
|
||||||
|
container.get<string>(TYPES.ApiGateway_AUTH_SERVER_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_SYNCING_SERVER_JS_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_PAYMENTS_SERVER_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_FILES_SERVER_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_WEB_SOCKET_SERVER_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_REVISIONS_SERVER_URL),
|
||||||
|
container.get<string>(TYPES.ApiGateway_EMAIL_SERVER_URL),
|
||||||
|
container.get<number>(TYPES.ApiGateway_HTTP_CALL_TIMEOUT),
|
||||||
|
container.get<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache),
|
||||||
|
container.get<winston.Logger>(TYPES.ApiGateway_Logger),
|
||||||
|
container.get<TimerInterface>(TYPES.ApiGateway_Timer),
|
||||||
|
container.get<ISessionsClient>(TYPES.ApiGateway_GRPCSessionsClient),
|
||||||
|
container.get<GRPCSyncingServerServiceProxy>(TYPES.ApiGateway_GRPCSyncingServerServiceProxy),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
container.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy).to(HttpServiceProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug('Configuration complete')
|
logger.debug('Configuration complete')
|
||||||
|
|
||||||
return container
|
return container
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export const TYPES = {
|
|||||||
// env vars
|
// env vars
|
||||||
ApiGateway_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
|
ApiGateway_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
|
||||||
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
|
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
|
||||||
|
ApiGateway_AUTH_SERVER_GRPC_URL: Symbol.for('ApiGateway_AUTH_SERVER_GRPC_URL'),
|
||||||
|
ApiGateway_SYNCING_SERVER_GRPC_URL: Symbol.for('ApiGateway_SYNCING_SERVER_GRPC_URL'),
|
||||||
ApiGateway_PAYMENTS_SERVER_URL: Symbol.for('ApiGateway_PAYMENTS_SERVER_URL'),
|
ApiGateway_PAYMENTS_SERVER_URL: Symbol.for('ApiGateway_PAYMENTS_SERVER_URL'),
|
||||||
ApiGateway_FILES_SERVER_URL: Symbol.for('ApiGateway_FILES_SERVER_URL'),
|
ApiGateway_FILES_SERVER_URL: Symbol.for('ApiGateway_FILES_SERVER_URL'),
|
||||||
ApiGateway_REVISIONS_SERVER_URL: Symbol.for('ApiGateway_REVISIONS_SERVER_URL'),
|
ApiGateway_REVISIONS_SERVER_URL: Symbol.for('ApiGateway_REVISIONS_SERVER_URL'),
|
||||||
@@ -23,9 +25,15 @@ export const TYPES = {
|
|||||||
ApiGateway_OptionalCrossServiceTokenMiddleware: Symbol.for('ApiGateway_OptionalCrossServiceTokenMiddleware'),
|
ApiGateway_OptionalCrossServiceTokenMiddleware: Symbol.for('ApiGateway_OptionalCrossServiceTokenMiddleware'),
|
||||||
ApiGateway_WebSocketAuthMiddleware: Symbol.for('ApiGateway_WebSocketAuthMiddleware'),
|
ApiGateway_WebSocketAuthMiddleware: Symbol.for('ApiGateway_WebSocketAuthMiddleware'),
|
||||||
ApiGateway_SubscriptionTokenAuthMiddleware: Symbol.for('ApiGateway_SubscriptionTokenAuthMiddleware'),
|
ApiGateway_SubscriptionTokenAuthMiddleware: Symbol.for('ApiGateway_SubscriptionTokenAuthMiddleware'),
|
||||||
|
// Mapping
|
||||||
|
Mapper_SyncRequestGRPCMapper: Symbol.for('Mapper_SyncRequestGRPCMapper'),
|
||||||
|
Mapper_SyncResponseGRPCMapper: Symbol.for('Mapper_SyncResponseGRPCMapper'),
|
||||||
// Services
|
// Services
|
||||||
|
ApiGateway_GRPCSyncingServerServiceProxy: Symbol.for('ApiGateway_GRPCSyncingServerServiceProxy'),
|
||||||
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
|
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
|
||||||
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
|
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
|
||||||
ApiGateway_Timer: Symbol.for('ApiGateway_Timer'),
|
ApiGateway_Timer: Symbol.for('ApiGateway_Timer'),
|
||||||
ApiGateway_EndpointResolver: Symbol.for('ApiGateway_EndpointResolver'),
|
ApiGateway_EndpointResolver: Symbol.for('ApiGateway_EndpointResolver'),
|
||||||
|
ApiGateway_GRPCSessionsClient: Symbol.for('ApiGateway_GRPCSessionsClient'),
|
||||||
|
ApiGateway_GRPCSyncingClient: Symbol.for('ApiGateway_GRPCSyncingClient'),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { AxiosError } from 'axios'
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
export abstract class AuthMiddleware extends BaseMiddleware {
|
export abstract class AuthMiddleware extends BaseMiddleware {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -49,6 +49,8 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.debug('[AuthMiddleware] Fetched cross-service token from underlying service')
|
||||||
|
|
||||||
crossServiceToken = (authResponse.data as { authToken: string }).authToken
|
crossServiceToken = (authResponse.data as { authToken: string }).authToken
|
||||||
crossServiceTokenFetchedFromCache = false
|
crossServiceTokenFetchedFromCache = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
|
import { Request, Response } from 'express'
|
||||||
import { BaseHttpController, all, controller, results } from 'inversify-express-utils'
|
import { BaseHttpController, all, controller, results } from 'inversify-express-utils'
|
||||||
|
|
||||||
@controller('')
|
@controller('')
|
||||||
export class FallbackController extends BaseHttpController {
|
export class FallbackController extends BaseHttpController {
|
||||||
@all('*')
|
@all('*')
|
||||||
public async fallback(): Promise<results.NotFoundResult> {
|
public async fallback(request: Request, response: Response): Promise<void | results.NotFoundResult> {
|
||||||
|
if (request.path === '/' && request.method === 'GET') {
|
||||||
|
response.send(
|
||||||
|
'<!DOCTYPE html><html lang="en"><head><meta name="robots" content="noindex"></head><body>Your home server is up and running! Enter the URL of this page into Standard Notes when registering or signing in to begin using your home server.</body></html>',
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return this.notFound()
|
return this.notFound()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDelete } from 'inversify-express-utils'
|
import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDelete } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../Bootstrap/Types'
|
import { TYPES } from '../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
@controller('')
|
@controller('')
|
||||||
export class LegacyController extends BaseHttpController {
|
export class LegacyController extends BaseHttpController {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Logger } from 'winston'
|
|||||||
|
|
||||||
import { TYPES } from '../Bootstrap/Types'
|
import { TYPES } from '../Bootstrap/Types'
|
||||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
import { AuthMiddleware } from './AuthMiddleware'
|
import { AuthMiddleware } from './AuthMiddleware'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Logger } from 'winston'
|
|||||||
|
|
||||||
import { TYPES } from '../Bootstrap/Types'
|
import { TYPES } from '../Bootstrap/Types'
|
||||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
import { AuthMiddleware } from './AuthMiddleware'
|
import { AuthMiddleware } from './AuthMiddleware'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export class WebSocketAuthMiddleware extends BaseMiddleware {
|
|||||||
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
|
|
||||||
response.locals.user = decodedToken.user
|
response.locals.user = decodedToken.user
|
||||||
|
response.locals.session = decodedToken.session
|
||||||
response.locals.roles = decodedToken.roles
|
response.locals.roles = decodedToken.roles
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = (error as AxiosError).isAxiosError
|
const errorMessage = (error as AxiosError).isAxiosError
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1')
|
@controller('/v1')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Request, Response } from 'express'
|
|||||||
import { controller, BaseHttpController, httpPost, httpGet, httpDelete } from 'inversify-express-utils'
|
import { controller, BaseHttpController, httpPost, httpGet, httpDelete } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/authenticators')
|
@controller('/v1/authenticators')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/files')
|
@controller('/v1/files')
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
@controller('/v1')
|
@controller('/v1')
|
||||||
export class InvoicesController extends BaseHttpController {
|
export class InvoicesController extends BaseHttpController {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/items', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v1/items', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/messages', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v1/messages', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/offline')
|
@controller('/v1/offline')
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
@controller('/v1')
|
@controller('/v1')
|
||||||
export class PaymentsController extends BaseHttpController {
|
export class PaymentsController extends BaseHttpController {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/sessions')
|
@controller('/v1/sessions')
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/shared-vaults/:sharedVaultUuid/users', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v1/shared-vaults/:sharedVaultUuid/users', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/subscription-invites')
|
@controller('/v1/subscription-invites')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/subscription-tokens')
|
@controller('/v1/subscription-tokens')
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from 'inversify-express-utils'
|
} from 'inversify-express-utils'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpDelete, httpPost } from 'inversify-
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v1/sockets')
|
@controller('/v1/sockets')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v2')
|
@controller('/v2')
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
||||||
import { inject } from 'inversify'
|
import { inject } from 'inversify'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
@controller('/v2')
|
@controller('/v2')
|
||||||
export class PaymentsControllerV2 extends BaseHttpController {
|
export class PaymentsControllerV2 extends BaseHttpController {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||||||
import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
|
import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
|
||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
|
||||||
@controller('/v2', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@controller('/v2', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { MapperInterface, Validator } from '@standardnotes/domain-core'
|
||||||
|
import { ItemHash, SyncRequest } from '@standardnotes/grpc'
|
||||||
|
|
||||||
|
export class SyncRequestGRPCMapper implements MapperInterface<Record<string, unknown>, SyncRequest> {
|
||||||
|
toDomain(_projection: SyncRequest): Record<string, unknown> {
|
||||||
|
throw new Error('Method not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
toProjection(domain: Record<string, unknown>): SyncRequest {
|
||||||
|
const syncRequest = new SyncRequest()
|
||||||
|
if ('items' in domain) {
|
||||||
|
syncRequest.setItemsList((domain.items as Record<string, unknown>[]).map((item) => this.createItemHash(item)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('shared_vault_uuids' in domain) {
|
||||||
|
const sharedVaultUuidsValidation = Validator.isNotEmpty(domain.shared_vault_uuids)
|
||||||
|
if (!sharedVaultUuidsValidation.isFailed()) {
|
||||||
|
syncRequest.setSharedVaultUuidsList(domain.shared_vault_uuids as string[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('compute_integrity' in domain) {
|
||||||
|
syncRequest.setComputeIntegrity(!!domain.compute_integrity)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('sync_token' in domain) {
|
||||||
|
syncRequest.setSyncToken(domain.sync_token as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('cursor_token' in domain) {
|
||||||
|
syncRequest.setCursorToken(domain.cursor_token as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('limit' in domain) {
|
||||||
|
syncRequest.setLimit(domain.limit as number)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('content_type' in domain) {
|
||||||
|
syncRequest.setContentType(domain.content_type as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('api' in domain) {
|
||||||
|
syncRequest.setApiVersion(domain.api as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return syncRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
private createItemHash(record: Record<string, unknown>): ItemHash {
|
||||||
|
const itemHash = new ItemHash()
|
||||||
|
itemHash.setUuid(record.uuid as string)
|
||||||
|
if (record.content) {
|
||||||
|
itemHash.setContent(record.content as string)
|
||||||
|
}
|
||||||
|
if (record.content_type) {
|
||||||
|
itemHash.setContentType(record.content_type as string)
|
||||||
|
}
|
||||||
|
if (record.deleted !== undefined) {
|
||||||
|
itemHash.setDeleted(!!record.deleted)
|
||||||
|
}
|
||||||
|
if (record.duplicate_of) {
|
||||||
|
itemHash.setDuplicateOf(record.duplicate_of as string)
|
||||||
|
}
|
||||||
|
if (record.auth_hash) {
|
||||||
|
itemHash.setAuthHash(record.auth_hash as string)
|
||||||
|
}
|
||||||
|
if (record.enc_item_key) {
|
||||||
|
itemHash.setEncItemKey(record.enc_item_key as string)
|
||||||
|
}
|
||||||
|
if (record.items_key_id) {
|
||||||
|
itemHash.setItemsKeyId(record.items_key_id as string)
|
||||||
|
}
|
||||||
|
if (record.key_system_identifier) {
|
||||||
|
itemHash.setKeySystemIdentifier(record.key_system_identifier as string)
|
||||||
|
}
|
||||||
|
if (record.shared_vault_uuid) {
|
||||||
|
itemHash.setSharedVaultUuid(record.shared_vault_uuid as string)
|
||||||
|
}
|
||||||
|
if (record.created_at) {
|
||||||
|
itemHash.setCreatedAt(record.created_at as string)
|
||||||
|
}
|
||||||
|
if (record.created_at_timestamp) {
|
||||||
|
itemHash.setCreatedAtTimestamp(record.created_at_timestamp as number)
|
||||||
|
}
|
||||||
|
if (record.updated_at) {
|
||||||
|
itemHash.setUpdatedAt(record.updated_at as string)
|
||||||
|
}
|
||||||
|
if (record.updated_at_timestamp) {
|
||||||
|
itemHash.setUpdatedAtTimestamp(record.updated_at_timestamp as number)
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemHash
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import { MapperInterface } from '@standardnotes/domain-core'
|
||||||
|
import {
|
||||||
|
ItemConflictRepresentation,
|
||||||
|
ItemHashRepresentation,
|
||||||
|
ItemRepresentation,
|
||||||
|
MessageRepresentation,
|
||||||
|
NotificationRepresentation,
|
||||||
|
SavedItemRepresentation,
|
||||||
|
SharedVaultInviteRepresentation,
|
||||||
|
SharedVaultRepresentation,
|
||||||
|
SyncResponse,
|
||||||
|
} from '@standardnotes/grpc'
|
||||||
|
|
||||||
|
import { ItemHttpRepresentation } from '../Http/ItemHttpRepresentation'
|
||||||
|
import { SavedItemHttpRepresentation } from '../Http/SavedItemHttpRepresentation'
|
||||||
|
import { ItemConflictHttpRepresentation } from '../Http/ItemConflictHttpRepresentation'
|
||||||
|
import { ItemHashHttpRepresentation } from '../Http/ItemHashHttpRepresentation'
|
||||||
|
import { MessageHttpRepresentation } from '../Http/MessageHttpRepresentation'
|
||||||
|
import { SharedVaultHttpRepresentation } from '../Http/SharedVaultHttpRepresentation'
|
||||||
|
import { SharedVaultInviteHttpRepresentation } from '../Http/SharedVaultInviteHttpRepresentation'
|
||||||
|
import { NotificationHttpRepresentation } from '../Http/NotificationHttpRepresentation'
|
||||||
|
import { SyncResponseHttpRepresentation } from '../Http/SyncResponseHttpRepresentation'
|
||||||
|
|
||||||
|
export class SyncResponseGRPCMapper implements MapperInterface<SyncResponse, SyncResponseHttpRepresentation> {
|
||||||
|
toDomain(_projection: SyncResponseHttpRepresentation): SyncResponse {
|
||||||
|
throw new Error('Method not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
toProjection(domain: SyncResponse): SyncResponseHttpRepresentation {
|
||||||
|
return {
|
||||||
|
retrieved_items: domain.getRetrievedItemsList().map((item) => this.createItem(item)),
|
||||||
|
saved_items: domain.getSavedItemsList().map((item) => this.createSavedItem(item)),
|
||||||
|
conflicts: domain.getConflictsList().map((conflict) => this.createConflict(conflict)),
|
||||||
|
sync_token: domain.getSyncToken(),
|
||||||
|
cursor_token: domain.getCursorToken(),
|
||||||
|
messages: domain.getMessagesList().map((message) => this.createMessage(message)),
|
||||||
|
shared_vaults: domain.getSharedVaultsList().map((sharedVault) => this.createSharedVault(sharedVault)),
|
||||||
|
shared_vault_invites: domain
|
||||||
|
.getSharedVaultInvitesList()
|
||||||
|
.map((sharedVaultInvite) => this.createSharedVaultInvite(sharedVaultInvite)),
|
||||||
|
notifications: domain.getNotificationsList().map((notification) => this.createNotification(notification)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createNotification(notification: NotificationRepresentation): NotificationHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: notification.getUuid(),
|
||||||
|
user_uuid: notification.getUserUuid(),
|
||||||
|
type: notification.getType(),
|
||||||
|
payload: notification.getPayload(),
|
||||||
|
created_at_timestamp: notification.getCreatedAtTimestamp(),
|
||||||
|
updated_at_timestamp: notification.getUpdatedAtTimestamp(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSharedVaultInvite(
|
||||||
|
sharedVaultInvite: SharedVaultInviteRepresentation,
|
||||||
|
): SharedVaultInviteHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: sharedVaultInvite.getUuid(),
|
||||||
|
shared_vault_uuid: sharedVaultInvite.getSharedVaultUuid(),
|
||||||
|
user_uuid: sharedVaultInvite.getUserUuid(),
|
||||||
|
sender_uuid: sharedVaultInvite.getSenderUuid(),
|
||||||
|
encrypted_message: sharedVaultInvite.getEncryptedMessage(),
|
||||||
|
permission: sharedVaultInvite.getPermission(),
|
||||||
|
created_at_timestamp: sharedVaultInvite.getCreatedAtTimestamp(),
|
||||||
|
updated_at_timestamp: sharedVaultInvite.getUpdatedAtTimestamp(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSharedVault(sharedVault: SharedVaultRepresentation): SharedVaultHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: sharedVault.getUuid(),
|
||||||
|
user_uuid: sharedVault.getUserUuid(),
|
||||||
|
file_upload_bytes_used: sharedVault.getFileUploadBytesUsed(),
|
||||||
|
created_at_timestamp: sharedVault.getCreatedAtTimestamp(),
|
||||||
|
updated_at_timestamp: sharedVault.getUpdatedAtTimestamp(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createMessage(message: MessageRepresentation): MessageHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: message.getUuid(),
|
||||||
|
recipient_uuid: message.getRecipientUuid(),
|
||||||
|
sender_uuid: message.getSenderUuid(),
|
||||||
|
encrypted_message: message.getEncryptedMessage(),
|
||||||
|
replaceability_identifier: message.getReplaceabilityIdentifier() ?? null,
|
||||||
|
created_at_timestamp: message.getCreatedAtTimestamp(),
|
||||||
|
updated_at_timestamp: message.getUpdatedAtTimestamp(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createConflict(conflict: ItemConflictRepresentation): ItemConflictHttpRepresentation {
|
||||||
|
return {
|
||||||
|
server_item: conflict.hasServerItem()
|
||||||
|
? this.createItem(conflict.getServerItem() as ItemRepresentation)
|
||||||
|
: undefined,
|
||||||
|
unsaved_item: conflict.hasUnsavedItem()
|
||||||
|
? this.createItemHash(conflict.getUnsavedItem() as ItemHashRepresentation)
|
||||||
|
: undefined,
|
||||||
|
type: conflict.getType(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createItemHash(itemHash: ItemHashRepresentation): ItemHashHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: itemHash.getUuid(),
|
||||||
|
user_uuid: itemHash.getUserUuid(),
|
||||||
|
content: itemHash.hasContent() ? (itemHash.getContent() as string) : undefined,
|
||||||
|
content_type: itemHash.hasContentType() ? (itemHash.getContentType() as string) : null,
|
||||||
|
deleted: itemHash.hasDeleted() ? (itemHash.getDeleted() as boolean) : false,
|
||||||
|
duplicate_of: itemHash.hasDuplicateOf() ? (itemHash.getDuplicateOf() as string) : null,
|
||||||
|
auth_hash: itemHash.hasAuthHash() ? (itemHash.getAuthHash() as string) : undefined,
|
||||||
|
enc_item_key: itemHash.hasEncItemKey() ? (itemHash.getEncItemKey() as string) : undefined,
|
||||||
|
items_key_id: itemHash.hasItemsKeyId() ? (itemHash.getItemsKeyId() as string) : undefined,
|
||||||
|
key_system_identifier: itemHash.hasKeySystemIdentifier() ? (itemHash.getKeySystemIdentifier() as string) : null,
|
||||||
|
shared_vault_uuid: itemHash.hasSharedVaultUuid() ? (itemHash.getSharedVaultUuid() as string) : null,
|
||||||
|
created_at: itemHash.hasCreatedAt() ? (itemHash.getCreatedAt() as string) : undefined,
|
||||||
|
created_at_timestamp: itemHash.hasCreatedAtTimestamp() ? (itemHash.getCreatedAtTimestamp() as number) : undefined,
|
||||||
|
updated_at: itemHash.hasUpdatedAt() ? (itemHash.getUpdatedAt() as string) : undefined,
|
||||||
|
updated_at_timestamp: itemHash.hasUpdatedAtTimestamp() ? (itemHash.getUpdatedAtTimestamp() as number) : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSavedItem(item: SavedItemRepresentation): SavedItemHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: item.getUuid(),
|
||||||
|
duplicate_of: item.hasDuplicateOf() ? (item.getDuplicateOf() as string) : null,
|
||||||
|
content_type: item.getContentType(),
|
||||||
|
auth_hash: item.hasAuthHash() ? (item.getAuthHash() as string) : null,
|
||||||
|
deleted: item.getDeleted(),
|
||||||
|
created_at: item.getCreatedAt(),
|
||||||
|
created_at_timestamp: item.getCreatedAtTimestamp(),
|
||||||
|
updated_at: item.getUpdatedAt(),
|
||||||
|
updated_at_timestamp: item.getUpdatedAtTimestamp(),
|
||||||
|
key_system_identifier: item.hasKeySystemIdentifier() ? (item.getKeySystemIdentifier() as string) : null,
|
||||||
|
shared_vault_uuid: item.hasSharedVaultUuid() ? (item.getSharedVaultUuid() as string) : null,
|
||||||
|
user_uuid: item.hasUserUuid() ? (item.getUserUuid() as string) : null,
|
||||||
|
last_edited_by_uuid: item.hasLastEditedByUuid() ? (item.getLastEditedByUuid() as string) : null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createItem(item: ItemRepresentation): ItemHttpRepresentation {
|
||||||
|
return {
|
||||||
|
uuid: item.getUuid(),
|
||||||
|
items_key_id: item.hasItemsKeyId() ? (item.getItemsKeyId() as string) : null,
|
||||||
|
duplicate_of: item.hasDuplicateOf() ? (item.getDuplicateOf() as string) : null,
|
||||||
|
enc_item_key: item.hasEncItemKey() ? (item.getEncItemKey() as string) : null,
|
||||||
|
content: item.hasContent() ? (item.getContent() as string) : null,
|
||||||
|
content_type: item.getContentType(),
|
||||||
|
auth_hash: item.hasAuthHash() ? (item.getAuthHash() as string) : null,
|
||||||
|
deleted: item.getDeleted(),
|
||||||
|
created_at: item.getCreatedAt(),
|
||||||
|
created_at_timestamp: item.getCreatedAtTimestamp(),
|
||||||
|
updated_at: item.getUpdatedAt(),
|
||||||
|
updated_at_timestamp: item.getUpdatedAtTimestamp(),
|
||||||
|
updated_with_session: item.hasUpdatedWithSession() ? (item.getUpdatedWithSession() as string) : null,
|
||||||
|
key_system_identifier: item.hasKeySystemIdentifier() ? (item.getKeySystemIdentifier() as string) : null,
|
||||||
|
shared_vault_uuid: item.hasSharedVaultUuid() ? (item.getSharedVaultUuid() as string) : null,
|
||||||
|
user_uuid: item.hasUserUuid() ? (item.getUserUuid() as string) : null,
|
||||||
|
last_edited_by_uuid: item.hasLastEditedByUuid() ? (item.getLastEditedByUuid() as string) : null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { ItemHttpRepresentation } from './ItemHttpRepresentation'
|
||||||
|
import { ItemHashHttpRepresentation } from './ItemHashHttpRepresentation'
|
||||||
|
|
||||||
|
export interface ItemConflictHttpRepresentation {
|
||||||
|
server_item?: ItemHttpRepresentation
|
||||||
|
unsaved_item?: ItemHashHttpRepresentation
|
||||||
|
type: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export interface ItemHashHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
user_uuid: string
|
||||||
|
content?: string
|
||||||
|
content_type: string | null
|
||||||
|
deleted?: boolean
|
||||||
|
duplicate_of?: string | null
|
||||||
|
auth_hash?: string
|
||||||
|
enc_item_key?: string
|
||||||
|
items_key_id?: string
|
||||||
|
key_system_identifier: string | null
|
||||||
|
shared_vault_uuid: string | null
|
||||||
|
created_at?: string
|
||||||
|
created_at_timestamp?: number
|
||||||
|
updated_at?: string
|
||||||
|
updated_at_timestamp?: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export interface ItemHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
items_key_id: string | null
|
||||||
|
duplicate_of: string | null
|
||||||
|
enc_item_key: string | null
|
||||||
|
content: string | null
|
||||||
|
content_type: string
|
||||||
|
auth_hash: string | null
|
||||||
|
deleted: boolean
|
||||||
|
created_at: string
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at: string
|
||||||
|
updated_at_timestamp: number
|
||||||
|
updated_with_session: string | null
|
||||||
|
key_system_identifier: string | null
|
||||||
|
shared_vault_uuid: string | null
|
||||||
|
user_uuid: string | null
|
||||||
|
last_edited_by_uuid: string | null
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export interface MessageHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
recipient_uuid: string
|
||||||
|
sender_uuid: string
|
||||||
|
encrypted_message: string
|
||||||
|
replaceability_identifier: string | null
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at_timestamp: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export interface NotificationHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
user_uuid: string
|
||||||
|
type: string
|
||||||
|
payload: string
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at_timestamp: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export interface SavedItemHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
duplicate_of: string | null
|
||||||
|
content_type: string
|
||||||
|
auth_hash: string | null
|
||||||
|
deleted: boolean
|
||||||
|
created_at: string
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at: string
|
||||||
|
updated_at_timestamp: number
|
||||||
|
key_system_identifier: string | null
|
||||||
|
shared_vault_uuid: string | null
|
||||||
|
user_uuid: string | null
|
||||||
|
last_edited_by_uuid: string | null
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface SharedVaultHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
user_uuid: string
|
||||||
|
file_upload_bytes_used: number
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at_timestamp: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export interface SharedVaultInviteHttpRepresentation {
|
||||||
|
uuid: string
|
||||||
|
shared_vault_uuid: string
|
||||||
|
user_uuid: string
|
||||||
|
sender_uuid: string
|
||||||
|
encrypted_message: string
|
||||||
|
permission: string
|
||||||
|
created_at_timestamp: number
|
||||||
|
updated_at_timestamp: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { ItemConflictHttpRepresentation } from './ItemConflictHttpRepresentation'
|
||||||
|
import { ItemHttpRepresentation } from './ItemHttpRepresentation'
|
||||||
|
import { MessageHttpRepresentation } from './MessageHttpRepresentation'
|
||||||
|
import { NotificationHttpRepresentation } from './NotificationHttpRepresentation'
|
||||||
|
import { SavedItemHttpRepresentation } from './SavedItemHttpRepresentation'
|
||||||
|
import { SharedVaultHttpRepresentation } from './SharedVaultHttpRepresentation'
|
||||||
|
import { SharedVaultInviteHttpRepresentation } from './SharedVaultInviteHttpRepresentation'
|
||||||
|
|
||||||
|
export type SyncResponseHttpRepresentation = {
|
||||||
|
retrieved_items: ItemHttpRepresentation[]
|
||||||
|
saved_items: SavedItemHttpRepresentation[]
|
||||||
|
conflicts: ItemConflictHttpRepresentation[]
|
||||||
|
sync_token: string
|
||||||
|
cursor_token?: string
|
||||||
|
messages: MessageHttpRepresentation[]
|
||||||
|
shared_vaults: SharedVaultHttpRepresentation[]
|
||||||
|
shared_vault_invites: SharedVaultInviteHttpRepresentation[]
|
||||||
|
notifications: NotificationHttpRepresentation[]
|
||||||
|
}
|
||||||
+12
-16
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ServiceProxyInterface } from '../Http/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
|
|
||||||
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -42,7 +42,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async callEmailServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
async callEmailServer(_request: Request, response: Response, _methodIdentifier: string): Promise<void> {
|
||||||
response.status(400).send({
|
response.status(400).send({
|
||||||
error: {
|
error: {
|
||||||
message: 'Email server is not available.',
|
message: 'Email server is not available.',
|
||||||
@@ -50,13 +50,13 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callAuthServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
async callAuthServer(request: never, response: never, methodIdentifier: string): Promise<void> {
|
||||||
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
|
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
|
||||||
if (!authService) {
|
if (!authService) {
|
||||||
throw new Error('Auth service not found')
|
throw new Error('Auth service not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceResponse = (await authService.handleRequest(request, response, endpointOrMethodIdentifier)) as {
|
const serviceResponse = (await authService.handleRequest(request, response, methodIdentifier)) as {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
json: Record<string, unknown>
|
json: Record<string, unknown>
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
async callAuthServerWithLegacyFormat(
|
async callAuthServerWithLegacyFormat(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
_endpointOrMethodIdentifier: string,
|
_methodIdentifier: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
response.status(400).send({
|
response.status(400).send({
|
||||||
error: {
|
error: {
|
||||||
@@ -76,13 +76,13 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callRevisionsServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
async callRevisionsServer(request: never, response: never, methodIdentifier: string): Promise<void> {
|
||||||
const service = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Revisions).getValue())
|
const service = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Revisions).getValue())
|
||||||
if (!service) {
|
if (!service) {
|
||||||
throw new Error('Revisions service not found')
|
throw new Error('Revisions service not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceResponse = (await service.handleRequest(request, response, endpointOrMethodIdentifier)) as {
|
const serviceResponse = (await service.handleRequest(request, response, methodIdentifier)) as {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
json: Record<string, unknown>
|
json: Record<string, unknown>
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
this.sendDecoratedResponse(response, serviceResponse)
|
this.sendDecoratedResponse(response, serviceResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callSyncingServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
|
async callSyncingServer(request: never, response: never, methodIdentifier: string): Promise<void> {
|
||||||
const service = this.serviceContainer.get(
|
const service = this.serviceContainer.get(
|
||||||
ServiceIdentifier.create(ServiceIdentifier.NAMES.SyncingServer).getValue(),
|
ServiceIdentifier.create(ServiceIdentifier.NAMES.SyncingServer).getValue(),
|
||||||
)
|
)
|
||||||
@@ -98,7 +98,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
throw new Error('Syncing service not found')
|
throw new Error('Syncing service not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceResponse = (await service.handleRequest(request, response, endpointOrMethodIdentifier)) as {
|
const serviceResponse = (await service.handleRequest(request, response, methodIdentifier)) as {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
json: Record<string, unknown>
|
json: Record<string, unknown>
|
||||||
}
|
}
|
||||||
@@ -106,11 +106,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
this.sendDecoratedResponse(response, serviceResponse)
|
this.sendDecoratedResponse(response, serviceResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callLegacySyncingServer(
|
async callLegacySyncingServer(_request: Request, response: Response, _methodIdentifier: string): Promise<void> {
|
||||||
_request: Request,
|
|
||||||
response: Response,
|
|
||||||
_endpointOrMethodIdentifier: string,
|
|
||||||
): Promise<void> {
|
|
||||||
response.status(400).send({
|
response.status(400).send({
|
||||||
error: {
|
error: {
|
||||||
message: 'Legacy syncing server endpoints are no longer available.',
|
message: 'Legacy syncing server endpoints are no longer available.',
|
||||||
@@ -118,7 +114,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callPaymentsServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
async callPaymentsServer(_request: Request, response: Response, _methodIdentifier: string): Promise<void> {
|
||||||
response.status(400).send({
|
response.status(400).send({
|
||||||
error: {
|
error: {
|
||||||
message: 'Payments server is not available.',
|
message: 'Payments server is not available.',
|
||||||
@@ -126,7 +122,7 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async callWebSocketServer(_request: Request, response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
|
async callWebSocketServer(_request: Request, response: Response, _methodIdentifier: string): Promise<void> {
|
||||||
response.status(400).send({
|
response.status(400).send({
|
||||||
error: {
|
error: {
|
||||||
message: 'Websockets server is not available.',
|
message: 'Websockets server is not available.',
|
||||||
@@ -6,7 +6,7 @@ import { Logger } from 'winston'
|
|||||||
|
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from './ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
@@ -72,16 +72,16 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
async callSyncingServer(
|
async callSyncingServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.callServer(this.syncingServerJsUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callRevisionsServer(
|
async callRevisionsServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.revisionsServerUrl) {
|
if (!this.revisionsServerUrl) {
|
||||||
@@ -89,37 +89,31 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await this.callServer(this.revisionsServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServer(this.revisionsServerUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callLegacySyncingServer(
|
async callLegacySyncingServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.callServerWithLegacyFormat(
|
await this.callServerWithLegacyFormat(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||||
this.syncingServerJsUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async callAuthServer(
|
async callAuthServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.callServer(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServer(this.authServerUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callEmailServer(
|
async callEmailServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.emailServerUrl) {
|
if (!this.emailServerUrl) {
|
||||||
@@ -128,13 +122,13 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.callServer(this.emailServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServer(this.emailServerUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async callWebSocketServer(
|
async callWebSocketServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.webSocketServerUrl) {
|
if (!this.webSocketServerUrl) {
|
||||||
@@ -145,22 +139,16 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
const isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat = request.headers.connectionid !== undefined
|
const isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat = request.headers.connectionid !== undefined
|
||||||
if (isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat) {
|
if (isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat) {
|
||||||
await this.callServerWithLegacyFormat(
|
await this.callServerWithLegacyFormat(this.webSocketServerUrl, request, response, endpoint, payload)
|
||||||
this.webSocketServerUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
await this.callServer(this.webSocketServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServer(this.webSocketServerUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async callPaymentsServer(
|
async callPaymentsServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||||
if (!this.paymentsServerUrl) {
|
if (!this.paymentsServerUrl) {
|
||||||
@@ -169,29 +157,23 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.callServerWithLegacyFormat(
|
await this.callServerWithLegacyFormat(this.paymentsServerUrl, request, response, endpoint, payload)
|
||||||
this.paymentsServerUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async callAuthServerWithLegacyFormat(
|
async callAuthServerWithLegacyFormat(
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpoint, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getServerResponse(
|
private async getServerResponse(
|
||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
retryAttempt?: number,
|
retryAttempt?: number,
|
||||||
): Promise<AxiosResponse | undefined> {
|
): Promise<AxiosResponse | undefined> {
|
||||||
@@ -212,15 +194,10 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(`Calling [${request.method}] ${serverUrl}/${endpointOrMethodIdentifier},
|
|
||||||
headers: ${JSON.stringify(headers)},
|
|
||||||
query: ${JSON.stringify(request.query)},
|
|
||||||
payload: ${JSON.stringify(payload)}`)
|
|
||||||
|
|
||||||
const serviceResponse = await this.httpClient.request({
|
const serviceResponse = await this.httpClient.request({
|
||||||
method: request.method as Method,
|
method: request.method as Method,
|
||||||
headers,
|
headers,
|
||||||
url: `${serverUrl}/${endpointOrMethodIdentifier}`,
|
url: `${serverUrl}/${endpoint}`,
|
||||||
data: this.getRequestData(payload),
|
data: this.getRequestData(payload),
|
||||||
maxContentLength: Infinity,
|
maxContentLength: Infinity,
|
||||||
maxBodyLength: Infinity,
|
maxBodyLength: Infinity,
|
||||||
@@ -237,9 +214,7 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retryAttempt) {
|
if (retryAttempt) {
|
||||||
this.logger.debug(
|
this.logger.debug(`Request to ${serverUrl}/${endpoint} succeeded after ${retryAttempt} retries`)
|
||||||
`Request to ${serverUrl}/${endpointOrMethodIdentifier} succeeded after ${retryAttempt} retries`,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return serviceResponse
|
return serviceResponse
|
||||||
@@ -251,18 +226,9 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(`Retrying request to ${serverUrl}/${endpoint} for the ${nextRetryAttempt} time`)
|
||||||
`Retrying request to ${serverUrl}/${endpointOrMethodIdentifier} for the ${nextRetryAttempt} time`,
|
|
||||||
)
|
|
||||||
|
|
||||||
return this.getServerResponse(
|
return this.getServerResponse(serverUrl, request, response, endpoint, payload, nextRetryAttempt)
|
||||||
serverUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
nextRetryAttempt,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let detailedErrorMessage = (error as Error).message
|
let detailedErrorMessage = (error as Error).message
|
||||||
@@ -272,8 +238,8 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
tooManyRetryAttempts
|
tooManyRetryAttempts
|
||||||
? `Request to ${serverUrl}/${endpointOrMethodIdentifier} timed out after ${retryAttempt} retries`
|
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
||||||
: `Could not pass the request to ${serverUrl}/${endpointOrMethodIdentifier} on underlying service: ${detailedErrorMessage}`,
|
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
|
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
|
||||||
@@ -304,19 +270,10 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const serviceResponse = await this.getServerResponse(
|
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||||
serverUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
|
|
||||||
this.logger.debug(`Response from underlying server: ${JSON.stringify(serviceResponse?.data)},
|
|
||||||
headers: ${JSON.stringify(serviceResponse?.headers)}`)
|
|
||||||
|
|
||||||
if (!serviceResponse) {
|
if (!serviceResponse) {
|
||||||
return
|
return
|
||||||
@@ -348,16 +305,10 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
serverUrl: string,
|
serverUrl: string,
|
||||||
request: Request,
|
request: Request,
|
||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||||
const serviceResponse = await this.getServerResponse(
|
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||||
serverUrl,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
endpointOrMethodIdentifier,
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!serviceResponse) {
|
if (!serviceResponse) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,414 @@
|
|||||||
|
import { AxiosInstance, AxiosError, AxiosResponse, Method } from 'axios'
|
||||||
|
import { Request, Response } from 'express'
|
||||||
|
import { Logger } from 'winston'
|
||||||
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
import { ISessionsClient, AuthorizationHeader, SessionValidationResponse } from '@standardnotes/grpc'
|
||||||
|
import * as grpc from '@grpc/grpc-js'
|
||||||
|
|
||||||
|
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||||
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
|
import { GRPCSyncingServerServiceProxy } from './GRPCSyncingServerServiceProxy'
|
||||||
|
|
||||||
|
export class GRPCServiceProxy implements ServiceProxyInterface {
|
||||||
|
constructor(
|
||||||
|
private httpClient: AxiosInstance,
|
||||||
|
private authServerUrl: string,
|
||||||
|
private syncingServerJsUrl: string,
|
||||||
|
private paymentsServerUrl: string,
|
||||||
|
private filesServerUrl: string,
|
||||||
|
private webSocketServerUrl: string,
|
||||||
|
private revisionsServerUrl: string,
|
||||||
|
private emailServerUrl: string,
|
||||||
|
private httpCallTimeout: number,
|
||||||
|
private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||||
|
private logger: Logger,
|
||||||
|
private timer: TimerInterface,
|
||||||
|
private sessionsClient: ISessionsClient,
|
||||||
|
private gRPCSyncingServerServiceProxy: GRPCSyncingServerServiceProxy,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async validateSession(headers: {
|
||||||
|
authorization: string
|
||||||
|
sharedVaultOwnerContext?: string
|
||||||
|
}): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const request = new AuthorizationHeader()
|
||||||
|
request.setBearerToken(headers.authorization)
|
||||||
|
|
||||||
|
const metadata = new grpc.Metadata()
|
||||||
|
metadata.set('x-shared-vault-owner-context', headers.sharedVaultOwnerContext ?? '')
|
||||||
|
|
||||||
|
this.logger.debug('[GRPCServiceProxy] Validating session via gRPC')
|
||||||
|
|
||||||
|
this.sessionsClient.validate(
|
||||||
|
request,
|
||||||
|
metadata,
|
||||||
|
(error: grpc.ServiceError | null, response: SessionValidationResponse) => {
|
||||||
|
if (error) {
|
||||||
|
const responseCode = error.metadata.get('x-auth-error-response-code').pop()
|
||||||
|
if (responseCode) {
|
||||||
|
return resolve({
|
||||||
|
status: +responseCode,
|
||||||
|
data: {
|
||||||
|
error: {
|
||||||
|
message: error.metadata.get('x-auth-error-message').pop(),
|
||||||
|
tag: error.metadata.get('x-auth-error-tag').pop(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
contentType: 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve({
|
||||||
|
status: 200,
|
||||||
|
data: {
|
||||||
|
authToken: response.getCrossServiceToken(),
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
contentType: 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async callSyncingServer(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
endpoint: string,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<void> {
|
||||||
|
const requestIsUsingLatestApiVersions =
|
||||||
|
payload !== undefined && typeof payload !== 'string' && 'api' in payload && payload.api === '20200115'
|
||||||
|
|
||||||
|
if (requestIsUsingLatestApiVersions && endpoint === 'items/sync') {
|
||||||
|
const result = await this.gRPCSyncingServerServiceProxy.sync(request, response, payload)
|
||||||
|
|
||||||
|
response.status(result.status).send({
|
||||||
|
meta: {
|
||||||
|
auth: {
|
||||||
|
userUuid: response.locals.user?.uuid,
|
||||||
|
roles: response.locals.roles,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
filesServerUrl: this.filesServerUrl,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: result.data,
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
async callRevisionsServer(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
endpoint: string,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<void> {
|
||||||
|
if (!this.revisionsServerUrl) {
|
||||||
|
response.status(400).send({ message: 'Revisions Server not configured' })
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await this.callServer(this.revisionsServerUrl, 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 callEmailServer(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
endpoint: string,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<void> {
|
||||||
|
if (!this.emailServerUrl) {
|
||||||
|
response.status(400).send({ message: 'Email Server not configured' })
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.callServer(this.emailServerUrl, request, response, endpoint, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
async callWebSocketServer(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
endpoint: string,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<void> {
|
||||||
|
if (!this.webSocketServerUrl) {
|
||||||
|
this.logger.debug('Websockets Server URL not defined. Skipped request to WebSockets API.')
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat = request.headers.connectionid !== undefined
|
||||||
|
if (isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat) {
|
||||||
|
await this.callServerWithLegacyFormat(this.webSocketServerUrl, request, response, endpoint, payload)
|
||||||
|
} else {
|
||||||
|
await this.callServer(this.webSocketServerUrl, request, response, endpoint, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async callPaymentsServer(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
endpoint: string,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||||
|
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,
|
||||||
|
retryAttempt?: number,
|
||||||
|
): 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retryAttempt) {
|
||||||
|
this.logger.debug(`Request to ${serverUrl}/${endpoint} succeeded after ${retryAttempt} retries`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse
|
||||||
|
} catch (error) {
|
||||||
|
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
|
||||||
|
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
|
||||||
|
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
||||||
|
await this.timer.sleep(50)
|
||||||
|
|
||||||
|
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
||||||
|
|
||||||
|
this.logger.debug(`Retrying request to ${serverUrl}/${endpoint} for the ${nextRetryAttempt} time`)
|
||||||
|
|
||||||
|
return this.getServerResponse(serverUrl, request, response, endpoint, payload, nextRetryAttempt)
|
||||||
|
}
|
||||||
|
|
||||||
|
let detailedErrorMessage = (error as Error).message
|
||||||
|
if (error instanceof AxiosError) {
|
||||||
|
detailedErrorMessage = `Status: ${error.status}, code: ${error.code}, message: ${error.message}`
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.error(
|
||||||
|
tooManyRetryAttempts
|
||||||
|
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
||||||
|
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
this.logger.debug(`Response error: ${JSON.stringify(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 && !isNaN(+((error as AxiosError).code as string))
|
||||||
|
? +((error as AxiosError).code as string)
|
||||||
|
: 500
|
||||||
|
|
||||||
|
const responseErrorMessage = (error as AxiosError).response?.data
|
||||||
|
|
||||||
|
response
|
||||||
|
.status(errorCode)
|
||||||
|
.send(
|
||||||
|
responseErrorMessage ??
|
||||||
|
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if (!serviceResponse) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.applyResponseHeaders(serviceResponse, response)
|
||||||
|
|
||||||
|
if (this.responseShouldNotBeDecorated(serviceResponse)) {
|
||||||
|
response.status(serviceResponse.status).send(serviceResponse.data)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.status(serviceResponse.status).send({
|
||||||
|
meta: {
|
||||||
|
auth: {
|
||||||
|
userUuid: response.locals.user?.uuid,
|
||||||
|
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 | Response<unknown, Record<string, unknown>>> {
|
||||||
|
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)
|
||||||
|
|
||||||
|
response.redirect(serviceResponse.request.res.responseUrl)
|
||||||
|
} else {
|
||||||
|
response.status(serviceResponse.status)
|
||||||
|
|
||||||
|
response.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 responseShouldNotBeDecorated(serviceResponse: AxiosResponse): boolean {
|
||||||
|
return (
|
||||||
|
serviceResponse.headers['content-type'] !== undefined &&
|
||||||
|
serviceResponse.headers['content-type'].toLowerCase().includes('text/html')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private requestTimedOutOrDidNotReachDestination(error: Record<string, unknown>): boolean {
|
||||||
|
return (
|
||||||
|
('code' in error && error.code === 'ETIMEDOUT') ||
|
||||||
|
('response' in error &&
|
||||||
|
'status' in (error.response as Record<string, unknown>) &&
|
||||||
|
[503, 504].includes((error.response as Record<string, unknown>).status as number))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { Request, Response } from 'express'
|
||||||
|
import { ISyncingClient, SyncRequest, SyncResponse } from '@standardnotes/grpc'
|
||||||
|
import { MapperInterface } from '@standardnotes/domain-core'
|
||||||
|
import { Metadata } from '@grpc/grpc-js'
|
||||||
|
|
||||||
|
import { SyncResponseHttpRepresentation } from '../../Mapping/Sync/Http/SyncResponseHttpRepresentation'
|
||||||
|
|
||||||
|
export class GRPCSyncingServerServiceProxy {
|
||||||
|
constructor(
|
||||||
|
private syncingClient: ISyncingClient,
|
||||||
|
private syncRequestGRPCMapper: MapperInterface<Record<string, unknown>, SyncRequest>,
|
||||||
|
private syncResponseGRPCMapper: MapperInterface<SyncResponse, SyncResponseHttpRepresentation>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async sync(
|
||||||
|
request: Request,
|
||||||
|
response: Response,
|
||||||
|
payload?: Record<string, unknown> | string,
|
||||||
|
): Promise<{ status: number; data: unknown }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const syncRequest = this.syncRequestGRPCMapper.toProjection(payload as Record<string, unknown>)
|
||||||
|
|
||||||
|
const metadata = new Metadata()
|
||||||
|
metadata.set('x-user-uuid', response.locals.user.uuid)
|
||||||
|
metadata.set('x-snjs-version', request.headers['x-snjs-version'] as string)
|
||||||
|
metadata.set('x-read-only-access', response.locals.readonlyAccess ? 'true' : 'false')
|
||||||
|
if (response.locals.session) {
|
||||||
|
metadata.set('x-session-uuid', response.locals.session.uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.syncingClient.syncItems(syncRequest, metadata, (error, syncResponse) => {
|
||||||
|
if (error) {
|
||||||
|
const responseCode = error.metadata.get('x-sync-error-response-code').pop()
|
||||||
|
if (responseCode) {
|
||||||
|
return resolve({
|
||||||
|
status: +responseCode,
|
||||||
|
data: { error: { message: error.metadata.get('x-sync-error-message').pop() } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve({ status: 200, data: this.syncResponseGRPCMapper.toProjection(syncResponse) })
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,4 +6,4 @@ sh supervisor/wait-for.sh localhost $AUTH_SERVER_PORT
|
|||||||
sh supervisor/wait-for.sh localhost $FILES_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $FILES_SERVER_PORT
|
||||||
sh supervisor/wait-for.sh localhost $REVISIONS_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $REVISIONS_SERVER_PORT
|
||||||
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ AUTH_JWT_TTL=60000
|
|||||||
ENCRYPTION_SERVER_KEY=change-me-!
|
ENCRYPTION_SERVER_KEY=change-me-!
|
||||||
|
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
GRPC_PORT=50051
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_REPLICA_HOST=127.0.0.1
|
DB_REPLICA_HOST=127.0.0.1
|
||||||
|
|||||||
@@ -3,6 +3,95 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.174.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.174.2...@standardnotes/auth-server@1.174.3) (2023-11-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** pass session uuid to web sockets controller ([edb0a76](https://github.com/standardnotes/server/commit/edb0a768d0b8c31298b31372e6cec16d003fd28d))
|
||||||
|
* pass session uuid to websockets token ([bcd1d83](https://github.com/standardnotes/server/commit/bcd1d830e6125fc5f8cc1312e581284221aaac8f))
|
||||||
|
|
||||||
|
## [1.174.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.174.1...@standardnotes/auth-server@1.174.2) (2023-11-28)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
## [1.174.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.174.0...@standardnotes/auth-server@1.174.1) (2023-11-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* repository config in package.json files ([ed1bf37](https://github.com/standardnotes/server/commit/ed1bf37287af23a25b8388ada95f0acdec8f71ea))
|
||||||
|
|
||||||
|
# [1.174.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.173.2...@standardnotes/auth-server@1.174.0) (2023-11-27)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add npm provenance to published packages ([e836abd](https://github.com/standardnotes/server/commit/e836abdef73d246940d8fffd9e65e17c64cd35c8))
|
||||||
|
|
||||||
|
## [1.173.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.173.1...@standardnotes/auth-server@1.173.2) (2023-11-23)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
## [1.173.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.173.0...@standardnotes/auth-server@1.173.1) (2023-11-22)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* error handling on gRPC ([#937](https://github.com/standardnotes/server/issues/937)) ([8f23c8a](https://github.com/standardnotes/server/commit/8f23c8ab3f03e9c23adfb31a33c5805492bc2f5b))
|
||||||
|
|
||||||
|
# [1.173.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.172.2...@standardnotes/auth-server@1.173.0) (2023-11-22)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add verifiying if user has no items before mass deleting spam accounts ([#936](https://github.com/standardnotes/server/issues/936)) ([c11abe1](https://github.com/standardnotes/server/commit/c11abe1bd36de7c0fb9850c20a8157c066fa9379))
|
||||||
|
|
||||||
|
## [1.172.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.172.1...@standardnotes/auth-server@1.172.2) (2023-11-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* define grpc max message size ([bfef16c](https://github.com/standardnotes/server/commit/bfef16ce3757b57ea1cb0cb7417d6bc935a52321))
|
||||||
|
|
||||||
|
## [1.172.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.172.0...@standardnotes/auth-server@1.172.1) (2023-11-20)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* setting gzip as default compression on grpc calls ([#933](https://github.com/standardnotes/server/issues/933)) ([2dff6a2](https://github.com/standardnotes/server/commit/2dff6a2ed3d105ca65996d47321a811e22e25099))
|
||||||
|
|
||||||
|
# [1.172.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.171.0...@standardnotes/auth-server@1.172.0) (2023-11-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **grpc:** add syncing protocol buffers ([#930](https://github.com/standardnotes/server/issues/930)) ([5b84f07](https://github.com/standardnotes/server/commit/5b84f078c6ae6330706895f7c57b67ff8c8d18ae))
|
||||||
|
|
||||||
|
# [1.171.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.170.0...@standardnotes/auth-server@1.171.0) (2023-11-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add debug logs for grpc communication ([6391a01](https://github.com/standardnotes/server/commit/6391a01b5703db23b566710d0520c1197c46144b))
|
||||||
|
|
||||||
|
# [1.170.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.169.2...@standardnotes/auth-server@1.170.0) (2023-11-16)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add grpc sessions validation server ([#928](https://github.com/standardnotes/server/issues/928)) ([4f62cac](https://github.com/standardnotes/server/commit/4f62cac213a6b5f503040ef6319e5198967974ce))
|
||||||
|
|
||||||
|
## [1.169.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.169.1...@standardnotes/auth-server@1.169.2) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
## [1.169.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.169.0...@standardnotes/auth-server@1.169.1) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
# [1.169.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.168.0...@standardnotes/auth-server@1.169.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add keep-alive connections to subservices ([#924](https://github.com/standardnotes/server/issues/924)) ([daad76d](https://github.com/standardnotes/server/commit/daad76d0ddae34c59dce45eedc4a055c4a11456d))
|
||||||
|
|
||||||
|
# [1.168.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.2...@standardnotes/auth-server@1.168.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/server/issues/923)) ([c24353c](https://github.com/standardnotes/server/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
## [1.167.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.1...@standardnotes/auth-server@1.167.2) (2023-11-08)
|
## [1.167.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.1...@standardnotes/auth-server@1.167.2) (2023-11-08)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
|
|||||||
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
|
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
|
||||||
|
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
|
import * as grpc from '@grpc/grpc-js'
|
||||||
import { urlencoded, json, Request, Response, NextFunction } from 'express'
|
import { urlencoded, json, Request, Response, NextFunction } from 'express'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
import * as dayjs from 'dayjs'
|
import * as dayjs from 'dayjs'
|
||||||
@@ -29,6 +30,10 @@ import { InversifyExpressServer } from 'inversify-express-utils'
|
|||||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||||
import TYPES from '../src/Bootstrap/Types'
|
import TYPES from '../src/Bootstrap/Types'
|
||||||
import { Env } from '../src/Bootstrap/Env'
|
import { Env } from '../src/Bootstrap/Env'
|
||||||
|
import { SessionsServer } from '../src/Infra/gRPC/SessionsServer'
|
||||||
|
import { SessionsService } from '@standardnotes/grpc'
|
||||||
|
import { AuthenticateRequest } from '../src/Domain/UseCase/AuthenticateRequest'
|
||||||
|
import { CreateCrossServiceToken } from '../src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
||||||
|
|
||||||
const container = new ContainerConfigLoader()
|
const container = new ContainerConfigLoader()
|
||||||
void container.load().then((container) => {
|
void container.load().then((container) => {
|
||||||
@@ -64,9 +69,68 @@ void container.load().then((container) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverInstance = server.build()
|
const serverInstance = server.build().listen(env.get('PORT'))
|
||||||
|
|
||||||
serverInstance.listen(env.get('PORT'))
|
const httpKeepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
: 10_000
|
||||||
|
|
||||||
|
serverInstance.keepAliveTimeout = httpKeepAliveTimeout
|
||||||
|
|
||||||
|
const grpcKeepAliveTimeout = env.get('GRPC_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
? +env.get('GRPC_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
: 10_000
|
||||||
|
|
||||||
|
const grpcMaxMessageSize = env.get('GRPC_MAX_MESSAGE_SIZE', true)
|
||||||
|
? +env.get('GRPC_MAX_MESSAGE_SIZE', true)
|
||||||
|
: 1024 * 1024 * 50
|
||||||
|
|
||||||
|
const grpcServer = new grpc.Server({
|
||||||
|
'grpc.keepalive_time_ms': grpcKeepAliveTimeout * 2,
|
||||||
|
'grpc.keepalive_timeout_ms': grpcKeepAliveTimeout,
|
||||||
|
'grpc.default_compression_algorithm': grpc.compressionAlgorithms.gzip,
|
||||||
|
'grpc.max_receive_message_length': grpcMaxMessageSize,
|
||||||
|
'grpc.max_send_message_length': grpcMaxMessageSize,
|
||||||
|
})
|
||||||
|
|
||||||
|
const gRPCPort = env.get('GRPC_PORT', true) ? +env.get('GRPC_PORT', true) : 50051
|
||||||
|
|
||||||
|
const sessionsServer = new SessionsServer(
|
||||||
|
container.get<AuthenticateRequest>(TYPES.Auth_AuthenticateRequest),
|
||||||
|
container.get<CreateCrossServiceToken>(TYPES.Auth_CreateCrossServiceToken),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
)
|
||||||
|
|
||||||
|
grpcServer.addService(SessionsService, {
|
||||||
|
validate: sessionsServer.validate.bind(sessionsServer),
|
||||||
|
})
|
||||||
|
grpcServer.bindAsync(`0.0.0.0:${gRPCPort}`, grpc.ServerCredentials.createInsecure(), (error, port) => {
|
||||||
|
if (error) {
|
||||||
|
logger.error(`Failed to bind gRPC server: ${error.message}`)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`gRPC server bound on port ${port}`)
|
||||||
|
|
||||||
|
grpcServer.start()
|
||||||
|
|
||||||
|
logger.info('gRPC server started')
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM signal received: closing HTTP server')
|
||||||
|
serverInstance.close(() => {
|
||||||
|
logger.info('HTTP server closed')
|
||||||
|
})
|
||||||
|
grpcServer.tryShutdown((error?: Error) => {
|
||||||
|
if (error) {
|
||||||
|
logger.error(`Failed to shutdown gRPC server: ${error.message}`)
|
||||||
|
} else {
|
||||||
|
logger.info('gRPC server closed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
logger.info(`Server started on port ${process.env.PORT}`)
|
logger.info(`Server started on port ${process.env.PORT}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,5 +22,11 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.Auth_DomainEventSubscriber)
|
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.Auth_DomainEventSubscriber)
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM received. Stopping worker...')
|
||||||
|
subscriber.stop()
|
||||||
|
logger.info('Worker stopped.')
|
||||||
|
})
|
||||||
|
|
||||||
subscriber.start()
|
subscriber.start()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,45 +6,45 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-web' )
|
'start-web' )
|
||||||
echo "[Docker] Starting Web..."
|
echo "[Docker] Starting Web..."
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'start-worker' )
|
'start-worker' )
|
||||||
echo "[Docker] Starting Worker..."
|
echo "[Docker] Starting Worker..."
|
||||||
node docker/entrypoint-worker.js
|
exec node docker/entrypoint-worker.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'cleanup' )
|
'cleanup' )
|
||||||
echo "[Docker] Starting Cleanup..."
|
echo "[Docker] Starting Cleanup..."
|
||||||
node docker/entrypoint-cleanup.js
|
exec node docker/entrypoint-cleanup.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'stats' )
|
'stats' )
|
||||||
echo "[Docker] Starting Persisting Stats..."
|
echo "[Docker] Starting Persisting Stats..."
|
||||||
node docker/entrypoint-stats.js
|
exec node docker/entrypoint-stats.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-daily-backup' )
|
'email-daily-backup' )
|
||||||
echo "[Docker] Starting Email Daily Backup..."
|
echo "[Docker] Starting Email Daily Backup..."
|
||||||
node docker/entrypoint-backup.js daily
|
exec node docker/entrypoint-backup.js daily
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-weekly-backup' )
|
'email-weekly-backup' )
|
||||||
echo "[Docker] Starting Email Weekly Backup..."
|
echo "[Docker] Starting Email Weekly Backup..."
|
||||||
node docker/entrypoint-backup.js weekly
|
exec node docker/entrypoint-backup.js weekly
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-backup' )
|
'email-backup' )
|
||||||
echo "[Docker] Starting Email Backup For Single User..."
|
echo "[Docker] Starting Email Backup For Single User..."
|
||||||
EMAIL=$1 && shift 1
|
EMAIL=$1 && shift 1
|
||||||
node docker/entrypoint-user-email-backup.js $EMAIL
|
exec node docker/entrypoint-user-email-backup.js $EMAIL
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'delete-accounts' )
|
'delete-accounts' )
|
||||||
echo "[Docker] Starting Accounts Deleting from CSV..."
|
echo "[Docker] Starting Accounts Deleting from CSV..."
|
||||||
FILE_NAME=$1 && shift 1
|
FILE_NAME=$1 && shift 1
|
||||||
MODE=$1 && shift 1
|
MODE=$1 && shift 1
|
||||||
node docker/entrypoint-delete-accounts.js $FILE_NAME $MODE
|
exec node docker/entrypoint-delete-accounts.js $FILE_NAME $MODE
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/auth-server",
|
"name": "@standardnotes/auth-server",
|
||||||
"version": "1.167.2",
|
"version": "1.174.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -10,7 +10,13 @@
|
|||||||
"author": "Karol Sójko <karol@standardnotes.com>",
|
"author": "Karol Sójko <karol@standardnotes.com>",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public",
|
||||||
|
"provenance": true
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:standardnotes/server.git",
|
||||||
|
"directory": "packages/auth"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -fr dist",
|
"clean": "rm -fr dist",
|
||||||
@@ -37,6 +43,7 @@
|
|||||||
"@aws-sdk/client-sqs": "^3.427.0",
|
"@aws-sdk/client-sqs": "^3.427.0",
|
||||||
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
||||||
"@cbor-extract/cbor-extract-linux-x64": "^2.1.1",
|
"@cbor-extract/cbor-extract-linux-x64": "^2.1.1",
|
||||||
|
"@grpc/grpc-js": "^1.9.11",
|
||||||
"@simplewebauthn/server": "^8.1.1",
|
"@simplewebauthn/server": "^8.1.1",
|
||||||
"@simplewebauthn/typescript-types": "^8.0.0",
|
"@simplewebauthn/typescript-types": "^8.0.0",
|
||||||
"@standardnotes/api": "^1.26.26",
|
"@standardnotes/api": "^1.26.26",
|
||||||
@@ -45,6 +52,7 @@
|
|||||||
"@standardnotes/domain-events": "workspace:*",
|
"@standardnotes/domain-events": "workspace:*",
|
||||||
"@standardnotes/domain-events-infra": "workspace:*",
|
"@standardnotes/domain-events-infra": "workspace:*",
|
||||||
"@standardnotes/features": "^1.59.7",
|
"@standardnotes/features": "^1.59.7",
|
||||||
|
"@standardnotes/grpc": "workspace:^",
|
||||||
"@standardnotes/predicates": "workspace:*",
|
"@standardnotes/predicates": "workspace:*",
|
||||||
"@standardnotes/responses": "^1.13.27",
|
"@standardnotes/responses": "^1.13.27",
|
||||||
"@standardnotes/security": "workspace:*",
|
"@standardnotes/security": "workspace:*",
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ import { TriggerEmailBackupForAllUsers } from '../Domain/UseCase/TriggerEmailBac
|
|||||||
import { CSVFileReaderInterface } from '../Domain/CSV/CSVFileReaderInterface'
|
import { CSVFileReaderInterface } from '../Domain/CSV/CSVFileReaderInterface'
|
||||||
import { S3CsvFileReader } from '../Infra/S3/S3CsvFileReader'
|
import { S3CsvFileReader } from '../Infra/S3/S3CsvFileReader'
|
||||||
import { DeleteAccountsFromCSVFile } from '../Domain/UseCase/DeleteAccountsFromCSVFile/DeleteAccountsFromCSVFile'
|
import { DeleteAccountsFromCSVFile } from '../Domain/UseCase/DeleteAccountsFromCSVFile/DeleteAccountsFromCSVFile'
|
||||||
|
import { AccountDeletionVerificationPassedEventHandler } from '../Domain/Handler/AccountDeletionVerificationPassedEventHandler'
|
||||||
|
|
||||||
export class ContainerConfigLoader {
|
export class ContainerConfigLoader {
|
||||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||||
@@ -1194,6 +1195,7 @@ export class ContainerConfigLoader {
|
|||||||
container.get<GetRegularSubscriptionForUser>(TYPES.Auth_GetRegularSubscriptionForUser),
|
container.get<GetRegularSubscriptionForUser>(TYPES.Auth_GetRegularSubscriptionForUser),
|
||||||
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
||||||
container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository),
|
container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository),
|
||||||
|
container.get<GetActiveSessionsForUser>(TYPES.Auth_GetActiveSessionsForUser),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container.bind<ProcessUserRequest>(TYPES.Auth_ProcessUserRequest).to(ProcessUserRequest)
|
container.bind<ProcessUserRequest>(TYPES.Auth_ProcessUserRequest).to(ProcessUserRequest)
|
||||||
@@ -1274,7 +1276,9 @@ export class ContainerConfigLoader {
|
|||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new DeleteAccountsFromCSVFile(
|
new DeleteAccountsFromCSVFile(
|
||||||
container.get<CSVFileReaderInterface>(TYPES.Auth_CSVFileReader),
|
container.get<CSVFileReaderInterface>(TYPES.Auth_CSVFileReader),
|
||||||
container.get<DeleteAccount>(TYPES.Auth_DeleteAccount),
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1328,6 +1332,14 @@ export class ContainerConfigLoader {
|
|||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
container
|
||||||
|
.bind<AccountDeletionVerificationPassedEventHandler>(TYPES.Auth_AccountDeletionVerificationPassedEventHandler)
|
||||||
|
.toConstantValue(
|
||||||
|
new AccountDeletionVerificationPassedEventHandler(
|
||||||
|
container.get<DeleteAccount>(TYPES.Auth_DeleteAccount),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<SubscriptionPurchasedEventHandler>(TYPES.Auth_SubscriptionPurchasedEventHandler)
|
.bind<SubscriptionPurchasedEventHandler>(TYPES.Auth_SubscriptionPurchasedEventHandler)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -1516,6 +1528,7 @@ export class ContainerConfigLoader {
|
|||||||
|
|
||||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
|
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
|
||||||
|
['ACCOUNT_DELETION_VERIFICATION_PASSED', container.get(TYPES.Auth_AccountDeletionVerificationPassedEventHandler)],
|
||||||
['SUBSCRIPTION_PURCHASED', container.get(TYPES.Auth_SubscriptionPurchasedEventHandler)],
|
['SUBSCRIPTION_PURCHASED', container.get(TYPES.Auth_SubscriptionPurchasedEventHandler)],
|
||||||
['SUBSCRIPTION_CANCELLED', container.get(TYPES.Auth_SubscriptionCancelledEventHandler)],
|
['SUBSCRIPTION_CANCELLED', container.get(TYPES.Auth_SubscriptionCancelledEventHandler)],
|
||||||
['SUBSCRIPTION_RENEWED', container.get(TYPES.Auth_SubscriptionRenewedEventHandler)],
|
['SUBSCRIPTION_RENEWED', container.get(TYPES.Auth_SubscriptionRenewedEventHandler)],
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ const TYPES = {
|
|||||||
Auth_DeleteAccountsFromCSVFile: Symbol.for('Auth_DeleteAccountsFromCSVFile'),
|
Auth_DeleteAccountsFromCSVFile: Symbol.for('Auth_DeleteAccountsFromCSVFile'),
|
||||||
// Handlers
|
// Handlers
|
||||||
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
||||||
|
Auth_AccountDeletionVerificationPassedEventHandler: Symbol.for('Auth_AccountDeletionVerificationPassedEventHandler'),
|
||||||
Auth_SubscriptionPurchasedEventHandler: Symbol.for('Auth_SubscriptionPurchasedEventHandler'),
|
Auth_SubscriptionPurchasedEventHandler: Symbol.for('Auth_SubscriptionPurchasedEventHandler'),
|
||||||
Auth_SubscriptionCancelledEventHandler: Symbol.for('Auth_SubscriptionCancelledEventHandler'),
|
Auth_SubscriptionCancelledEventHandler: Symbol.for('Auth_SubscriptionCancelledEventHandler'),
|
||||||
Auth_SubscriptionReassignedEventHandler: Symbol.for('Auth_SubscriptionReassignedEventHandler'),
|
Auth_SubscriptionReassignedEventHandler: Symbol.for('Auth_SubscriptionReassignedEventHandler'),
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
StatisticPersistenceRequestedEvent,
|
StatisticPersistenceRequestedEvent,
|
||||||
SessionCreatedEvent,
|
SessionCreatedEvent,
|
||||||
SessionRefreshedEvent,
|
SessionRefreshedEvent,
|
||||||
|
AccountDeletionVerificationRequestedEvent,
|
||||||
} from '@standardnotes/domain-events'
|
} from '@standardnotes/domain-events'
|
||||||
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
|
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
@@ -33,6 +34,24 @@ import { KeyParamsData } from '@standardnotes/responses'
|
|||||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||||
constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
|
constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
|
||||||
|
|
||||||
|
createAccountDeletionVerificationRequestedEvent(dto: {
|
||||||
|
userUuid: string
|
||||||
|
email: string
|
||||||
|
}): AccountDeletionVerificationRequestedEvent {
|
||||||
|
return {
|
||||||
|
type: 'ACCOUNT_DELETION_VERIFICATION_REQUESTED',
|
||||||
|
createdAt: this.timer.getUTCDate(),
|
||||||
|
meta: {
|
||||||
|
correlation: {
|
||||||
|
userIdentifier: dto.userUuid,
|
||||||
|
userIdentifierType: 'uuid',
|
||||||
|
},
|
||||||
|
origin: DomainEventService.Auth,
|
||||||
|
},
|
||||||
|
payload: dto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createSessionCreatedEvent(dto: { userUuid: string }): SessionCreatedEvent {
|
createSessionCreatedEvent(dto: { userUuid: string }): SessionCreatedEvent {
|
||||||
return {
|
return {
|
||||||
type: 'SESSION_CREATED',
|
type: 'SESSION_CREATED',
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
StatisticPersistenceRequestedEvent,
|
StatisticPersistenceRequestedEvent,
|
||||||
SessionCreatedEvent,
|
SessionCreatedEvent,
|
||||||
SessionRefreshedEvent,
|
SessionRefreshedEvent,
|
||||||
|
AccountDeletionVerificationRequestedEvent,
|
||||||
} from '@standardnotes/domain-events'
|
} from '@standardnotes/domain-events'
|
||||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||||
import { KeyParamsData } from '@standardnotes/responses'
|
import { KeyParamsData } from '@standardnotes/responses'
|
||||||
@@ -56,6 +57,10 @@ export interface DomainEventFactoryInterface {
|
|||||||
ownerUuid: string
|
ownerUuid: string
|
||||||
}
|
}
|
||||||
}): AccountDeletionRequestedEvent
|
}): AccountDeletionRequestedEvent
|
||||||
|
createAccountDeletionVerificationRequestedEvent(dto: {
|
||||||
|
userUuid: string
|
||||||
|
email: string
|
||||||
|
}): AccountDeletionVerificationRequestedEvent
|
||||||
createUserRolesChangedEvent(userUuid: string, email: string, currentRoles: string[]): UserRolesChangedEvent
|
createUserRolesChangedEvent(userUuid: string, email: string, currentRoles: string[]): UserRolesChangedEvent
|
||||||
createUserEmailChangedEvent(userUuid: string, fromEmail: string, toEmail: string): UserEmailChangedEvent
|
createUserEmailChangedEvent(userUuid: string, fromEmail: string, toEmail: string): UserEmailChangedEvent
|
||||||
createUserDisabledSessionUserAgentLoggingEvent(dto: {
|
createUserDisabledSessionUserAgentLoggingEvent(dto: {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { AccountDeletionVerificationPassedEvent, DomainEventHandlerInterface } from '@standardnotes/domain-events'
|
||||||
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
|
import { DeleteAccount } from '../UseCase/DeleteAccount/DeleteAccount'
|
||||||
|
|
||||||
|
export class AccountDeletionVerificationPassedEventHandler implements DomainEventHandlerInterface {
|
||||||
|
constructor(
|
||||||
|
private deleteAccount: DeleteAccount,
|
||||||
|
private logger: Logger,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async handle(event: AccountDeletionVerificationPassedEvent): Promise<void> {
|
||||||
|
const result = await this.deleteAccount.execute({
|
||||||
|
userUuid: event.payload.userUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.isFailed()) {
|
||||||
|
this.logger.error(`AccountDeletionVerificationPassedEventHandler failed: ${result.getError()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -22,6 +22,7 @@ import { GetRegularSubscriptionForUser } from '../GetRegularSubscriptionForUser/
|
|||||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||||
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
||||||
import { EncryptionVersion } from '../../Encryption/EncryptionVersion'
|
import { EncryptionVersion } from '../../Encryption/EncryptionVersion'
|
||||||
|
import { GetActiveSessionsForUser } from '../GetActiveSessionsForUser'
|
||||||
|
|
||||||
describe('CreateCrossServiceToken', () => {
|
describe('CreateCrossServiceToken', () => {
|
||||||
let userProjector: ProjectorInterface<User>
|
let userProjector: ProjectorInterface<User>
|
||||||
@@ -32,6 +33,7 @@ describe('CreateCrossServiceToken', () => {
|
|||||||
let getRegularSubscription: GetRegularSubscriptionForUser
|
let getRegularSubscription: GetRegularSubscriptionForUser
|
||||||
let getSubscriptionSetting: GetSubscriptionSetting
|
let getSubscriptionSetting: GetSubscriptionSetting
|
||||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||||
|
let getActiveSessionsForUser: GetActiveSessionsForUser
|
||||||
const jwtTTL = 60
|
const jwtTTL = 60
|
||||||
|
|
||||||
let session: Session
|
let session: Session
|
||||||
@@ -49,11 +51,15 @@ describe('CreateCrossServiceToken', () => {
|
|||||||
getRegularSubscription,
|
getRegularSubscription,
|
||||||
getSubscriptionSetting,
|
getSubscriptionSetting,
|
||||||
sharedVaultUserRepository,
|
sharedVaultUserRepository,
|
||||||
|
getActiveSessionsForUser,
|
||||||
)
|
)
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
session = {} as jest.Mocked<Session>
|
session = {} as jest.Mocked<Session>
|
||||||
|
|
||||||
|
getActiveSessionsForUser = {} as jest.Mocked<GetActiveSessionsForUser>
|
||||||
|
getActiveSessionsForUser.execute = jest.fn().mockReturnValue({ sessions: [session] })
|
||||||
|
|
||||||
user = {
|
user = {
|
||||||
uuid: '00000000-0000-0000-0000-000000000000',
|
uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
email: 'test@test.te',
|
email: 'test@test.te',
|
||||||
@@ -195,6 +201,69 @@ describe('CreateCrossServiceToken', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should create a cross service token for a user and a specific session', async () => {
|
||||||
|
await createUseCase().execute({
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: 'role1',
|
||||||
|
uuid: '1-3-4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
belongs_to_shared_vaults: [
|
||||||
|
{
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
permission: 'read',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
session: {
|
||||||
|
test: 'test',
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
email: 'test@test.te',
|
||||||
|
uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
60,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create a cross service token for a user and specific session if the session is missing', async () => {
|
||||||
|
getActiveSessionsForUser.execute = jest.fn().mockReturnValue({ sessions: [] })
|
||||||
|
|
||||||
|
await createUseCase().execute({
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(tokenEncoder.encodeExpirableToken).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
name: 'role1',
|
||||||
|
uuid: '1-3-4',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
belongs_to_shared_vaults: [
|
||||||
|
{
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
permission: 'read',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
user: {
|
||||||
|
email: 'test@test.te',
|
||||||
|
uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
60,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('should throw an error if user does not exist', async () => {
|
it('should throw an error if user does not exist', async () => {
|
||||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO'
|
|||||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||||
import { GetSubscriptionSetting } from '../GetSubscriptionSetting/GetSubscriptionSetting'
|
import { GetSubscriptionSetting } from '../GetSubscriptionSetting/GetSubscriptionSetting'
|
||||||
import { GetRegularSubscriptionForUser } from '../GetRegularSubscriptionForUser/GetRegularSubscriptionForUser'
|
import { GetRegularSubscriptionForUser } from '../GetRegularSubscriptionForUser/GetRegularSubscriptionForUser'
|
||||||
|
import { GetActiveSessionsForUser } from '../GetActiveSessionsForUser'
|
||||||
|
|
||||||
export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -23,6 +24,7 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
|||||||
private getRegularSubscription: GetRegularSubscriptionForUser,
|
private getRegularSubscription: GetRegularSubscriptionForUser,
|
||||||
private getSubscriptionSettingUseCase: GetSubscriptionSetting,
|
private getSubscriptionSettingUseCase: GetSubscriptionSetting,
|
||||||
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||||
|
private getActiveSessions: GetActiveSessionsForUser,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(dto: CreateCrossServiceTokenDTO): Promise<Result<string>> {
|
async execute(dto: CreateCrossServiceTokenDTO): Promise<Result<string>> {
|
||||||
@@ -84,6 +86,14 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
|||||||
|
|
||||||
if (dto.session !== undefined) {
|
if (dto.session !== undefined) {
|
||||||
authTokenData.session = this.projectSession(dto.session)
|
authTokenData.session = this.projectSession(dto.session)
|
||||||
|
} else if (dto.sessionUuid !== undefined) {
|
||||||
|
const activeSessionsResponse = await this.getActiveSessions.execute({
|
||||||
|
userUuid: user.uuid,
|
||||||
|
sessionUuid: dto.sessionUuid,
|
||||||
|
})
|
||||||
|
if (activeSessionsResponse.sessions.length) {
|
||||||
|
authTokenData.session = this.projectSession(activeSessionsResponse.sessions[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok(this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL))
|
return Result.ok(this.tokenEncoder.encodeExpirableToken(authTokenData, this.jwtTTL))
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ export type CreateCrossServiceTokenDTO = Either<
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
userUuid: string
|
userUuid: string
|
||||||
|
sessionUuid?: string
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
+38
-9
@@ -1,33 +1,51 @@
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { Result } from '@standardnotes/domain-core'
|
import { Result } from '@standardnotes/domain-core'
|
||||||
|
import { AccountDeletionVerificationRequestedEvent, DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||||
|
|
||||||
import { CSVFileReaderInterface } from '../../CSV/CSVFileReaderInterface'
|
import { CSVFileReaderInterface } from '../../CSV/CSVFileReaderInterface'
|
||||||
import { DeleteAccount } from '../DeleteAccount/DeleteAccount'
|
|
||||||
import { DeleteAccountsFromCSVFile } from './DeleteAccountsFromCSVFile'
|
import { DeleteAccountsFromCSVFile } from './DeleteAccountsFromCSVFile'
|
||||||
|
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||||
|
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||||
|
import { User } from '../../User/User'
|
||||||
|
|
||||||
describe('DeleteAccountsFromCSVFile', () => {
|
describe('DeleteAccountsFromCSVFile', () => {
|
||||||
let csvFileReader: CSVFileReaderInterface
|
let csvFileReader: CSVFileReaderInterface
|
||||||
let deleteAccount: DeleteAccount
|
let userRepository: UserRepositoryInterface
|
||||||
|
let domainEventPublisher: DomainEventPublisherInterface
|
||||||
|
let domainEventFactory: DomainEventFactoryInterface
|
||||||
let logger: Logger
|
let logger: Logger
|
||||||
|
|
||||||
const createUseCase = () => new DeleteAccountsFromCSVFile(csvFileReader, deleteAccount, logger)
|
const createUseCase = () =>
|
||||||
|
new DeleteAccountsFromCSVFile(csvFileReader, domainEventPublisher, domainEventFactory, userRepository, logger)
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
const user = {} as jest.Mocked<User>
|
||||||
|
|
||||||
csvFileReader = {} as jest.Mocked<CSVFileReaderInterface>
|
csvFileReader = {} as jest.Mocked<CSVFileReaderInterface>
|
||||||
csvFileReader.getValues = jest.fn().mockResolvedValue(Result.ok(['email1']))
|
csvFileReader.getValues = jest.fn().mockResolvedValue(Result.ok(['email1']))
|
||||||
|
|
||||||
deleteAccount = {} as jest.Mocked<DeleteAccount>
|
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||||
deleteAccount.execute = jest.fn().mockResolvedValue(Result.ok(''))
|
userRepository.findAllByUsernameOrEmail = jest.fn().mockResolvedValue([user])
|
||||||
|
|
||||||
|
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||||
|
domainEventPublisher.publish = jest.fn()
|
||||||
|
|
||||||
|
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||||
|
domainEventFactory.createAccountDeletionVerificationRequestedEvent = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue({} as jest.Mocked<AccountDeletionVerificationRequestedEvent>)
|
||||||
|
|
||||||
logger = {} as jest.Mocked<Logger>
|
logger = {} as jest.Mocked<Logger>
|
||||||
logger.info = jest.fn()
|
logger.info = jest.fn()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete accounts', async () => {
|
it('should request account deletion verification', async () => {
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
|
|
||||||
const result = await useCase.execute({ fileName: 'test.csv', dryRun: false })
|
const result = await useCase.execute({ fileName: 'test.csv', dryRun: false })
|
||||||
|
|
||||||
|
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||||
|
|
||||||
expect(result.isFailed()).toBeFalsy()
|
expect(result.isFailed()).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -56,12 +74,12 @@ describe('DeleteAccountsFromCSVFile', () => {
|
|||||||
|
|
||||||
const result = await useCase.execute({ fileName: 'test.csv', dryRun: true })
|
const result = await useCase.execute({ fileName: 'test.csv', dryRun: true })
|
||||||
|
|
||||||
expect(deleteAccount.execute).not.toHaveBeenCalled()
|
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||||
expect(result.isFailed()).toBeFalsy()
|
expect(result.isFailed()).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return error if delete account fails', async () => {
|
it('should return error username is invalid', async () => {
|
||||||
deleteAccount.execute = jest.fn().mockResolvedValue(Result.fail('Oops'))
|
csvFileReader.getValues = jest.fn().mockResolvedValue(Result.ok(['']))
|
||||||
|
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
|
|
||||||
@@ -69,4 +87,15 @@ describe('DeleteAccountsFromCSVFile', () => {
|
|||||||
|
|
||||||
expect(result.isFailed()).toBeTruthy()
|
expect(result.isFailed()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should do nothing if users could not be found', async () => {
|
||||||
|
userRepository.findAllByUsernameOrEmail = jest.fn().mockResolvedValue([])
|
||||||
|
|
||||||
|
const useCase = createUseCase()
|
||||||
|
|
||||||
|
const result = await useCase.execute({ fileName: 'test.csv', dryRun: false })
|
||||||
|
|
||||||
|
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||||
|
expect(result.isFailed()).toBeFalsy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+20
-8
@@ -1,14 +1,18 @@
|
|||||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
import { Result, UseCaseInterface, Username } from '@standardnotes/domain-core'
|
||||||
|
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
import { DeleteAccount } from '../DeleteAccount/DeleteAccount'
|
|
||||||
import { CSVFileReaderInterface } from '../../CSV/CSVFileReaderInterface'
|
import { CSVFileReaderInterface } from '../../CSV/CSVFileReaderInterface'
|
||||||
import { DeleteAccountsFromCSVFileDTO } from './DeleteAccountsFromCSVFileDTO'
|
import { DeleteAccountsFromCSVFileDTO } from './DeleteAccountsFromCSVFileDTO'
|
||||||
|
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||||
|
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||||
|
|
||||||
export class DeleteAccountsFromCSVFile implements UseCaseInterface<void> {
|
export class DeleteAccountsFromCSVFile implements UseCaseInterface<void> {
|
||||||
constructor(
|
constructor(
|
||||||
private csvFileReader: CSVFileReaderInterface,
|
private csvFileReader: CSVFileReaderInterface,
|
||||||
private deleteAccount: DeleteAccount,
|
private domainEventPublisher: DomainEventPublisherInterface,
|
||||||
|
private domainEventFactory: DomainEventFactoryInterface,
|
||||||
|
private userRepository: UserRepositoryInterface,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -33,12 +37,20 @@ export class DeleteAccountsFromCSVFile implements UseCaseInterface<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const email of emails) {
|
for (const email of emails) {
|
||||||
const deleteAccountOrError = await this.deleteAccount.execute({
|
const usernameOrError = Username.create(email)
|
||||||
username: email,
|
if (usernameOrError.isFailed()) {
|
||||||
})
|
return Result.fail(usernameOrError.getError())
|
||||||
|
}
|
||||||
|
const username = usernameOrError.getValue()
|
||||||
|
|
||||||
if (deleteAccountOrError.isFailed()) {
|
const users = await this.userRepository.findAllByUsernameOrEmail(username)
|
||||||
return Result.fail(deleteAccountOrError.getError())
|
for (const user of users) {
|
||||||
|
await this.domainEventPublisher.publish(
|
||||||
|
this.domainEventFactory.createAccountDeletionVerificationRequestedEvent({
|
||||||
|
userUuid: user.uuid,
|
||||||
|
email: user.email,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,4 +65,10 @@ describe('GetActiveSessionsForUser', () => {
|
|||||||
|
|
||||||
expect(sessionRepository.findAllByRefreshExpirationAndUserUuid).toHaveBeenCalledWith('1-2-3')
|
expect(sessionRepository.findAllByRefreshExpirationAndUserUuid).toHaveBeenCalledWith('1-2-3')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should get a single session for a user', async () => {
|
||||||
|
expect(await createUseCase().execute({ userUuid: '1-2-3', sessionUuid: '2-3-4' })).toEqual({
|
||||||
|
sessions: [session2],
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterfac
|
|||||||
import { GetActiveSessionsForUserDTO } from './GetActiveSessionsForUserDTO'
|
import { GetActiveSessionsForUserDTO } from './GetActiveSessionsForUserDTO'
|
||||||
import { GetActiveSessionsForUserResponse } from './GetActiveSessionsForUserResponse'
|
import { GetActiveSessionsForUserResponse } from './GetActiveSessionsForUserResponse'
|
||||||
import { UseCaseInterface } from './UseCaseInterface'
|
import { UseCaseInterface } from './UseCaseInterface'
|
||||||
|
import { Session } from '../Session/Session'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class GetActiveSessionsForUser implements UseCaseInterface {
|
export class GetActiveSessionsForUser implements UseCaseInterface {
|
||||||
@@ -18,13 +19,26 @@ export class GetActiveSessionsForUser implements UseCaseInterface {
|
|||||||
const ephemeralSessions = await this.ephemeralSessionRepository.findAllByUserUuid(dto.userUuid)
|
const ephemeralSessions = await this.ephemeralSessionRepository.findAllByUserUuid(dto.userUuid)
|
||||||
const sessions = await this.sessionRepository.findAllByRefreshExpirationAndUserUuid(dto.userUuid)
|
const sessions = await this.sessionRepository.findAllByRefreshExpirationAndUserUuid(dto.userUuid)
|
||||||
|
|
||||||
return {
|
const activeSessions = sessions.concat(ephemeralSessions).sort((a, b) => {
|
||||||
sessions: sessions.concat(ephemeralSessions).sort((a, b) => {
|
const dateA = a.refreshExpiration instanceof Date ? a.refreshExpiration : new Date(a.refreshExpiration)
|
||||||
const dateA = a.refreshExpiration instanceof Date ? a.refreshExpiration : new Date(a.refreshExpiration)
|
const dateB = b.refreshExpiration instanceof Date ? b.refreshExpiration : new Date(b.refreshExpiration)
|
||||||
const dateB = b.refreshExpiration instanceof Date ? b.refreshExpiration : new Date(b.refreshExpiration)
|
|
||||||
|
|
||||||
return dateB.getTime() - dateA.getTime()
|
return dateB.getTime() - dateA.getTime()
|
||||||
}),
|
})
|
||||||
|
|
||||||
|
if (dto.sessionUuid) {
|
||||||
|
let sessions: Session[] = []
|
||||||
|
const session = activeSessions.find((session) => session.uuid === dto.sessionUuid)
|
||||||
|
if (session) {
|
||||||
|
sessions = [session]
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
sessions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessions: activeSessions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export type GetActiveSessionsForUserDTO = {
|
export type GetActiveSessionsForUserDTO = {
|
||||||
userUuid: string
|
userUuid: string
|
||||||
|
sessionUuid?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export interface UserRepositoryInterface {
|
|||||||
streamTeam(memberEmail?: Email): Promise<ReadStream>
|
streamTeam(memberEmail?: Email): Promise<ReadStream>
|
||||||
findOneByUuid(uuid: Uuid): Promise<User | null>
|
findOneByUuid(uuid: Uuid): Promise<User | null>
|
||||||
findOneByUsernameOrEmail(usernameOrEmail: Email | Username): Promise<User | null>
|
findOneByUsernameOrEmail(usernameOrEmail: Email | Username): Promise<User | null>
|
||||||
|
findAllByUsernameOrEmail(usernameOrEmail: Email | Username): Promise<User[]>
|
||||||
findAllCreatedBetween(dto: { start: Date; end: Date; offset: number; limit: number }): Promise<User[]>
|
findAllCreatedBetween(dto: { start: Date; end: Date; offset: number; limit: number }): Promise<User[]>
|
||||||
countAllCreatedBetween(start: Date, end: Date): Promise<number>
|
countAllCreatedBetween(start: Date, end: Date): Promise<number>
|
||||||
save(user: User): Promise<User>
|
save(user: User): Promise<User>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export class BaseWebSocketsController extends BaseHttpController {
|
|||||||
|
|
||||||
const resultOrError = await this.createCrossServiceToken.execute({
|
const resultOrError = await this.createCrossServiceToken.execute({
|
||||||
userUuid: token.userUuid,
|
userUuid: token.userUuid,
|
||||||
|
sessionUuid: token.sessionUuid,
|
||||||
})
|
})
|
||||||
if (resultOrError.isFailed()) {
|
if (resultOrError.isFailed()) {
|
||||||
return this.json(
|
return this.json(
|
||||||
|
|||||||
@@ -69,7 +69,13 @@ export class TypeORMUserRepository implements UserRepositoryInterface {
|
|||||||
return this.ormRepository
|
return this.ormRepository
|
||||||
.createQueryBuilder('user')
|
.createQueryBuilder('user')
|
||||||
.where('user.email = :email', { email: usernameOrEmail.value })
|
.where('user.email = :email', { email: usernameOrEmail.value })
|
||||||
.cache(`user_email_${usernameOrEmail.value}`, 60000)
|
|
||||||
.getOne()
|
.getOne()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findAllByUsernameOrEmail(usernameOrEmail: Email | Username): Promise<User[]> {
|
||||||
|
return this.ormRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.where('user.email = :email', { email: usernameOrEmail.value })
|
||||||
|
.getMany()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import * as grpc from '@grpc/grpc-js'
|
||||||
|
import { Status } from '@grpc/grpc-js/build/src/constants'
|
||||||
|
|
||||||
|
import { AuthorizationHeader, ISessionsServer, SessionValidationResponse } from '@standardnotes/grpc'
|
||||||
|
|
||||||
|
import { AuthenticateRequest } from '../../Domain/UseCase/AuthenticateRequest'
|
||||||
|
import { User } from '../../Domain/User/User'
|
||||||
|
import { CreateCrossServiceToken } from '../../Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
||||||
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
|
export class SessionsServer implements ISessionsServer {
|
||||||
|
constructor(
|
||||||
|
private authenticateRequest: AuthenticateRequest,
|
||||||
|
private createCrossServiceToken: CreateCrossServiceToken,
|
||||||
|
private logger: Logger,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async validate(
|
||||||
|
call: grpc.ServerUnaryCall<AuthorizationHeader, SessionValidationResponse>,
|
||||||
|
callback: grpc.sendUnaryData<SessionValidationResponse>,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
this.logger.debug('[SessionsServer] Validating session via gRPC')
|
||||||
|
|
||||||
|
const authenticateRequestResponse = await this.authenticateRequest.execute({
|
||||||
|
authorizationHeader: call.request.getBearerToken(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!authenticateRequestResponse.success) {
|
||||||
|
const metadata = new grpc.Metadata()
|
||||||
|
metadata.set('x-auth-error-message', authenticateRequestResponse.errorMessage as string)
|
||||||
|
metadata.set('x-auth-error-tag', authenticateRequestResponse.errorTag as string)
|
||||||
|
metadata.set('x-auth-error-response-code', authenticateRequestResponse.responseCode.toString())
|
||||||
|
return callback(
|
||||||
|
{
|
||||||
|
code: Status.PERMISSION_DENIED,
|
||||||
|
message: authenticateRequestResponse.errorMessage,
|
||||||
|
name: authenticateRequestResponse.errorTag,
|
||||||
|
metadata,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = authenticateRequestResponse.user as User
|
||||||
|
|
||||||
|
const sharedVaultOwnerMetadata = call.metadata.get('x-shared-vault-owner-context')
|
||||||
|
let sharedVaultOwnerContext = undefined
|
||||||
|
if (sharedVaultOwnerMetadata.length > 0 && sharedVaultOwnerMetadata[0].length > 0) {
|
||||||
|
sharedVaultOwnerContext = sharedVaultOwnerMetadata[0].toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultOrError = await this.createCrossServiceToken.execute({
|
||||||
|
user,
|
||||||
|
session: authenticateRequestResponse.session,
|
||||||
|
sharedVaultOwnerContext,
|
||||||
|
})
|
||||||
|
if (resultOrError.isFailed()) {
|
||||||
|
const metadata = new grpc.Metadata()
|
||||||
|
metadata.set('x-auth-error-message', resultOrError.getError())
|
||||||
|
metadata.set('x-auth-error-response-code', '400')
|
||||||
|
|
||||||
|
return callback(
|
||||||
|
{
|
||||||
|
code: Status.INVALID_ARGUMENT,
|
||||||
|
message: resultOrError.getError(),
|
||||||
|
name: 'INVALID_ARGUMENT',
|
||||||
|
metadata,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = new SessionValidationResponse()
|
||||||
|
response.setCrossServiceToken(resultOrError.getValue())
|
||||||
|
|
||||||
|
this.logger.debug('[SessionsServer] Session validated via gRPC')
|
||||||
|
|
||||||
|
callback(null, response)
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`[SessionsServer] Error validating session via gRPC: ${(error as Error).message}`)
|
||||||
|
|
||||||
|
callback(
|
||||||
|
{
|
||||||
|
code: Status.UNKNOWN,
|
||||||
|
message: 'An error occurred while validating session',
|
||||||
|
name: 'UNKNOWN',
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,4 +3,4 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user