From b3b617ea0b4f4574f6aa7cfae0e9fa8f868f1f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Wed, 17 May 2023 15:38:12 +0200 Subject: [PATCH] feat: bundle syncing server into home server setup (#611) * feat(syncing-server): move inversify express controllers to new structure * wip: syncing server service binding for home server * fix(syncing-server): container bindings * fix(api-gateway): rename https service to service proxy * fix: proxying requests to syncing server * fix: responses and version binding --- .pnp.cjs | 11 +- packages/api-gateway/src/Bootstrap/Service.ts | 24 +- .../src/Controller/AuthMiddleware.ts | 2 +- .../SubscriptionTokenAuthMiddleware.ts | 2 +- .../src/Controller/WebSocketAuthMiddleware.ts | 2 +- .../src/Controller/v1/ItemsController.ts | 8 +- .../src/Controller/v1/UsersController.ts | 2 +- .../src/Service/Http/HttpServiceProxy.ts | 2 +- .../Service/Proxy/DirectCallServiceProxy.ts | 7 +- .../src/Service/Resolver/EndpointResolver.ts | 4 + packages/auth/src/Bootstrap/Container.ts | 2 +- packages/auth/src/Bootstrap/Service.ts | 2 +- packages/home-server/bin/server.ts | 18 +- packages/home-server/package.json | 1 + packages/syncing-server/bin/server.ts | 12 +- packages/syncing-server/bin/worker.ts | 10 +- .../Bootstrap/CommonContainerConfigLoader.ts | 119 ---- .../syncing-server/src/Bootstrap/Container.ts | 516 ++++++++++++++++++ .../src/Bootstrap/DataSource.ts | 95 ++-- .../Bootstrap/ServerContainerConfigLoader.ts | 154 ------ .../syncing-server/src/Bootstrap/Service.ts | 42 ++ .../syncing-server/src/Bootstrap/Types.ts | 120 ++-- .../Bootstrap/WorkerContainerConfigLoader.ts | 207 ------- .../syncing-server/src/Bootstrap/index.ts | 1 + .../InversifyExpressHealthCheckController.ts} | 2 +- .../InversifyExpressItemsController.spec.ts} | 38 +- .../InversifyExpressItemsController.ts} | 39 +- .../InversifyExpressAuthMiddleware.spec.ts} | 6 +- .../InversifyExpressAuthMiddleware.ts} | 2 +- packages/syncing-server/src/index.ts | 1 + yarn.lock | 3 +- 31 files changed, 780 insertions(+), 674 deletions(-) delete mode 100644 packages/syncing-server/src/Bootstrap/CommonContainerConfigLoader.ts create mode 100644 packages/syncing-server/src/Bootstrap/Container.ts delete mode 100644 packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts create mode 100644 packages/syncing-server/src/Bootstrap/Service.ts delete mode 100644 packages/syncing-server/src/Bootstrap/WorkerContainerConfigLoader.ts create mode 100644 packages/syncing-server/src/Bootstrap/index.ts rename packages/syncing-server/src/{Controller/HealthCheckController.ts => Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts} (76%) rename packages/syncing-server/src/{Controller/ItemsController.spec.ts => Infra/InversifyExpressUtils/InversifyExpressItemsController.spec.ts} (83%) rename packages/syncing-server/src/{Controller/ItemsController.ts => Infra/InversifyExpressUtils/InversifyExpressItemsController.ts} (58%) rename packages/syncing-server/src/{Controller/AuthMiddleware.spec.ts => Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.spec.ts} (94%) rename packages/syncing-server/src/{Controller/AuthMiddleware.ts => Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.ts} (95%) create mode 100644 packages/syncing-server/src/index.ts diff --git a/.pnp.cjs b/.pnp.cjs index 38c69666b..65dc0fcbd 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -4626,6 +4626,7 @@ const RAW_RUNTIME_STATE = ["@standardnotes/auth-server", "workspace:packages/auth"],\ ["@standardnotes/domain-core", "workspace:packages/domain-core"],\ ["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\ + ["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\ ["@types/cors", "npm:2.8.13"],\ ["@types/express", "npm:4.17.17"],\ ["@types/prettyjson", "npm:0.0.30"],\ @@ -4732,7 +4733,7 @@ const RAW_RUNTIME_STATE = ["reflect-metadata", "npm:0.1.13"],\ ["sqlite3", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.1.6"],\ ["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\ - ["typeorm", "virtual:365b8c88cdf194291829ee28b79556e2328175d26a621363e703848100bea0042e9500db2a1206c9bbc3a4a76a1d169639ef774b2ea3a1a98584a9936b58c6be#npm:0.3.15"],\ + ["typeorm", "virtual:67ad3a1ca34e24ce4821cc48979e98af0c3e5dd7aabc7ad0b5d22d1d977d6f943f81c9f141a420105ebdc61ef777e508a96c7946081decd98f8c30543d468b33#npm:0.3.15"],\ ["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin::version=5.0.4&hash=b5f058"],\ ["winston", "npm:3.8.2"]\ ],\ @@ -4924,7 +4925,7 @@ const RAW_RUNTIME_STATE = ["reflect-metadata", "npm:0.1.13"],\ ["sqlite3", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.1.6"],\ ["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\ - ["typeorm", "virtual:365b8c88cdf194291829ee28b79556e2328175d26a621363e703848100bea0042e9500db2a1206c9bbc3a4a76a1d169639ef774b2ea3a1a98584a9936b58c6be#npm:0.3.15"],\ + ["typeorm", "virtual:67ad3a1ca34e24ce4821cc48979e98af0c3e5dd7aabc7ad0b5d22d1d977d6f943f81c9f141a420105ebdc61ef777e508a96c7946081decd98f8c30543d468b33#npm:0.3.15"],\ ["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin::version=5.0.4&hash=b5f058"],\ ["ua-parser-js", "npm:1.0.35"],\ ["uuid", "npm:9.0.0"],\ @@ -15165,10 +15166,10 @@ const RAW_RUNTIME_STATE = ],\ "linkType": "HARD"\ }],\ - ["virtual:365b8c88cdf194291829ee28b79556e2328175d26a621363e703848100bea0042e9500db2a1206c9bbc3a4a76a1d169639ef774b2ea3a1a98584a9936b58c6be#npm:0.3.15", {\ - "packageLocation": "./.yarn/__virtual__/typeorm-virtual-7fe891193c/0/cache/typeorm-npm-0.3.15-20a6c4f754-db890f14cb.zip/node_modules/typeorm/",\ + ["virtual:67ad3a1ca34e24ce4821cc48979e98af0c3e5dd7aabc7ad0b5d22d1d977d6f943f81c9f141a420105ebdc61ef777e508a96c7946081decd98f8c30543d468b33#npm:0.3.15", {\ + "packageLocation": "./.yarn/__virtual__/typeorm-virtual-91f15b21d5/0/cache/typeorm-npm-0.3.15-20a6c4f754-db890f14cb.zip/node_modules/typeorm/",\ "packageDependencies": [\ - ["typeorm", "virtual:365b8c88cdf194291829ee28b79556e2328175d26a621363e703848100bea0042e9500db2a1206c9bbc3a4a76a1d169639ef774b2ea3a1a98584a9936b58c6be#npm:0.3.15"],\ + ["typeorm", "virtual:67ad3a1ca34e24ce4821cc48979e98af0c3e5dd7aabc7ad0b5d22d1d977d6f943f81c9f141a420105ebdc61ef777e508a96c7946081decd98f8c30543d468b33#npm:0.3.15"],\ ["@google-cloud/spanner", null],\ ["@sap/hana-client", null],\ ["@sqltools/formatter", "npm:1.2.5"],\ diff --git a/packages/api-gateway/src/Bootstrap/Service.ts b/packages/api-gateway/src/Bootstrap/Service.ts index 9778244d1..f4d9e7199 100644 --- a/packages/api-gateway/src/Bootstrap/Service.ts +++ b/packages/api-gateway/src/Bootstrap/Service.ts @@ -1,28 +1,14 @@ -import { - ControllerContainerInterface, - ServiceContainerInterface, - ServiceIdentifier, - ServiceInterface, -} from '@standardnotes/domain-core' +import { ServiceContainerInterface, ServiceIdentifier, ServiceInterface } from '@standardnotes/domain-core' import { ContainerConfigLoader } from './Container' export class Service implements ServiceInterface { - constructor( - private serviceContainer: ServiceContainerInterface, - private controllerContainer: ControllerContainerInterface, - ) { - this.serviceContainer.register(ServiceIdentifier.create(ServiceIdentifier.NAMES.ApiGateway).getValue(), this) + constructor(private serviceContainer: ServiceContainerInterface) { + this.serviceContainer.register(this.getId(), this) } - async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise { - const method = this.controllerContainer.get(endpointOrMethodIdentifier) - - if (!method) { - throw new Error(`Method ${endpointOrMethodIdentifier} not found`) - } - - return method(request, response) + async handleRequest(_request: never, _response: never, _endpointOrMethodIdentifier: string): Promise { + throw new Error('Requests are handled via inversify-express at ApiGateway level') } async getContainer(): Promise { diff --git a/packages/api-gateway/src/Controller/AuthMiddleware.ts b/packages/api-gateway/src/Controller/AuthMiddleware.ts index cdd74e7f4..b1f005366 100644 --- a/packages/api-gateway/src/Controller/AuthMiddleware.ts +++ b/packages/api-gateway/src/Controller/AuthMiddleware.ts @@ -77,7 +77,7 @@ export class AuthMiddleware extends BaseMiddleware { }) } - response.locals.userUuid = decodedToken.user.uuid + response.locals.user = decodedToken.user response.locals.roles = decodedToken.roles } catch (error) { const errorMessage = (error as AxiosError).isAxiosError diff --git a/packages/api-gateway/src/Controller/SubscriptionTokenAuthMiddleware.ts b/packages/api-gateway/src/Controller/SubscriptionTokenAuthMiddleware.ts index d7b8bf4ff..ae05317e0 100644 --- a/packages/api-gateway/src/Controller/SubscriptionTokenAuthMiddleware.ts +++ b/packages/api-gateway/src/Controller/SubscriptionTokenAuthMiddleware.ts @@ -118,7 +118,7 @@ export class SubscriptionTokenAuthMiddleware extends BaseMiddleware { verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] }) ) - response.locals.userUuid = decodedToken.user.uuid + response.locals.user = decodedToken.user response.locals.roles = decodedToken.roles } } diff --git a/packages/api-gateway/src/Controller/WebSocketAuthMiddleware.ts b/packages/api-gateway/src/Controller/WebSocketAuthMiddleware.ts index dc3cda050..146f95334 100644 --- a/packages/api-gateway/src/Controller/WebSocketAuthMiddleware.ts +++ b/packages/api-gateway/src/Controller/WebSocketAuthMiddleware.ts @@ -63,7 +63,7 @@ export class WebSocketAuthMiddleware extends BaseMiddleware { response.locals.freeUser = decodedToken.roles.length === 1 && decodedToken.roles.find((role) => role.name === RoleName.NAMES.CoreUser) !== undefined - response.locals.userUuid = decodedToken.user.uuid + response.locals.user = decodedToken.user response.locals.roles = decodedToken.roles } catch (error) { const errorMessage = (error as AxiosError).isAxiosError diff --git a/packages/api-gateway/src/Controller/v1/ItemsController.ts b/packages/api-gateway/src/Controller/v1/ItemsController.ts index c12c0c2df..fcbfd24ee 100644 --- a/packages/api-gateway/src/Controller/v1/ItemsController.ts +++ b/packages/api-gateway/src/Controller/v1/ItemsController.ts @@ -8,7 +8,7 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv @controller('/v1/items', TYPES.AuthMiddleware) export class ItemsController extends BaseHttpController { constructor( - @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface, + @inject(TYPES.ServiceProxy) private serviceProxy: ServiceProxyInterface, @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface, ) { super() @@ -16,7 +16,7 @@ export class ItemsController extends BaseHttpController { @httpPost('/') async sync(request: Request, response: Response): Promise { - await this.httpService.callSyncingServer( + await this.serviceProxy.callSyncingServer( request, response, this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'items/sync'), @@ -26,7 +26,7 @@ export class ItemsController extends BaseHttpController { @httpPost('/check-integrity') async checkIntegrity(request: Request, response: Response): Promise { - await this.httpService.callSyncingServer( + await this.serviceProxy.callSyncingServer( request, response, this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'items/check-integrity'), @@ -36,7 +36,7 @@ export class ItemsController extends BaseHttpController { @httpGet('/:uuid') async getItem(request: Request, response: Response): Promise { - await this.httpService.callSyncingServer( + await this.serviceProxy.callSyncingServer( request, response, this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'items/:uuid', request.params.uuid), diff --git a/packages/api-gateway/src/Controller/v1/UsersController.ts b/packages/api-gateway/src/Controller/v1/UsersController.ts index 0ddd77d34..ca325d38d 100644 --- a/packages/api-gateway/src/Controller/v1/UsersController.ts +++ b/packages/api-gateway/src/Controller/v1/UsersController.ts @@ -227,7 +227,7 @@ export class UsersController extends BaseHttpController { this.endpointResolver.resolveEndpointOrMethodIdentifier( 'GET', 'users/:userUuid/subscription', - response.locals.userUuid, + response.locals.user.uuid, ), ) } diff --git a/packages/api-gateway/src/Service/Http/HttpServiceProxy.ts b/packages/api-gateway/src/Service/Http/HttpServiceProxy.ts index 6b63fc650..42586a8c6 100644 --- a/packages/api-gateway/src/Service/Http/HttpServiceProxy.ts +++ b/packages/api-gateway/src/Service/Http/HttpServiceProxy.ts @@ -262,7 +262,7 @@ export class HttpServiceProxy implements ServiceProxyInterface { response.status(serviceResponse.status).send({ meta: { auth: { - userUuid: response.locals.userUuid, + userUuid: response.locals.user?.uuid, roles: response.locals.roles, }, server: { diff --git a/packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts b/packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts index 68ce0c2c9..0f305c859 100644 --- a/packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts +++ b/packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts @@ -77,7 +77,12 @@ export class DirectCallServiceProxy implements ServiceProxyInterface { throw new Error('Syncing service not found') } - await service.handleRequest(request, response, endpointOrMethodIdentifier) + const serviceResponse = (await service.handleRequest(request, response, endpointOrMethodIdentifier)) as { + statusCode: number + json: Record + } + + void (response as Response).status(serviceResponse.statusCode).send(serviceResponse.json) } async callLegacySyncingServer( diff --git a/packages/api-gateway/src/Service/Resolver/EndpointResolver.ts b/packages/api-gateway/src/Service/Resolver/EndpointResolver.ts index 7f079e72d..af873125f 100644 --- a/packages/api-gateway/src/Service/Resolver/EndpointResolver.ts +++ b/packages/api-gateway/src/Service/Resolver/EndpointResolver.ts @@ -51,6 +51,10 @@ export class EndpointResolver implements EndpointResolverInterface { ['[GET]:users/:userUuid/subscription', 'auth.users.getSubscription'], ['[GET]:offline/users/subscription', 'auth.users.getOfflineSubscriptionByToken'], ['[POST]:users/:userUuid/requests', 'auth.users.createRequest'], + // Syncing Server + ['[POST]:items/sync', 'sync.items.sync'], + ['[POST]:items/check-integrity', 'sync.items.check_integrity'], + ['[GET]:items/:uuid', 'sync.items.get_item'], ]) resolveEndpointOrMethodIdentifier(method: string, endpoint: string, ...params: string[]): string { diff --git a/packages/auth/src/Bootstrap/Container.ts b/packages/auth/src/Bootstrap/Container.ts index 8b350c0be..4e7e27e9c 100644 --- a/packages/auth/src/Bootstrap/Container.ts +++ b/packages/auth/src/Bootstrap/Container.ts @@ -517,7 +517,7 @@ export class ContainerConfigLoader { .toConstantValue(env.get('USER_SERVER_CHANGE_EMAIL_URL', true)) container.bind(TYPES.Auth_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) container.bind(TYPES.Auth_SYNCING_SERVER_URL).toConstantValue(env.get('SYNCING_SERVER_URL', true)) - container.bind(TYPES.Auth_VERSION).toConstantValue(env.get('VERSION')) + container.bind(TYPES.Auth_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development') container.bind(TYPES.Auth_PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true)) container .bind(TYPES.Auth_SESSION_TRACE_DAYS_TTL) diff --git a/packages/auth/src/Bootstrap/Service.ts b/packages/auth/src/Bootstrap/Service.ts index 8bd2d6b3e..b68caefca 100644 --- a/packages/auth/src/Bootstrap/Service.ts +++ b/packages/auth/src/Bootstrap/Service.ts @@ -14,7 +14,7 @@ export class Service implements ServiceInterface { private controllerContainer: ControllerContainerInterface, private directCallDomainEventPublisher: DirectCallDomainEventPublisher, ) { - this.serviceContainer.register(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue(), this) + this.serviceContainer.register(this.getId(), this) } async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise { diff --git a/packages/home-server/bin/server.ts b/packages/home-server/bin/server.ts index b183c388b..7393dea5e 100644 --- a/packages/home-server/bin/server.ts +++ b/packages/home-server/bin/server.ts @@ -4,6 +4,7 @@ import { ControllerContainer, ServiceContainer } from '@standardnotes/domain-cor import { Service as ApiGatewayService, TYPES as ApiGatewayTYPES } from '@standardnotes/api-gateway' import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra' import { Service as AuthService } from '@standardnotes/auth-server' +import { Service as SyncingService } from '@standardnotes/syncing-server' import { Container } from 'inversify' import { InversifyExpressServer } from 'inversify-express-utils' import helmet from 'helmet' @@ -20,12 +21,14 @@ const startServer = async (): Promise => { const serviceContainer = new ServiceContainer() const directCallDomainEventPublisher = new DirectCallDomainEventPublisher() - const apiGatewayService = new ApiGatewayService(serviceContainer, controllerContainer) + const apiGatewayService = new ApiGatewayService(serviceContainer) const authService = new AuthService(serviceContainer, controllerContainer, directCallDomainEventPublisher) + const syncingService = new SyncingService(serviceContainer, controllerContainer, directCallDomainEventPublisher) const container = Container.merge( (await apiGatewayService.getContainer()) as Container, (await authService.getContainer()) as Container, + (await syncingService.getContainer()) as Container, ) const env: Env = new Env() @@ -93,12 +96,7 @@ const startServer = async (): Promise => { logger.info(`Server started on port ${process.env.PORT}`) } -Promise.resolve(startServer()) - .then(() => { - // eslint-disable-next-line no-console - console.log('Server started') - }) - .catch((error) => { - // eslint-disable-next-line no-console - console.log(`Could not start server: ${error.message}`) - }) +Promise.resolve(startServer()).catch((error) => { + // eslint-disable-next-line no-console + console.log(`Could not start server: ${error.message}`) +}) diff --git a/packages/home-server/package.json b/packages/home-server/package.json index 677bff9bf..c192cd2b9 100644 --- a/packages/home-server/package.json +++ b/packages/home-server/package.json @@ -22,6 +22,7 @@ "@standardnotes/auth-server": "workspace:^", "@standardnotes/domain-core": "workspace:^", "@standardnotes/domain-events-infra": "workspace:^", + "@standardnotes/syncing-server": "workspace:^", "cors": "2.8.5", "dotenv": "^16.0.1", "express": "^4.18.2", diff --git a/packages/syncing-server/bin/server.ts b/packages/syncing-server/bin/server.ts index f8115f400..ffffb3919 100644 --- a/packages/syncing-server/bin/server.ts +++ b/packages/syncing-server/bin/server.ts @@ -2,8 +2,8 @@ import 'reflect-metadata' import 'newrelic' -import '../src/Controller/HealthCheckController' -import '../src/Controller/ItemsController' +import '../src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController' +import '../src/Infra/InversifyExpressUtils/InversifyExpressItemsController' import helmet from 'helmet' import * as cors from 'cors' @@ -13,9 +13,9 @@ import * as winston from 'winston' import { InversifyExpressServer } from 'inversify-express-utils' import TYPES from '../src/Bootstrap/Types' import { Env } from '../src/Bootstrap/Env' -import { ServerContainerConfigLoader } from '../src/Bootstrap/ServerContainerConfigLoader' +import { ContainerConfigLoader } from '../src/Bootstrap/Container' -const container = new ServerContainerConfigLoader() +const container = new ContainerConfigLoader() void container.load().then((container) => { const env: Env = new Env() env.load() @@ -24,7 +24,7 @@ void container.load().then((container) => { server.setConfig((app) => { app.use((_request: Request, response: Response, next: NextFunction) => { - response.setHeader('X-SSJS-Version', container.get(TYPES.VERSION)) + response.setHeader('X-SSJS-Version', container.get(TYPES.Sync_VERSION)) next() }) /* eslint-disable */ @@ -54,7 +54,7 @@ void container.load().then((container) => { app.use(cors()) }) - const logger: winston.Logger = container.get(TYPES.Logger) + const logger: winston.Logger = container.get(TYPES.Sync_Logger) server.setErrorConfig((app) => { app.use((error: Record, _request: Request, response: Response, _next: NextFunction) => { diff --git a/packages/syncing-server/bin/worker.ts b/packages/syncing-server/bin/worker.ts index b1211aea3..648a18d20 100644 --- a/packages/syncing-server/bin/worker.ts +++ b/packages/syncing-server/bin/worker.ts @@ -7,18 +7,20 @@ import { Logger } from 'winston' import TYPES from '../src/Bootstrap/Types' import { Env } from '../src/Bootstrap/Env' import { DomainEventSubscriberFactoryInterface } from '@standardnotes/domain-events' -import { WorkerContainerConfigLoader } from '../src/Bootstrap/WorkerContainerConfigLoader' +import { ContainerConfigLoader } from '../src/Bootstrap/Container' -const container = new WorkerContainerConfigLoader() +const container = new ContainerConfigLoader() void container.load().then((container) => { const env: Env = new Env() env.load() - const logger: Logger = container.get(TYPES.Logger) + const logger: Logger = container.get(TYPES.Sync_Logger) logger.info('Starting worker...') - const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(TYPES.DomainEventSubscriberFactory) + const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get( + TYPES.Sync_DomainEventSubscriberFactory, + ) subscriberFactory.create().start() setInterval(() => logger.info('Alive and kicking!'), 20 * 60 * 1000) diff --git a/packages/syncing-server/src/Bootstrap/CommonContainerConfigLoader.ts b/packages/syncing-server/src/Bootstrap/CommonContainerConfigLoader.ts deleted file mode 100644 index 77342b0cb..000000000 --- a/packages/syncing-server/src/Bootstrap/CommonContainerConfigLoader.ts +++ /dev/null @@ -1,119 +0,0 @@ -import * as winston from 'winston' -import { Container, interfaces } from 'inversify' - -import { Env } from './Env' -import TYPES from './Types' -import { AppDataSource } from './DataSource' -import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns' -import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface' -import { TypeORMItemRepository } from '../Infra/TypeORM/TypeORMItemRepository' -import { Repository } from 'typeorm' -import { Item } from '../Domain/Item/Item' -import { ItemProjection } from '../Projection/ItemProjection' -import { ProjectorInterface } from '../Projection/ProjectorInterface' -import { ItemProjector } from '../Projection/ItemProjector' -import { SNSDomainEventPublisher } from '@standardnotes/domain-events-infra' -import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface' -import { DomainEventFactory } from '../Domain/Event/DomainEventFactory' -import { Timer, TimerInterface } from '@standardnotes/time' -import { ItemTransferCalculatorInterface } from '../Domain/Item/ItemTransferCalculatorInterface' -import { ItemTransferCalculator } from '../Domain/Item/ItemTransferCalculator' -// eslint-disable-next-line @typescript-eslint/no-var-requires -const newrelicFormatter = require('@newrelic/winston-enricher') - -export class CommonContainerConfigLoader { - async load(): Promise { - const env: Env = new Env() - env.load() - - const container = new Container({ - defaultScope: 'Singleton', - }) - - await AppDataSource.initialize() - - container.bind(TYPES.Env).toConstantValue(env) - - container.bind(TYPES.Logger).toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - const newrelicWinstonFormatter = newrelicFormatter(winston) - const winstonFormatters = [winston.format.splat(), winston.format.json()] - if (env.get('NEW_RELIC_ENABLED', true) === 'true') { - winstonFormatters.push(newrelicWinstonFormatter()) - } - - const logger = winston.createLogger({ - level: env.get('LOG_LEVEL') || 'info', - format: winston.format.combine(...winstonFormatters), - transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL') || 'info' })], - }) - - return logger - }) - - container.bind(TYPES.SNS).toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - const snsConfig: SNSClientConfig = { - apiVersion: 'latest', - region: env.get('SNS_AWS_REGION', true), - } - if (env.get('SNS_ENDPOINT', true)) { - snsConfig.endpoint = env.get('SNS_ENDPOINT', true) - } - if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) { - snsConfig.credentials = { - accessKeyId: env.get('SNS_ACCESS_KEY_ID', true), - secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true), - } - } - - return new SNSClient(snsConfig) - }) - - // Repositories - container.bind(TYPES.ItemRepository).toDynamicValue((context: interfaces.Context) => { - return new TypeORMItemRepository(context.container.get(TYPES.ORMItemRepository)) - }) - - // ORM - container.bind>(TYPES.ORMItemRepository).toDynamicValue(() => AppDataSource.getRepository(Item)) - - // Projectors - container - .bind>(TYPES.ItemProjector) - .toDynamicValue((context: interfaces.Context) => { - return new ItemProjector(context.container.get(TYPES.Timer)) - }) - - // env vars - container.bind(TYPES.SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN')) - container.bind(TYPES.SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true)) - - container.bind(TYPES.Timer).toDynamicValue(() => new Timer()) - - container - .bind(TYPES.DomainEventPublisher) - .toDynamicValue((context: interfaces.Context) => { - return new SNSDomainEventPublisher(context.container.get(TYPES.SNS), context.container.get(TYPES.SNS_TOPIC_ARN)) - }) - - container - .bind(TYPES.DomainEventFactory) - .toDynamicValue((context: interfaces.Context) => { - return new DomainEventFactory(context.container.get(TYPES.Timer)) - }) - - container - .bind(TYPES.ItemTransferCalculator) - .toDynamicValue((context: interfaces.Context) => { - return new ItemTransferCalculator( - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.Logger), - ) - }) - - return container - } -} diff --git a/packages/syncing-server/src/Bootstrap/Container.ts b/packages/syncing-server/src/Bootstrap/Container.ts new file mode 100644 index 000000000..97f4a4a10 --- /dev/null +++ b/packages/syncing-server/src/Bootstrap/Container.ts @@ -0,0 +1,516 @@ +import * as winston from 'winston' +import { Container, interfaces } from 'inversify' + +import { Env } from './Env' +import TYPES from './Types' +import { AppDataSource } from './DataSource' +import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns' +import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface' +import { TypeORMItemRepository } from '../Infra/TypeORM/TypeORMItemRepository' +import { Repository } from 'typeorm' +import { Item } from '../Domain/Item/Item' +import { ItemProjection } from '../Projection/ItemProjection' +import { ProjectorInterface } from '../Projection/ProjectorInterface' +import { ItemProjector } from '../Projection/ItemProjector' +import { + DirectCallDomainEventPublisher, + DirectCallEventMessageHandler, + SNSDomainEventPublisher, + SQSDomainEventSubscriberFactory, + SQSEventMessageHandler, + SQSNewRelicEventMessageHandler, +} from '@standardnotes/domain-events-infra' +import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface' +import { DomainEventFactory } from '../Domain/Event/DomainEventFactory' +import { Timer, TimerInterface } from '@standardnotes/time' +import { ItemTransferCalculatorInterface } from '../Domain/Item/ItemTransferCalculatorInterface' +import { ItemTransferCalculator } from '../Domain/Item/ItemTransferCalculator' +import { ItemConflict } from '../Domain/Item/ItemConflict' +import { ItemFactory } from '../Domain/Item/ItemFactory' +import { ItemFactoryInterface } from '../Domain/Item/ItemFactoryInterface' +import { ItemService } from '../Domain/Item/ItemService' +import { ItemServiceInterface } from '../Domain/Item/ItemServiceInterface' +import { ContentFilter } from '../Domain/Item/SaveRule/ContentFilter' +import { ContentTypeFilter } from '../Domain/Item/SaveRule/ContentTypeFilter' +import { OwnershipFilter } from '../Domain/Item/SaveRule/OwnershipFilter' +import { TimeDifferenceFilter } from '../Domain/Item/SaveRule/TimeDifferenceFilter' +import { UuidFilter } from '../Domain/Item/SaveRule/UuidFilter' +import { ItemSaveValidator } from '../Domain/Item/SaveValidator/ItemSaveValidator' +import { ItemSaveValidatorInterface } from '../Domain/Item/SaveValidator/ItemSaveValidatorInterface' +import { SyncResponseFactory20161215 } from '../Domain/Item/SyncResponse/SyncResponseFactory20161215' +import { SyncResponseFactory20200115 } from '../Domain/Item/SyncResponse/SyncResponseFactory20200115' +import { SyncResponseFactoryResolver } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolver' +import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' +import { CheckIntegrity } from '../Domain/UseCase/CheckIntegrity/CheckIntegrity' +import { GetItem } from '../Domain/UseCase/GetItem/GetItem' +import { SyncItems } from '../Domain/UseCase/SyncItems' +import { InversifyExpressAuthMiddleware } from '../Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware' +import { ItemConflictProjection } from '../Projection/ItemConflictProjection' +import { ItemConflictProjector } from '../Projection/ItemConflictProjector' +import { SavedItemProjection } from '../Projection/SavedItemProjection' +import { SavedItemProjector } from '../Projection/SavedItemProjector' +import { S3Client } from '@aws-sdk/client-s3' +import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs' +import { ContentDecoder } from '@standardnotes/common' +import { + DomainEventMessageHandlerInterface, + DomainEventHandlerInterface, + DomainEventSubscriberFactoryInterface, + DomainEventPublisherInterface, +} from '@standardnotes/domain-events' +import axios, { AxiosInstance } from 'axios' +import { AuthHttpServiceInterface } from '../Domain/Auth/AuthHttpServiceInterface' +import { ExtensionsHttpService } from '../Domain/Extension/ExtensionsHttpService' +import { ExtensionsHttpServiceInterface } from '../Domain/Extension/ExtensionsHttpServiceInterface' +import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler' +import { DuplicateItemSyncedEventHandler } from '../Domain/Handler/DuplicateItemSyncedEventHandler' +import { EmailBackupRequestedEventHandler } from '../Domain/Handler/EmailBackupRequestedEventHandler' +import { ItemRevisionCreationRequestedEventHandler } from '../Domain/Handler/ItemRevisionCreationRequestedEventHandler' +import { ItemBackupServiceInterface } from '../Domain/Item/ItemBackupServiceInterface' +import { FSItemBackupService } from '../Infra/FS/FSItemBackupService' +import { AuthHttpService } from '../Infra/HTTP/AuthHttpService' +import { S3ItemBackupService } from '../Infra/S3/S3ItemBackupService' +import { ControllerContainer, ControllerContainerInterface } from '@standardnotes/domain-core' +import { InversifyExpressItemsController } from '../Infra/InversifyExpressUtils/InversifyExpressItemsController' +// eslint-disable-next-line @typescript-eslint/no-var-requires +const newrelicFormatter = require('@newrelic/winston-enricher') + +export class ContainerConfigLoader { + private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000 + private readonly DEFAULT_MAX_ITEMS_LIMIT = 300 + private readonly DEFAULT_FILE_UPLOAD_PATH = `${__dirname}/../../uploads` + + async load(configuration?: { + controllerConatiner?: ControllerContainerInterface + directCallDomainEventPublisher?: DirectCallDomainEventPublisher + }): Promise { + const directCallDomainEventPublisher = + configuration?.directCallDomainEventPublisher ?? new DirectCallDomainEventPublisher() + + const env: Env = new Env() + env.load() + + const container = new Container({ + defaultScope: 'Singleton', + }) + + await AppDataSource.initialize() + + const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite' + + container.bind(TYPES.Sync_Env).toConstantValue(env) + + container.bind(TYPES.Sync_Logger).toDynamicValue((context: interfaces.Context) => { + const env: Env = context.container.get(TYPES.Sync_Env) + + const newrelicWinstonFormatter = newrelicFormatter(winston) + const winstonFormatters = [winston.format.splat(), winston.format.json()] + if (env.get('NEW_RELIC_ENABLED', true) === 'true') { + winstonFormatters.push(newrelicWinstonFormatter()) + } + + const logger = winston.createLogger({ + level: env.get('LOG_LEVEL') || 'info', + format: winston.format.combine(...winstonFormatters), + transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL') || 'info' })], + }) + + return logger + }) + + if (isConfiguredForHomeServer) { + container + .bind(TYPES.Sync_DomainEventPublisher) + .toConstantValue(directCallDomainEventPublisher) + } else { + container.bind(TYPES.Sync_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN')) + container.bind(TYPES.Sync_SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true)) + container.bind(TYPES.Sync_SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL')) + container.bind(TYPES.Sync_S3_AWS_REGION).toConstantValue(env.get('S3_AWS_REGION', true)) + container.bind(TYPES.Sync_S3_BACKUP_BUCKET_NAME).toConstantValue(env.get('S3_BACKUP_BUCKET_NAME', true)) + container.bind(TYPES.Sync_EXTENSIONS_SERVER_URL).toConstantValue(env.get('EXTENSIONS_SERVER_URL', true)) + + container.bind(TYPES.Sync_SNS).toDynamicValue((context: interfaces.Context) => { + const env: Env = context.container.get(TYPES.Sync_Env) + + const snsConfig: SNSClientConfig = { + apiVersion: 'latest', + region: env.get('SNS_AWS_REGION', true), + } + if (env.get('SNS_ENDPOINT', true)) { + snsConfig.endpoint = env.get('SNS_ENDPOINT', true) + } + if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) { + snsConfig.credentials = { + accessKeyId: env.get('SNS_ACCESS_KEY_ID', true), + secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true), + } + } + + return new SNSClient(snsConfig) + }) + + container + .bind(TYPES.Sync_DomainEventPublisher) + .toDynamicValue((context: interfaces.Context) => { + return new SNSDomainEventPublisher( + context.container.get(TYPES.Sync_SNS), + context.container.get(TYPES.Sync_SNS_TOPIC_ARN), + ) + }) + + container.bind(TYPES.Sync_SQS).toDynamicValue((context: interfaces.Context) => { + const env: Env = context.container.get(TYPES.Sync_Env) + + const sqsConfig: SQSClientConfig = { + region: env.get('SQS_AWS_REGION'), + } + if (env.get('SQS_ENDPOINT', true)) { + sqsConfig.endpoint = env.get('SQS_ENDPOINT', true) + } + if (env.get('SQS_ACCESS_KEY_ID', true) && env.get('SQS_SECRET_ACCESS_KEY', true)) { + sqsConfig.credentials = { + accessKeyId: env.get('SQS_ACCESS_KEY_ID', true), + secretAccessKey: env.get('SQS_SECRET_ACCESS_KEY', true), + } + } + + return new SQSClient(sqsConfig) + }) + + container.bind(TYPES.Sync_S3).toDynamicValue((context: interfaces.Context) => { + const env: Env = context.container.get(TYPES.Sync_Env) + + let s3Client = undefined + if (env.get('S3_AWS_REGION', true)) { + s3Client = new S3Client({ + apiVersion: 'latest', + region: env.get('S3_AWS_REGION', true), + }) + } + + return s3Client + }) + } + + // Repositories + container.bind(TYPES.Sync_ItemRepository).toDynamicValue((context: interfaces.Context) => { + return new TypeORMItemRepository(context.container.get(TYPES.Sync_ORMItemRepository)) + }) + + // ORM + container + .bind>(TYPES.Sync_ORMItemRepository) + .toDynamicValue(() => AppDataSource.getRepository(Item)) + + // Projectors + container + .bind>(TYPES.Sync_ItemProjector) + .toDynamicValue((context: interfaces.Context) => { + return new ItemProjector(context.container.get(TYPES.Sync_Timer)) + }) + + container.bind(TYPES.Sync_Timer).toDynamicValue(() => new Timer()) + + container + .bind(TYPES.Sync_DomainEventFactory) + .toDynamicValue((context: interfaces.Context) => { + return new DomainEventFactory(context.container.get(TYPES.Sync_Timer)) + }) + + container + .bind(TYPES.Sync_ItemTransferCalculator) + .toDynamicValue((context: interfaces.Context) => { + return new ItemTransferCalculator( + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_Logger), + ) + }) + + // Middleware + container + .bind(TYPES.Sync_AuthMiddleware) + .toDynamicValue((context: interfaces.Context) => { + return new InversifyExpressAuthMiddleware( + context.container.get(TYPES.Sync_AUTH_JWT_SECRET), + context.container.get(TYPES.Sync_Logger), + ) + }) + + // Projectors + container + .bind>(TYPES.Sync_SavedItemProjector) + .toDynamicValue((context: interfaces.Context) => { + return new SavedItemProjector(context.container.get(TYPES.Sync_Timer)) + }) + container + .bind>(TYPES.Sync_ItemConflictProjector) + .toDynamicValue((context: interfaces.Context) => { + return new ItemConflictProjector(context.container.get(TYPES.Sync_ItemProjector)) + }) + + // env vars + container.bind(TYPES.Sync_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET')) + container + .bind(TYPES.Sync_REVISIONS_FREQUENCY) + .toConstantValue(env.get('REVISIONS_FREQUENCY', true) ? +env.get('REVISIONS_FREQUENCY', true) : 300) + container.bind(TYPES.Sync_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) + container.bind(TYPES.Sync_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development') + container + .bind(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT) + .toConstantValue( + env.get('CONTENT_SIZE_TRANSFER_LIMIT', true) + ? +env.get('CONTENT_SIZE_TRANSFER_LIMIT', true) + : this.DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT, + ) + container + .bind(TYPES.Sync_MAX_ITEMS_LIMIT) + .toConstantValue( + env.get('MAX_ITEMS_LIMIT', true) ? +env.get('MAX_ITEMS_LIMIT', true) : this.DEFAULT_MAX_ITEMS_LIMIT, + ) + + // use cases + container.bind(TYPES.Sync_SyncItems).toDynamicValue((context: interfaces.Context) => { + return new SyncItems(context.container.get(TYPES.Sync_ItemService)) + }) + container.bind(TYPES.Sync_CheckIntegrity).toDynamicValue((context: interfaces.Context) => { + return new CheckIntegrity(context.container.get(TYPES.Sync_ItemRepository)) + }) + container.bind(TYPES.Sync_GetItem).toDynamicValue((context: interfaces.Context) => { + return new GetItem(context.container.get(TYPES.Sync_ItemRepository)) + }) + + // Services + container.bind(TYPES.Sync_ItemService).toDynamicValue((context: interfaces.Context) => { + return new ItemService( + context.container.get(TYPES.Sync_ItemSaveValidator), + context.container.get(TYPES.Sync_ItemFactory), + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_DomainEventPublisher), + context.container.get(TYPES.Sync_DomainEventFactory), + context.container.get(TYPES.Sync_REVISIONS_FREQUENCY), + context.container.get(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT), + context.container.get(TYPES.Sync_ItemTransferCalculator), + context.container.get(TYPES.Sync_Timer), + context.container.get(TYPES.Sync_ItemProjector), + context.container.get(TYPES.Sync_MAX_ITEMS_LIMIT), + context.container.get(TYPES.Sync_Logger), + ) + }) + container + .bind(TYPES.Sync_SyncResponseFactory20161215) + .toDynamicValue((context: interfaces.Context) => { + return new SyncResponseFactory20161215(context.container.get(TYPES.Sync_ItemProjector)) + }) + container + .bind(TYPES.Sync_SyncResponseFactory20200115) + .toDynamicValue((context: interfaces.Context) => { + return new SyncResponseFactory20200115( + context.container.get(TYPES.Sync_ItemProjector), + context.container.get(TYPES.Sync_ItemConflictProjector), + context.container.get(TYPES.Sync_SavedItemProjector), + ) + }) + container + .bind(TYPES.Sync_SyncResponseFactoryResolver) + .toDynamicValue((context: interfaces.Context) => { + return new SyncResponseFactoryResolver( + context.container.get(TYPES.Sync_SyncResponseFactory20161215), + context.container.get(TYPES.Sync_SyncResponseFactory20200115), + ) + }) + + container.bind(TYPES.Sync_ItemFactory).toDynamicValue((context: interfaces.Context) => { + return new ItemFactory(context.container.get(TYPES.Sync_Timer), context.container.get(TYPES.Sync_ItemProjector)) + }) + + container.bind(TYPES.Sync_OwnershipFilter).toDynamicValue(() => new OwnershipFilter()) + container + .bind(TYPES.Sync_TimeDifferenceFilter) + .toDynamicValue( + (context: interfaces.Context) => new TimeDifferenceFilter(context.container.get(TYPES.Sync_Timer)), + ) + container.bind(TYPES.Sync_UuidFilter).toDynamicValue(() => new UuidFilter()) + container.bind(TYPES.Sync_ContentTypeFilter).toDynamicValue(() => new ContentTypeFilter()) + container.bind(TYPES.Sync_ContentFilter).toDynamicValue(() => new ContentFilter()) + + container + .bind(TYPES.Sync_ItemSaveValidator) + .toDynamicValue((context: interfaces.Context) => { + return new ItemSaveValidator([ + context.container.get(TYPES.Sync_OwnershipFilter), + context.container.get(TYPES.Sync_TimeDifferenceFilter), + context.container.get(TYPES.Sync_UuidFilter), + context.container.get(TYPES.Sync_ContentTypeFilter), + context.container.get(TYPES.Sync_ContentFilter), + ]) + }) + + // env vars + container + .bind(TYPES.Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE) + .toConstantValue( + env.get('EMAIL_ATTACHMENT_MAX_BYTE_SIZE', true) ? +env.get('EMAIL_ATTACHMENT_MAX_BYTE_SIZE', true) : 10485760, + ) + container.bind(TYPES.Sync_NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) + container + .bind(TYPES.Sync_FILE_UPLOAD_PATH) + .toConstantValue( + env.get('FILE_UPLOAD_PATH', true) ? env.get('FILE_UPLOAD_PATH', true) : this.DEFAULT_FILE_UPLOAD_PATH, + ) + + // Handlers + container + .bind(TYPES.Sync_DuplicateItemSyncedEventHandler) + .toDynamicValue((context: interfaces.Context) => { + return new DuplicateItemSyncedEventHandler( + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_DomainEventFactory), + context.container.get(TYPES.Sync_DomainEventPublisher), + context.container.get(TYPES.Sync_Logger), + ) + }) + container + .bind(TYPES.Sync_AccountDeletionRequestedEventHandler) + .toDynamicValue((context: interfaces.Context) => { + return new AccountDeletionRequestedEventHandler( + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_Logger), + ) + }) + container + .bind(TYPES.Sync_ItemRevisionCreationRequestedEventHandler) + .toDynamicValue((context: interfaces.Context) => { + return new ItemRevisionCreationRequestedEventHandler( + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_ItemBackupService), + context.container.get(TYPES.Sync_DomainEventFactory), + context.container.get(TYPES.Sync_DomainEventPublisher), + ) + }) + + // Services + container.bind(TYPES.Sync_ContentDecoder).toDynamicValue(() => new ContentDecoder()) + container.bind(TYPES.Sync_HTTPClient).toDynamicValue(() => axios.create()) + container + .bind(TYPES.Sync_ExtensionsHttpService) + .toDynamicValue((context: interfaces.Context) => { + return new ExtensionsHttpService( + context.container.get(TYPES.Sync_HTTPClient), + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_ContentDecoder), + context.container.get(TYPES.Sync_DomainEventPublisher), + context.container.get(TYPES.Sync_DomainEventFactory), + context.container.get(TYPES.Sync_Logger), + ) + }) + + container + .bind(TYPES.Sync_ItemBackupService) + .toDynamicValue((context: interfaces.Context) => { + const env: Env = context.container.get(TYPES.Sync_Env) + + if (env.get('S3_AWS_REGION', true)) { + return new S3ItemBackupService( + context.container.get(TYPES.Sync_S3_BACKUP_BUCKET_NAME), + context.container.get(TYPES.Sync_ItemProjector), + context.container.get(TYPES.Sync_Logger), + context.container.get(TYPES.Sync_S3), + ) + } else { + return new FSItemBackupService( + context.container.get(TYPES.Sync_FILE_UPLOAD_PATH), + context.container.get(TYPES.Sync_ItemProjector), + context.container.get(TYPES.Sync_Logger), + ) + } + }) + + const eventHandlers: Map = new Map([ + ['DUPLICATE_ITEM_SYNCED', container.get(TYPES.Sync_DuplicateItemSyncedEventHandler)], + ['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Sync_AccountDeletionRequestedEventHandler)], + ['ITEM_REVISION_CREATION_REQUESTED', container.get(TYPES.Sync_ItemRevisionCreationRequestedEventHandler)], + ]) + if (!isConfiguredForHomeServer) { + container.bind(TYPES.Sync_AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL')) + + container + .bind(TYPES.Sync_AuthHttpService) + .toDynamicValue((context: interfaces.Context) => { + return new AuthHttpService( + context.container.get(TYPES.Sync_HTTPClient), + context.container.get(TYPES.Sync_AUTH_SERVER_URL), + ) + }) + + container + .bind(TYPES.Sync_EmailBackupRequestedEventHandler) + .toDynamicValue((context: interfaces.Context) => { + return new EmailBackupRequestedEventHandler( + context.container.get(TYPES.Sync_ItemRepository), + context.container.get(TYPES.Sync_AuthHttpService), + context.container.get(TYPES.Sync_ItemBackupService), + context.container.get(TYPES.Sync_DomainEventPublisher), + context.container.get(TYPES.Sync_DomainEventFactory), + context.container.get(TYPES.Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE), + context.container.get(TYPES.Sync_ItemTransferCalculator), + context.container.get(TYPES.Sync_S3_BACKUP_BUCKET_NAME), + context.container.get(TYPES.Sync_Logger), + ) + }) + + eventHandlers.set('EMAIL_BACKUP_REQUESTED', container.get(TYPES.Sync_EmailBackupRequestedEventHandler)) + } + + if (isConfiguredForHomeServer) { + const directCallEventMessageHandler = new DirectCallEventMessageHandler( + eventHandlers, + container.get(TYPES.Sync_Logger), + ) + directCallDomainEventPublisher.register(directCallEventMessageHandler) + + container + .bind(TYPES.Sync_DomainEventMessageHandler) + .toConstantValue(directCallEventMessageHandler) + } else { + container + .bind(TYPES.Sync_DomainEventMessageHandler) + .toConstantValue( + env.get('NEW_RELIC_ENABLED', true) === 'true' + ? new SQSNewRelicEventMessageHandler(eventHandlers, container.get(TYPES.Sync_Logger)) + : new SQSEventMessageHandler(eventHandlers, container.get(TYPES.Sync_Logger)), + ) + } + + container + .bind(TYPES.Sync_DomainEventSubscriberFactory) + .toDynamicValue((context: interfaces.Context) => { + return new SQSDomainEventSubscriberFactory( + context.container.get(TYPES.Sync_SQS), + context.container.get(TYPES.Sync_SQS_QUEUE_URL), + context.container.get(TYPES.Sync_DomainEventMessageHandler), + ) + }) + + container + .bind(TYPES.Sync_ControllerContainer) + .toConstantValue(configuration?.controllerConatiner ?? new ControllerContainer()) + + if (isConfiguredForHomeServer) { + container + .bind(TYPES.Sync_InversifyExpressItemsController) + .toConstantValue( + new InversifyExpressItemsController( + container.get(TYPES.Sync_SyncItems), + container.get(TYPES.Sync_CheckIntegrity), + container.get(TYPES.Sync_GetItem), + container.get(TYPES.Sync_ItemProjector), + container.get(TYPES.Sync_SyncResponseFactoryResolver), + container.get(TYPES.Sync_ControllerContainer), + ), + ) + } + + return container + } +} diff --git a/packages/syncing-server/src/Bootstrap/DataSource.ts b/packages/syncing-server/src/Bootstrap/DataSource.ts index 1a7c24905..924582464 100644 --- a/packages/syncing-server/src/Bootstrap/DataSource.ts +++ b/packages/syncing-server/src/Bootstrap/DataSource.ts @@ -13,55 +13,62 @@ const maxQueryExecutionTime = env.get('DB_MAX_QUERY_EXECUTION_TIME', true) ? +env.get('DB_MAX_QUERY_EXECUTION_TIME', true) : 45_000 -const inReplicaMode = env.get('DB_REPLICA_HOST', true) ? true : false +const commonDataSourceOptions = { + maxQueryExecutionTime, + entities: [Item], + migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`], + migrationsRun: true, + logging: env.get('DB_DEBUG_LEVEL', true) ?? 'info', +} -const replicationConfig = { - master: { - host: env.get('DB_HOST'), - port: parseInt(env.get('DB_PORT')), - username: env.get('DB_USERNAME'), - password: env.get('DB_PASSWORD'), - database: env.get('DB_DATABASE'), - }, - slaves: [ - { - host: env.get('DB_REPLICA_HOST', true), +let dataSource: DataSource +if (isConfiguredForMySQL) { + const inReplicaMode = env.get('DB_REPLICA_HOST', true) ? true : false + + const replicationConfig = { + master: { + host: env.get('DB_HOST'), port: parseInt(env.get('DB_PORT')), username: env.get('DB_USERNAME'), password: env.get('DB_PASSWORD'), database: env.get('DB_DATABASE'), }, - ], - removeNodeErrorCount: 10, - restoreNodeTimeout: 5, + slaves: [ + { + host: env.get('DB_REPLICA_HOST', true), + port: parseInt(env.get('DB_PORT')), + username: env.get('DB_USERNAME'), + password: env.get('DB_PASSWORD'), + database: env.get('DB_DATABASE'), + }, + ], + removeNodeErrorCount: 10, + restoreNodeTimeout: 5, + } + + const mySQLDataSourceOptions: MysqlConnectionOptions = { + ...commonDataSourceOptions, + type: 'mysql', + charset: 'utf8mb4', + supportBigNumbers: true, + bigNumberStrings: false, + replication: inReplicaMode ? replicationConfig : undefined, + host: inReplicaMode ? undefined : env.get('DB_HOST'), + port: inReplicaMode ? undefined : parseInt(env.get('DB_PORT')), + username: inReplicaMode ? undefined : env.get('DB_USERNAME'), + password: inReplicaMode ? undefined : env.get('DB_PASSWORD'), + database: inReplicaMode ? undefined : env.get('DB_DATABASE'), + } + + dataSource = new DataSource(mySQLDataSourceOptions) +} else { + const sqliteDataSourceOptions: SqliteConnectionOptions = { + ...commonDataSourceOptions, + type: 'sqlite', + database: `data/${env.get('DB_DATABASE')}.sqlite`, + } + + dataSource = new DataSource(sqliteDataSourceOptions) } -const commonDataSourceOptions = { - maxQueryExecutionTime, - entities: [Item], - migrations: [`dist/migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`], - migrationsRun: true, - logging: env.get('DB_DEBUG_LEVEL'), -} - -const mySQLDataSourceOptions: MysqlConnectionOptions = { - ...commonDataSourceOptions, - type: 'mysql', - charset: 'utf8mb4', - supportBigNumbers: true, - bigNumberStrings: false, - replication: inReplicaMode ? replicationConfig : undefined, - host: inReplicaMode ? undefined : env.get('DB_HOST'), - port: inReplicaMode ? undefined : parseInt(env.get('DB_PORT')), - username: inReplicaMode ? undefined : env.get('DB_USERNAME'), - password: inReplicaMode ? undefined : env.get('DB_PASSWORD'), - database: inReplicaMode ? undefined : env.get('DB_DATABASE'), -} - -const sqliteDataSourceOptions: SqliteConnectionOptions = { - ...commonDataSourceOptions, - type: 'sqlite', - database: `data/${env.get('DB_DATABASE')}.sqlite`, -} - -export const AppDataSource = new DataSource(isConfiguredForMySQL ? mySQLDataSourceOptions : sqliteDataSourceOptions) +export const AppDataSource = dataSource diff --git a/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts b/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts deleted file mode 100644 index eac851c16..000000000 --- a/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { Container, interfaces } from 'inversify' - -import { Env } from './Env' -import TYPES from './Types' -import { AuthMiddleware } from '../Controller/AuthMiddleware' -import { Item } from '../Domain/Item/Item' -import { SyncResponseFactory20161215 } from '../Domain/Item/SyncResponse/SyncResponseFactory20161215' -import { SyncResponseFactory20200115 } from '../Domain/Item/SyncResponse/SyncResponseFactory20200115' -import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' -import { SyncResponseFactoryResolver } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolver' -import { ItemServiceInterface } from '../Domain/Item/ItemServiceInterface' -import { ItemService } from '../Domain/Item/ItemService' -import { SyncItems } from '../Domain/UseCase/SyncItems' -import { ItemConflictProjector } from '../Projection/ItemConflictProjector' -import { ItemSaveValidatorInterface } from '../Domain/Item/SaveValidator/ItemSaveValidatorInterface' -import { ItemSaveValidator } from '../Domain/Item/SaveValidator/ItemSaveValidator' -import { OwnershipFilter } from '../Domain/Item/SaveRule/OwnershipFilter' -import { TimeDifferenceFilter } from '../Domain/Item/SaveRule/TimeDifferenceFilter' -import { ItemFactoryInterface } from '../Domain/Item/ItemFactoryInterface' -import { ItemFactory } from '../Domain/Item/ItemFactory' -import { UuidFilter } from '../Domain/Item/SaveRule/UuidFilter' -import { ContentTypeFilter } from '../Domain/Item/SaveRule/ContentTypeFilter' -import { ContentFilter } from '../Domain/Item/SaveRule/ContentFilter' -import { CheckIntegrity } from '../Domain/UseCase/CheckIntegrity/CheckIntegrity' -import { GetItem } from '../Domain/UseCase/GetItem/GetItem' -import { ProjectorInterface } from '../Projection/ProjectorInterface' -import { SavedItemProjection } from '../Projection/SavedItemProjection' -import { SavedItemProjector } from '../Projection/SavedItemProjector' -import { ItemConflict } from '../Domain/Item/ItemConflict' -import { ItemConflictProjection } from '../Projection/ItemConflictProjection' -import { CommonContainerConfigLoader } from './CommonContainerConfigLoader' - -export class ServerContainerConfigLoader extends CommonContainerConfigLoader { - private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000 - private readonly DEFAULT_MAX_ITEMS_LIMIT = 300 - - override async load(): Promise { - const container = await super.load() - - const env: Env = container.get(TYPES.Env) - - // Middleware - container.bind(TYPES.AuthMiddleware).toDynamicValue((context: interfaces.Context) => { - return new AuthMiddleware(context.container.get(TYPES.AUTH_JWT_SECRET), context.container.get(TYPES.Logger)) - }) - - // Projectors - container - .bind>(TYPES.SavedItemProjector) - .toDynamicValue((context: interfaces.Context) => { - return new SavedItemProjector(context.container.get(TYPES.Timer)) - }) - container - .bind>(TYPES.ItemConflictProjector) - .toDynamicValue((context: interfaces.Context) => { - return new ItemConflictProjector(context.container.get(TYPES.ItemProjector)) - }) - - // env vars - container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET')) - container.bind(TYPES.REVISIONS_FREQUENCY).toConstantValue(env.get('REVISIONS_FREQUENCY')) - container.bind(TYPES.NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) - container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION')) - container - .bind(TYPES.CONTENT_SIZE_TRANSFER_LIMIT) - .toConstantValue( - env.get('CONTENT_SIZE_TRANSFER_LIMIT', true) - ? +env.get('CONTENT_SIZE_TRANSFER_LIMIT', true) - : this.DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT, - ) - container - .bind(TYPES.MAX_ITEMS_LIMIT) - .toConstantValue( - env.get('MAX_ITEMS_LIMIT', true) ? +env.get('MAX_ITEMS_LIMIT', true) : this.DEFAULT_MAX_ITEMS_LIMIT, - ) - - // use cases - container.bind(TYPES.SyncItems).toDynamicValue((context: interfaces.Context) => { - return new SyncItems(context.container.get(TYPES.ItemService)) - }) - container.bind(TYPES.CheckIntegrity).toDynamicValue((context: interfaces.Context) => { - return new CheckIntegrity(context.container.get(TYPES.ItemRepository)) - }) - container.bind(TYPES.GetItem).toDynamicValue((context: interfaces.Context) => { - return new GetItem(context.container.get(TYPES.ItemRepository)) - }) - - // Services - container.bind(TYPES.ItemService).toDynamicValue((context: interfaces.Context) => { - return new ItemService( - context.container.get(TYPES.ItemSaveValidator), - context.container.get(TYPES.ItemFactory), - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.DomainEventPublisher), - context.container.get(TYPES.DomainEventFactory), - context.container.get(TYPES.REVISIONS_FREQUENCY), - context.container.get(TYPES.CONTENT_SIZE_TRANSFER_LIMIT), - context.container.get(TYPES.ItemTransferCalculator), - context.container.get(TYPES.Timer), - context.container.get(TYPES.ItemProjector), - context.container.get(TYPES.MAX_ITEMS_LIMIT), - context.container.get(TYPES.Logger), - ) - }) - container - .bind(TYPES.SyncResponseFactory20161215) - .toDynamicValue((context: interfaces.Context) => { - return new SyncResponseFactory20161215(context.container.get(TYPES.ItemProjector)) - }) - container - .bind(TYPES.SyncResponseFactory20200115) - .toDynamicValue((context: interfaces.Context) => { - return new SyncResponseFactory20200115( - context.container.get(TYPES.ItemProjector), - context.container.get(TYPES.ItemConflictProjector), - context.container.get(TYPES.SavedItemProjector), - ) - }) - container - .bind(TYPES.SyncResponseFactoryResolver) - .toDynamicValue((context: interfaces.Context) => { - return new SyncResponseFactoryResolver( - context.container.get(TYPES.SyncResponseFactory20161215), - context.container.get(TYPES.SyncResponseFactory20200115), - ) - }) - - container.bind(TYPES.ItemFactory).toDynamicValue((context: interfaces.Context) => { - return new ItemFactory(context.container.get(TYPES.Timer), context.container.get(TYPES.ItemProjector)) - }) - - container.bind(TYPES.OwnershipFilter).toDynamicValue(() => new OwnershipFilter()) - container - .bind(TYPES.TimeDifferenceFilter) - .toDynamicValue((context: interfaces.Context) => new TimeDifferenceFilter(context.container.get(TYPES.Timer))) - container.bind(TYPES.UuidFilter).toDynamicValue(() => new UuidFilter()) - container.bind(TYPES.ContentTypeFilter).toDynamicValue(() => new ContentTypeFilter()) - container.bind(TYPES.ContentFilter).toDynamicValue(() => new ContentFilter()) - - container - .bind(TYPES.ItemSaveValidator) - .toDynamicValue((context: interfaces.Context) => { - return new ItemSaveValidator([ - context.container.get(TYPES.OwnershipFilter), - context.container.get(TYPES.TimeDifferenceFilter), - context.container.get(TYPES.UuidFilter), - context.container.get(TYPES.ContentTypeFilter), - context.container.get(TYPES.ContentFilter), - ]) - }) - - return container - } -} diff --git a/packages/syncing-server/src/Bootstrap/Service.ts b/packages/syncing-server/src/Bootstrap/Service.ts new file mode 100644 index 000000000..422a688e8 --- /dev/null +++ b/packages/syncing-server/src/Bootstrap/Service.ts @@ -0,0 +1,42 @@ +import { + ControllerContainerInterface, + ServiceContainerInterface, + ServiceIdentifier, + ServiceInterface, +} from '@standardnotes/domain-core' + +import { ContainerConfigLoader } from './Container' +import { DirectCallDomainEventPublisher } from '@standardnotes/domain-events-infra' + +export class Service implements ServiceInterface { + constructor( + private serviceContainer: ServiceContainerInterface, + private controllerContainer: ControllerContainerInterface, + private directCallDomainEventPublisher: DirectCallDomainEventPublisher, + ) { + this.serviceContainer.register(this.getId(), this) + } + + async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise { + const method = this.controllerContainer.get(endpointOrMethodIdentifier) + + if (!method) { + throw new Error(`Method ${endpointOrMethodIdentifier} not found`) + } + + return method(request, response) + } + + async getContainer(): Promise { + const config = new ContainerConfigLoader() + + return config.load({ + controllerConatiner: this.controllerContainer, + directCallDomainEventPublisher: this.directCallDomainEventPublisher, + }) + } + + getId(): ServiceIdentifier { + return ServiceIdentifier.create(ServiceIdentifier.NAMES.SyncingServer).getValue() + } +} diff --git a/packages/syncing-server/src/Bootstrap/Types.ts b/packages/syncing-server/src/Bootstrap/Types.ts index 759a291d1..a626da18f 100644 --- a/packages/syncing-server/src/Bootstrap/Types.ts +++ b/packages/syncing-server/src/Bootstrap/Types.ts @@ -1,71 +1,73 @@ const TYPES = { - DBConnection: Symbol.for('DBConnection'), - Logger: Symbol.for('Logger'), - Redis: Symbol.for('Redis'), - SNS: Symbol.for('SNS'), - SQS: Symbol.for('SQS'), - S3: Symbol.for('S3'), - Env: Symbol.for('Env'), + Sync_DBConnection: Symbol.for('Sync_DBConnection'), + Sync_Logger: Symbol.for('Sync_Logger'), + Sync_Redis: Symbol.for('Sync_Redis'), + Sync_SNS: Symbol.for('Sync_SNS'), + Sync_SQS: Symbol.for('Sync_SQS'), + Sync_S3: Symbol.for('Sync_S3'), + Sync_Env: Symbol.for('Sync_Env'), // Repositories - ItemRepository: Symbol.for('ItemRepository'), + Sync_ItemRepository: Symbol.for('Sync_ItemRepository'), // ORM - ORMItemRepository: Symbol.for('ORMItemRepository'), + Sync_ORMItemRepository: Symbol.for('Sync_ORMItemRepository'), // Middleware - AuthMiddleware: Symbol.for('AuthMiddleware'), + Sync_AuthMiddleware: Symbol.for('Sync_AuthMiddleware'), // Projectors - ItemProjector: Symbol.for('ItemProjector'), - SavedItemProjector: Symbol.for('SavedItemProjector'), - ItemConflictProjector: Symbol.for('ItemConflictProjector'), + Sync_ItemProjector: Symbol.for('Sync_ItemProjector'), + Sync_SavedItemProjector: Symbol.for('Sync_SavedItemProjector'), + Sync_ItemConflictProjector: Symbol.for('Sync_ItemConflictProjector'), // env vars - REDIS_URL: Symbol.for('REDIS_URL'), - SNS_TOPIC_ARN: Symbol.for('SNS_TOPIC_ARN'), - SNS_AWS_REGION: Symbol.for('SNS_AWS_REGION'), - SQS_QUEUE_URL: Symbol.for('SQS_QUEUE_URL'), - SQS_AWS_REGION: Symbol.for('SQS_AWS_REGION'), - AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'), - EXTENSIONS_SERVER_URL: Symbol.for('EXTENSIONS_SERVER_URL'), - AUTH_SERVER_URL: Symbol.for('AUTH_SERVER_URL'), - S3_AWS_REGION: Symbol.for('S3_AWS_REGION'), - S3_BACKUP_BUCKET_NAME: Symbol.for('S3_BACKUP_BUCKET_NAME'), - EMAIL_ATTACHMENT_MAX_BYTE_SIZE: Symbol.for('EMAIL_ATTACHMENT_MAX_BYTE_SIZE'), - REVISIONS_FREQUENCY: Symbol.for('REVISIONS_FREQUENCY'), - NEW_RELIC_ENABLED: Symbol.for('NEW_RELIC_ENABLED'), - VERSION: Symbol.for('VERSION'), - CONTENT_SIZE_TRANSFER_LIMIT: Symbol.for('CONTENT_SIZE_TRANSFER_LIMIT'), - MAX_ITEMS_LIMIT: Symbol.for('MAX_ITEMS_LIMIT'), - FILE_UPLOAD_PATH: Symbol.for('FILE_UPLOAD_PATH'), + Sync_REDIS_URL: Symbol.for('Sync_REDIS_URL'), + Sync_SNS_TOPIC_ARN: Symbol.for('Sync_SNS_TOPIC_ARN'), + Sync_SNS_AWS_REGION: Symbol.for('Sync_SNS_AWS_REGION'), + Sync_SQS_QUEUE_URL: Symbol.for('Sync_SQS_QUEUE_URL'), + Sync_SQS_AWS_REGION: Symbol.for('Sync_SQS_AWS_REGION'), + Sync_AUTH_JWT_SECRET: Symbol.for('Sync_AUTH_JWT_SECRET'), + Sync_EXTENSIONS_SERVER_URL: Symbol.for('Sync_EXTENSIONS_SERVER_URL'), + Sync_AUTH_SERVER_URL: Symbol.for('Sync_AUTH_SERVER_URL'), + Sync_S3_AWS_REGION: Symbol.for('Sync_S3_AWS_REGION'), + Sync_S3_BACKUP_BUCKET_NAME: Symbol.for('Sync_S3_BACKUP_BUCKET_NAME'), + Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE: Symbol.for('Sync_EMAIL_ATTACHMENT_MAX_BYTE_SIZE'), + Sync_REVISIONS_FREQUENCY: Symbol.for('Sync_REVISIONS_FREQUENCY'), + Sync_NEW_RELIC_ENABLED: Symbol.for('Sync_NEW_RELIC_ENABLED'), + Sync_VERSION: Symbol.for('Sync_VERSION'), + Sync_CONTENT_SIZE_TRANSFER_LIMIT: Symbol.for('Sync_CONTENT_SIZE_TRANSFER_LIMIT'), + Sync_MAX_ITEMS_LIMIT: Symbol.for('Sync_MAX_ITEMS_LIMIT'), + Sync_FILE_UPLOAD_PATH: Symbol.for('Sync_FILE_UPLOAD_PATH'), // use cases - SyncItems: Symbol.for('SyncItems'), - CheckIntegrity: Symbol.for('CheckIntegrity'), - GetItem: Symbol.for('GetItem'), + Sync_SyncItems: Symbol.for('Sync_SyncItems'), + Sync_CheckIntegrity: Symbol.for('Sync_CheckIntegrity'), + Sync_GetItem: Symbol.for('Sync_GetItem'), // Handlers - AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'), - DuplicateItemSyncedEventHandler: Symbol.for('DuplicateItemSyncedEventHandler'), - EmailBackupRequestedEventHandler: Symbol.for('EmailBackupRequestedEventHandler'), - ItemRevisionCreationRequestedEventHandler: Symbol.for('ItemRevisionCreationRequestedEventHandler'), + Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'), + Sync_DuplicateItemSyncedEventHandler: Symbol.for('Sync_DuplicateItemSyncedEventHandler'), + Sync_EmailBackupRequestedEventHandler: Symbol.for('Sync_EmailBackupRequestedEventHandler'), + Sync_ItemRevisionCreationRequestedEventHandler: Symbol.for('Sync_ItemRevisionCreationRequestedEventHandler'), // Services - ContentDecoder: Symbol.for('ContentDecoder'), - DomainEventPublisher: Symbol.for('DomainEventPublisher'), - DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'), - DomainEventFactory: Symbol.for('DomainEventFactory'), - DomainEventMessageHandler: Symbol.for('DomainEventMessageHandler'), - HTTPClient: Symbol.for('HTTPClient'), - ItemService: Symbol.for('ItemService'), - Timer: Symbol.for('Timer'), - SyncResponseFactory20161215: Symbol.for('SyncResponseFactory20161215'), - SyncResponseFactory20200115: Symbol.for('SyncResponseFactory20200115'), - SyncResponseFactoryResolver: Symbol.for('SyncResponseFactoryResolver'), - AuthHttpService: Symbol.for('AuthHttpService'), - ExtensionsHttpService: Symbol.for('ExtensionsHttpService'), - ItemBackupService: Symbol.for('ItemBackupService'), - ItemSaveValidator: Symbol.for('ItemSaveValidator'), - OwnershipFilter: Symbol.for('OwnershipFilter'), - TimeDifferenceFilter: Symbol.for('TimeDifferenceFilter'), - UuidFilter: Symbol.for('UuidFilter'), - ContentTypeFilter: Symbol.for('ContentTypeFilter'), - ContentFilter: Symbol.for('ContentFilter'), - ItemFactory: Symbol.for('ItemFactory'), - ItemTransferCalculator: Symbol.for('ItemTransferCalculator'), + Sync_ContentDecoder: Symbol.for('Sync_ContentDecoder'), + Sync_DomainEventPublisher: Symbol.for('Sync_DomainEventPublisher'), + Sync_DomainEventSubscriberFactory: Symbol.for('Sync_DomainEventSubscriberFactory'), + Sync_DomainEventFactory: Symbol.for('Sync_DomainEventFactory'), + Sync_DomainEventMessageHandler: Symbol.for('Sync_DomainEventMessageHandler'), + Sync_HTTPClient: Symbol.for('Sync_HTTPClient'), + Sync_ItemService: Symbol.for('Sync_ItemService'), + Sync_Timer: Symbol.for('Sync_Timer'), + Sync_SyncResponseFactory20161215: Symbol.for('Sync_SyncResponseFactory20161215'), + Sync_SyncResponseFactory20200115: Symbol.for('Sync_SyncResponseFactory20200115'), + Sync_SyncResponseFactoryResolver: Symbol.for('Sync_SyncResponseFactoryResolver'), + Sync_AuthHttpService: Symbol.for('Sync_AuthHttpService'), + Sync_ExtensionsHttpService: Symbol.for('Sync_ExtensionsHttpService'), + Sync_ItemBackupService: Symbol.for('Sync_ItemBackupService'), + Sync_ItemSaveValidator: Symbol.for('Sync_ItemSaveValidator'), + Sync_OwnershipFilter: Symbol.for('Sync_OwnershipFilter'), + Sync_TimeDifferenceFilter: Symbol.for('Sync_TimeDifferenceFilter'), + Sync_UuidFilter: Symbol.for('Sync_UuidFilter'), + Sync_ContentTypeFilter: Symbol.for('Sync_ContentTypeFilter'), + Sync_ContentFilter: Symbol.for('Sync_ContentFilter'), + Sync_ItemFactory: Symbol.for('Sync_ItemFactory'), + Sync_ItemTransferCalculator: Symbol.for('Sync_ItemTransferCalculator'), + Sync_ControllerContainer: Symbol.for('Sync_ControllerContainer'), + Sync_InversifyExpressItemsController: Symbol.for('Sync_InversifyExpressItemsController'), } export default TYPES diff --git a/packages/syncing-server/src/Bootstrap/WorkerContainerConfigLoader.ts b/packages/syncing-server/src/Bootstrap/WorkerContainerConfigLoader.ts deleted file mode 100644 index ec6b89385..000000000 --- a/packages/syncing-server/src/Bootstrap/WorkerContainerConfigLoader.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs' -import { S3Client } from '@aws-sdk/client-s3' -import { Container, interfaces } from 'inversify' -import { - DomainEventHandlerInterface, - DomainEventMessageHandlerInterface, - DomainEventSubscriberFactoryInterface, -} from '@standardnotes/domain-events' - -import { Env } from './Env' -import TYPES from './Types' -import { ContentDecoder } from '../Domain/Item/ContentDecoder' -import { AuthHttpServiceInterface } from '../Domain/Auth/AuthHttpServiceInterface' -import { AuthHttpService } from '../Infra/HTTP/AuthHttpService' -import { ExtensionsHttpServiceInterface } from '../Domain/Extension/ExtensionsHttpServiceInterface' -import { ExtensionsHttpService } from '../Domain/Extension/ExtensionsHttpService' -import { ItemBackupServiceInterface } from '../Domain/Item/ItemBackupServiceInterface' -import { S3ItemBackupService } from '../Infra/S3/S3ItemBackupService' -import { DuplicateItemSyncedEventHandler } from '../Domain/Handler/DuplicateItemSyncedEventHandler' -import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler' -// eslint-disable-next-line @typescript-eslint/no-var-requires -const axios = require('axios') -import { AxiosInstance } from 'axios' -import { - SQSDomainEventSubscriberFactory, - SQSEventMessageHandler, - SQSNewRelicEventMessageHandler, -} from '@standardnotes/domain-events-infra' -import { EmailBackupRequestedEventHandler } from '../Domain/Handler/EmailBackupRequestedEventHandler' -import { ItemRevisionCreationRequestedEventHandler } from '../Domain/Handler/ItemRevisionCreationRequestedEventHandler' -import { FSItemBackupService } from '../Infra/FS/FSItemBackupService' -import { CommonContainerConfigLoader } from './CommonContainerConfigLoader' - -export class WorkerContainerConfigLoader extends CommonContainerConfigLoader { - private readonly DEFAULT_FILE_UPLOAD_PATH = `${__dirname}/../../uploads` - - override async load(): Promise { - const container = await super.load() - - const env: Env = container.get(TYPES.Env) - - container.bind(TYPES.SQS).toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - const sqsConfig: SQSClientConfig = { - region: env.get('SQS_AWS_REGION'), - } - if (env.get('SQS_ENDPOINT', true)) { - sqsConfig.endpoint = env.get('SQS_ENDPOINT', true) - } - if (env.get('SQS_ACCESS_KEY_ID', true) && env.get('SQS_SECRET_ACCESS_KEY', true)) { - sqsConfig.credentials = { - accessKeyId: env.get('SQS_ACCESS_KEY_ID', true), - secretAccessKey: env.get('SQS_SECRET_ACCESS_KEY', true), - } - } - - return new SQSClient(sqsConfig) - }) - - container.bind(TYPES.S3).toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - let s3Client = undefined - if (env.get('S3_AWS_REGION', true)) { - s3Client = new S3Client({ - apiVersion: 'latest', - region: env.get('S3_AWS_REGION', true), - }) - } - - return s3Client - }) - - // env vars - container.bind(TYPES.SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL')) - container.bind(TYPES.EXTENSIONS_SERVER_URL).toConstantValue(env.get('EXTENSIONS_SERVER_URL', true)) - container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL')) - container.bind(TYPES.S3_AWS_REGION).toConstantValue(env.get('S3_AWS_REGION', true)) - container.bind(TYPES.S3_BACKUP_BUCKET_NAME).toConstantValue(env.get('S3_BACKUP_BUCKET_NAME', true)) - container.bind(TYPES.EMAIL_ATTACHMENT_MAX_BYTE_SIZE).toConstantValue(env.get('EMAIL_ATTACHMENT_MAX_BYTE_SIZE')) - container.bind(TYPES.NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) - container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION')) - container - .bind(TYPES.FILE_UPLOAD_PATH) - .toConstantValue( - env.get('FILE_UPLOAD_PATH', true) ? env.get('FILE_UPLOAD_PATH', true) : this.DEFAULT_FILE_UPLOAD_PATH, - ) - - // Handlers - container - .bind(TYPES.DuplicateItemSyncedEventHandler) - .toDynamicValue((context: interfaces.Context) => { - return new DuplicateItemSyncedEventHandler( - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.DomainEventFactory), - context.container.get(TYPES.DomainEventPublisher), - context.container.get(TYPES.Logger), - ) - }) - container - .bind(TYPES.AccountDeletionRequestedEventHandler) - .toDynamicValue((context: interfaces.Context) => { - return new AccountDeletionRequestedEventHandler( - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.Logger), - ) - }) - container - .bind(TYPES.EmailBackupRequestedEventHandler) - .toDynamicValue((context: interfaces.Context) => { - return new EmailBackupRequestedEventHandler( - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.AuthHttpService), - context.container.get(TYPES.ItemBackupService), - context.container.get(TYPES.DomainEventPublisher), - context.container.get(TYPES.DomainEventFactory), - context.container.get(TYPES.EMAIL_ATTACHMENT_MAX_BYTE_SIZE), - context.container.get(TYPES.ItemTransferCalculator), - context.container.get(TYPES.S3_BACKUP_BUCKET_NAME), - context.container.get(TYPES.Logger), - ) - }) - container - .bind(TYPES.ItemRevisionCreationRequestedEventHandler) - .toDynamicValue((context: interfaces.Context) => { - return new ItemRevisionCreationRequestedEventHandler( - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.ItemBackupService), - context.container.get(TYPES.DomainEventFactory), - context.container.get(TYPES.DomainEventPublisher), - ) - }) - - // Services - container.bind(TYPES.ContentDecoder).toDynamicValue(() => new ContentDecoder()) - container.bind(TYPES.HTTPClient).toDynamicValue(() => axios.create()) - container.bind(TYPES.AuthHttpService).toDynamicValue((context: interfaces.Context) => { - return new AuthHttpService(context.container.get(TYPES.HTTPClient), context.container.get(TYPES.AUTH_SERVER_URL)) - }) - container - .bind(TYPES.ExtensionsHttpService) - .toDynamicValue((context: interfaces.Context) => { - return new ExtensionsHttpService( - context.container.get(TYPES.HTTPClient), - context.container.get(TYPES.ItemRepository), - context.container.get(TYPES.ContentDecoder), - context.container.get(TYPES.DomainEventPublisher), - context.container.get(TYPES.DomainEventFactory), - context.container.get(TYPES.Logger), - ) - }) - - container - .bind(TYPES.ItemBackupService) - .toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - if (env.get('S3_AWS_REGION', true)) { - return new S3ItemBackupService( - context.container.get(TYPES.S3_BACKUP_BUCKET_NAME), - context.container.get(TYPES.ItemProjector), - context.container.get(TYPES.Logger), - context.container.get(TYPES.S3), - ) - } else { - return new FSItemBackupService( - context.container.get(TYPES.FILE_UPLOAD_PATH), - context.container.get(TYPES.ItemProjector), - context.container.get(TYPES.Logger), - ) - } - }) - - container - .bind(TYPES.DomainEventMessageHandler) - .toDynamicValue((context: interfaces.Context) => { - const env: Env = context.container.get(TYPES.Env) - - const eventHandlers: Map = new Map([ - ['DUPLICATE_ITEM_SYNCED', context.container.get(TYPES.DuplicateItemSyncedEventHandler)], - ['ACCOUNT_DELETION_REQUESTED', context.container.get(TYPES.AccountDeletionRequestedEventHandler)], - ['EMAIL_BACKUP_REQUESTED', context.container.get(TYPES.EmailBackupRequestedEventHandler)], - ['ITEM_REVISION_CREATION_REQUESTED', context.container.get(TYPES.ItemRevisionCreationRequestedEventHandler)], - ]) - - const handler = - env.get('NEW_RELIC_ENABLED', true) === 'true' - ? new SQSNewRelicEventMessageHandler(eventHandlers, context.container.get(TYPES.Logger)) - : new SQSEventMessageHandler(eventHandlers, context.container.get(TYPES.Logger)) - - return handler - }) - - container - .bind(TYPES.DomainEventSubscriberFactory) - .toDynamicValue((context: interfaces.Context) => { - return new SQSDomainEventSubscriberFactory( - context.container.get(TYPES.SQS), - context.container.get(TYPES.SQS_QUEUE_URL), - context.container.get(TYPES.DomainEventMessageHandler), - ) - }) - - return container - } -} diff --git a/packages/syncing-server/src/Bootstrap/index.ts b/packages/syncing-server/src/Bootstrap/index.ts new file mode 100644 index 000000000..22cddecef --- /dev/null +++ b/packages/syncing-server/src/Bootstrap/index.ts @@ -0,0 +1 @@ +export * from './Service' diff --git a/packages/syncing-server/src/Controller/HealthCheckController.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts similarity index 76% rename from packages/syncing-server/src/Controller/HealthCheckController.ts rename to packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts index 431e74056..535288409 100644 --- a/packages/syncing-server/src/Controller/HealthCheckController.ts +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts @@ -1,7 +1,7 @@ import { controller, httpGet } from 'inversify-express-utils' @controller('/healthcheck') -export class HealthCheckController { +export class InversifyExpressHealthCheckController { @httpGet('/') public async get(): Promise { return 'OK' diff --git a/packages/syncing-server/src/Controller/ItemsController.spec.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.spec.ts similarity index 83% rename from packages/syncing-server/src/Controller/ItemsController.spec.ts rename to packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.spec.ts index 14b3a2623..31d5f3327 100644 --- a/packages/syncing-server/src/Controller/ItemsController.spec.ts +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.spec.ts @@ -3,20 +3,21 @@ import 'reflect-metadata' import * as express from 'express' import { ContentType } from '@standardnotes/common' -import { ItemsController } from './ItemsController' +import { InversifyExpressItemsController } from './InversifyExpressItemsController' import { results } from 'inversify-express-utils' -import { SyncItems } from '../Domain/UseCase/SyncItems' -import { ApiVersion } from '../Domain/Api/ApiVersion' -import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' -import { SyncResponseFactoryInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryInterface' -import { SyncResponse20200115 } from '../Domain/Item/SyncResponse/SyncResponse20200115' -import { CheckIntegrity } from '../Domain/UseCase/CheckIntegrity/CheckIntegrity' -import { GetItem } from '../Domain/UseCase/GetItem/GetItem' -import { Item } from '../Domain/Item/Item' -import { ProjectorInterface } from '../Projection/ProjectorInterface' -import { ItemProjection } from '../Projection/ItemProjection' +import { Item } from '../../Domain/Item/Item' +import { ItemProjection } from '../../Projection/ItemProjection' +import { ProjectorInterface } from '../../Projection/ProjectorInterface' +import { ApiVersion } from '../../Domain/Api/ApiVersion' +import { SyncResponse20200115 } from '../../Domain/Item/SyncResponse/SyncResponse20200115' +import { SyncResponseFactoryInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryInterface' +import { SyncResponseFactoryResolverInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' +import { CheckIntegrity } from '../../Domain/UseCase/CheckIntegrity/CheckIntegrity' +import { GetItem } from '../../Domain/UseCase/GetItem/GetItem' +import { SyncItems } from '../../Domain/UseCase/SyncItems' +import { ControllerContainerInterface } from '@standardnotes/domain-core' -describe('ItemsController', () => { +describe('InversifyExpressItemsController', () => { let syncItems: SyncItems let checkIntegrity: CheckIntegrity let getItem: GetItem @@ -26,11 +27,22 @@ describe('ItemsController', () => { let syncResponceFactoryResolver: SyncResponseFactoryResolverInterface let syncResponseFactory: SyncResponseFactoryInterface let syncResponse: SyncResponse20200115 + let controllerContainer: ControllerContainerInterface const createController = () => - new ItemsController(syncItems, checkIntegrity, getItem, itemProjector, syncResponceFactoryResolver) + new InversifyExpressItemsController( + syncItems, + checkIntegrity, + getItem, + itemProjector, + syncResponceFactoryResolver, + controllerContainer, + ) beforeEach(() => { + controllerContainer = {} as jest.Mocked + controllerContainer.register = jest.fn() + itemProjector = {} as jest.Mocked> itemProjector.projectFull = jest.fn().mockReturnValue({ foo: 'bar' }) diff --git a/packages/syncing-server/src/Controller/ItemsController.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.ts similarity index 58% rename from packages/syncing-server/src/Controller/ItemsController.ts rename to packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.ts index 48f9a1a53..a7dd81888 100644 --- a/packages/syncing-server/src/Controller/ItemsController.ts +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressItemsController.ts @@ -1,27 +1,34 @@ import { Request, Response } from 'express' import { inject } from 'inversify' import { BaseHttpController, controller, httpGet, httpPost, results } from 'inversify-express-utils' -import TYPES from '../Bootstrap/Types' -import { ApiVersion } from '../Domain/Api/ApiVersion' -import { Item } from '../Domain/Item/Item' -import { SyncResponseFactoryResolverInterface } from '../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' -import { CheckIntegrity } from '../Domain/UseCase/CheckIntegrity/CheckIntegrity' -import { GetItem } from '../Domain/UseCase/GetItem/GetItem' -import { SyncItems } from '../Domain/UseCase/SyncItems' -import { ItemProjection } from '../Projection/ItemProjection' -import { ProjectorInterface } from '../Projection/ProjectorInterface' -@controller('/items', TYPES.AuthMiddleware) -export class ItemsController extends BaseHttpController { +import TYPES from '../../Bootstrap/Types' +import { Item } from '../../Domain/Item/Item' +import { SyncResponseFactoryResolverInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface' +import { CheckIntegrity } from '../../Domain/UseCase/CheckIntegrity/CheckIntegrity' +import { GetItem } from '../../Domain/UseCase/GetItem/GetItem' +import { SyncItems } from '../../Domain/UseCase/SyncItems' +import { ItemProjection } from '../../Projection/ItemProjection' +import { ProjectorInterface } from '../../Projection/ProjectorInterface' +import { ApiVersion } from '../../Domain/Api/ApiVersion' +import { ControllerContainerInterface } from '@standardnotes/domain-core' + +@controller('/items', TYPES.Sync_AuthMiddleware) +export class InversifyExpressItemsController extends BaseHttpController { constructor( - @inject(TYPES.SyncItems) private syncItems: SyncItems, - @inject(TYPES.CheckIntegrity) private checkIntegrity: CheckIntegrity, - @inject(TYPES.GetItem) private getItem: GetItem, - @inject(TYPES.ItemProjector) private itemProjector: ProjectorInterface, - @inject(TYPES.SyncResponseFactoryResolver) + @inject(TYPES.Sync_SyncItems) private syncItems: SyncItems, + @inject(TYPES.Sync_CheckIntegrity) private checkIntegrity: CheckIntegrity, + @inject(TYPES.Sync_GetItem) private getItem: GetItem, + @inject(TYPES.Sync_ItemProjector) private itemProjector: ProjectorInterface, + @inject(TYPES.Sync_SyncResponseFactoryResolver) private syncResponseFactoryResolver: SyncResponseFactoryResolverInterface, + @inject(TYPES.Sync_ControllerContainer) private controllerContainer: ControllerContainerInterface, ) { super() + + this.controllerContainer.register('sync.items.sync', this.sync.bind(this)) + this.controllerContainer.register('sync.items.check_integrity', this.checkItemsIntegrity.bind(this)) + this.controllerContainer.register('sync.items.get_item', this.getSingleItem.bind(this)) } @httpPost('/sync') diff --git a/packages/syncing-server/src/Controller/AuthMiddleware.spec.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.spec.ts similarity index 94% rename from packages/syncing-server/src/Controller/AuthMiddleware.spec.ts rename to packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.spec.ts index 283d72032..541ef4e6f 100644 --- a/packages/syncing-server/src/Controller/AuthMiddleware.spec.ts +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.spec.ts @@ -2,19 +2,19 @@ import 'reflect-metadata' import * as winston from 'winston' -import { AuthMiddleware } from './AuthMiddleware' +import { InversifyExpressAuthMiddleware } from './InversifyExpressAuthMiddleware' import { NextFunction, Request, Response } from 'express' import { sign } from 'jsonwebtoken' import { RoleName } from '@standardnotes/domain-core' -describe('AuthMiddleware', () => { +describe('InversifyExpressAuthMiddleware', () => { let logger: winston.Logger const jwtSecret = 'auth_jwt_secret' let request: Request let response: Response let next: NextFunction - const createMiddleware = () => new AuthMiddleware(jwtSecret, logger) + const createMiddleware = () => new InversifyExpressAuthMiddleware(jwtSecret, logger) beforeEach(() => { logger = {} as jest.Mocked diff --git a/packages/syncing-server/src/Controller/AuthMiddleware.ts b/packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.ts similarity index 95% rename from packages/syncing-server/src/Controller/AuthMiddleware.ts rename to packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.ts index bb41c9ffe..5803e9770 100644 --- a/packages/syncing-server/src/Controller/AuthMiddleware.ts +++ b/packages/syncing-server/src/Infra/InversifyExpressUtils/Middleware/InversifyExpressAuthMiddleware.ts @@ -5,7 +5,7 @@ import { CrossServiceTokenData } from '@standardnotes/security' import * as winston from 'winston' import { RoleName } from '@standardnotes/domain-core' -export class AuthMiddleware extends BaseMiddleware { +export class InversifyExpressAuthMiddleware extends BaseMiddleware { constructor(private authJWTSecret: string, private logger: winston.Logger) { super() } diff --git a/packages/syncing-server/src/index.ts b/packages/syncing-server/src/index.ts new file mode 100644 index 000000000..c82bbe40e --- /dev/null +++ b/packages/syncing-server/src/index.ts @@ -0,0 +1 @@ +export * from './Bootstrap' diff --git a/yarn.lock b/yarn.lock index da8a3de18..6f9795149 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4249,6 +4249,7 @@ __metadata: "@standardnotes/auth-server": "workspace:^" "@standardnotes/domain-core": "workspace:^" "@standardnotes/domain-events-infra": "workspace:^" + "@standardnotes/syncing-server": "workspace:^" "@types/cors": "npm:^2.8.9" "@types/express": "npm:^4.17.14" "@types/prettyjson": "npm:^0.0.30" @@ -4483,7 +4484,7 @@ __metadata: languageName: unknown linkType: soft -"@standardnotes/syncing-server@workspace:packages/syncing-server": +"@standardnotes/syncing-server@workspace:^, @standardnotes/syncing-server@workspace:packages/syncing-server": version: 0.0.0-use.local resolution: "@standardnotes/syncing-server@workspace:packages/syncing-server" dependencies: