mirror of
https://github.com/standardnotes/server
synced 2026-01-20 14:04:34 -05:00
Compare commits
32 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14794d1a5f | ||
|
|
6b130ef045 | ||
|
|
25a6126ef4 | ||
|
|
a2df09fb5b | ||
|
|
465b2741fb | ||
|
|
724dc5c86c | ||
|
|
f4208c19a7 | ||
|
|
6fed293716 | ||
|
|
29ffaf04c4 | ||
|
|
bc9182f214 | ||
|
|
91c70a51a0 | ||
|
|
dfe30d7f5e | ||
|
|
815d5460e7 | ||
|
|
8a63c6768b | ||
|
|
f7c29848f1 | ||
|
|
78b9426c1c | ||
|
|
87b22ac684 | ||
|
|
46c30d197a | ||
|
|
36b8354350 | ||
|
|
b6702c7182 | ||
|
|
09d7f608cd | ||
|
|
d023a27377 | ||
|
|
190595febf | ||
|
|
b25edec26c | ||
|
|
85d0c12dad | ||
|
|
25c98ef078 | ||
|
|
af51baea9a | ||
|
|
e97b16606c | ||
|
|
5ff9e43899 | ||
|
|
d3a49e109c | ||
|
|
e3dbff6996 | ||
|
|
d9f5410afd |
@@ -8,7 +8,6 @@ DB_USERNAME=std_notes_user
|
||||
DB_PASSWORD=changeme123
|
||||
DB_DATABASE=standard_notes_db
|
||||
DB_DEBUG_LEVEL=all
|
||||
DB_MIGRATIONS_PATH=dist/migrations/*.js
|
||||
|
||||
#########
|
||||
# CACHE #
|
||||
|
||||
22
.github/workflows/proxy.yml
vendored
Normal file
22
.github/workflows/proxy.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Proxy Server
|
||||
|
||||
concurrency:
|
||||
group: proxy_server
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*standardnotes/proxy-server*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call_server_application_workflow:
|
||||
name: Server Application
|
||||
uses: standardnotes/server/.github/workflows/common-server-application.yml@main
|
||||
with:
|
||||
service_name: proxy
|
||||
workspace_name: "@standardnotes/proxy-server"
|
||||
deploy_worker: false
|
||||
package_path: packages/proxy
|
||||
secrets: inherit
|
||||
53
.pnp.cjs
generated
53
.pnp.cjs
generated
@@ -53,6 +53,10 @@ const RAW_RUNTIME_STATE =
|
||||
"name": "@standardnotes/predicates",\
|
||||
"reference": "workspace:packages/predicates"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/proxy-server",\
|
||||
"reference": "workspace:packages/proxy"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/revisions-server",\
|
||||
"reference": "workspace:packages/revisions"\
|
||||
@@ -103,6 +107,7 @@ const RAW_RUNTIME_STATE =
|
||||
["@standardnotes/event-store", ["workspace:packages/event-store"]],\
|
||||
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
||||
["@standardnotes/predicates", ["workspace:packages/predicates"]],\
|
||||
["@standardnotes/proxy-server", ["workspace:packages/proxy"]],\
|
||||
["@standardnotes/revisions-server", ["workspace:packages/revisions"]],\
|
||||
["@standardnotes/scheduler-server", ["workspace:packages/scheduler"]],\
|
||||
["@standardnotes/security", ["workspace:packages/security"]],\
|
||||
@@ -4461,6 +4466,23 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/proxy-server", [\
|
||||
["workspace:packages/proxy", {\
|
||||
"packageLocation": "./packages/proxy/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/proxy-server", "workspace:packages/proxy"],\
|
||||
["@types/http-proxy", "npm:1.17.9"],\
|
||||
["@types/newrelic", "npm:9.4.0"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.48.2"],\
|
||||
["eslint", "npm:8.32.0"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
["http-proxy", "npm:1.18.1"],\
|
||||
["newrelic", "npm:9.8.0"],\
|
||||
["typescript", "patch:typescript@npm%3A4.8.4#optional!builtin<compat/typescript>::version=4.8.4&hash=701156"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/responses", [\
|
||||
["npm:1.13.4", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.13.4-70cbd72561-4803ee14bd.zip/node_modules/@standardnotes/responses/",\
|
||||
@@ -5076,6 +5098,16 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/http-proxy", [\
|
||||
["npm:1.17.9", {\
|
||||
"packageLocation": "./.yarn/cache/@types-http-proxy-npm-1.17.9-fa2f5ce316-3ee577db82.zip/node_modules/@types/http-proxy/",\
|
||||
"packageDependencies": [\
|
||||
["@types/http-proxy", "npm:1.17.9"],\
|
||||
["@types/node", "npm:18.0.3"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/inversify-express-utils", [\
|
||||
["npm:2.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/@types-inversify-express-utils-npm-2.0.0-e78182955d-9841bfddff.zip/node_modules/@types/inversify-express-utils/",\
|
||||
@@ -9314,6 +9346,18 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["http-proxy", [\
|
||||
["npm:1.18.1", {\
|
||||
"packageLocation": "./.yarn/cache/http-proxy-npm-1.18.1-a313c479c5-5d681e4231.zip/node_modules/http-proxy/",\
|
||||
"packageDependencies": [\
|
||||
["http-proxy", "npm:1.18.1"],\
|
||||
["eventemitter3", "npm:4.0.7"],\
|
||||
["follow-redirects", "virtual:4b63965ac1b2157b91a1875529bea3b0bbc3068d3676d1bef28bff5cf6689705374a86cc3832f95ba8d934037a93cc0e09c3662c13ca0e747800d7ca279a53c0#npm:1.15.2"],\
|
||||
["requires-port", "npm:1.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["http-proxy-agent", [\
|
||||
["npm:5.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/http-proxy-agent-npm-5.0.0-7f1f121b83-b59a9b4bdd.zip/node_modules/http-proxy-agent/",\
|
||||
@@ -13006,6 +13050,15 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["requires-port", [\
|
||||
["npm:1.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/requires-port-npm-1.0.0-fd036b488a-28a1064f04.zip/node_modules/requires-port/",\
|
||||
"packageDependencies": [\
|
||||
["requires-port", "npm:1.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["resolve", [\
|
||||
["patch:resolve@npm%3A1.22.1#optional!builtin<compat/resolve>::version=1.22.1&hash=07638b", {\
|
||||
"packageLocation": "./.yarn/cache/resolve-patch-bc26c25fbb-a6f214b97d.zip/node_modules/resolve/",\
|
||||
|
||||
BIN
.yarn/cache/@types-http-proxy-npm-1.17.9-fa2f5ce316-3ee577db82.zip
vendored
Normal file
BIN
.yarn/cache/@types-http-proxy-npm-1.17.9-fa2f5ce316-3ee577db82.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/http-proxy-npm-1.18.1-a313c479c5-5d681e4231.zip
vendored
Normal file
BIN
.yarn/cache/http-proxy-npm-1.18.1-a313c479c5-5d681e4231.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/requires-port-npm-1.0.0-fd036b488a-28a1064f04.zip
vendored
Normal file
BIN
.yarn/cache/requires-port-npm-1.0.0-fd036b488a-28a1064f04.zip
vendored
Normal file
Binary file not shown.
@@ -31,7 +31,8 @@ RUN mkdir -p \
|
||||
/opt/bundled/auth \
|
||||
/opt/bundled/files \
|
||||
/opt/bundled/revisions \
|
||||
/opt/bundled/api-gateway
|
||||
/opt/bundled/api-gateway \
|
||||
/opt/shared/uploads
|
||||
|
||||
RUN yarn workspace @standardnotes/syncing-server bundle --no-compress --output-directory /opt/bundled/syncing-server
|
||||
RUN yarn workspace @standardnotes/auth-server bundle --no-compress --output-directory /opt/bundled/auth
|
||||
|
||||
@@ -19,12 +19,10 @@ services:
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SERVICES=sns,sqs
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- HOSTNAME_EXTERNAL=localstack
|
||||
- LS_LOG=warn
|
||||
volumes:
|
||||
- ./docker/localstack_bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- standardnotes_self_hosted
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
services:
|
||||
server:
|
||||
image: standardnotes/server
|
||||
env_file: .env.sample
|
||||
env_file: .env
|
||||
container_name: server_self_hosted
|
||||
ports:
|
||||
- 3000:3000
|
||||
- 3125:3104
|
||||
volumes:
|
||||
- ./logs:/var/lib/server/logs
|
||||
- ./uploads:/opt/bundled/files/packages/files/dist/uploads
|
||||
networks:
|
||||
- standardnotes_self_hosted
|
||||
|
||||
@@ -19,12 +20,10 @@ services:
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SERVICES=sns,sqs
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- HOSTNAME_EXTERNAL=localstack
|
||||
- LS_LOG=warn
|
||||
volumes:
|
||||
- ./docker/localstack_bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./localstack_bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
|
||||
networks:
|
||||
- standardnotes_self_hosted
|
||||
|
||||
|
||||
@@ -44,9 +44,7 @@ fi
|
||||
if [ -z "$DB_DEBUG_LEVEL" ]; then
|
||||
export DB_DEBUG_LEVEL="all"
|
||||
fi
|
||||
if [ -z "$DB_MIGRATIONS_PATH" ]; then
|
||||
export DB_MIGRATIONS_PATH="dist/migrations/*.js"
|
||||
fi
|
||||
export DB_MIGRATIONS_PATH="dist/migrations/*.js"
|
||||
|
||||
#########
|
||||
# CACHE #
|
||||
@@ -235,9 +233,7 @@ export SYNCING_SERVER_NEW_RELIC_ENABLED=false
|
||||
export SYNCING_SERVER_NEW_RELIC_APP_NAME="Syncing Server JS"
|
||||
export SYNCING_SERVER_NEW_RELIC_NO_CONFIG_FILE=true
|
||||
|
||||
if [ -z "$SYNCING_SERVER_FILE_UPLOAD_PATH" ]; then
|
||||
export SYNCING_SERVER_FILE_UPLOAD_PATH="data/uploads"
|
||||
fi
|
||||
export SYNCING_SERVER_FILE_UPLOAD_PATH="/opt/shared/uploads"
|
||||
|
||||
printenv | grep SYNCING_SERVER_ | sed 's/SYNCING_SERVER_//g' > /opt/bundled/syncing-server/packages/syncing-server/.env
|
||||
|
||||
@@ -356,10 +352,9 @@ export API_GATEWAY_AUTH_SERVER_URL=http://localhost:$AUTH_SERVER_PORT
|
||||
export API_GATEWAY_WORKSPACE_SERVER_URL=http://localhost:3004
|
||||
export API_GATEWAY_REVISIONS_SERVER_URL=http://localhost:3005
|
||||
if [ -z "$PUBLIC_FILES_SERVER_URL" ]; then
|
||||
export API_GATEWAY_FILES_SERVER_URL=http://localhost:$FILES_SERVER_PORT
|
||||
else
|
||||
export API_GATEWAY_FILES_SERVER_URL=$PUBLIC_FILES_SERVER_URL
|
||||
export PUBLIC_FILES_SERVER_URL=http://localhost:3125
|
||||
fi
|
||||
export API_GATEWAY_FILES_SERVER_URL=$PUBLIC_FILES_SERVER_URL
|
||||
|
||||
printenv | grep API_GATEWAY_ | sed 's/API_GATEWAY_//g' > /opt/bundled/api-gateway/packages/api-gateway/.env
|
||||
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.20.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.20.2...@standardnotes/analytics@2.20.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.20.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.20.1...@standardnotes/analytics@2.20.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.20.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.20.0...@standardnotes/analytics@2.20.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.20.1",
|
||||
"version": "2.20.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.49.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.48.3...@standardnotes/api-gateway@1.49.0) (2023-02-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** proxy endpoint for request passing ([bc9182f](https://github.com/standardnotes/api-gateway/commit/bc9182f214c5386c5f1dd0bcbafbce34d413b6e8))
|
||||
|
||||
### Features
|
||||
|
||||
* **proxy:** add proxy server ([dfe30d7](https://github.com/standardnotes/api-gateway/commit/dfe30d7f5e8598ec1886db0e061b7d593cc27e29))
|
||||
|
||||
## [1.48.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.48.2...@standardnotes/api-gateway@1.48.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.48.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.48.1...@standardnotes/api-gateway@1.48.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.48.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.48.0...@standardnotes/api-gateway@1.48.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -22,6 +22,7 @@ import '../src/Controller/v1/SubscriptionInvitesController'
|
||||
import '../src/Controller/v1/WorkspacesController'
|
||||
import '../src/Controller/v1/InvitesController'
|
||||
import '../src/Controller/v1/AuthenticatorsController'
|
||||
import '../src/Controller/v1/ProxyController'
|
||||
|
||||
import '../src/Controller/v2/PaymentsControllerV2'
|
||||
import '../src/Controller/v2/ActionsControllerV2'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.48.1",
|
||||
"version": "1.49.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -61,6 +61,7 @@ export class ContainerConfigLoader {
|
||||
container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
|
||||
container.bind(TYPES.WORKSPACE_SERVER_URL).toConstantValue(env.get('WORKSPACE_SERVER_URL', true))
|
||||
container.bind(TYPES.WEB_SOCKET_SERVER_URL).toConstantValue(env.get('WEB_SOCKET_SERVER_URL', true))
|
||||
container.bind(TYPES.PROXY_SERVER_URL).toConstantValue(env.get('PROXY_SERVER_URL', true))
|
||||
container
|
||||
.bind(TYPES.HTTP_CALL_TIMEOUT)
|
||||
.toConstantValue(env.get('HTTP_CALL_TIMEOUT', true) ? +env.get('HTTP_CALL_TIMEOUT', true) : 60_000)
|
||||
|
||||
@@ -11,6 +11,7 @@ const TYPES = {
|
||||
EMAIL_SERVER_URL: Symbol.for('EMAIL_SERVER_URL'),
|
||||
WORKSPACE_SERVER_URL: Symbol.for('WORKSPACE_SERVER_URL'),
|
||||
WEB_SOCKET_SERVER_URL: Symbol.for('WEB_SOCKET_SERVER_URL'),
|
||||
PROXY_SERVER_URL: Symbol.for('PROXY_SERVER_URL'),
|
||||
AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'),
|
||||
HTTP_CALL_TIMEOUT: Symbol.for('HTTP_CALL_TIMEOUT'),
|
||||
VERSION: Symbol.for('VERSION'),
|
||||
|
||||
18
packages/api-gateway/src/Controller/v1/ProxyController.ts
Normal file
18
packages/api-gateway/src/Controller/v1/ProxyController.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { all, BaseHttpController, controller } from 'inversify-express-utils'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/proxy')
|
||||
export class ProxyController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
super()
|
||||
}
|
||||
|
||||
@all('*', TYPES.AuthMiddleware)
|
||||
async createToken(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callProxyServer(request, response, request.path.replace('/v1/proxy', ''), request.body)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
@inject(TYPES.WEB_SOCKET_SERVER_URL) private webSocketServerUrl: string,
|
||||
@inject(TYPES.REVISIONS_SERVER_URL) private revisionsServerUrl: string,
|
||||
@inject(TYPES.EMAIL_SERVER_URL) private emailServerUrl: string,
|
||||
@inject(TYPES.PROXY_SERVER_URL) private proxyServerUrl: string,
|
||||
@inject(TYPES.HTTP_CALL_TIMEOUT) private httpCallTimeout: number,
|
||||
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
@@ -111,6 +112,21 @@ export class HttpService implements HttpServiceInterface {
|
||||
await this.callServer(this.webSocketServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callProxyServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
if (!this.proxyServerUrl) {
|
||||
this.logger.debug('Proxy Server URL not defined. Skipped request to Proxy.')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.callServer(this.proxyServerUrl, request, response, endpoint, payload)
|
||||
}
|
||||
|
||||
async callPaymentsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
|
||||
@@ -55,4 +55,10 @@ export interface HttpServiceInterface {
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
callProxyServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpoint: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.88.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.88.2...@standardnotes/auth-server@1.88.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.88.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.88.1...@standardnotes/auth-server@1.88.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.88.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.88.0...@standardnotes/auth-server@1.88.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as utc from 'dayjs/plugin/utc'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
||||
import { Stream } from 'stream'
|
||||
|
||||
const requestRecalculation = async (
|
||||
userRepository: UserRepositoryInterface,
|
||||
domainEventFactory: DomainEventFactoryInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
logger: Logger,
|
||||
): Promise<void> => {
|
||||
const stream = await userRepository.streamAll()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
stream
|
||||
.pipe(
|
||||
new Stream.Transform({
|
||||
objectMode: true,
|
||||
transform: async (rawUserData, _encoding, callback) => {
|
||||
try {
|
||||
await domainEventPublisher.publish(
|
||||
domainEventFactory.createUserContentSizeRecalculationRequestedEvent(rawUserData.user_uuid),
|
||||
)
|
||||
} catch (error) {
|
||||
logger.error(`Could not process user ${rawUserData.user_uuid}: ${(error as Error).message}`)
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
}),
|
||||
)
|
||||
.on('finish', resolve)
|
||||
.on('error', reject)
|
||||
})
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Logger)
|
||||
|
||||
logger.info('Starting content size recalculation requests ...')
|
||||
|
||||
const userRepository: UserRepositoryInterface = container.get(TYPES.UserRepository)
|
||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
|
||||
|
||||
Promise.resolve(requestRecalculation(userRepository, domainEventFactory, domainEventPublisher, logger))
|
||||
.then(() => {
|
||||
logger.info('content size recalculation requesting complete')
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not finish content size recalculation requesting : ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -55,11 +55,6 @@ case "$COMMAND" in
|
||||
node docker/entrypoint-backup.js one_drive daily
|
||||
;;
|
||||
|
||||
'content-recalculation' )
|
||||
echo "[Docker] Starting Content Size Recalculation..."
|
||||
node docker/entrypoint-content.js
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "[Docker] Unknown command"
|
||||
;;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.88.1",
|
||||
"version": "1.88.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
DomainEventService,
|
||||
WebSocketMessageRequestedEvent,
|
||||
ExitDiscountApplyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
MuteEmailsSettingChangedEvent,
|
||||
EmailRequestedEvent,
|
||||
StatisticPersistenceRequestedEvent,
|
||||
@@ -70,23 +69,6 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
}
|
||||
}
|
||||
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent {
|
||||
return {
|
||||
type: 'USER_CONTENT_SIZE_RECALCULATION_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.Auth,
|
||||
},
|
||||
payload: {
|
||||
userUuid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
createExitDiscountApplyRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
discountCode: string
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
PredicateVerifiedEvent,
|
||||
WebSocketMessageRequestedEvent,
|
||||
ExitDiscountApplyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
MuteEmailsSettingChangedEvent,
|
||||
EmailRequestedEvent,
|
||||
StatisticPersistenceRequestedEvent,
|
||||
@@ -22,7 +21,6 @@ import {
|
||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||
|
||||
export interface DomainEventFactoryInterface {
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent
|
||||
createWebSocketMessageRequestedEvent(dto: { userUuid: string; message: JSONString }): WebSocketMessageRequestedEvent
|
||||
createEmailRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.9.70](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.69...@standardnotes/domain-events-infra@1.9.70) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.69](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.68...@standardnotes/domain-events-infra@1.9.69) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.68](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.67...@standardnotes/domain-events-infra@1.9.68) (2023-01-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.9.68",
|
||||
"version": "1.9.70",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.107.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.107.0...@standardnotes/domain-events@2.107.1) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
# [2.107.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.106.2...@standardnotes/domain-events@2.107.0) (2023-02-20)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-events:** add email sent event ([190595f](https://github.com/standardnotes/server/commit/190595febf935f0f47818a2d9f7926a5f351a458))
|
||||
|
||||
## [2.106.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.106.1...@standardnotes/domain-events@2.106.2) (2023-01-20)
|
||||
|
||||
### Reverts
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.106.2",
|
||||
"version": "2.107.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { EmailSentEventPayload } from './EmailSentEventPayload'
|
||||
|
||||
export interface EmailSentEvent extends DomainEventInterface {
|
||||
type: 'EMAIL_SENT'
|
||||
payload: EmailSentEventPayload
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export interface EmailSentEventPayload {
|
||||
userEmail: string
|
||||
messageIdentifier: string
|
||||
level: string
|
||||
subject: string
|
||||
body: string
|
||||
sender?: string
|
||||
additionalStyles?: string
|
||||
attachments?: Array<{
|
||||
filePath: string
|
||||
fileName: string
|
||||
attachmentFileName: string
|
||||
attachmentContentType: string
|
||||
}>
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { RevisionsOwnershipUpdateRequestedEventPayload } from './RevisionsOwnershipUpdateRequestedEventPayload'
|
||||
|
||||
export interface RevisionsOwnershipUpdateRequestedEvent extends DomainEventInterface {
|
||||
type: 'REVISIONS_OWNERSHIP_UPDATE_REQUESTED'
|
||||
payload: RevisionsOwnershipUpdateRequestedEventPayload
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface RevisionsOwnershipUpdateRequestedEventPayload {
|
||||
itemUuid: string
|
||||
userUuid: string
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { UserContentSizeRecalculationRequestedEventPayload } from './UserContentSizeRecalculationRequestedEventPayload'
|
||||
|
||||
export interface UserContentSizeRecalculationRequestedEvent extends DomainEventInterface {
|
||||
type: 'USER_CONTENT_SIZE_RECALCULATION_REQUESTED'
|
||||
payload: UserContentSizeRecalculationRequestedEventPayload
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export interface UserContentSizeRecalculationRequestedEventPayload {
|
||||
userUuid: string
|
||||
}
|
||||
@@ -14,6 +14,8 @@ export * from './Event/EmailBackupRequestedEvent'
|
||||
export * from './Event/EmailBackupRequestedEventPayload'
|
||||
export * from './Event/EmailRequestedEvent'
|
||||
export * from './Event/EmailRequestedEventPayload'
|
||||
export * from './Event/EmailSentEvent'
|
||||
export * from './Event/EmailSentEventPayload'
|
||||
export * from './Event/EmailSubscriptionUnsubscribedEvent'
|
||||
export * from './Event/EmailSubscriptionUnsubscribedEventPayload'
|
||||
export * from './Event/ExitDiscountAppliedEvent'
|
||||
@@ -52,8 +54,6 @@ export * from './Event/RefundProcessedEvent'
|
||||
export * from './Event/RefundProcessedEventPayload'
|
||||
export * from './Event/RevisionsCopyRequestedEvent'
|
||||
export * from './Event/RevisionsCopyRequestedEventPayload'
|
||||
export * from './Event/RevisionsOwnershipUpdateRequestedEvent'
|
||||
export * from './Event/RevisionsOwnershipUpdateRequestedEventPayload'
|
||||
export * from './Event/SharedSubscriptionInvitationCanceledEvent'
|
||||
export * from './Event/SharedSubscriptionInvitationCanceledEventPayload'
|
||||
export * from './Event/SharedSubscriptionInvitationCreatedEvent'
|
||||
@@ -78,8 +78,6 @@ export * from './Event/SubscriptionRevertRequestedEvent'
|
||||
export * from './Event/SubscriptionRevertRequestedEventPayload'
|
||||
export * from './Event/SubscriptionSyncRequestedEvent'
|
||||
export * from './Event/SubscriptionSyncRequestedEventPayload'
|
||||
export * from './Event/UserContentSizeRecalculationRequestedEvent'
|
||||
export * from './Event/UserContentSizeRecalculationRequestedEventPayload'
|
||||
export * from './Event/UserDisabledSessionUserAgentLoggingEvent'
|
||||
export * from './Event/UserDisabledSessionUserAgentLoggingEventPayload'
|
||||
export * from './Event/UserEmailChangedEvent'
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.7.2](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.7.1...@standardnotes/event-store@1.7.2) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.7.1](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.7.0...@standardnotes/event-store@1.7.1) (2023-02-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **event-store:** add handling of email sent events ([d023a27](https://github.com/standardnotes/server/commit/d023a2737772e01eca8dc2c848ddebe43bb58734))
|
||||
|
||||
# [1.7.0](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.68...@standardnotes/event-store@1.7.0) (2023-02-15)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.7.0",
|
||||
"version": "1.7.2",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -81,6 +81,7 @@ export class ContainerConfigLoader {
|
||||
['LISTED_ACCOUNT_CREATED', container.get(TYPES.EventHandler)],
|
||||
['LISTED_ACCOUNT_DELETED', container.get(TYPES.EventHandler)],
|
||||
['EMAIL_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
['EMAIL_SENT', container.get(TYPES.EventHandler)],
|
||||
['SHARED_SUBSCRIPTION_INVITATION_CREATED', container.get(TYPES.EventHandler)],
|
||||
['EMAIL_BACKUP_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
['PAYMENT_FAILED', container.get(TYPES.EventHandler)],
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.10.2...@standardnotes/files-server@1.10.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.10.1...@standardnotes/files-server@1.10.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.10.0...@standardnotes/files-server@1.10.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.10.1",
|
||||
"version": "1.10.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
1
packages/proxy/.eslintignore
Normal file
1
packages/proxy/.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
dist
|
||||
6
packages/proxy/.eslintrc
Normal file
6
packages/proxy/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
26
packages/proxy/CHANGELOG.md
Normal file
26
packages/proxy/CHANGELOG.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.3](https://github.com/standardnotes/server/compare/@standardnotes/proxy-server@1.1.2...@standardnotes/proxy-server@1.1.3) (2023-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/proxy-server
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/server/compare/@standardnotes/proxy-server@1.1.1...@standardnotes/proxy-server@1.1.2) (2023-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/proxy-server
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/server/compare/@standardnotes/proxy-server@1.1.0...@standardnotes/proxy-server@1.1.1) (2023-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/proxy-server
|
||||
|
||||
# 1.1.0 (2023-02-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **proxy:** prevent from passing auth tokens to proxy destination ([91c70a5](https://github.com/standardnotes/server/commit/91c70a51a067c606afc3570764367a6d60910ce3))
|
||||
|
||||
### Features
|
||||
|
||||
* **proxy:** add proxy server ([dfe30d7](https://github.com/standardnotes/server/commit/dfe30d7f5e8598ec1886db0e061b7d593cc27e29))
|
||||
17
packages/proxy/Dockerfile
Normal file
17
packages/proxy/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM node:18.13.0-alpine
|
||||
|
||||
RUN apk add --update \
|
||||
curl \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
RUN corepack enable
|
||||
|
||||
COPY ./ /workspace
|
||||
|
||||
WORKDIR /workspace/packages/proxy
|
||||
|
||||
ENTRYPOINT [ "/workspace/packages/proxy/docker/entrypoint.sh" ]
|
||||
|
||||
CMD [ "start-web" ]
|
||||
93
packages/proxy/bin/server.ts
Normal file
93
packages/proxy/bin/server.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import * as http from 'http'
|
||||
import * as httpProxy from 'http-proxy'
|
||||
import * as path from 'path'
|
||||
|
||||
const proxy = httpProxy.createProxyServer({
|
||||
secure: true,
|
||||
})
|
||||
|
||||
proxy.on('error', (error, req, res) => {
|
||||
console.error(error.message)
|
||||
;(res as http.ServerResponse).writeHead(500, {
|
||||
'Content-Type': 'text/plain',
|
||||
})
|
||||
res.end(`Proxying failed for URL: ${req.url} Error: ${error.message}`)
|
||||
})
|
||||
|
||||
// 10 MB in bytes
|
||||
const MAX_IMAGE_SIZE = 10 * 1024 * 1024
|
||||
|
||||
proxy.on('proxyRes', (proxyRes, _req, res) => {
|
||||
const contentLength = parseInt(proxyRes.headers['content-length'] as string)
|
||||
if (contentLength > MAX_IMAGE_SIZE) {
|
||||
res.writeHead(413, { 'Content-Type': 'text/plain' })
|
||||
res.end(`Image size exceeds the limit of ${MAX_IMAGE_SIZE} bytes.`)
|
||||
return
|
||||
}
|
||||
|
||||
// validate response content type to be image
|
||||
const contentType = proxyRes.headers['content-type'] as string
|
||||
if (!contentType.startsWith('image/')) {
|
||||
res.writeHead(400, { 'Content-Type': 'text/plain' })
|
||||
res.end(`Invalid content type: ${contentType}`)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
http
|
||||
.createServer((req, res) => {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*')
|
||||
res.setHeader('Access-Control-Request-Method', '*')
|
||||
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
|
||||
res.setHeader('Access-Control-Allow-Headers', '*')
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(200)
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
|
||||
if (req.url === '/healthcheck') {
|
||||
res.writeHead(200)
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
|
||||
delete req.headers.authorization
|
||||
delete req.headers['x-auth-token']
|
||||
delete req.headers['x-auth-offline-token']
|
||||
|
||||
/** Remove / or // prefixes */
|
||||
const target = (req.url as string).replace(/^\/+/, '')
|
||||
|
||||
try {
|
||||
const url = new URL(target)
|
||||
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
throw new Error('Invalid URL protocol')
|
||||
}
|
||||
|
||||
if (url.hostname === '') {
|
||||
throw new Error('Invalid URL hostname')
|
||||
}
|
||||
|
||||
const ext = path.extname(url.pathname)
|
||||
if (!['.jpg', '.jpeg', '.png', '.gif'].includes(ext)) {
|
||||
res.writeHead(400)
|
||||
res.end('Only image files can be proxied')
|
||||
return
|
||||
}
|
||||
|
||||
req.url = url.href
|
||||
proxy.web(req, res, {
|
||||
target: target,
|
||||
ignorePath: false,
|
||||
prependPath: false,
|
||||
toProxy: true,
|
||||
})
|
||||
} catch (error) {
|
||||
res.writeHead(500)
|
||||
res.end(`Invalid URL: ${target}`)
|
||||
}
|
||||
})
|
||||
.listen(3000)
|
||||
@@ -4,7 +4,7 @@ const path = require('path')
|
||||
|
||||
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
||||
|
||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/content.js')))
|
||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/server.js')))
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
17
packages/proxy/docker/entrypoint.sh
Executable file
17
packages/proxy/docker/entrypoint.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
COMMAND=$1 && shift 1
|
||||
|
||||
case "$COMMAND" in
|
||||
'start-web' )
|
||||
echo "[Docker] Starting Web..."
|
||||
node docker/entrypoint-server.js
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "Unknown command"
|
||||
;;
|
||||
esac
|
||||
|
||||
exec "$@"
|
||||
4
packages/proxy/linter.tsconfig.json
Normal file
4
packages/proxy/linter.tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
33
packages/proxy/package.json
Normal file
33
packages/proxy/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@standardnotes/proxy-server",
|
||||
"version": "1.1.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
"private": true,
|
||||
"description": "Proxy Server",
|
||||
"main": "dist/src/index.js",
|
||||
"typings": "dist/src/index.d.ts",
|
||||
"repository": "git@github.com:standardnotes/server.git",
|
||||
"author": "Karol Sójko <karolsojko@standardnotes.com>",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"build": "tsc --build",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"start": "yarn node dist/bin/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/http-proxy": "^1.17.9",
|
||||
"http-proxy": "^1.18.1",
|
||||
"newrelic": "^9.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/newrelic": "^9.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
11
packages/proxy/tsconfig.json
Normal file
11
packages/proxy/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"bin/**/*",
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.4](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.12.3...@standardnotes/revisions-server@1.12.4) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
## [1.12.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.12.2...@standardnotes/revisions-server@1.12.3) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
## [1.12.2](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.12.1...@standardnotes/revisions-server@1.12.2) (2023-02-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **revisions:** initial migration to check if user_uuid exists on table ([85d0c12](https://github.com/standardnotes/server/commit/85d0c12dadffe3ed7b8c0717725813e168e20b6c))
|
||||
|
||||
## [1.12.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.12.0...@standardnotes/revisions-server@1.12.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
@@ -28,6 +28,14 @@ export class init1669113322388 implements MigrationInterface {
|
||||
return
|
||||
}
|
||||
|
||||
const revisionsTableHasUserUuidColumnQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = "revisions" AND column_name = "user_uuid"',
|
||||
)
|
||||
const revisionsTableHasUserUuidColumn = revisionsTableHasUserUuidColumnQueryResult[0].count === 1
|
||||
if (revisionsTableHasUserUuidColumn) {
|
||||
return
|
||||
}
|
||||
|
||||
await queryRunner.query('ALTER TABLE `revisions` ADD COLUMN `user_uuid` varchar(36) NULL')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.12.1",
|
||||
"version": "1.12.4",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -36,7 +36,6 @@ const TYPES = {
|
||||
ItemDumpedEventHandler: Symbol.for('ItemDumpedEventHandler'),
|
||||
AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
|
||||
RevisionsCopyRequestedEventHandler: Symbol.for('RevisionsCopyRequestedEventHandler'),
|
||||
RevisionsOwnershipUpdateRequestedEventHandler: Symbol.for('RevisionsOwnershipUpdateRequestedEventHandler'),
|
||||
// Services
|
||||
CrossServiceTokenDecoder: Symbol.for('CrossServiceTokenDecoder'),
|
||||
DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'),
|
||||
|
||||
@@ -23,7 +23,6 @@ import { FSDumpRepository } from '../Infra/FS/FSDumpRepository'
|
||||
import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler'
|
||||
import { RevisionsCopyRequestedEventHandler } from '../Domain/Handler/RevisionsCopyRequestedEventHandler'
|
||||
import { CopyRevisions } from '../Domain/UseCase/CopyRevisions/CopyRevisions'
|
||||
import { RevisionsOwnershipUpdateRequestedEventHandler } from '../Domain/Handler/RevisionsOwnershipUpdateRequestedEventHandler'
|
||||
import { CommonContainerConfigLoader } from './CommonContainerConfigLoader'
|
||||
import { Env } from './Env'
|
||||
|
||||
@@ -120,11 +119,6 @@ export class WorkerContainerConfigLoader extends CommonContainerConfigLoader {
|
||||
context.container.get(TYPES.Logger),
|
||||
)
|
||||
})
|
||||
container
|
||||
.bind<RevisionsOwnershipUpdateRequestedEventHandler>(TYPES.RevisionsOwnershipUpdateRequestedEventHandler)
|
||||
.toDynamicValue((context: interfaces.Context) => {
|
||||
return new RevisionsOwnershipUpdateRequestedEventHandler(context.container.get(TYPES.RevisionRepository))
|
||||
})
|
||||
|
||||
container
|
||||
.bind<DomainEventMessageHandlerInterface>(TYPES.DomainEventMessageHandler)
|
||||
@@ -135,10 +129,6 @@ export class WorkerContainerConfigLoader extends CommonContainerConfigLoader {
|
||||
['ITEM_DUMPED', context.container.get(TYPES.ItemDumpedEventHandler)],
|
||||
['ACCOUNT_DELETION_REQUESTED', context.container.get(TYPES.AccountDeletionRequestedEventHandler)],
|
||||
['REVISIONS_COPY_REQUESTED', context.container.get(TYPES.RevisionsCopyRequestedEventHandler)],
|
||||
[
|
||||
'REVISIONS_OWNERSHIP_UPDATE_REQUESTED',
|
||||
context.container.get(TYPES.RevisionsOwnershipUpdateRequestedEventHandler),
|
||||
],
|
||||
])
|
||||
|
||||
const handler =
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
import { DomainEventHandlerInterface, RevisionsOwnershipUpdateRequestedEvent } from '@standardnotes/domain-events'
|
||||
import { RevisionRepositoryInterface } from '../Revision/RevisionRepositoryInterface'
|
||||
|
||||
export class RevisionsOwnershipUpdateRequestedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(private revisionRepository: RevisionRepositoryInterface) {}
|
||||
|
||||
async handle(event: RevisionsOwnershipUpdateRequestedEvent): Promise<void> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const itemUuidOrError = Uuid.create(event.payload.itemUuid)
|
||||
if (itemUuidOrError.isFailed()) {
|
||||
return
|
||||
}
|
||||
const itemUuid = itemUuidOrError.getValue()
|
||||
|
||||
await this.revisionRepository.updateUserUuid(itemUuid, userUuid)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.17.3](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.17.2...@standardnotes/scheduler-server@1.17.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.17.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.17.1...@standardnotes/scheduler-server@1.17.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.17.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.17.0...@standardnotes/scheduler-server@1.17.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.17.1",
|
||||
"version": "1.17.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.31.5](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.31.4...@standardnotes/syncing-server@1.31.5) (2023-02-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** numbering of the backup emails ([f7c2984](https://github.com/standardnotes/syncing-server-js/commit/f7c29848f1b1bc8a1f39a5b7f246c52f242ed60a))
|
||||
|
||||
## [1.31.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.31.3...@standardnotes/syncing-server@1.31.4) (2023-02-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** creating email backup attachment files ([87b22ac](https://github.com/standardnotes/syncing-server-js/commit/87b22ac684732feaf3aef49496b25fbcda5bd888))
|
||||
|
||||
## [1.31.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.31.2...@standardnotes/syncing-server@1.31.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.31.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.31.1...@standardnotes/syncing-server@1.31.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.31.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.31.0...@standardnotes/syncing-server@1.31.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { WorkerContainerConfigLoader } from '../src/Bootstrap/WorkerContainerConfigLoader'
|
||||
|
||||
const inputArgs = process.argv.slice(2)
|
||||
const userUuid = inputArgs[0]
|
||||
|
||||
const fixContentSize = async (
|
||||
domainEventFactory: DomainEventFactoryInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
): Promise<void> => {
|
||||
await domainEventPublisher.publish(domainEventFactory.createUserContentSizeRecalculationRequestedEvent(userUuid))
|
||||
}
|
||||
|
||||
const container = new WorkerContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Logger)
|
||||
|
||||
logger.info(`Starting content size fixing for user ${userUuid} ...`)
|
||||
|
||||
if (!userUuid) {
|
||||
logger.error('No user uuid passed as argument. Skipped.')
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
|
||||
|
||||
Promise.resolve(fixContentSize(domainEventFactory, domainEventPublisher))
|
||||
.then(() => {
|
||||
logger.info('Content size fix complete.')
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not finish content size fix: ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
||||
|
||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/content.js')))
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
exports.default = index
|
||||
@@ -14,12 +14,6 @@ case "$COMMAND" in
|
||||
node docker/entrypoint-worker.js
|
||||
;;
|
||||
|
||||
'content-size-recalculate' )
|
||||
echo "[Docker] Starting Content Size Recalculation..."
|
||||
USER_UUID=$1 && shift 1
|
||||
node docker/entrypoint-content.js $USER_UUID
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "[Docker] Unknown command"
|
||||
;;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.31.1",
|
||||
"version": "1.31.5",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
ItemDumpedEvent,
|
||||
ItemRevisionCreationRequestedEvent,
|
||||
RevisionsCopyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
@@ -69,23 +68,6 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
}
|
||||
}
|
||||
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent {
|
||||
return {
|
||||
type: 'USER_CONTENT_SIZE_RECALCULATION_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.SyncingServer,
|
||||
},
|
||||
payload: {
|
||||
userUuid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
createDuplicateItemSyncedEvent(itemUuid: string, userUuid: string): DuplicateItemSyncedEvent {
|
||||
return {
|
||||
type: 'DUPLICATE_ITEM_SYNCED',
|
||||
|
||||
@@ -4,11 +4,9 @@ import {
|
||||
ItemDumpedEvent,
|
||||
ItemRevisionCreationRequestedEvent,
|
||||
RevisionsCopyRequestedEvent,
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
|
||||
export interface DomainEventFactoryInterface {
|
||||
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent
|
||||
createEmailRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
messageIdentifier: string
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('CloudBackupRequestedEventHandler', () => {
|
||||
}
|
||||
|
||||
itemBackupService = {} as jest.Mocked<ItemBackupServiceInterface>
|
||||
itemBackupService.backup = jest.fn().mockReturnValue('backup-file-name')
|
||||
itemBackupService.backup = jest.fn().mockReturnValue(['backup-file-name'])
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.debug = jest.fn()
|
||||
@@ -133,6 +133,14 @@ describe('CloudBackupRequestedEventHandler', () => {
|
||||
expect(expectedError).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should not trigger cloud backup if backup filename is not returned', async () => {
|
||||
itemBackupService.backup = jest.fn().mockReturnValue([])
|
||||
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(extensionsHttpService.triggerCloudBackupOnExtensionsServer).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should trigger cloud backup on extensions server with muted emails', async () => {
|
||||
event.payload.userHasEmailsMuted = true
|
||||
|
||||
|
||||
@@ -34,14 +34,19 @@ export class CloudBackupRequestedEventHandler implements DomainEventHandlerInter
|
||||
return
|
||||
}
|
||||
|
||||
const backupFilename = await this.itemBackupService.backup(items, authParams)
|
||||
const backupFilenames = await this.itemBackupService.backup(items, authParams)
|
||||
if (backupFilenames.length === 0) {
|
||||
this.logger.warn(`No backup files created for user ${event.payload.userUuid}`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.logger.debug(`Sending ${items.length} items to extensions server for user ${event.payload.userUuid}`)
|
||||
|
||||
await this.extensionsHttpService.triggerCloudBackupOnExtensionsServer({
|
||||
cloudProvider: event.payload.cloudProvider,
|
||||
authParams,
|
||||
backupFilename,
|
||||
backupFilename: backupFilenames[0],
|
||||
forceMute: event.payload.userHasEmailsMuted,
|
||||
muteEmailsSettingUuid: event.payload.muteEmailsSettingUuid,
|
||||
extensionsServerUrl: this.getExtensionsServerUrl(event),
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('EmailBackupRequestedEventHandler', () => {
|
||||
}
|
||||
|
||||
itemBackupService = {} as jest.Mocked<ItemBackupServiceInterface>
|
||||
itemBackupService.backup = jest.fn().mockReturnValue('backup-file-name')
|
||||
itemBackupService.backup = jest.fn().mockReturnValue(['backup-file-name'])
|
||||
|
||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
@@ -84,14 +84,14 @@ describe('EmailBackupRequestedEventHandler', () => {
|
||||
it('should inform that multipart backup attachment for email was created', async () => {
|
||||
itemBackupService.backup = jest
|
||||
.fn()
|
||||
.mockReturnValueOnce('backup-file-name-1')
|
||||
.mockReturnValueOnce('backup-file-name-2')
|
||||
.mockReturnValueOnce(['backup-file-name-1'])
|
||||
.mockReturnValueOnce(['backup-file-name-2', 'backup-file-name-3'])
|
||||
itemTransferCalculator.computeItemUuidBundlesToFetch = jest.fn().mockReturnValue([['1-2-3'], ['2-3-4']])
|
||||
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalledTimes(2)
|
||||
expect(domainEventFactory.createEmailRequestedEvent).toHaveBeenCalledTimes(2)
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalledTimes(3)
|
||||
expect(domainEventFactory.createEmailRequestedEvent).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('should not inform that backup attachment for email was created if user key params cannot be obtained', async () => {
|
||||
|
||||
@@ -51,7 +51,7 @@ export class EmailBackupRequestedEventHandler implements DomainEventHandlerInter
|
||||
this.emailAttachmentMaxByteSize,
|
||||
)
|
||||
|
||||
let bundleIndex = 1
|
||||
const backupFileNames: string[] = []
|
||||
for (const itemUuidBundle of itemUuidBundles) {
|
||||
const items = await this.itemRepository.findAll({
|
||||
uuids: itemUuidBundle,
|
||||
@@ -59,23 +59,25 @@ export class EmailBackupRequestedEventHandler implements DomainEventHandlerInter
|
||||
sortOrder: 'ASC',
|
||||
})
|
||||
|
||||
const backupFileName = await this.itemBackupService.backup(items, authParams)
|
||||
const bundleBackupFileNames = await this.itemBackupService.backup(
|
||||
items,
|
||||
authParams,
|
||||
this.emailAttachmentMaxByteSize,
|
||||
)
|
||||
|
||||
this.logger.debug(`Data backed up into: ${backupFileName}`)
|
||||
backupFileNames.push(...bundleBackupFileNames)
|
||||
}
|
||||
|
||||
if (backupFileName.length === 0) {
|
||||
this.logger.error(`Could not create a backup file for user ${event.payload.userUuid}`)
|
||||
|
||||
return
|
||||
}
|
||||
const dateOnly = new Date().toISOString().substring(0, 10)
|
||||
const dateOnly = new Date().toISOString().substring(0, 10)
|
||||
let bundleIndex = 1
|
||||
|
||||
for (const backupFileName of backupFileNames) {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createEmailRequestedEvent({
|
||||
body: getBody(authParams.identifier as string),
|
||||
level: EmailLevel.LEVELS.System,
|
||||
messageIdentifier: 'DATA_BACKUP',
|
||||
subject: getSubject(bundleIndex++, itemUuidBundles.length, dateOnly),
|
||||
subject: getSubject(bundleIndex++, backupFileNames.length, dateOnly),
|
||||
userEmail: authParams.identifier as string,
|
||||
sender: 'backups@standardnotes.org',
|
||||
attachments: [
|
||||
|
||||
@@ -2,6 +2,6 @@ import { KeyParamsData } from '@standardnotes/responses'
|
||||
import { Item } from './Item'
|
||||
|
||||
export interface ItemBackupServiceInterface {
|
||||
backup(items: Array<Item>, authParams: KeyParamsData): Promise<string>
|
||||
backup(items: Array<Item>, authParams: KeyParamsData, contentSizeLimit?: number): Promise<string[]>
|
||||
dump(item: Item): Promise<string>
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class FSItemBackupService implements ItemBackupServiceInterface {
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async backup(_items: Item[], _authParams: KeyParamsData): Promise<string> {
|
||||
async backup(_items: Item[], _authParams: KeyParamsData, _contentSizeLimit?: number): Promise<string[]> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
|
||||
|
||||
@@ -37,21 +37,52 @@ export class S3ItemBackupService implements ItemBackupServiceInterface {
|
||||
return s3Key
|
||||
}
|
||||
|
||||
async backup(items: Item[], authParams: KeyParamsData): Promise<string> {
|
||||
async backup(items: Item[], authParams: KeyParamsData, contentSizeLimit?: number): Promise<string[]> {
|
||||
if (!this.s3BackupBucketName || this.s3Client === undefined) {
|
||||
this.logger.warn('S3 backup not configured')
|
||||
|
||||
return ''
|
||||
return []
|
||||
}
|
||||
|
||||
const fileNames = []
|
||||
let itemProjections: Array<ItemProjection> = []
|
||||
let contentSizeCounter = 0
|
||||
for (const item of items) {
|
||||
const itemProjection = await this.itemProjector.projectFull(item)
|
||||
|
||||
if (contentSizeLimit === undefined) {
|
||||
itemProjections.push(itemProjection)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
const itemContentSize = Buffer.byteLength(JSON.stringify(itemProjection))
|
||||
|
||||
if (contentSizeCounter + itemContentSize <= contentSizeLimit) {
|
||||
itemProjections.push(itemProjection)
|
||||
|
||||
contentSizeCounter += itemContentSize
|
||||
} else {
|
||||
const backupFileName = await this.createBackupFile(itemProjections, authParams)
|
||||
fileNames.push(backupFileName)
|
||||
|
||||
itemProjections = [itemProjection]
|
||||
contentSizeCounter = itemContentSize
|
||||
}
|
||||
}
|
||||
|
||||
if (itemProjections.length > 0) {
|
||||
const backupFileName = await this.createBackupFile(itemProjections, authParams)
|
||||
fileNames.push(backupFileName)
|
||||
}
|
||||
|
||||
return fileNames
|
||||
}
|
||||
|
||||
private async createBackupFile(itemProjections: ItemProjection[], authParams: KeyParamsData): Promise<string> {
|
||||
const fileName = uuid.v4()
|
||||
|
||||
const itemProjections = []
|
||||
for (const item of items) {
|
||||
itemProjections.push(await this.itemProjector.projectFull(item))
|
||||
}
|
||||
|
||||
await this.s3Client.send(
|
||||
await (this.s3Client as S3Client).send(
|
||||
new PutObjectCommand({
|
||||
Bucket: this.s3BackupBucketName,
|
||||
Key: fileName,
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.3](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.6.2...@standardnotes/websockets-server@1.6.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.6.2](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.6.1...@standardnotes/websockets-server@1.6.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.6.1](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.6.0...@standardnotes/websockets-server@1.6.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/websockets-server",
|
||||
"version": "1.6.1",
|
||||
"version": "1.6.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.20.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.2...@standardnotes/workspace-server@1.20.3) (2023-02-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
## [1.20.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.1...@standardnotes/workspace-server@1.20.2) (2023-02-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
## [1.20.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.0...@standardnotes/workspace-server@1.20.1) (2023-02-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/workspace-server",
|
||||
"version": "1.20.1",
|
||||
"version": "1.20.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
{
|
||||
"path": "./packages/predicates"
|
||||
},
|
||||
{
|
||||
"path": "./packages/proxy"
|
||||
},
|
||||
{
|
||||
"path": "./packages/revisions"
|
||||
},
|
||||
|
||||
46
yarn.lock
46
yarn.lock
@@ -3559,6 +3559,21 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/proxy-server@workspace:packages/proxy":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/proxy-server@workspace:packages/proxy"
|
||||
dependencies:
|
||||
"@types/http-proxy": "npm:^1.17.9"
|
||||
"@types/newrelic": "npm:^9.4.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^5.48.2"
|
||||
eslint: "npm:^8.32.0"
|
||||
eslint-plugin-prettier: "npm:^4.0.0"
|
||||
http-proxy: "npm:^1.18.1"
|
||||
newrelic: "npm:^9.8.0"
|
||||
typescript: "npm:^4.8.4"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/responses@npm:1.13.6":
|
||||
version: 1.13.6
|
||||
resolution: "@standardnotes/responses@npm:1.13.6"
|
||||
@@ -4124,6 +4139,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/http-proxy@npm:^1.17.9":
|
||||
version: 1.17.9
|
||||
resolution: "@types/http-proxy@npm:1.17.9"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
checksum: 3ee577db823f0beb7d0a7eb8b21b0d488b43afb008161d7f4f714c5c53bea2d648b1ed5123c7f58136bc3881f4d2dfc31b5bc0b047c6b7cdb17865bc0b831499
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/inversify-express-utils@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "@types/inversify-express-utils@npm:2.0.0"
|
||||
@@ -6671,7 +6695,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eventemitter3@npm:^4.0.4":
|
||||
"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.4":
|
||||
version: 4.0.7
|
||||
resolution: "eventemitter3@npm:4.0.7"
|
||||
checksum: e6ecb1ac2fee59b0ba0e778564cec0a1fe0631f28a50f24aa0e7ba367e718c5f9b23156fb2c1d238bcebe7923dfff37a63c39b519121a47c7bf78c38c96febd8
|
||||
@@ -6972,7 +6996,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.15.0":
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.0":
|
||||
version: 1.15.2
|
||||
resolution: "follow-redirects@npm:1.15.2"
|
||||
peerDependenciesMeta:
|
||||
@@ -7507,6 +7531,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"http-proxy@npm:^1.18.1":
|
||||
version: 1.18.1
|
||||
resolution: "http-proxy@npm:1.18.1"
|
||||
dependencies:
|
||||
eventemitter3: "npm:^4.0.0"
|
||||
follow-redirects: "npm:^1.0.0"
|
||||
requires-port: "npm:^1.0.0"
|
||||
checksum: 5d681e4231e3de09359e6fb14c2cc3fb79536b4b465cb0c2af4616e6754af0a6f1e33baccd83038f39a377dbb1e0b16b02c3a41458685e1754e3611b6dd10d64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"http-status-codes@npm:^2.1.4":
|
||||
version: 2.2.0
|
||||
resolution: "http-status-codes@npm:2.2.0"
|
||||
@@ -10757,6 +10792,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"requires-port@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "requires-port@npm:1.0.0"
|
||||
checksum: 28a1064f043588514802bff52dacac500c43b642383109145c55ff8bac26b3cf1ca951abc824446c773309c45dd049608986c1e15142ae7e336b9926065a1830
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve-alpn@npm:^1.2.0":
|
||||
version: 1.2.1
|
||||
resolution: "resolve-alpn@npm:1.2.1"
|
||||
|
||||
Reference in New Issue
Block a user