Prechádzať zdrojové kódy

feat: home-server package initial setup with Api Gateway and Auth services (#605)

* fix(api-gateway): reduce exports

* wip controllers

* fix: imports of controllers

* fix(api-gateway): rename http service interface to proxy interface

* wip: self-registering services and controllers

* wip: add registering controller method bindings and services in container

* feat: merge two services together

* wip: resolving endpoints to direct code calls

* wip: bind controller container to a singleton

* fix: controller binding to instantiate and self-register on controller container

* fix: move signout endpoint to auth controller

* wip: define inversify controllers in the controller container

* fix(auth): bind inversify controllers to controller container

* fix(auth): linter issues

* fix(auth): specs

* fix(auth): inversify controllers bindings

* wip: endpoint resolving

* wip: add endpoint for more auth controllers

* wip: add sessions controller endpoint resolvings

* wip: add subscription invites endpoint resolvings

* wip: add subscription tokens endpoint resolvings

* wip: add all binding for auth server controllers

* wip: fix migrations path

* fix: configure default env vars and ci setup
Karol Sójko 2 rokov pred
rodič
commit
dc71e6777f
100 zmenil súbory, kde vykonal 1835 pridanie a 947 odobranie
  1. 1 0
      .env.sample
  2. 4 0
      .pnp.cjs
  3. 23 7
      packages/api-gateway/src/Bootstrap/Container.ts
  4. 37 0
      packages/api-gateway/src/Bootstrap/Service.ts
  5. 2 1
      packages/api-gateway/src/Bootstrap/Types.ts
  6. 1 1
      packages/api-gateway/src/Bootstrap/index.ts
  7. 2 2
      packages/api-gateway/src/Controller/LegacyController.ts
  8. 43 14
      packages/api-gateway/src/Controller/v1/ActionsController.ts
  9. 25 7
      packages/api-gateway/src/Controller/v1/AuthenticatorsController.ts
  10. 12 3
      packages/api-gateway/src/Controller/v1/FilesController.ts
  11. 2 2
      packages/api-gateway/src/Controller/v1/InvoicesController.ts
  12. 24 5
      packages/api-gateway/src/Controller/v1/ItemsController.ts
  13. 18 4
      packages/api-gateway/src/Controller/v1/OfflineController.ts
  14. 2 2
      packages/api-gateway/src/Controller/v1/PaymentsController.ts
  15. 30 8
      packages/api-gateway/src/Controller/v1/SessionsController.ts
  16. 36 6
      packages/api-gateway/src/Controller/v1/SubscriptionInvitesController.ts
  17. 12 3
      packages/api-gateway/src/Controller/v1/TokensController.ts
  18. 116 18
      packages/api-gateway/src/Controller/v1/UsersController.ts
  19. 20 5
      packages/api-gateway/src/Controller/v1/WebSocketsController.ts
  20. 18 4
      packages/api-gateway/src/Controller/v2/ActionsControllerV2.ts
  21. 2 2
      packages/api-gateway/src/Controller/v2/PaymentsControllerV2.ts
  22. 27 5
      packages/api-gateway/src/Controller/v2/RevisionsControllerV2.ts
  23. 0 2
      packages/api-gateway/src/Infra/index.ts
  24. 52 26
      packages/api-gateway/src/Service/Http/HttpServiceProxy.ts
  25. 9 9
      packages/api-gateway/src/Service/Http/ServiceProxyInterface.ts
  26. 74 0
      packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts
  27. 70 0
      packages/api-gateway/src/Service/Resolver/EndpointResolver.ts
  28. 3 0
      packages/api-gateway/src/Service/Resolver/EndpointResolverInterface.ts
  29. 0 3
      packages/api-gateway/src/Service/index.ts
  30. 0 2
      packages/api-gateway/src/index.ts
  31. 5 5
      packages/auth/bin/backup.ts
  32. 3 3
      packages/auth/bin/cleanup.ts
  33. 2 2
      packages/auth/bin/server.ts
  34. 3 3
      packages/auth/bin/stats.ts
  35. 6 6
      packages/auth/bin/user_email_backup.ts
  36. 4 2
      packages/auth/bin/worker.ts
  37. 1 0
      packages/auth/package.json
  38. 460 340
      packages/auth/src/Bootstrap/Container.ts
  39. 50 43
      packages/auth/src/Bootstrap/DataSource.ts
  40. 37 0
      packages/auth/src/Bootstrap/Service.ts
  41. 212 202
      packages/auth/src/Bootstrap/Types.ts
  42. 1 0
      packages/auth/src/Bootstrap/index.ts
  43. 12 1
      packages/auth/src/Controller/AdminController.spec.ts
  44. 12 5
      packages/auth/src/Controller/AdminController.ts
  45. 2 2
      packages/auth/src/Controller/ApiGatewayAuthMiddleware.ts
  46. 2 2
      packages/auth/src/Controller/ApiGatewayOfflineAuthMiddleware.ts
  47. 6 0
      packages/auth/src/Controller/AuthController.spec.ts
  48. 40 12
      packages/auth/src/Controller/AuthController.ts
  49. 2 2
      packages/auth/src/Controller/AuthMiddleware.ts
  50. 1 1
      packages/auth/src/Controller/AuthMiddlewareWithoutResponse.ts
  51. 6 1
      packages/auth/src/Controller/FeaturesController.spec.ts
  52. 8 2
      packages/auth/src/Controller/FeaturesController.ts
  53. 2 2
      packages/auth/src/Controller/InternalController.ts
  54. 6 1
      packages/auth/src/Controller/ListedController.spec.ts
  55. 8 2
      packages/auth/src/Controller/ListedController.ts
  56. 2 2
      packages/auth/src/Controller/LockMiddleware.ts
  57. 7 0
      packages/auth/src/Controller/OfflineController.spec.ts
  58. 16 9
      packages/auth/src/Controller/OfflineController.ts
  59. 2 2
      packages/auth/src/Controller/OfflineUserAuthMiddleware.ts
  60. 6 1
      packages/auth/src/Controller/SessionController.spec.ts
  61. 12 5
      packages/auth/src/Controller/SessionController.ts
  62. 12 1
      packages/auth/src/Controller/SessionsController.spec.ts
  63. 9 5
      packages/auth/src/Controller/SessionsController.ts
  64. 7 1
      packages/auth/src/Controller/SettingsController.spec.ts
  65. 15 8
      packages/auth/src/Controller/SettingsController.ts
  66. 5 5
      packages/auth/src/Controller/SubscriptionInvitesController.ts
  67. 6 1
      packages/auth/src/Controller/SubscriptionSettingsController.spec.ts
  68. 8 2
      packages/auth/src/Controller/SubscriptionSettingsController.ts
  69. 7 0
      packages/auth/src/Controller/SubscriptionTokensController.spec.ts
  70. 12 8
      packages/auth/src/Controller/SubscriptionTokensController.ts
  71. 1 1
      packages/auth/src/Controller/UserRequestsController.ts
  72. 6 0
      packages/auth/src/Controller/UsersController.spec.ts
  73. 17 10
      packages/auth/src/Controller/UsersController.ts
  74. 6 1
      packages/auth/src/Controller/ValetTokenController.spec.ts
  75. 8 3
      packages/auth/src/Controller/ValetTokenController.ts
  76. 3 3
      packages/auth/src/Domain/Auth/AuthResponseFactory20161215.ts
  77. 7 7
      packages/auth/src/Domain/Auth/AuthResponseFactory20200115.ts
  78. 4 4
      packages/auth/src/Domain/Auth/AuthResponseFactoryResolver.ts
  79. 4 4
      packages/auth/src/Domain/Auth/AuthenticationMethodResolver.ts
  80. 3 3
      packages/auth/src/Domain/Encryption/CrypterNode.ts
  81. 1 1
      packages/auth/src/Domain/Event/DomainEventFactory.ts
  82. 3 3
      packages/auth/src/Domain/Feature/FeatureService.ts
  83. 6 5
      packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.ts
  84. 5 5
      packages/auth/src/Domain/Handler/ExtensionKeyGrantedEventHandler.ts
  85. 4 3
      packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts
  86. 5 4
      packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts
  87. 3 3
      packages/auth/src/Domain/Handler/ListedAccountCreatedEventHandler.ts
  88. 3 3
      packages/auth/src/Domain/Handler/ListedAccountDeletedEventHandler.ts
  89. 5 5
      packages/auth/src/Domain/Handler/PredicateVerificationRequestedEventHandler.ts
  90. 1 1
      packages/auth/src/Domain/Handler/SharedSubscriptionInvitationCreatedEventHandler.ts
  91. 3 2
      packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.ts
  92. 6 5
      packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.ts
  93. 8 6
      packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts
  94. 8 6
      packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts
  95. 6 5
      packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.ts
  96. 6 5
      packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.ts
  97. 11 9
      packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts
  98. 2 2
      packages/auth/src/Domain/Handler/UserDisabledSessionUserAgentLoggingEventHandler.ts
  99. 4 4
      packages/auth/src/Domain/Handler/UserEmailChangedEventHandler.ts
  100. 4 4
      packages/auth/src/Domain/Handler/UserRegisteredEventHandler.ts

+ 1 - 0
.env.sample

@@ -15,6 +15,7 @@ DB_TYPE=mysql
 
 REDIS_PORT=6379
 REDIS_HOST=cache
+CACHE_TYPE=redis
 
 ########
 # KEYS #

+ 4 - 0
.pnp.cjs

@@ -4623,8 +4623,11 @@ const RAW_RUNTIME_STATE =
         "packageDependencies": [\
           ["@standardnotes/home-server", "workspace:packages/home-server"],\
           ["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
+          ["@standardnotes/auth-server", "workspace:packages/auth"],\
+          ["@standardnotes/domain-core", "workspace:packages/domain-core"],\
           ["@types/cors", "npm:2.8.13"],\
           ["@types/express", "npm:4.17.17"],\
+          ["@types/prettyjson", "npm:0.0.30"],\
           ["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.59.2"],\
           ["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.59.2"],\
           ["cors", "npm:2.8.5"],\
@@ -4637,6 +4640,7 @@ const RAW_RUNTIME_STATE =
           ["inversify", "npm:6.0.1"],\
           ["inversify-express-utils", "npm:6.4.3"],\
           ["prettier", "npm:2.8.8"],\
+          ["prettyjson", "npm:1.2.5"],\
           ["reflect-metadata", "npm:0.1.13"],\
           ["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
           ["winston", "npm:3.8.2"]\

+ 23 - 7
packages/api-gateway/src/Bootstrap/Container.ts

@@ -9,19 +9,23 @@ import { Timer, TimerInterface } from '@standardnotes/time'
 import { Env } from './Env'
 import { TYPES } from './Types'
 import { AuthMiddleware } from '../Controller/AuthMiddleware'
-import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
-import { HttpService } from '../Service/Http/HttpService'
+import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
+import { HttpServiceProxy } from '../Service/Http/HttpServiceProxy'
 import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
 import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
 import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
 import { WebSocketAuthMiddleware } from '../Controller/WebSocketAuthMiddleware'
 import { InMemoryCrossServiceTokenCache } from '../Infra/InMemory/InMemoryCrossServiceTokenCache'
+import { DirectCallServiceProxy } from '../Service/Proxy/DirectCallServiceProxy'
+import { ServiceContainerInterface } from '@standardnotes/domain-core'
+import { EndpointResolverInterface } from '../Service/Resolver/EndpointResolverInterface'
+import { EndpointResolver } from '../Service/Resolver/EndpointResolver'
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const newrelicFormatter = require('@newrelic/winston-enricher')
 
 export class ContainerConfigLoader {
-  async load(): Promise<Container> {
+  async load(serviceContainer?: ServiceContainerInterface): Promise<Container> {
     const env: Env = new Env()
     env.load()
 
@@ -57,14 +61,14 @@ export class ContainerConfigLoader {
     container.bind<AxiosInstance>(TYPES.HTTPClient).toConstantValue(axios.create())
 
     // env vars
-    container.bind(TYPES.SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL'))
-    container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL'))
+    container.bind(TYPES.SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
+    container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL', true))
     container.bind(TYPES.REVISIONS_SERVER_URL).toConstantValue(env.get('REVISIONS_SERVER_URL', true))
     container.bind(TYPES.EMAIL_SERVER_URL).toConstantValue(env.get('EMAIL_SERVER_URL', true))
     container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
     container.bind(TYPES.FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true))
-    container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
     container.bind(TYPES.WEB_SOCKET_SERVER_URL).toConstantValue(env.get('WEB_SOCKET_SERVER_URL', true))
+    container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
     container
       .bind(TYPES.HTTP_CALL_TIMEOUT)
       .toConstantValue(env.get('HTTP_CALL_TIMEOUT', true) ? +env.get('HTTP_CALL_TIMEOUT', true) : 60_000)
@@ -79,7 +83,16 @@ export class ContainerConfigLoader {
       .to(SubscriptionTokenAuthMiddleware)
 
     // Services
-    container.bind<HttpServiceInterface>(TYPES.HTTPService).to(HttpService)
+    if (isConfiguredForHomeServer) {
+      if (!serviceContainer) {
+        throw new Error('Service container is required when configured for home server')
+      }
+      container
+        .bind<ServiceProxyInterface>(TYPES.ServiceProxy)
+        .toConstantValue(new DirectCallServiceProxy(serviceContainer))
+    } else {
+      container.bind<ServiceProxyInterface>(TYPES.ServiceProxy).to(HttpServiceProxy)
+    }
     container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
 
     if (isConfiguredForHomeServer) {
@@ -89,6 +102,9 @@ export class ContainerConfigLoader {
     } else {
       container.bind<CrossServiceTokenCacheInterface>(TYPES.CrossServiceTokenCache).to(RedisCrossServiceTokenCache)
     }
+    container
+      .bind<EndpointResolverInterface>(TYPES.EndpointResolver)
+      .toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
 
     return container
   }

+ 37 - 0
packages/api-gateway/src/Bootstrap/Service.ts

@@ -0,0 +1,37 @@
+import {
+  ControllerContainerInterface,
+  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)
+  }
+
+  async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise<unknown> {
+    const method = this.controllerContainer.get(endpointOrMethodIdentifier)
+
+    if (!method) {
+      throw new Error(`Method ${endpointOrMethodIdentifier} not found`)
+    }
+
+    return method(request, response)
+  }
+
+  async getContainer(): Promise<unknown> {
+    const config = new ContainerConfigLoader()
+
+    return config.load(this.serviceContainer)
+  }
+
+  getId(): ServiceIdentifier {
+    return ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue()
+  }
+}

+ 2 - 1
packages/api-gateway/src/Bootstrap/Types.ts

@@ -19,9 +19,10 @@ export const TYPES = {
   WebSocketAuthMiddleware: Symbol.for('WebSocketAuthMiddleware'),
   SubscriptionTokenAuthMiddleware: Symbol.for('SubscriptionTokenAuthMiddleware'),
   // Services
-  HTTPService: Symbol.for('HTTPService'),
+  ServiceProxy: Symbol.for('ServiceProxy'),
   CrossServiceTokenCache: Symbol.for('CrossServiceTokenCache'),
   Timer: Symbol.for('Timer'),
+  EndpointResolver: Symbol.for('EndpointResolver'),
 }
 
 // export default TYPES

+ 1 - 1
packages/api-gateway/src/Bootstrap/index.ts

@@ -1,3 +1,3 @@
 export * from './Container'
-export * from './Env'
+export * from './Service'
 export * from './Types'

+ 2 - 2
packages/api-gateway/src/Controller/LegacyController.ts

@@ -2,14 +2,14 @@ import { Request, Response } from 'express'
 import { inject } from 'inversify'
 import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDelete } from 'inversify-express-utils'
 import { TYPES } from '../Bootstrap/Types'
-import { HttpServiceInterface } from '../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
 
 @controller('')
 export class LegacyController extends BaseHttpController {
   private AUTH_ROUTES: Map<string, string>
   private PARAMETRIZED_AUTH_ROUTES: Map<string, string>
 
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
     super()
 
     this.AUTH_ROUTES = new Map([

+ 43 - 14
packages/api-gateway/src/Controller/v1/ActionsController.ts

@@ -2,37 +2,51 @@ import { Request, Response } from 'express'
 import { inject } from 'inversify'
 import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1')
 export class ActionsController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private serviceProxy: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/login')
   async login(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/sign_in', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/sign_in'),
+      request.body,
+    )
   }
 
   @httpGet('/login-params')
   async loginParams(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/params', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'auth/params'),
+      request.body,
+    )
   }
 
   @httpPost('/logout')
   async logout(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/sign_out', request.body)
-  }
-
-  @httpGet('/auth/methods')
-  async methods(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/methods', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/sign_out'),
+      request.body,
+    )
   }
 
   @httpGet('/unsubscribe/:token')
   async emailUnsubscribe(request: Request, response: Response): Promise<void> {
-    await this.httpService.callEmailServer(
+    await this.serviceProxy.callEmailServer(
       request,
       response,
       `subscriptions/actions/unsubscribe/${request.params.token}`,
@@ -42,16 +56,31 @@ export class ActionsController extends BaseHttpController {
 
   @httpPost('/recovery/codes', TYPES.AuthMiddleware)
   async recoveryCodes(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/recovery/codes', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/recovery/codes'),
+      request.body,
+    )
   }
 
   @httpPost('/recovery/login')
   async recoveryLogin(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/recovery/login', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/recovery/login'),
+      request.body,
+    )
   }
 
   @httpPost('/recovery/login-params')
   async recoveryParams(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/recovery/params', request.body)
+    await this.serviceProxy.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/recovery/params'),
+      request.body,
+    )
   }
 }

+ 25 - 7
packages/api-gateway/src/Controller/v1/AuthenticatorsController.ts

@@ -3,11 +3,15 @@ import { Request, Response } from 'express'
 import { controller, BaseHttpController, httpPost, httpGet, httpDelete } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/authenticators')
 export class AuthenticatorsController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
@@ -16,14 +20,23 @@ export class AuthenticatorsController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `authenticators/${request.params.authenticatorId}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'DELETE',
+        'authenticators/:authenticatorId',
+        request.params.authenticatorId,
+      ),
       request.body,
     )
   }
 
   @httpGet('/', TYPES.AuthMiddleware)
   async list(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'authenticators/', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'authenticators/'),
+      request.body,
+    )
   }
 
   @httpGet('/generate-registration-options', TYPES.AuthMiddleware)
@@ -31,7 +44,7 @@ export class AuthenticatorsController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      'authenticators/generate-registration-options',
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'authenticators/generate-registration-options'),
       request.body,
     )
   }
@@ -41,13 +54,18 @@ export class AuthenticatorsController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      'authenticators/generate-authentication-options',
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'authenticators/generate-authentication-options'),
       request.body,
     )
   }
 
   @httpPost('/verify-registration', TYPES.AuthMiddleware)
   async verifyRegistration(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'authenticators/verify-registration', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'authenticators/verify-registration'),
+      request.body,
+    )
   }
 }

+ 12 - 3
packages/api-gateway/src/Controller/v1/FilesController.ts

@@ -3,16 +3,25 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/files')
 export class FilesController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/valet-tokens', TYPES.AuthMiddleware)
   async createToken(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'valet-tokens', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'valet-tokens'),
+      request.body,
+    )
   }
 }

+ 2 - 2
packages/api-gateway/src/Controller/v1/InvoicesController.ts

@@ -2,11 +2,11 @@ import { Request, Response } from 'express'
 import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
 import { inject } from 'inversify'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
 
 @controller('/v1')
 export class InvoicesController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
     super()
   }
 

+ 24 - 5
packages/api-gateway/src/Controller/v1/ItemsController.ts

@@ -2,26 +2,45 @@ import { Request, Response } from 'express'
 import { inject } from 'inversify'
 import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/items', TYPES.AuthMiddleware)
 export class ItemsController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/')
   async sync(request: Request, response: Response): Promise<void> {
-    await this.httpService.callSyncingServer(request, response, 'items/sync', request.body)
+    await this.httpService.callSyncingServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'items/sync'),
+      request.body,
+    )
   }
 
   @httpPost('/check-integrity')
   async checkIntegrity(request: Request, response: Response): Promise<void> {
-    await this.httpService.callSyncingServer(request, response, 'items/check-integrity', request.body)
+    await this.httpService.callSyncingServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'items/check-integrity'),
+      request.body,
+    )
   }
 
   @httpGet('/:uuid')
   async getItem(request: Request, response: Response): Promise<void> {
-    await this.httpService.callSyncingServer(request, response, `items/${request.params.uuid}`, request.body)
+    await this.httpService.callSyncingServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'items/:uuid', request.params.uuid),
+      request.body,
+    )
   }
 }

+ 18 - 4
packages/api-gateway/src/Controller/v1/OfflineController.ts

@@ -3,22 +3,36 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/offline')
 export class OfflineController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpGet('/features')
   async getOfflineFeatures(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'offline/features', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'offline/features'),
+      request.body,
+    )
   }
 
   @httpPost('/subscription-tokens')
   async createOfflineSubscriptionToken(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'offline/subscription-tokens', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'offline/subscription-tokens'),
+      request.body,
+    )
   }
 
   @httpPost('/payments/stripe-setup-intent')

+ 2 - 2
packages/api-gateway/src/Controller/v1/PaymentsController.ts

@@ -2,11 +2,11 @@ import { Request, Response } from 'express'
 import { inject } from 'inversify'
 import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
 
 @controller('/v1')
 export class PaymentsController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
     super()
   }
 

+ 30 - 8
packages/api-gateway/src/Controller/v1/SessionsController.ts

@@ -2,33 +2,55 @@ import { Request, Response } from 'express'
 import { inject } from 'inversify'
 import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/sessions')
 export class SessionsController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpGet('/', TYPES.AuthMiddleware)
   async getSessions(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'sessions')
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'sessions'),
+    )
   }
 
   @httpDelete('/:uuid', TYPES.AuthMiddleware)
   async deleteSession(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'session', {
-      uuid: request.params.uuid,
-    })
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'session'),
+      {
+        uuid: request.params.uuid,
+      },
+    )
   }
 
   @httpDelete('/', TYPES.AuthMiddleware)
   async deleteSessions(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'session/all')
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'session/all'),
+    )
   }
 
   @httpPost('/refresh')
   async refreshSession(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'session/refresh', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'session/refresh'),
+      request.body,
+    )
   }
 }

+ 36 - 6
packages/api-gateway/src/Controller/v1/SubscriptionInvitesController.ts

@@ -3,31 +3,61 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/subscription-invites')
 export class SubscriptionInvitesController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/', TYPES.AuthMiddleware)
   async inviteToSubscriptionSharing(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'subscription-invites', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'subscription-invites'),
+      request.body,
+    )
   }
 
   @httpGet('/', TYPES.AuthMiddleware)
   async listInvites(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'subscription-invites', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'subscription-invites'),
+      request.body,
+    )
   }
 
   @httpDelete('/:inviteUuid', TYPES.AuthMiddleware)
   async cancelSubscriptionSharing(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `subscription-invites/${request.params.inviteUuid}`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'DELETE',
+        'subscription-invites/:inviteUuid',
+        request.params.inviteUuid,
+      ),
+    )
   }
 
   @httpPost('/:inviteUuid/accept', TYPES.AuthMiddleware)
   async acceptInvite(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `subscription-invites/${request.params.inviteUuid}/accept`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'POST',
+        'subscription-invites/:inviteUuid/accept',
+        request.params.inviteUuid,
+      ),
+    )
   }
 }

+ 12 - 3
packages/api-gateway/src/Controller/v1/TokensController.ts

@@ -3,16 +3,25 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/subscription-tokens')
 export class TokensController extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/', TYPES.AuthMiddleware)
   async createToken(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'subscription-tokens', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'subscription-tokens'),
+      request.body,
+    )
   }
 }

+ 116 - 18
packages/api-gateway/src/Controller/v1/UsersController.ts

@@ -13,13 +13,15 @@ import {
 } from 'inversify-express-utils'
 import { Logger } from 'winston'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
 import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/users')
 export class UsersController extends BaseHttpController {
   constructor(
-    @inject(TYPES.HTTPService) private httpService: HttpServiceInterface,
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {
     super()
@@ -37,7 +39,12 @@ export class UsersController extends BaseHttpController {
 
   @httpPatch('/:userId', TYPES.AuthMiddleware)
   async updateUser(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userId}`, request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('PATCH', 'users/:userId', request.params.userId),
+      request.body,
+    )
   }
 
   @httpPut('/:userUuid/password', TYPES.AuthMiddleware)
@@ -49,7 +56,11 @@ export class UsersController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `users/${request.params.userUuid}/attributes/credentials`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'PUT',
+        'users/:userUuid/attributes/credentials',
+        request.params.userUuid,
+      ),
       request.body,
     )
   }
@@ -59,14 +70,22 @@ export class UsersController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `users/${request.params.userUuid}/attributes/credentials`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'PUT',
+        'users/:userUuid/attributes/credentials',
+        request.params.userUuid,
+      ),
       request.body,
     )
   }
 
   @httpGet('/:userId/params', TYPES.AuthMiddleware)
   async getKeyParams(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/params')
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'auth/params'),
+    )
   }
 
   @all('/:userId/mfa', TYPES.AuthMiddleware)
@@ -76,22 +95,49 @@ export class UsersController extends BaseHttpController {
 
   @httpPost('/:userUuid/integrations/listed', TYPES.AuthMiddleware)
   async createListedAccount(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'listed', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'listed'),
+      request.body,
+    )
   }
 
   @httpPost('/')
   async register(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth'),
+      request.body,
+    )
   }
 
   @httpGet('/:userUuid/settings', TYPES.AuthMiddleware)
   async listSettings(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/settings`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/settings',
+        request.params.userUuid,
+      ),
+    )
   }
 
   @httpPut('/:userUuid/settings', TYPES.AuthMiddleware)
   async putSetting(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/settings`, request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'PUT',
+        'users/:userUuid/settings',
+        request.params.userUuid,
+      ),
+      request.body,
+    )
   }
 
   @httpGet('/:userUuid/settings/:settingName', TYPES.AuthMiddleware)
@@ -99,7 +145,12 @@ export class UsersController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `users/${request.params.userUuid}/settings/${request.params.settingName}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/settings/:settingName',
+        request.params.userUuid,
+        request.params.settingName,
+      ),
     )
   }
 
@@ -108,7 +159,12 @@ export class UsersController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `users/${request.params.userUuid}/settings/${request.params.settingName}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'DELETE',
+        'users/:userUuid/settings/:settingName',
+        request.params.userUuid,
+        request.params.settingName,
+      ),
       request.body,
     )
   }
@@ -118,29 +174,62 @@ export class UsersController extends BaseHttpController {
     await this.httpService.callAuthServer(
       request,
       response,
-      `users/${request.params.userUuid}/subscription-settings/${request.params.subscriptionSettingName}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/subscription-settings/:subscriptionSettingName',
+        request.params.userUuid,
+        request.params.subscriptionSettingName,
+      ),
     )
   }
 
   @httpGet('/:userUuid/features', TYPES.AuthMiddleware)
   async getFeatures(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/features`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/features',
+        request.params.userUuid,
+      ),
+    )
   }
 
   @httpGet('/:userUuid/subscription', TYPES.AuthMiddleware)
   async getSubscription(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/subscription`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/subscription',
+        request.params.userUuid,
+      ),
+    )
   }
 
   @httpGet('/subscription', TYPES.SubscriptionTokenAuthMiddleware)
   async getSubscriptionBySubscriptionToken(request: Request, response: Response): Promise<void> {
     if (response.locals.tokenAuthenticationMethod === TokenAuthenticationMethod.OfflineSubscriptionToken) {
-      await this.httpService.callAuthServer(request, response, 'offline/users/subscription')
+      await this.httpService.callAuthServer(
+        request,
+        response,
+        this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'offline/users/subscription'),
+      )
 
       return
     }
 
-    await this.httpService.callAuthServer(request, response, `users/${response.locals.userUuid}/subscription`)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'users/:userUuid/subscription',
+        response.locals.userUuid,
+      ),
+    )
   }
 
   @httpDelete('/:userUuid', TYPES.AuthMiddleware)
@@ -150,6 +239,15 @@ export class UsersController extends BaseHttpController {
 
   @httpPost('/:userUuid/requests', TYPES.AuthMiddleware)
   async submitRequest(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, `users/${request.params.userUuid}/requests`, request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'POST',
+        'users/:userUuid/requests',
+        request.params.userUuid,
+      ),
+      request.body,
+    )
   }
 }

+ 20 - 5
packages/api-gateway/src/Controller/v1/WebSocketsController.ts

@@ -4,12 +4,14 @@ import { BaseHttpController, controller, httpDelete, httpPost } from 'inversify-
 import { Logger } from 'winston'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v1/sockets')
 export class WebSocketsController extends BaseHttpController {
   constructor(
-    @inject(TYPES.HTTPService) private httpService: HttpServiceInterface,
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
     @inject(TYPES.Logger) private logger: Logger,
   ) {
     super()
@@ -17,7 +19,12 @@ export class WebSocketsController extends BaseHttpController {
 
   @httpPost('/tokens', TYPES.AuthMiddleware)
   async createWebSocketConnectionToken(request: Request, response: Response): Promise<void> {
-    await this.httpService.callWebSocketServer(request, response, 'sockets/tokens', request.body)
+    await this.httpService.callWebSocketServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'sockets/tokens'),
+      request.body,
+    )
   }
 
   @httpPost('/connections', TYPES.WebSocketAuthMiddleware)
@@ -33,7 +40,11 @@ export class WebSocketsController extends BaseHttpController {
     await this.httpService.callWebSocketServer(
       request,
       response,
-      `sockets/connections/${request.headers.connectionid}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'POST',
+        'sockets/connections/:connectionId',
+        request.headers.connectionid as string,
+      ),
       request.body,
     )
   }
@@ -51,7 +62,11 @@ export class WebSocketsController extends BaseHttpController {
     await this.httpService.callWebSocketServer(
       request,
       response,
-      `sockets/connections/${request.headers.connectionid}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'DELETE',
+        'sockets/connections/:connectionId',
+        request.headers.connectionid as string,
+      ),
       request.body,
     )
   }

+ 18 - 4
packages/api-gateway/src/Controller/v2/ActionsControllerV2.ts

@@ -3,21 +3,35 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v2')
 export class ActionsControllerV2 extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpPost('/login')
   async login(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/pkce_sign_in', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/pkce_sign_in'),
+      request.body,
+    )
   }
 
   @httpPost('/login-params')
   async loginParams(request: Request, response: Response): Promise<void> {
-    await this.httpService.callAuthServer(request, response, 'auth/pkce_params', request.body)
+    await this.httpService.callAuthServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/pkce_params'),
+      request.body,
+    )
   }
 }

+ 2 - 2
packages/api-gateway/src/Controller/v2/PaymentsControllerV2.ts

@@ -2,11 +2,11 @@ import { Request, Response } from 'express'
 import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
 import { inject } from 'inversify'
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
 
 @controller('/v2')
 export class PaymentsControllerV2 extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
     super()
   }
 

+ 27 - 5
packages/api-gateway/src/Controller/v2/RevisionsControllerV2.ts

@@ -3,17 +3,29 @@ import { inject } from 'inversify'
 import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
 
 import { TYPES } from '../../Bootstrap/Types'
-import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
+import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
+import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
 
 @controller('/v2/items/:itemUuid/revisions', TYPES.AuthMiddleware)
 export class RevisionsControllerV2 extends BaseHttpController {
-  constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
+  constructor(
+    @inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
+    @inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
+  ) {
     super()
   }
 
   @httpGet('/')
   async getRevisions(request: Request, response: Response): Promise<void> {
-    await this.httpService.callRevisionsServer(request, response, `items/${request.params.itemUuid}/revisions`)
+    await this.httpService.callRevisionsServer(
+      request,
+      response,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'items/:itemUuid/revisions',
+        request.params.itemUuid,
+      ),
+    )
   }
 
   @httpGet('/:id')
@@ -21,7 +33,12 @@ export class RevisionsControllerV2 extends BaseHttpController {
     await this.httpService.callRevisionsServer(
       request,
       response,
-      `items/${request.params.itemUuid}/revisions/${request.params.id}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'GET',
+        'items/:itemUuid/revisions/:id',
+        request.params.itemUuid,
+        request.params.id,
+      ),
     )
   }
 
@@ -30,7 +47,12 @@ export class RevisionsControllerV2 extends BaseHttpController {
     await this.httpService.callRevisionsServer(
       request,
       response,
-      `items/${request.params.itemUuid}/revisions/${request.params.id}`,
+      this.endpointResolver.resolveEndpointOrMethodIdentifier(
+        'DELETE',
+        'items/:itemUuid/revisions/:id',
+        request.params.itemUuid,
+        request.params.id,
+      ),
     )
   }
 }

+ 0 - 2
packages/api-gateway/src/Infra/index.ts

@@ -1,2 +0,0 @@
-export * from './InMemory/InMemoryCrossServiceTokenCache'
-export * from './Redis/RedisCrossServiceTokenCache'

+ 52 - 26
packages/api-gateway/src/Service/Http/HttpService.ts → packages/api-gateway/src/Service/Http/HttpServiceProxy.ts

@@ -6,10 +6,10 @@ import { Logger } from 'winston'
 
 import { TYPES } from '../../Bootstrap/Types'
 import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
-import { HttpServiceInterface } from './HttpServiceInterface'
+import { ServiceProxyInterface } from './ServiceProxyInterface'
 
 @injectable()
-export class HttpService implements HttpServiceInterface {
+export class HttpServiceProxy implements ServiceProxyInterface {
   constructor(
     @inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
     @inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
@@ -27,16 +27,16 @@ export class HttpService implements HttpServiceInterface {
   async callSyncingServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    await this.callServer(this.syncingServerJsUrl, request, response, endpoint, payload)
+    await this.callServer(this.syncingServerJsUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   async callRevisionsServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
     if (!this.revisionsServerUrl) {
@@ -44,31 +44,37 @@ export class HttpService implements HttpServiceInterface {
 
       return
     }
-    await this.callServer(this.revisionsServerUrl, request, response, endpoint, payload)
+    await this.callServer(this.revisionsServerUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   async callLegacySyncingServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    await this.callServerWithLegacyFormat(this.syncingServerJsUrl, request, response, endpoint, payload)
+    await this.callServerWithLegacyFormat(
+      this.syncingServerJsUrl,
+      request,
+      response,
+      endpointOrMethodIdentifier,
+      payload,
+    )
   }
 
   async callAuthServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    await this.callServer(this.authServerUrl, request, response, endpoint, payload)
+    await this.callServer(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   async callEmailServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
     if (!this.emailServerUrl) {
@@ -77,13 +83,13 @@ export class HttpService implements HttpServiceInterface {
       return
     }
 
-    await this.callServer(this.emailServerUrl, request, response, endpoint, payload)
+    await this.callServer(this.emailServerUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   async callWebSocketServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
     if (!this.webSocketServerUrl) {
@@ -92,13 +98,13 @@ export class HttpService implements HttpServiceInterface {
       return
     }
 
-    await this.callServer(this.webSocketServerUrl, request, response, endpoint, payload)
+    await this.callServer(this.webSocketServerUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   async callPaymentsServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
     if (!this.paymentsServerUrl) {
@@ -106,23 +112,29 @@ export class HttpService implements HttpServiceInterface {
 
       return
     }
-    await this.callServerWithLegacyFormat(this.paymentsServerUrl, request, response, endpoint, payload)
+    await this.callServerWithLegacyFormat(
+      this.paymentsServerUrl,
+      request,
+      response,
+      endpointOrMethodIdentifier,
+      payload,
+    )
   }
 
   async callAuthServerWithLegacyFormat(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpoint, payload)
+    await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
   }
 
   private async getServerResponse(
     serverUrl: string,
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<AxiosResponse | undefined> {
     try {
@@ -142,7 +154,7 @@ export class HttpService implements HttpServiceInterface {
         headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
       }
 
-      this.logger.debug(`Calling [${request.method}] ${serverUrl}/${endpoint},
+      this.logger.debug(`Calling [${request.method}] ${serverUrl}/${endpointOrMethodIdentifier},
         headers: ${JSON.stringify(headers)},
         query: ${JSON.stringify(request.query)},
         payload: ${JSON.stringify(payload)}`)
@@ -150,7 +162,7 @@ export class HttpService implements HttpServiceInterface {
       const serviceResponse = await this.httpClient.request({
         method: request.method as Method,
         headers,
-        url: `${serverUrl}/${endpoint}`,
+        url: `${serverUrl}/${endpointOrMethodIdentifier}`,
         data: this.getRequestData(payload),
         maxContentLength: Infinity,
         maxBodyLength: Infinity,
@@ -172,7 +184,9 @@ export class HttpService implements HttpServiceInterface {
         ? JSON.stringify((error as AxiosError).response?.data)
         : (error as Error).message
 
-      this.logger.error(`Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${errorMessage}`)
+      this.logger.error(
+        `Could not pass the request to ${serverUrl}/${endpointOrMethodIdentifier} on underlying service: ${errorMessage}`,
+      )
 
       this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
 
@@ -195,10 +209,16 @@ export class HttpService implements HttpServiceInterface {
     serverUrl: string,
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
+    const serviceResponse = await this.getServerResponse(
+      serverUrl,
+      request,
+      response,
+      endpointOrMethodIdentifier,
+      payload,
+    )
 
     this.logger.debug(`Response from underlying server: ${JSON.stringify(serviceResponse?.data)},
       headers: ${JSON.stringify(serviceResponse?.headers)}`)
@@ -233,10 +253,16 @@ export class HttpService implements HttpServiceInterface {
     serverUrl: string,
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
+    const serviceResponse = await this.getServerResponse(
+      serverUrl,
+      request,
+      response,
+      endpointOrMethodIdentifier,
+      payload,
+    )
 
     if (!serviceResponse) {
       return

+ 9 - 9
packages/api-gateway/src/Service/Http/HttpServiceInterface.ts → packages/api-gateway/src/Service/Http/ServiceProxyInterface.ts

@@ -1,52 +1,52 @@
 import { Request, Response } from 'express'
 
-export interface HttpServiceInterface {
+export interface ServiceProxyInterface {
   callEmailServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callAuthServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callAuthServerWithLegacyFormat(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callRevisionsServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callSyncingServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callLegacySyncingServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callPaymentsServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
   callWebSocketServer(
     request: Request,
     response: Response,
-    endpoint: string,
+    endpointOrMethodIdentifier: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void>
 }

+ 74 - 0
packages/api-gateway/src/Service/Proxy/DirectCallServiceProxy.ts

@@ -0,0 +1,74 @@
+import { Request, Response } from 'express'
+
+import { ServiceProxyInterface } from '../Http/ServiceProxyInterface'
+import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
+
+export class DirectCallServiceProxy implements ServiceProxyInterface {
+  constructor(private serviceContainer: ServiceContainerInterface) {}
+
+  async callEmailServer(_request: Request, _response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
+    throw new Error('Email server is not available.')
+  }
+
+  async callAuthServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
+    const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
+    if (!authService) {
+      throw new Error('Auth service not found')
+    }
+
+    const serviceResponse = (await authService.handleRequest(request, response, endpointOrMethodIdentifier)) as {
+      statusCode: number
+      json: Record<string, unknown>
+    }
+
+    void (response as Response).status(serviceResponse.statusCode).send(serviceResponse.json)
+  }
+
+  async callAuthServerWithLegacyFormat(
+    _request: Request,
+    _response: Response,
+    _endpointOrMethodIdentifier: string,
+  ): Promise<void> {
+    throw new Error('Legacy auth endpoints are no longer available.')
+  }
+
+  async callRevisionsServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
+    const service = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Revisions).getValue())
+    if (!service) {
+      throw new Error('Revisions service not found')
+    }
+
+    await service.handleRequest(request, response, endpointOrMethodIdentifier)
+  }
+
+  async callSyncingServer(request: never, response: never, endpointOrMethodIdentifier: string): Promise<void> {
+    const service = this.serviceContainer.get(
+      ServiceIdentifier.create(ServiceIdentifier.NAMES.SyncingServer).getValue(),
+    )
+    if (!service) {
+      throw new Error('Syncing service not found')
+    }
+
+    await service.handleRequest(request, response, endpointOrMethodIdentifier)
+  }
+
+  async callLegacySyncingServer(
+    _request: Request,
+    _response: Response,
+    _endpointOrMethodIdentifier: string,
+  ): Promise<void> {
+    throw new Error('Legacy syncing server endpoints are no longer available.')
+  }
+
+  async callPaymentsServer(_request: Request, _response: Response, _endpointOrMethodIdentifier: string): Promise<void> {
+    throw new Error('Payments server is not available.')
+  }
+
+  async callWebSocketServer(
+    _request: Request,
+    _response: Response,
+    _endpointOrMethodIdentifier: string,
+  ): Promise<void> {
+    throw new Error('Websockets server is not available.')
+  }
+}

+ 70 - 0
packages/api-gateway/src/Service/Resolver/EndpointResolver.ts

@@ -0,0 +1,70 @@
+import { EndpointResolverInterface } from './EndpointResolverInterface'
+
+export class EndpointResolver implements EndpointResolverInterface {
+  constructor(private isConfiguredForHomeServer: boolean) {}
+
+  private readonly endpointToIdentifierMap: Map<string, string> = new Map([
+    // Actions Controller
+    ['[POST]:auth/sign_in', 'auth.signIn'],
+    ['[GET]:auth/params', 'auth.params'],
+    ['[POST]:auth/sign_out', 'auth.signOut'],
+    ['[POST]:auth/recovery/codes', 'auth.generateRecoveryCodes'],
+    ['[POST]:auth/recovery/login', 'auth.signInWithRecoveryCodes'],
+    ['[POST]:auth/recovery/params', 'auth.recoveryKeyParams'],
+    // Authenticators Controller
+    ['[DELETE]:authenticators/:authenticatorId', 'auth.authenticators.delete'],
+    ['[GET]:authenticators/', 'auth.authenticators.list'],
+    ['[GET]:authenticators/generate-registration-options', 'auth.authenticators.generateRegistrationOptions'],
+    ['[POST]:authenticators/generate-authentication-options', 'auth.authenticators.generateAuthenticationOptions'],
+    ['[POST]:authenticators/verify-registration', 'auth.authenticators.verifyRegistrationResponse'],
+    // Files Controller
+    ['[POST]:valet-tokens', 'auth.valet-tokens.create'],
+    // Offline Controller
+    ['[GET]:offline/features', 'auth.offline.features'],
+    ['[POST]:offline/subscription-tokens', 'auth.offline.subscriptionTokens.create'],
+    // Sessions Controller
+    ['[GET]:sessions', 'auth.sessions.list'],
+    ['[DELETE]:session', 'auth.sessions.delete'],
+    ['[DELETE]:session/all', 'auth.sessions.deleteAll'],
+    ['[POST]:session/refresh', 'auth.sessions.refresh'],
+    // Subscription Invites Controller
+    ['[POST]:subscription-invites', 'auth.subscriptionInvites.create'],
+    ['[GET]:subscription-invites', 'auth.subscriptionInvites.list'],
+    ['[DELETE]:subscription-invites/:inviteUuid', 'auth.subscriptionInvites.delete'],
+    ['[POST]:subscription-invites/:inviteUuid/accept', 'auth.subscriptionInvites.accept'],
+    // Tokens Controller
+    ['[POST]:subscription-tokens', 'auth.subscription-tokens.create'],
+    // Users Controller
+    ['[PATCH]:users/:userId', 'auth.users.update'],
+    ['[PUT]:users/:userUuid/attributes/credentials', 'auth.users.updateCredentials'],
+    ['[PUT]:auth/params', 'auth.users.getKeyParams'],
+    ['[POST]:listed', 'auth.users.createListedAccount'],
+    ['[POST]:auth', 'auth.users.register'],
+    ['[GET]:users/:userUuid/settings', 'auth.users.getSettings'],
+    ['[PUT]:users/:userUuid/settings', 'auth.users.updateSetting'],
+    ['[GET]:users/:userUuid/settings/:settingName', 'auth.users.getSetting'],
+    ['[DELETE]:users/:userUuid/settings/:settingName', 'auth.users.deleteSetting'],
+    ['[GET]:users/:userUuid/subscription-settings/:subscriptionSettingName', 'auth.users.getSubscriptionSetting'],
+    ['[GET]:users/:userUuid/features', 'auth.users.getFeatures'],
+    ['[GET]:users/:userUuid/subscription', 'auth.users.getSubscription'],
+    ['[GET]:offline/users/subscription', 'auth.users.getOfflineSubscriptionByToken'],
+    ['[POST]:users/:userUuid/requests', 'auth.users.createRequest'],
+  ])
+
+  resolveEndpointOrMethodIdentifier(method: string, endpoint: string, ...params: string[]): string {
+    if (!this.isConfiguredForHomeServer) {
+      if (params.length > 0) {
+        return params.reduce((acc, param) => acc.replace(/:[a-zA-Z0-9]+/, param), endpoint)
+      }
+
+      return endpoint
+    }
+    const identifier = this.endpointToIdentifierMap.get(`[${method}]:${endpoint}`)
+
+    if (!identifier) {
+      throw new Error(`Endpoint ${endpoint} not found`)
+    }
+
+    return identifier
+  }
+}

+ 3 - 0
packages/api-gateway/src/Service/Resolver/EndpointResolverInterface.ts

@@ -0,0 +1,3 @@
+export interface EndpointResolverInterface {
+  resolveEndpointOrMethodIdentifier(method: string, endpoint: string, ...params: string[]): string
+}

+ 0 - 3
packages/api-gateway/src/Service/index.ts

@@ -1,3 +0,0 @@
-export * from './Cache/CrossServiceTokenCacheInterface'
-export * from './Http/HttpService'
-export * from './Http/HttpServiceInterface'

+ 0 - 2
packages/api-gateway/src/index.ts

@@ -1,4 +1,2 @@
 export * from './Bootstrap'
 export * from './Controller'
-export * from './Infra'
-export * from './Service'

+ 5 - 5
packages/auth/bin/backup.ts

@@ -84,14 +84,14 @@ 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.Auth_Logger)
 
   logger.info(`Starting ${backupFrequency} ${backupProvider} backup requesting...`)
 
-  const settingRepository: SettingRepositoryInterface = container.get(TYPES.SettingRepository)
-  const roleService: RoleServiceInterface = container.get(TYPES.RoleService)
-  const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
-  const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
+  const settingRepository: SettingRepositoryInterface = container.get(TYPES.Auth_SettingRepository)
+  const roleService: RoleServiceInterface = container.get(TYPES.Auth_RoleService)
+  const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
+  const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
 
   Promise.resolve(requestBackups(settingRepository, roleService, domainEventFactory, domainEventPublisher))
     .then(() => {

+ 3 - 3
packages/auth/bin/cleanup.ts

@@ -25,12 +25,12 @@ 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.Auth_Logger)
 
   logger.info('Starting sessions and session traces cleanup')
 
-  const cleanupSessionTraces: CleanupSessionTraces = container.get(TYPES.CleanupSessionTraces)
-  const cleanupExpiredSessions: CleanupExpiredSessions = container.get(TYPES.CleanupExpiredSessions)
+  const cleanupSessionTraces: CleanupSessionTraces = container.get(TYPES.Auth_CleanupSessionTraces)
+  const cleanupExpiredSessions: CleanupExpiredSessions = container.get(TYPES.Auth_CleanupExpiredSessions)
 
   Promise.resolve(cleanup(cleanupSessionTraces, cleanupExpiredSessions))
     .then(() => {

+ 2 - 2
packages/auth/bin/server.ts

@@ -44,7 +44,7 @@ void container.load().then((container) => {
 
   server.setConfig((app) => {
     app.use((_request: Request, response: Response, next: NextFunction) => {
-      response.setHeader('X-Auth-Version', container.get(TYPES.VERSION))
+      response.setHeader('X-Auth-Version', container.get(TYPES.Auth_VERSION))
       next()
     })
     app.use(json())
@@ -52,7 +52,7 @@ void container.load().then((container) => {
     app.use(cors())
   })
 
-  const logger: winston.Logger = container.get(TYPES.Logger)
+  const logger: winston.Logger = container.get(TYPES.Auth_Logger)
 
   server.setErrorConfig((app) => {
     app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {

+ 3 - 3
packages/auth/bin/stats.ts

@@ -15,12 +15,12 @@ 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.Auth_Logger)
 
   logger.info('Starting session traces cleanup')
 
-  const persistStats: PersistStatistics = container.get(TYPES.PersistStatistics)
-  const timer: TimerInterface = container.get(TYPES.Timer)
+  const persistStats: PersistStatistics = container.get(TYPES.Auth_PersistStatistics)
+  const timer: TimerInterface = container.get(TYPES.Auth_Timer)
 
   Promise.resolve(
     persistStats.execute({

+ 6 - 6
packages/auth/bin/user_email_backup.ts

@@ -72,15 +72,15 @@ 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.Auth_Logger)
 
   logger.info(`Starting email backup requesting for ${backupEmail} ...`)
 
-  const settingRepository: SettingRepositoryInterface = container.get(TYPES.SettingRepository)
-  const userRepository: UserRepositoryInterface = container.get(TYPES.UserRepository)
-  const roleService: RoleServiceInterface = container.get(TYPES.RoleService)
-  const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
-  const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
+  const settingRepository: SettingRepositoryInterface = container.get(TYPES.Auth_SettingRepository)
+  const userRepository: UserRepositoryInterface = container.get(TYPES.Auth_UserRepository)
+  const roleService: RoleServiceInterface = container.get(TYPES.Auth_RoleService)
+  const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
+  const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
 
   Promise.resolve(
     requestBackups(userRepository, settingRepository, roleService, domainEventFactory, domainEventPublisher),

+ 4 - 2
packages/auth/bin/worker.ts

@@ -18,11 +18,13 @@ 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.Auth_Logger)
 
   logger.info('Starting worker...')
 
-  const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(TYPES.DomainEventSubscriberFactory)
+  const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(
+    TYPES.Auth_DomainEventSubscriberFactory,
+  )
   subscriberFactory.create().start()
 
   setInterval(() => logger.info('Alive and kicking!'), 20 * 60 * 1000)

+ 1 - 0
packages/auth/package.json

@@ -15,6 +15,7 @@
     "setup:env": "cp .env.sample .env",
     "build": "tsc --build",
     "lint": "eslint . --ext .ts",
+    "lint:fix": "eslint . --fix --ext .ts",
     "pretest": "yarn lint && yarn build",
     "test": "jest --coverage --config=./jest.config.js --maxWorkers=50%",
     "start": "yarn node dist/bin/server.js",

+ 460 - 340
packages/auth/src/Bootstrap/Container.ts

@@ -187,7 +187,13 @@ import { UserRequestsController } from '../Controller/UserRequestsController'
 import { EmailSubscriptionUnsubscribedEventHandler } from '../Domain/Handler/EmailSubscriptionUnsubscribedEventHandler'
 import { SessionTraceRepositoryInterface } from '../Domain/Session/SessionTraceRepositoryInterface'
 import { TypeORMSessionTraceRepository } from '../Infra/TypeORM/TypeORMSessionTraceRepository'
-import { CacheEntry, CacheEntryRepositoryInterface, MapperInterface } from '@standardnotes/domain-core'
+import {
+  CacheEntry,
+  CacheEntryRepositoryInterface,
+  ControllerContainer,
+  ControllerContainerInterface,
+  MapperInterface,
+} from '@standardnotes/domain-core'
 import { SessionTracePersistenceMapper } from '../Mapping/SessionTracePersistenceMapper'
 import { SessionTrace } from '../Domain/Session/SessionTrace'
 import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
@@ -226,12 +232,17 @@ import { TypeORMEphemeralSessionRepository } from '../Infra/TypeORM/TypeORMEphem
 import { TypeORMOfflineSubscriptionTokenRepository } from '../Infra/TypeORM/TypeORMOfflineSubscriptionTokenRepository'
 import { TypeORMPKCERepository } from '../Infra/TypeORM/TypeORMPKCERepository'
 import { TypeORMSubscriptionTokenRepository } from '../Infra/TypeORM/TypeORMSubscriptionTokenRepository'
+import { InversifyExpressAuthController } from '../Infra/InversifyExpressUtils/InversifyExpressAuthController'
+import { InversifyExpressAuthenticatorsController } from '../Infra/InversifyExpressUtils/InversifyExpressAuthenticatorsController'
+import { InversifyExpressSubscriptionInvitesController } from '../Infra/InversifyExpressUtils/InversifyExpressSubscriptionInvitesController'
+import { InversifyExpressUserRequestsController } from '../Infra/InversifyExpressUtils/InversifyExpressUserRequestsController'
+import { InversifyExpressWebSocketsController } from '../Infra/InversifyExpressUtils/InversifyExpressWebSocketsController'
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const newrelicFormatter = require('@newrelic/winston-enricher')
 
 export class ContainerConfigLoader {
-  async load(): Promise<Container> {
+  async load(controllerConatiner?: ControllerContainerInterface): Promise<Container> {
     const env: Env = new Env()
     env.load()
 
@@ -241,16 +252,18 @@ export class ContainerConfigLoader {
 
     const isConfiguredForHomeServer = env.get('DB_TYPE') === 'sqlite'
 
-    const redisUrl = env.get('REDIS_URL')
-    const isRedisInClusterMode = redisUrl.indexOf(',') > 0
-    let redis
-    if (isRedisInClusterMode) {
-      redis = new Redis.Cluster(redisUrl.split(','))
-    } else {
-      redis = new Redis(redisUrl)
-    }
+    if (!isConfiguredForHomeServer) {
+      const redisUrl = env.get('REDIS_URL')
+      const isRedisInClusterMode = redisUrl.indexOf(',') > 0
+      let redis
+      if (isRedisInClusterMode) {
+        redis = new Redis.Cluster(redisUrl.split(','))
+      } else {
+        redis = new Redis(redisUrl)
+      }
 
-    container.bind(TYPES.Redis).toConstantValue(redis)
+      container.bind(TYPES.Auth_Redis).toConstantValue(redis)
+    }
 
     const newrelicWinstonFormatter = newrelicFormatter(winston)
     const winstonFormatters = [winston.format.splat(), winston.format.json()]
@@ -263,9 +276,9 @@ export class ContainerConfigLoader {
       format: winston.format.combine(...winstonFormatters),
       transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL') || 'info' })],
     })
-    container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
+    container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(logger)
 
-    container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
+    container.bind<TimerInterface>(TYPES.Auth_Timer).toConstantValue(new Timer())
 
     const snsConfig: SNSClientConfig = {
       region: env.get('SNS_AWS_REGION', true),
@@ -279,7 +292,7 @@ export class ContainerConfigLoader {
         secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true),
       }
     }
-    container.bind<SNSClient>(TYPES.SNS).toConstantValue(new SNSClient(snsConfig))
+    container.bind<SNSClient>(TYPES.Auth_SNS).toConstantValue(new SNSClient(snsConfig))
 
     const sqsConfig: SQSClientConfig = {
       region: env.get('SQS_AWS_REGION', true),
@@ -293,611 +306,718 @@ export class ContainerConfigLoader {
         secretAccessKey: env.get('SQS_SECRET_ACCESS_KEY', true),
       }
     }
-    container.bind<SQSClient>(TYPES.SQS).toConstantValue(new SQSClient(sqsConfig))
+    container.bind<SQSClient>(TYPES.Auth_SQS).toConstantValue(new SQSClient(sqsConfig))
 
     // Mapping
     container
-      .bind<MapperInterface<SessionTrace, TypeORMSessionTrace>>(TYPES.SessionTracePersistenceMapper)
+      .bind<MapperInterface<SessionTrace, TypeORMSessionTrace>>(TYPES.Auth_SessionTracePersistenceMapper)
       .toConstantValue(new SessionTracePersistenceMapper())
     container
-      .bind<MapperInterface<Authenticator, TypeORMAuthenticator>>(TYPES.AuthenticatorPersistenceMapper)
+      .bind<MapperInterface<Authenticator, TypeORMAuthenticator>>(TYPES.Auth_AuthenticatorPersistenceMapper)
       .toConstantValue(new AuthenticatorPersistenceMapper())
     container
-      .bind<MapperInterface<Authenticator, AuthenticatorHttpProjection>>(TYPES.AuthenticatorHttpMapper)
+      .bind<MapperInterface<Authenticator, AuthenticatorHttpProjection>>(TYPES.Auth_AuthenticatorHttpMapper)
       .toConstantValue(new AuthenticatorHttpMapper())
     container
       .bind<MapperInterface<AuthenticatorChallenge, TypeORMAuthenticatorChallenge>>(
-        TYPES.AuthenticatorChallengePersistenceMapper,
+        TYPES.Auth_AuthenticatorChallengePersistenceMapper,
       )
       .toConstantValue(new AuthenticatorChallengePersistenceMapper())
     container
-      .bind<MapperInterface<CacheEntry, TypeORMCacheEntry>>(TYPES.CacheEntryPersistenceMapper)
+      .bind<MapperInterface<CacheEntry, TypeORMCacheEntry>>(TYPES.Auth_CacheEntryPersistenceMapper)
       .toConstantValue(new CacheEntryPersistenceMapper())
 
     // ORM
     container
-      .bind<Repository<OfflineSetting>>(TYPES.ORMOfflineSettingRepository)
+      .bind<Repository<OfflineSetting>>(TYPES.Auth_ORMOfflineSettingRepository)
       .toConstantValue(AppDataSource.getRepository(OfflineSetting))
     container
-      .bind<Repository<OfflineUserSubscription>>(TYPES.ORMOfflineUserSubscriptionRepository)
+      .bind<Repository<OfflineUserSubscription>>(TYPES.Auth_ORMOfflineUserSubscriptionRepository)
       .toConstantValue(AppDataSource.getRepository(OfflineUserSubscription))
     container
-      .bind<Repository<RevokedSession>>(TYPES.ORMRevokedSessionRepository)
+      .bind<Repository<RevokedSession>>(TYPES.Auth_ORMRevokedSessionRepository)
       .toConstantValue(AppDataSource.getRepository(RevokedSession))
-    container.bind<Repository<Role>>(TYPES.ORMRoleRepository).toConstantValue(AppDataSource.getRepository(Role))
+    container.bind<Repository<Role>>(TYPES.Auth_ORMRoleRepository).toConstantValue(AppDataSource.getRepository(Role))
     container
-      .bind<Repository<Session>>(TYPES.ORMSessionRepository)
+      .bind<Repository<Session>>(TYPES.Auth_ORMSessionRepository)
       .toConstantValue(AppDataSource.getRepository(Session))
     container
-      .bind<Repository<Setting>>(TYPES.ORMSettingRepository)
+      .bind<Repository<Setting>>(TYPES.Auth_ORMSettingRepository)
       .toConstantValue(AppDataSource.getRepository(Setting))
     container
-      .bind<Repository<SharedSubscriptionInvitation>>(TYPES.ORMSharedSubscriptionInvitationRepository)
+      .bind<Repository<SharedSubscriptionInvitation>>(TYPES.Auth_ORMSharedSubscriptionInvitationRepository)
       .toConstantValue(AppDataSource.getRepository(SharedSubscriptionInvitation))
     container
-      .bind<Repository<SubscriptionSetting>>(TYPES.ORMSubscriptionSettingRepository)
+      .bind<Repository<SubscriptionSetting>>(TYPES.Auth_ORMSubscriptionSettingRepository)
       .toConstantValue(AppDataSource.getRepository(SubscriptionSetting))
-    container.bind<Repository<User>>(TYPES.ORMUserRepository).toConstantValue(AppDataSource.getRepository(User))
+    container.bind<Repository<User>>(TYPES.Auth_ORMUserRepository).toConstantValue(AppDataSource.getRepository(User))
     container
-      .bind<Repository<UserSubscription>>(TYPES.ORMUserSubscriptionRepository)
+      .bind<Repository<UserSubscription>>(TYPES.Auth_ORMUserSubscriptionRepository)
       .toConstantValue(AppDataSource.getRepository(UserSubscription))
     container
-      .bind<Repository<TypeORMSessionTrace>>(TYPES.ORMSessionTraceRepository)
+      .bind<Repository<TypeORMSessionTrace>>(TYPES.Auth_ORMSessionTraceRepository)
       .toConstantValue(AppDataSource.getRepository(TypeORMSessionTrace))
     container
-      .bind<Repository<TypeORMAuthenticator>>(TYPES.ORMAuthenticatorRepository)
+      .bind<Repository<TypeORMAuthenticator>>(TYPES.Auth_ORMAuthenticatorRepository)
       .toConstantValue(AppDataSource.getRepository(TypeORMAuthenticator))
     container
-      .bind<Repository<TypeORMAuthenticatorChallenge>>(TYPES.ORMAuthenticatorChallengeRepository)
+      .bind<Repository<TypeORMAuthenticatorChallenge>>(TYPES.Auth_ORMAuthenticatorChallengeRepository)
       .toConstantValue(AppDataSource.getRepository(TypeORMAuthenticatorChallenge))
     container
-      .bind<Repository<TypeORMCacheEntry>>(TYPES.ORMCacheEntryRepository)
+      .bind<Repository<TypeORMCacheEntry>>(TYPES.Auth_ORMCacheEntryRepository)
       .toConstantValue(AppDataSource.getRepository(TypeORMCacheEntry))
 
     // Repositories
-    container.bind<SessionRepositoryInterface>(TYPES.SessionRepository).to(TypeORMSessionRepository)
+    container.bind<SessionRepositoryInterface>(TYPES.Auth_SessionRepository).to(TypeORMSessionRepository)
     container
-      .bind<RevokedSessionRepositoryInterface>(TYPES.RevokedSessionRepository)
+      .bind<RevokedSessionRepositoryInterface>(TYPES.Auth_RevokedSessionRepository)
       .to(TypeORMRevokedSessionRepository)
-    container.bind<UserRepositoryInterface>(TYPES.UserRepository).to(TypeORMUserRepository)
-    container.bind<SettingRepositoryInterface>(TYPES.SettingRepository).to(TypeORMSettingRepository)
+    container.bind<UserRepositoryInterface>(TYPES.Auth_UserRepository).to(TypeORMUserRepository)
+    container.bind<SettingRepositoryInterface>(TYPES.Auth_SettingRepository).to(TypeORMSettingRepository)
     container
-      .bind<SubscriptionSettingRepositoryInterface>(TYPES.SubscriptionSettingRepository)
+      .bind<SubscriptionSettingRepositoryInterface>(TYPES.Auth_SubscriptionSettingRepository)
       .to(TypeORMSubscriptionSettingRepository)
     container
-      .bind<OfflineSettingRepositoryInterface>(TYPES.OfflineSettingRepository)
+      .bind<OfflineSettingRepositoryInterface>(TYPES.Auth_OfflineSettingRepository)
       .to(TypeORMOfflineSettingRepository)
-    container.bind<RoleRepositoryInterface>(TYPES.RoleRepository).to(TypeORMRoleRepository)
+    container.bind<RoleRepositoryInterface>(TYPES.Auth_RoleRepository).to(TypeORMRoleRepository)
     container
-      .bind<UserSubscriptionRepositoryInterface>(TYPES.UserSubscriptionRepository)
+      .bind<UserSubscriptionRepositoryInterface>(TYPES.Auth_UserSubscriptionRepository)
       .to(TypeORMUserSubscriptionRepository)
     container
-      .bind<OfflineUserSubscriptionRepositoryInterface>(TYPES.OfflineUserSubscriptionRepository)
+      .bind<OfflineUserSubscriptionRepositoryInterface>(TYPES.Auth_OfflineUserSubscriptionRepository)
       .to(TypeORMOfflineUserSubscriptionRepository)
     container
-      .bind<SharedSubscriptionInvitationRepositoryInterface>(TYPES.SharedSubscriptionInvitationRepository)
+      .bind<SharedSubscriptionInvitationRepositoryInterface>(TYPES.Auth_SharedSubscriptionInvitationRepository)
       .to(TypeORMSharedSubscriptionInvitationRepository)
     container
-      .bind<SessionTraceRepositoryInterface>(TYPES.SessionTraceRepository)
+      .bind<SessionTraceRepositoryInterface>(TYPES.Auth_SessionTraceRepository)
       .toConstantValue(
         new TypeORMSessionTraceRepository(
-          container.get(TYPES.ORMSessionTraceRepository),
-          container.get(TYPES.SessionTracePersistenceMapper),
+          container.get(TYPES.Auth_ORMSessionTraceRepository),
+          container.get(TYPES.Auth_SessionTracePersistenceMapper),
         ),
       )
     container
-      .bind<AuthenticatorRepositoryInterface>(TYPES.AuthenticatorRepository)
+      .bind<AuthenticatorRepositoryInterface>(TYPES.Auth_AuthenticatorRepository)
       .toConstantValue(
         new TypeORMAuthenticatorRepository(
-          container.get(TYPES.ORMAuthenticatorRepository),
-          container.get(TYPES.AuthenticatorPersistenceMapper),
+          container.get(TYPES.Auth_ORMAuthenticatorRepository),
+          container.get(TYPES.Auth_AuthenticatorPersistenceMapper),
         ),
       )
     container
-      .bind<AuthenticatorChallengeRepositoryInterface>(TYPES.AuthenticatorChallengeRepository)
+      .bind<AuthenticatorChallengeRepositoryInterface>(TYPES.Auth_AuthenticatorChallengeRepository)
       .toConstantValue(
         new TypeORMAuthenticatorChallengeRepository(
-          container.get(TYPES.ORMAuthenticatorChallengeRepository),
-          container.get(TYPES.AuthenticatorChallengePersistenceMapper),
+          container.get(TYPES.Auth_ORMAuthenticatorChallengeRepository),
+          container.get(TYPES.Auth_AuthenticatorChallengePersistenceMapper),
         ),
       )
     container
-      .bind<CacheEntryRepositoryInterface>(TYPES.CacheEntryRepository)
+      .bind<CacheEntryRepositoryInterface>(TYPES.Auth_CacheEntryRepository)
       .toConstantValue(
         new TypeORMCacheEntryRepository(
-          container.get(TYPES.ORMCacheEntryRepository),
-          container.get(TYPES.CacheEntryPersistenceMapper),
+          container.get(TYPES.Auth_ORMCacheEntryRepository),
+          container.get(TYPES.Auth_CacheEntryPersistenceMapper),
         ),
       )
 
     // Middleware
-    container.bind<AuthMiddleware>(TYPES.AuthMiddleware).to(AuthMiddleware)
-    container.bind<SessionMiddleware>(TYPES.SessionMiddleware).to(SessionMiddleware)
-    container.bind<LockMiddleware>(TYPES.LockMiddleware).to(LockMiddleware)
-    container.bind<AuthMiddlewareWithoutResponse>(TYPES.AuthMiddlewareWithoutResponse).to(AuthMiddlewareWithoutResponse)
-    container.bind<ApiGatewayAuthMiddleware>(TYPES.ApiGatewayAuthMiddleware).to(ApiGatewayAuthMiddleware)
+    container.bind<AuthMiddleware>(TYPES.Auth_AuthMiddleware).to(AuthMiddleware)
+    container.bind<SessionMiddleware>(TYPES.Auth_SessionMiddleware).to(SessionMiddleware)
+    container.bind<LockMiddleware>(TYPES.Auth_LockMiddleware).to(LockMiddleware)
+    container
+      .bind<AuthMiddlewareWithoutResponse>(TYPES.Auth_AuthMiddlewareWithoutResponse)
+      .to(AuthMiddlewareWithoutResponse)
+    container.bind<ApiGatewayAuthMiddleware>(TYPES.Auth_ApiGatewayAuthMiddleware).to(ApiGatewayAuthMiddleware)
     container
-      .bind<ApiGatewayOfflineAuthMiddleware>(TYPES.ApiGatewayOfflineAuthMiddleware)
+      .bind<ApiGatewayOfflineAuthMiddleware>(TYPES.Auth_ApiGatewayOfflineAuthMiddleware)
       .to(ApiGatewayOfflineAuthMiddleware)
-    container.bind<OfflineUserAuthMiddleware>(TYPES.OfflineUserAuthMiddleware).to(OfflineUserAuthMiddleware)
+    container.bind<OfflineUserAuthMiddleware>(TYPES.Auth_OfflineUserAuthMiddleware).to(OfflineUserAuthMiddleware)
 
     // Projectors
-    container.bind<SessionProjector>(TYPES.SessionProjector).to(SessionProjector)
-    container.bind<UserProjector>(TYPES.UserProjector).to(UserProjector)
-    container.bind<RoleProjector>(TYPES.RoleProjector).to(RoleProjector)
-    container.bind<PermissionProjector>(TYPES.PermissionProjector).to(PermissionProjector)
-    container.bind<SettingProjector>(TYPES.SettingProjector).to(SettingProjector)
-    container.bind<SubscriptionSettingProjector>(TYPES.SubscriptionSettingProjector).to(SubscriptionSettingProjector)
+    container.bind<SessionProjector>(TYPES.Auth_SessionProjector).to(SessionProjector)
+    container.bind<UserProjector>(TYPES.Auth_UserProjector).to(UserProjector)
+    container.bind<RoleProjector>(TYPES.Auth_RoleProjector).to(RoleProjector)
+    container.bind<PermissionProjector>(TYPES.Auth_PermissionProjector).to(PermissionProjector)
+    container.bind<SettingProjector>(TYPES.Auth_SettingProjector).to(SettingProjector)
+    container
+      .bind<SubscriptionSettingProjector>(TYPES.Auth_SubscriptionSettingProjector)
+      .to(SubscriptionSettingProjector)
 
     // Factories
-    container.bind<SettingFactoryInterface>(TYPES.SettingFactory).to(SettingFactory)
+    container.bind<SettingFactoryInterface>(TYPES.Auth_SettingFactory).to(SettingFactory)
 
     // env vars
-    container.bind(TYPES.JWT_SECRET).toConstantValue(env.get('JWT_SECRET'))
-    container.bind(TYPES.LEGACY_JWT_SECRET).toConstantValue(env.get('LEGACY_JWT_SECRET'))
-    container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
-    container.bind(TYPES.AUTH_JWT_TTL).toConstantValue(+env.get('AUTH_JWT_TTL'))
-    container.bind(TYPES.VALET_TOKEN_SECRET).toConstantValue(env.get('VALET_TOKEN_SECRET', true))
-    container.bind(TYPES.VALET_TOKEN_TTL).toConstantValue(+env.get('VALET_TOKEN_TTL', true))
-    container
-      .bind(TYPES.WEB_SOCKET_CONNECTION_TOKEN_SECRET)
+    container.bind(TYPES.Auth_JWT_SECRET).toConstantValue(env.get('JWT_SECRET'))
+    container.bind(TYPES.Auth_LEGACY_JWT_SECRET).toConstantValue(env.get('LEGACY_JWT_SECRET', true))
+    container.bind(TYPES.Auth_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
+    container
+      .bind(TYPES.Auth_AUTH_JWT_TTL)
+      .toConstantValue(env.get('AUTH_JWT_TTL', true) ? +env.get('AUTH_JWT_TTL') : 60_000)
+    container.bind(TYPES.Auth_VALET_TOKEN_SECRET).toConstantValue(env.get('VALET_TOKEN_SECRET', true))
+    container.bind(TYPES.Auth_VALET_TOKEN_TTL).toConstantValue(+env.get('VALET_TOKEN_TTL', true))
+    container
+      .bind(TYPES.Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET)
       .toConstantValue(env.get('WEB_SOCKET_CONNECTION_TOKEN_SECRET', true))
-    container.bind(TYPES.ENCRYPTION_SERVER_KEY).toConstantValue(env.get('ENCRYPTION_SERVER_KEY'))
-    container.bind(TYPES.ACCESS_TOKEN_AGE).toConstantValue(env.get('ACCESS_TOKEN_AGE'))
-    container.bind(TYPES.REFRESH_TOKEN_AGE).toConstantValue(env.get('REFRESH_TOKEN_AGE'))
-    container.bind(TYPES.MAX_LOGIN_ATTEMPTS).toConstantValue(env.get('MAX_LOGIN_ATTEMPTS'))
-    container.bind(TYPES.FAILED_LOGIN_LOCKOUT).toConstantValue(env.get('FAILED_LOGIN_LOCKOUT'))
-    container.bind(TYPES.PSEUDO_KEY_PARAMS_KEY).toConstantValue(env.get('PSEUDO_KEY_PARAMS_KEY'))
-    container.bind(TYPES.EPHEMERAL_SESSION_AGE).toConstantValue(env.get('EPHEMERAL_SESSION_AGE'))
-    container.bind(TYPES.REDIS_URL).toConstantValue(env.get('REDIS_URL'))
-    container
-      .bind(TYPES.DISABLE_USER_REGISTRATION)
+    container.bind(TYPES.Auth_ENCRYPTION_SERVER_KEY).toConstantValue(env.get('ENCRYPTION_SERVER_KEY'))
+    container
+      .bind(TYPES.Auth_ACCESS_TOKEN_AGE)
+      .toConstantValue(env.get('ACCESS_TOKEN_AGE', true) ? +env.get('ACCESS_TOKEN_AGE', true) : 5184000)
+    container
+      .bind(TYPES.Auth_REFRESH_TOKEN_AGE)
+      .toConstantValue(env.get('REFRESH_TOKEN_AGE', true) ? +env.get('REFRESH_TOKEN_AGE', true) : 31556926)
+    container
+      .bind(TYPES.Auth_MAX_LOGIN_ATTEMPTS)
+      .toConstantValue(env.get('MAX_LOGIN_ATTEMPTS', true) ? +env.get('MAX_LOGIN_ATTEMPTS', true) : 6)
+    container
+      .bind(TYPES.Auth_FAILED_LOGIN_LOCKOUT)
+      .toConstantValue(env.get('FAILED_LOGIN_LOCKOUT', true) ? +env.get('FAILED_LOGIN_LOCKOUT', true) : 3600)
+    container.bind(TYPES.Auth_PSEUDO_KEY_PARAMS_KEY).toConstantValue(env.get('PSEUDO_KEY_PARAMS_KEY'))
+    container
+      .bind(TYPES.Auth_EPHEMERAL_SESSION_AGE)
+      .toConstantValue(env.get('EPHEMERAL_SESSION_AGE', true) ? +env.get('EPHEMERAL_SESSION_AGE', true) : 259200)
+    container.bind(TYPES.Auth_REDIS_URL).toConstantValue(env.get('REDIS_URL', true))
+    container
+      .bind(TYPES.Auth_DISABLE_USER_REGISTRATION)
       .toConstantValue(env.get('DISABLE_USER_REGISTRATION', true) === 'true')
-    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.SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL'))
-    container.bind(TYPES.USER_SERVER_REGISTRATION_URL).toConstantValue(env.get('USER_SERVER_REGISTRATION_URL', true))
-    container.bind(TYPES.USER_SERVER_AUTH_KEY).toConstantValue(env.get('USER_SERVER_AUTH_KEY', true))
-    container.bind(TYPES.USER_SERVER_CHANGE_EMAIL_URL).toConstantValue(env.get('USER_SERVER_CHANGE_EMAIL_URL', true))
-    container.bind(TYPES.NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true))
-    container.bind(TYPES.SYNCING_SERVER_URL).toConstantValue(env.get('SYNCING_SERVER_URL'))
-    container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION'))
-    container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
-    container
-      .bind(TYPES.SESSION_TRACE_DAYS_TTL)
+    container.bind(TYPES.Auth_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
+    container.bind(TYPES.Auth_SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true))
+    container.bind(TYPES.Auth_SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL', true))
+    container
+      .bind(TYPES.Auth_USER_SERVER_REGISTRATION_URL)
+      .toConstantValue(env.get('USER_SERVER_REGISTRATION_URL', true))
+    container.bind(TYPES.Auth_USER_SERVER_AUTH_KEY).toConstantValue(env.get('USER_SERVER_AUTH_KEY', true))
+    container
+      .bind(TYPES.Auth_USER_SERVER_CHANGE_EMAIL_URL)
+      .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_PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
+    container
+      .bind(TYPES.Auth_SESSION_TRACE_DAYS_TTL)
       .toConstantValue(env.get('SESSION_TRACE_DAYS_TTL', true) ? +env.get('SESSION_TRACE_DAYS_TTL', true) : 90)
     container
-      .bind(TYPES.U2F_RELYING_PARTY_NAME)
+      .bind(TYPES.Auth_U2F_RELYING_PARTY_NAME)
       .toConstantValue(env.get('U2F_RELYING_PARTY_NAME', true) ?? 'Standard Notes')
     container
-      .bind(TYPES.U2F_RELYING_PARTY_ID)
+      .bind(TYPES.Auth_U2F_RELYING_PARTY_ID)
       .toConstantValue(env.get('U2F_RELYING_PARTY_ID', true) ?? 'app.standardnotes.com')
     container
-      .bind(TYPES.U2F_EXPECTED_ORIGIN)
+      .bind(TYPES.Auth_U2F_EXPECTED_ORIGIN)
       .toConstantValue(
         env.get('U2F_EXPECTED_ORIGIN', true)
           ? env.get('U2F_EXPECTED_ORIGIN', true).split(',')
           : ['https://app.standardnotes.com'],
       )
     container
-      .bind(TYPES.U2F_REQUIRE_USER_VERIFICATION)
+      .bind(TYPES.Auth_U2F_REQUIRE_USER_VERIFICATION)
       .toConstantValue(env.get('U2F_REQUIRE_USER_VERIFICATION', true) === 'true')
     container
-      .bind(TYPES.READONLY_USERS)
+      .bind(TYPES.Auth_READONLY_USERS)
       .toConstantValue(env.get('READONLY_USERS', true) ? env.get('READONLY_USERS', true).split(',') : [])
 
     if (isConfiguredForHomeServer) {
       container
-        .bind<LockRepositoryInterface>(TYPES.LockRepository)
+        .bind<LockRepositoryInterface>(TYPES.Auth_LockRepository)
         .toConstantValue(
           new TypeORMLockRepository(
-            container.get(TYPES.CacheEntryRepository),
-            container.get(TYPES.Timer),
-            container.get(TYPES.MAX_LOGIN_ATTEMPTS),
-            container.get(TYPES.FAILED_LOGIN_LOCKOUT),
+            container.get(TYPES.Auth_CacheEntryRepository),
+            container.get(TYPES.Auth_Timer),
+            container.get(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
+            container.get(TYPES.Auth_FAILED_LOGIN_LOCKOUT),
           ),
         )
       container
-        .bind<EphemeralSessionRepositoryInterface>(TYPES.EphemeralSessionRepository)
+        .bind<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository)
         .toConstantValue(
           new TypeORMEphemeralSessionRepository(
-            container.get(TYPES.CacheEntryRepository),
-            container.get(TYPES.EPHEMERAL_SESSION_AGE),
-            container.get(TYPES.Timer),
+            container.get(TYPES.Auth_CacheEntryRepository),
+            container.get(TYPES.Auth_EPHEMERAL_SESSION_AGE),
+            container.get(TYPES.Auth_Timer),
           ),
         )
       container
-        .bind<OfflineSubscriptionTokenRepositoryInterface>(TYPES.OfflineSubscriptionTokenRepository)
+        .bind<OfflineSubscriptionTokenRepositoryInterface>(TYPES.Auth_OfflineSubscriptionTokenRepository)
         .toConstantValue(
           new TypeORMOfflineSubscriptionTokenRepository(
-            container.get(TYPES.CacheEntryRepository),
-            container.get(TYPES.Timer),
+            container.get(TYPES.Auth_CacheEntryRepository),
+            container.get(TYPES.Auth_Timer),
           ),
         )
       container
-        .bind<PKCERepositoryInterface>(TYPES.PKCERepository)
+        .bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository)
         .toConstantValue(
           new TypeORMPKCERepository(
-            container.get(TYPES.CacheEntryRepository),
-            container.get(TYPES.Logger),
-            container.get(TYPES.Timer),
+            container.get(TYPES.Auth_CacheEntryRepository),
+            container.get(TYPES.Auth_Logger),
+            container.get(TYPES.Auth_Timer),
           ),
         )
       container
-        .bind<SubscriptionTokenRepositoryInterface>(TYPES.SubscriptionTokenRepository)
+        .bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
         .toConstantValue(
-          new TypeORMSubscriptionTokenRepository(container.get(TYPES.CacheEntryRepository), container.get(TYPES.Timer)),
+          new TypeORMSubscriptionTokenRepository(
+            container.get(TYPES.Auth_CacheEntryRepository),
+            container.get(TYPES.Auth_Timer),
+          ),
         )
     } else {
-      container.bind<PKCERepositoryInterface>(TYPES.PKCERepository).to(RedisPKCERepository)
-      container.bind<LockRepositoryInterface>(TYPES.LockRepository).to(LockRepository)
+      container.bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository).to(RedisPKCERepository)
+      container.bind<LockRepositoryInterface>(TYPES.Auth_LockRepository).to(LockRepository)
       container
-        .bind<EphemeralSessionRepositoryInterface>(TYPES.EphemeralSessionRepository)
+        .bind<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository)
         .to(RedisEphemeralSessionRepository)
       container
-        .bind<OfflineSubscriptionTokenRepositoryInterface>(TYPES.OfflineSubscriptionTokenRepository)
+        .bind<OfflineSubscriptionTokenRepositoryInterface>(TYPES.Auth_OfflineSubscriptionTokenRepository)
         .to(RedisOfflineSubscriptionTokenRepository)
       container
-        .bind<SubscriptionTokenRepositoryInterface>(TYPES.SubscriptionTokenRepository)
+        .bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
         .to(RedisSubscriptionTokenRepository)
     }
 
     // Services
-    container.bind<UAParser>(TYPES.DeviceDetector).toConstantValue(new UAParser())
-    container.bind<SessionService>(TYPES.SessionService).to(SessionService)
-    container.bind<AuthResponseFactory20161215>(TYPES.AuthResponseFactory20161215).to(AuthResponseFactory20161215)
-    container.bind<AuthResponseFactory20190520>(TYPES.AuthResponseFactory20190520).to(AuthResponseFactory20190520)
-    container.bind<AuthResponseFactory20200115>(TYPES.AuthResponseFactory20200115).to(AuthResponseFactory20200115)
-    container.bind<AuthResponseFactoryResolver>(TYPES.AuthResponseFactoryResolver).to(AuthResponseFactoryResolver)
-    container.bind<KeyParamsFactory>(TYPES.KeyParamsFactory).to(KeyParamsFactory)
+    container.bind<UAParser>(TYPES.Auth_DeviceDetector).toConstantValue(new UAParser())
+    container.bind<SessionService>(TYPES.Auth_SessionService).to(SessionService)
+    container.bind<AuthResponseFactory20161215>(TYPES.Auth_AuthResponseFactory20161215).to(AuthResponseFactory20161215)
+    container.bind<AuthResponseFactory20190520>(TYPES.Auth_AuthResponseFactory20190520).to(AuthResponseFactory20190520)
+    container.bind<AuthResponseFactory20200115>(TYPES.Auth_AuthResponseFactory20200115).to(AuthResponseFactory20200115)
+    container.bind<AuthResponseFactoryResolver>(TYPES.Auth_AuthResponseFactoryResolver).to(AuthResponseFactoryResolver)
+    container.bind<KeyParamsFactory>(TYPES.Auth_KeyParamsFactory).to(KeyParamsFactory)
     container
-      .bind<TokenDecoderInterface<SessionTokenData>>(TYPES.SessionTokenDecoder)
-      .toConstantValue(new TokenDecoder<SessionTokenData>(container.get(TYPES.JWT_SECRET)))
+      .bind<TokenDecoderInterface<SessionTokenData>>(TYPES.Auth_SessionTokenDecoder)
+      .toConstantValue(new TokenDecoder<SessionTokenData>(container.get(TYPES.Auth_JWT_SECRET)))
     container
-      .bind<TokenDecoderInterface<SessionTokenData>>(TYPES.FallbackSessionTokenDecoder)
-      .toConstantValue(new TokenDecoder<SessionTokenData>(container.get(TYPES.LEGACY_JWT_SECRET)))
+      .bind<TokenDecoderInterface<SessionTokenData>>(TYPES.Auth_FallbackSessionTokenDecoder)
+      .toConstantValue(new TokenDecoder<SessionTokenData>(container.get(TYPES.Auth_LEGACY_JWT_SECRET)))
     container
-      .bind<TokenDecoderInterface<CrossServiceTokenData>>(TYPES.CrossServiceTokenDecoder)
-      .toConstantValue(new TokenDecoder<CrossServiceTokenData>(container.get(TYPES.AUTH_JWT_SECRET)))
+      .bind<TokenDecoderInterface<CrossServiceTokenData>>(TYPES.Auth_CrossServiceTokenDecoder)
+      .toConstantValue(new TokenDecoder<CrossServiceTokenData>(container.get(TYPES.Auth_AUTH_JWT_SECRET)))
     container
-      .bind<TokenDecoderInterface<OfflineUserTokenData>>(TYPES.OfflineUserTokenDecoder)
-      .toConstantValue(new TokenDecoder<OfflineUserTokenData>(container.get(TYPES.AUTH_JWT_SECRET)))
+      .bind<TokenDecoderInterface<OfflineUserTokenData>>(TYPES.Auth_OfflineUserTokenDecoder)
+      .toConstantValue(new TokenDecoder<OfflineUserTokenData>(container.get(TYPES.Auth_AUTH_JWT_SECRET)))
     container
-      .bind<TokenDecoderInterface<WebSocketConnectionTokenData>>(TYPES.WebSocketConnectionTokenDecoder)
+      .bind<TokenDecoderInterface<WebSocketConnectionTokenData>>(TYPES.Auth_WebSocketConnectionTokenDecoder)
       .toConstantValue(
-        new TokenDecoder<WebSocketConnectionTokenData>(container.get(TYPES.WEB_SOCKET_CONNECTION_TOKEN_SECRET)),
+        new TokenDecoder<WebSocketConnectionTokenData>(container.get(TYPES.Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET)),
       )
     container
-      .bind<TokenEncoderInterface<OfflineUserTokenData>>(TYPES.OfflineUserTokenEncoder)
-      .toConstantValue(new TokenEncoder<OfflineUserTokenData>(container.get(TYPES.AUTH_JWT_SECRET)))
-    container
-      .bind<TokenEncoderInterface<SessionTokenData>>(TYPES.SessionTokenEncoder)
-      .toConstantValue(new TokenEncoder<SessionTokenData>(container.get(TYPES.JWT_SECRET)))
-    container
-      .bind<TokenEncoderInterface<CrossServiceTokenData>>(TYPES.CrossServiceTokenEncoder)
-      .toConstantValue(new TokenEncoder<CrossServiceTokenData>(container.get(TYPES.AUTH_JWT_SECRET)))
-    container
-      .bind<TokenEncoderInterface<ValetTokenData>>(TYPES.ValetTokenEncoder)
-      .toConstantValue(new TokenEncoder<ValetTokenData>(container.get(TYPES.VALET_TOKEN_SECRET)))
-    container.bind<AuthenticationMethodResolver>(TYPES.AuthenticationMethodResolver).to(AuthenticationMethodResolver)
-    container.bind<DomainEventFactory>(TYPES.DomainEventFactory).to(DomainEventFactory)
-    container.bind<AxiosInstance>(TYPES.HTTPClient).toConstantValue(axios.create())
-    container.bind<CrypterInterface>(TYPES.Crypter).to(CrypterNode)
-    container.bind<SettingServiceInterface>(TYPES.SettingService).to(SettingService)
-    container.bind<SubscriptionSettingServiceInterface>(TYPES.SubscriptionSettingService).to(SubscriptionSettingService)
-    container.bind<OfflineSettingServiceInterface>(TYPES.OfflineSettingService).to(OfflineSettingService)
-    container.bind<CryptoNode>(TYPES.CryptoNode).toConstantValue(new CryptoNode())
-    container.bind<ContentDecoderInterface>(TYPES.ContenDecoder).toConstantValue(new ContentDecoder())
-    container.bind<ClientServiceInterface>(TYPES.WebSocketsClientService).to(WebSocketsClientService)
-    container.bind<RoleServiceInterface>(TYPES.RoleService).to(RoleService)
-    container.bind<RoleToSubscriptionMapInterface>(TYPES.RoleToSubscriptionMap).to(RoleToSubscriptionMap)
-    container.bind<SettingsAssociationServiceInterface>(TYPES.SettingsAssociationService).to(SettingsAssociationService)
-    container
-      .bind<SubscriptionSettingsAssociationServiceInterface>(TYPES.SubscriptionSettingsAssociationService)
+      .bind<TokenEncoderInterface<OfflineUserTokenData>>(TYPES.Auth_OfflineUserTokenEncoder)
+      .toConstantValue(new TokenEncoder<OfflineUserTokenData>(container.get(TYPES.Auth_AUTH_JWT_SECRET)))
+    container
+      .bind<TokenEncoderInterface<SessionTokenData>>(TYPES.Auth_SessionTokenEncoder)
+      .toConstantValue(new TokenEncoder<SessionTokenData>(container.get(TYPES.Auth_JWT_SECRET)))
+    container
+      .bind<TokenEncoderInterface<CrossServiceTokenData>>(TYPES.Auth_CrossServiceTokenEncoder)
+      .toConstantValue(new TokenEncoder<CrossServiceTokenData>(container.get(TYPES.Auth_AUTH_JWT_SECRET)))
+    container
+      .bind<TokenEncoderInterface<ValetTokenData>>(TYPES.Auth_ValetTokenEncoder)
+      .toConstantValue(new TokenEncoder<ValetTokenData>(container.get(TYPES.Auth_VALET_TOKEN_SECRET)))
+    container
+      .bind<AuthenticationMethodResolver>(TYPES.Auth_AuthenticationMethodResolver)
+      .to(AuthenticationMethodResolver)
+    container.bind<DomainEventFactory>(TYPES.Auth_DomainEventFactory).to(DomainEventFactory)
+    container.bind<AxiosInstance>(TYPES.Auth_HTTPClient).toConstantValue(axios.create())
+    container.bind<CrypterInterface>(TYPES.Auth_Crypter).to(CrypterNode)
+    container.bind<SettingServiceInterface>(TYPES.Auth_SettingService).to(SettingService)
+    container
+      .bind<SubscriptionSettingServiceInterface>(TYPES.Auth_SubscriptionSettingService)
+      .to(SubscriptionSettingService)
+    container.bind<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService).to(OfflineSettingService)
+    container.bind<CryptoNode>(TYPES.Auth_CryptoNode).toConstantValue(new CryptoNode())
+    container.bind<ContentDecoderInterface>(TYPES.Auth_ContenDecoder).toConstantValue(new ContentDecoder())
+    container.bind<ClientServiceInterface>(TYPES.Auth_WebSocketsClientService).to(WebSocketsClientService)
+    container.bind<RoleServiceInterface>(TYPES.Auth_RoleService).to(RoleService)
+    container.bind<RoleToSubscriptionMapInterface>(TYPES.Auth_RoleToSubscriptionMap).to(RoleToSubscriptionMap)
+    container
+      .bind<SettingsAssociationServiceInterface>(TYPES.Auth_SettingsAssociationService)
+      .to(SettingsAssociationService)
+    container
+      .bind<SubscriptionSettingsAssociationServiceInterface>(TYPES.Auth_SubscriptionSettingsAssociationService)
       .to(SubscriptionSettingsAssociationService)
-    container.bind<FeatureServiceInterface>(TYPES.FeatureService).to(FeatureService)
-    container.bind<SettingInterpreterInterface>(TYPES.SettingInterpreter).to(SettingInterpreter)
-    container.bind<SettingDecrypterInterface>(TYPES.SettingDecrypter).to(SettingDecrypter)
+    container.bind<FeatureServiceInterface>(TYPES.Auth_FeatureService).to(FeatureService)
+    container.bind<SettingInterpreterInterface>(TYPES.Auth_SettingInterpreter).to(SettingInterpreter)
+    container.bind<SettingDecrypterInterface>(TYPES.Auth_SettingDecrypter).to(SettingDecrypter)
     container
-      .bind<SelectorInterface<ProtocolVersion>>(TYPES.ProtocolVersionSelector)
+      .bind<SelectorInterface<ProtocolVersion>>(TYPES.Auth_ProtocolVersionSelector)
       .toConstantValue(new DeterministicSelector<ProtocolVersion>())
     container
-      .bind<SelectorInterface<boolean>>(TYPES.BooleanSelector)
+      .bind<SelectorInterface<boolean>>(TYPES.Auth_BooleanSelector)
       .toConstantValue(new DeterministicSelector<boolean>())
-    container.bind<UserSubscriptionServiceInterface>(TYPES.UserSubscriptionService).to(UserSubscriptionService)
+    container.bind<UserSubscriptionServiceInterface>(TYPES.Auth_UserSubscriptionService).to(UserSubscriptionService)
 
     container
-      .bind<SNSDomainEventPublisher>(TYPES.DomainEventPublisher)
-      .toConstantValue(new SNSDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)))
+      .bind<SNSDomainEventPublisher>(TYPES.Auth_DomainEventPublisher)
+      .toConstantValue(
+        new SNSDomainEventPublisher(container.get(TYPES.Auth_SNS), container.get(TYPES.Auth_SNS_TOPIC_ARN)),
+      )
 
     // use cases
     container
-      .bind<TraceSession>(TYPES.TraceSession)
+      .bind<TraceSession>(TYPES.Auth_TraceSession)
       .toConstantValue(
         new TraceSession(
-          container.get(TYPES.SessionTraceRepository),
-          container.get(TYPES.Timer),
-          container.get(TYPES.SESSION_TRACE_DAYS_TTL),
+          container.get(TYPES.Auth_SessionTraceRepository),
+          container.get(TYPES.Auth_Timer),
+          container.get(TYPES.Auth_SESSION_TRACE_DAYS_TTL),
         ),
       )
     container
-      .bind<PersistStatistics>(TYPES.PersistStatistics)
+      .bind<PersistStatistics>(TYPES.Auth_PersistStatistics)
       .toConstantValue(
         new PersistStatistics(
-          container.get(TYPES.SessionTraceRepository),
-          container.get(TYPES.DomainEventPublisher),
-          container.get(TYPES.DomainEventFactory),
-          container.get(TYPES.Timer),
+          container.get(TYPES.Auth_SessionTraceRepository),
+          container.get(TYPES.Auth_DomainEventPublisher),
+          container.get(TYPES.Auth_DomainEventFactory),
+          container.get(TYPES.Auth_Timer),
         ),
       )
     container
-      .bind<GenerateAuthenticatorRegistrationOptions>(TYPES.GenerateAuthenticatorRegistrationOptions)
+      .bind<GenerateAuthenticatorRegistrationOptions>(TYPES.Auth_GenerateAuthenticatorRegistrationOptions)
       .toConstantValue(
         new GenerateAuthenticatorRegistrationOptions(
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.AuthenticatorChallengeRepository),
-          container.get(TYPES.U2F_RELYING_PARTY_NAME),
-          container.get(TYPES.U2F_RELYING_PARTY_ID),
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.FeatureService),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_AuthenticatorChallengeRepository),
+          container.get(TYPES.Auth_U2F_RELYING_PARTY_NAME),
+          container.get(TYPES.Auth_U2F_RELYING_PARTY_ID),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_FeatureService),
         ),
       )
     container
-      .bind<VerifyAuthenticatorRegistrationResponse>(TYPES.VerifyAuthenticatorRegistrationResponse)
+      .bind<VerifyAuthenticatorRegistrationResponse>(TYPES.Auth_VerifyAuthenticatorRegistrationResponse)
       .toConstantValue(
         new VerifyAuthenticatorRegistrationResponse(
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.AuthenticatorChallengeRepository),
-          container.get(TYPES.U2F_RELYING_PARTY_ID),
-          container.get(TYPES.U2F_EXPECTED_ORIGIN),
-          container.get(TYPES.U2F_REQUIRE_USER_VERIFICATION),
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.FeatureService),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_AuthenticatorChallengeRepository),
+          container.get(TYPES.Auth_U2F_RELYING_PARTY_ID),
+          container.get(TYPES.Auth_U2F_EXPECTED_ORIGIN),
+          container.get(TYPES.Auth_U2F_REQUIRE_USER_VERIFICATION),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_FeatureService),
         ),
       )
     container
-      .bind<GenerateAuthenticatorAuthenticationOptions>(TYPES.GenerateAuthenticatorAuthenticationOptions)
+      .bind<GenerateAuthenticatorAuthenticationOptions>(TYPES.Auth_GenerateAuthenticatorAuthenticationOptions)
       .toConstantValue(
         new GenerateAuthenticatorAuthenticationOptions(
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.AuthenticatorChallengeRepository),
-          container.get(TYPES.PSEUDO_KEY_PARAMS_KEY),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_AuthenticatorChallengeRepository),
+          container.get(TYPES.Auth_PSEUDO_KEY_PARAMS_KEY),
         ),
       )
     container
-      .bind<VerifyAuthenticatorAuthenticationResponse>(TYPES.VerifyAuthenticatorAuthenticationResponse)
+      .bind<VerifyAuthenticatorAuthenticationResponse>(TYPES.Auth_VerifyAuthenticatorAuthenticationResponse)
       .toConstantValue(
         new VerifyAuthenticatorAuthenticationResponse(
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.AuthenticatorChallengeRepository),
-          container.get(TYPES.U2F_RELYING_PARTY_ID),
-          container.get(TYPES.U2F_EXPECTED_ORIGIN),
-          container.get(TYPES.U2F_REQUIRE_USER_VERIFICATION),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_AuthenticatorChallengeRepository),
+          container.get(TYPES.Auth_U2F_RELYING_PARTY_ID),
+          container.get(TYPES.Auth_U2F_EXPECTED_ORIGIN),
+          container.get(TYPES.Auth_U2F_REQUIRE_USER_VERIFICATION),
         ),
       )
     container
-      .bind<ListAuthenticators>(TYPES.ListAuthenticators)
+      .bind<ListAuthenticators>(TYPES.Auth_ListAuthenticators)
       .toConstantValue(
         new ListAuthenticators(
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.FeatureService),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_FeatureService),
         ),
       )
     container
-      .bind<DeleteAuthenticator>(TYPES.DeleteAuthenticator)
+      .bind<DeleteAuthenticator>(TYPES.Auth_DeleteAuthenticator)
       .toConstantValue(
         new DeleteAuthenticator(
-          container.get(TYPES.AuthenticatorRepository),
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.FeatureService),
+          container.get(TYPES.Auth_AuthenticatorRepository),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_FeatureService),
         ),
       )
     container
-      .bind<GenerateRecoveryCodes>(TYPES.GenerateRecoveryCodes)
+      .bind<GenerateRecoveryCodes>(TYPES.Auth_GenerateRecoveryCodes)
       .toConstantValue(
         new GenerateRecoveryCodes(
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.SettingService),
-          container.get(TYPES.CryptoNode),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_SettingService),
+          container.get(TYPES.Auth_CryptoNode),
         ),
       )
 
     container
-      .bind<CleanupSessionTraces>(TYPES.CleanupSessionTraces)
-      .toConstantValue(new CleanupSessionTraces(container.get(TYPES.SessionTraceRepository)))
+      .bind<CleanupSessionTraces>(TYPES.Auth_CleanupSessionTraces)
+      .toConstantValue(new CleanupSessionTraces(container.get(TYPES.Auth_SessionTraceRepository)))
     container
-      .bind<CleanupExpiredSessions>(TYPES.CleanupExpiredSessions)
-      .toConstantValue(new CleanupExpiredSessions(container.get(TYPES.SessionRepository)))
-    container.bind<AuthenticateUser>(TYPES.AuthenticateUser).to(AuthenticateUser)
-    container.bind<AuthenticateRequest>(TYPES.AuthenticateRequest).to(AuthenticateRequest)
-    container.bind<RefreshSessionToken>(TYPES.RefreshSessionToken).to(RefreshSessionToken)
-    container.bind<SignIn>(TYPES.SignIn).to(SignIn)
-    container.bind<VerifyMFA>(TYPES.VerifyMFA).to(VerifyMFA)
-    container.bind<ClearLoginAttempts>(TYPES.ClearLoginAttempts).to(ClearLoginAttempts)
-    container.bind<IncreaseLoginAttempts>(TYPES.IncreaseLoginAttempts).to(IncreaseLoginAttempts)
+      .bind<CleanupExpiredSessions>(TYPES.Auth_CleanupExpiredSessions)
+      .toConstantValue(new CleanupExpiredSessions(container.get(TYPES.Auth_SessionRepository)))
+    container.bind<AuthenticateUser>(TYPES.Auth_AuthenticateUser).to(AuthenticateUser)
+    container.bind<AuthenticateRequest>(TYPES.Auth_AuthenticateRequest).to(AuthenticateRequest)
+    container.bind<RefreshSessionToken>(TYPES.Auth_RefreshSessionToken).to(RefreshSessionToken)
+    container.bind<SignIn>(TYPES.Auth_SignIn).to(SignIn)
+    container.bind<VerifyMFA>(TYPES.Auth_VerifyMFA).to(VerifyMFA)
+    container.bind<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts).to(ClearLoginAttempts)
+    container.bind<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts).to(IncreaseLoginAttempts)
     container
-      .bind<GetUserKeyParamsRecovery>(TYPES.GetUserKeyParamsRecovery)
+      .bind<GetUserKeyParamsRecovery>(TYPES.Auth_GetUserKeyParamsRecovery)
       .toConstantValue(
         new GetUserKeyParamsRecovery(
-          container.get(TYPES.KeyParamsFactory),
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.PKCERepository),
-          container.get(TYPES.SettingService),
+          container.get(TYPES.Auth_KeyParamsFactory),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_PKCERepository),
+          container.get(TYPES.Auth_SettingService),
         ),
       )
-    container.bind<GetUserKeyParams>(TYPES.GetUserKeyParams).to(GetUserKeyParams)
-    container.bind<UpdateUser>(TYPES.UpdateUser).to(UpdateUser)
-    container.bind<Register>(TYPES.Register).to(Register)
-    container.bind<GetActiveSessionsForUser>(TYPES.GetActiveSessionsForUser).to(GetActiveSessionsForUser)
-    container.bind<DeletePreviousSessionsForUser>(TYPES.DeletePreviousSessionsForUser).to(DeletePreviousSessionsForUser)
-    container.bind<DeleteSessionForUser>(TYPES.DeleteSessionForUser).to(DeleteSessionForUser)
-    container.bind<ChangeCredentials>(TYPES.ChangeCredentials).to(ChangeCredentials)
-    container.bind<GetSettings>(TYPES.GetSettings).to(GetSettings)
-    container.bind<GetSetting>(TYPES.GetSetting).to(GetSetting)
-    container.bind<GetUserFeatures>(TYPES.GetUserFeatures).to(GetUserFeatures)
-    container.bind<UpdateSetting>(TYPES.UpdateSetting).to(UpdateSetting)
-    container.bind<DeleteSetting>(TYPES.DeleteSetting).to(DeleteSetting)
-    container
-      .bind<SignInWithRecoveryCodes>(TYPES.SignInWithRecoveryCodes)
+    container.bind<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams).to(GetUserKeyParams)
+    container.bind<UpdateUser>(TYPES.Auth_UpdateUser).to(UpdateUser)
+    container.bind<Register>(TYPES.Auth_Register).to(Register)
+    container.bind<GetActiveSessionsForUser>(TYPES.Auth_GetActiveSessionsForUser).to(GetActiveSessionsForUser)
+    container
+      .bind<DeletePreviousSessionsForUser>(TYPES.Auth_DeletePreviousSessionsForUser)
+      .to(DeletePreviousSessionsForUser)
+    container.bind<DeleteSessionForUser>(TYPES.Auth_DeleteSessionForUser).to(DeleteSessionForUser)
+    container.bind<ChangeCredentials>(TYPES.Auth_ChangeCredentials).to(ChangeCredentials)
+    container.bind<GetSettings>(TYPES.Auth_GetSettings).to(GetSettings)
+    container.bind<GetSetting>(TYPES.Auth_GetSetting).to(GetSetting)
+    container.bind<GetUserFeatures>(TYPES.Auth_GetUserFeatures).to(GetUserFeatures)
+    container.bind<UpdateSetting>(TYPES.Auth_UpdateSetting).to(UpdateSetting)
+    container.bind<DeleteSetting>(TYPES.Auth_DeleteSetting).to(DeleteSetting)
+    container
+      .bind<SignInWithRecoveryCodes>(TYPES.Auth_SignInWithRecoveryCodes)
       .toConstantValue(
         new SignInWithRecoveryCodes(
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.AuthResponseFactory20200115),
-          container.get(TYPES.PKCERepository),
-          container.get(TYPES.Crypter),
-          container.get(TYPES.SettingService),
-          container.get(TYPES.GenerateRecoveryCodes),
-          container.get(TYPES.IncreaseLoginAttempts),
-          container.get(TYPES.ClearLoginAttempts),
-          container.get(TYPES.DeleteSetting),
-          container.get(TYPES.AuthenticatorRepository),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_AuthResponseFactory20200115),
+          container.get(TYPES.Auth_PKCERepository),
+          container.get(TYPES.Auth_Crypter),
+          container.get(TYPES.Auth_SettingService),
+          container.get(TYPES.Auth_GenerateRecoveryCodes),
+          container.get(TYPES.Auth_IncreaseLoginAttempts),
+          container.get(TYPES.Auth_ClearLoginAttempts),
+          container.get(TYPES.Auth_DeleteSetting),
+          container.get(TYPES.Auth_AuthenticatorRepository),
         ),
       )
-    container.bind<DeleteAccount>(TYPES.DeleteAccount).to(DeleteAccount)
-    container.bind<GetUserSubscription>(TYPES.GetUserSubscription).to(GetUserSubscription)
-    container.bind<GetUserOfflineSubscription>(TYPES.GetUserOfflineSubscription).to(GetUserOfflineSubscription)
-    container.bind<CreateSubscriptionToken>(TYPES.CreateSubscriptionToken).to(CreateSubscriptionToken)
-    container.bind<AuthenticateSubscriptionToken>(TYPES.AuthenticateSubscriptionToken).to(AuthenticateSubscriptionToken)
+    container.bind<DeleteAccount>(TYPES.Auth_DeleteAccount).to(DeleteAccount)
+    container.bind<GetUserSubscription>(TYPES.Auth_GetUserSubscription).to(GetUserSubscription)
+    container.bind<GetUserOfflineSubscription>(TYPES.Auth_GetUserOfflineSubscription).to(GetUserOfflineSubscription)
+    container.bind<CreateSubscriptionToken>(TYPES.Auth_CreateSubscriptionToken).to(CreateSubscriptionToken)
+    container
+      .bind<AuthenticateSubscriptionToken>(TYPES.Auth_AuthenticateSubscriptionToken)
+      .to(AuthenticateSubscriptionToken)
     container
-      .bind<AuthenticateOfflineSubscriptionToken>(TYPES.AuthenticateOfflineSubscriptionToken)
+      .bind<AuthenticateOfflineSubscriptionToken>(TYPES.Auth_AuthenticateOfflineSubscriptionToken)
       .to(AuthenticateOfflineSubscriptionToken)
     container
-      .bind<CreateOfflineSubscriptionToken>(TYPES.CreateOfflineSubscriptionToken)
+      .bind<CreateOfflineSubscriptionToken>(TYPES.Auth_CreateOfflineSubscriptionToken)
       .to(CreateOfflineSubscriptionToken)
-    container.bind<CreateValetToken>(TYPES.CreateValetToken).to(CreateValetToken)
-    container.bind<CreateListedAccount>(TYPES.CreateListedAccount).to(CreateListedAccount)
-    container.bind<InviteToSharedSubscription>(TYPES.InviteToSharedSubscription).to(InviteToSharedSubscription)
+    container.bind<CreateValetToken>(TYPES.Auth_CreateValetToken).to(CreateValetToken)
+    container.bind<CreateListedAccount>(TYPES.Auth_CreateListedAccount).to(CreateListedAccount)
+    container.bind<InviteToSharedSubscription>(TYPES.Auth_InviteToSharedSubscription).to(InviteToSharedSubscription)
     container
-      .bind<AcceptSharedSubscriptionInvitation>(TYPES.AcceptSharedSubscriptionInvitation)
+      .bind<AcceptSharedSubscriptionInvitation>(TYPES.Auth_AcceptSharedSubscriptionInvitation)
       .to(AcceptSharedSubscriptionInvitation)
     container
-      .bind<DeclineSharedSubscriptionInvitation>(TYPES.DeclineSharedSubscriptionInvitation)
+      .bind<DeclineSharedSubscriptionInvitation>(TYPES.Auth_DeclineSharedSubscriptionInvitation)
       .to(DeclineSharedSubscriptionInvitation)
     container
-      .bind<CancelSharedSubscriptionInvitation>(TYPES.CancelSharedSubscriptionInvitation)
+      .bind<CancelSharedSubscriptionInvitation>(TYPES.Auth_CancelSharedSubscriptionInvitation)
       .to(CancelSharedSubscriptionInvitation)
     container
-      .bind<ListSharedSubscriptionInvitations>(TYPES.ListSharedSubscriptionInvitations)
+      .bind<ListSharedSubscriptionInvitations>(TYPES.Auth_ListSharedSubscriptionInvitations)
       .to(ListSharedSubscriptionInvitations)
-    container.bind<VerifyPredicate>(TYPES.VerifyPredicate).to(VerifyPredicate)
-    container.bind<CreateCrossServiceToken>(TYPES.CreateCrossServiceToken).to(CreateCrossServiceToken)
-    container.bind<ProcessUserRequest>(TYPES.ProcessUserRequest).to(ProcessUserRequest)
+    container.bind<VerifyPredicate>(TYPES.Auth_VerifyPredicate).to(VerifyPredicate)
+    container.bind<CreateCrossServiceToken>(TYPES.Auth_CreateCrossServiceToken).to(CreateCrossServiceToken)
+    container.bind<ProcessUserRequest>(TYPES.Auth_ProcessUserRequest).to(ProcessUserRequest)
 
     // Controller
-    container.bind<AuthController>(TYPES.AuthController).to(AuthController)
     container
-      .bind<AuthenticatorsController>(TYPES.AuthenticatorsController)
+      .bind<ControllerContainerInterface>(TYPES.Auth_ControllerContainer)
+      .toConstantValue(controllerConatiner ?? new ControllerContainer())
+    container
+      .bind<AuthController>(TYPES.Auth_AuthController)
+      .toConstantValue(
+        new AuthController(
+          container.get(TYPES.Auth_ClearLoginAttempts),
+          container.get(TYPES.Auth_Register),
+          container.get(TYPES.Auth_DomainEventPublisher),
+          container.get(TYPES.Auth_DomainEventFactory),
+          container.get(TYPES.Auth_SignInWithRecoveryCodes),
+          container.get(TYPES.Auth_GetUserKeyParamsRecovery),
+          container.get(TYPES.Auth_GenerateRecoveryCodes),
+          container.get(TYPES.Auth_Logger),
+          container.get(TYPES.Auth_SessionService),
+        ),
+      )
+    container
+      .bind<AuthenticatorsController>(TYPES.Auth_AuthenticatorsController)
       .toConstantValue(
         new AuthenticatorsController(
-          container.get(TYPES.GenerateAuthenticatorRegistrationOptions),
-          container.get(TYPES.VerifyAuthenticatorRegistrationResponse),
-          container.get(TYPES.GenerateAuthenticatorAuthenticationOptions),
-          container.get(TYPES.ListAuthenticators),
-          container.get(TYPES.DeleteAuthenticator),
-          container.get(TYPES.AuthenticatorHttpMapper),
+          container.get(TYPES.Auth_GenerateAuthenticatorRegistrationOptions),
+          container.get(TYPES.Auth_VerifyAuthenticatorRegistrationResponse),
+          container.get(TYPES.Auth_GenerateAuthenticatorAuthenticationOptions),
+          container.get(TYPES.Auth_ListAuthenticators),
+          container.get(TYPES.Auth_DeleteAuthenticator),
+          container.get(TYPES.Auth_AuthenticatorHttpMapper),
         ),
       )
-    container.bind<SubscriptionInvitesController>(TYPES.SubscriptionInvitesController).to(SubscriptionInvitesController)
-    container.bind<UserRequestsController>(TYPES.UserRequestsController).to(UserRequestsController)
+    container
+      .bind<SubscriptionInvitesController>(TYPES.Auth_SubscriptionInvitesController)
+      .to(SubscriptionInvitesController)
+    container.bind<UserRequestsController>(TYPES.Auth_UserRequestsController).to(UserRequestsController)
 
     // Handlers
-    container.bind<UserRegisteredEventHandler>(TYPES.UserRegisteredEventHandler).to(UserRegisteredEventHandler)
+    container.bind<UserRegisteredEventHandler>(TYPES.Auth_UserRegisteredEventHandler).to(UserRegisteredEventHandler)
     container
-      .bind<AccountDeletionRequestedEventHandler>(TYPES.AccountDeletionRequestedEventHandler)
+      .bind<AccountDeletionRequestedEventHandler>(TYPES.Auth_AccountDeletionRequestedEventHandler)
       .to(AccountDeletionRequestedEventHandler)
     container
-      .bind<SubscriptionPurchasedEventHandler>(TYPES.SubscriptionPurchasedEventHandler)
+      .bind<SubscriptionPurchasedEventHandler>(TYPES.Auth_SubscriptionPurchasedEventHandler)
       .to(SubscriptionPurchasedEventHandler)
     container
-      .bind<SubscriptionCancelledEventHandler>(TYPES.SubscriptionCancelledEventHandler)
+      .bind<SubscriptionCancelledEventHandler>(TYPES.Auth_SubscriptionCancelledEventHandler)
       .to(SubscriptionCancelledEventHandler)
     container
-      .bind<SubscriptionRenewedEventHandler>(TYPES.SubscriptionRenewedEventHandler)
+      .bind<SubscriptionRenewedEventHandler>(TYPES.Auth_SubscriptionRenewedEventHandler)
       .to(SubscriptionRenewedEventHandler)
     container
-      .bind<SubscriptionRefundedEventHandler>(TYPES.SubscriptionRefundedEventHandler)
+      .bind<SubscriptionRefundedEventHandler>(TYPES.Auth_SubscriptionRefundedEventHandler)
       .to(SubscriptionRefundedEventHandler)
     container
-      .bind<SubscriptionExpiredEventHandler>(TYPES.SubscriptionExpiredEventHandler)
+      .bind<SubscriptionExpiredEventHandler>(TYPES.Auth_SubscriptionExpiredEventHandler)
       .to(SubscriptionExpiredEventHandler)
     container
-      .bind<SubscriptionSyncRequestedEventHandler>(TYPES.SubscriptionSyncRequestedEventHandler)
+      .bind<SubscriptionSyncRequestedEventHandler>(TYPES.Auth_SubscriptionSyncRequestedEventHandler)
       .to(SubscriptionSyncRequestedEventHandler)
     container
-      .bind<ExtensionKeyGrantedEventHandler>(TYPES.ExtensionKeyGrantedEventHandler)
+      .bind<ExtensionKeyGrantedEventHandler>(TYPES.Auth_ExtensionKeyGrantedEventHandler)
       .to(ExtensionKeyGrantedEventHandler)
     container
-      .bind<SubscriptionReassignedEventHandler>(TYPES.SubscriptionReassignedEventHandler)
+      .bind<SubscriptionReassignedEventHandler>(TYPES.Auth_SubscriptionReassignedEventHandler)
       .to(SubscriptionReassignedEventHandler)
-    container.bind<UserEmailChangedEventHandler>(TYPES.UserEmailChangedEventHandler).to(UserEmailChangedEventHandler)
-    container.bind<FileUploadedEventHandler>(TYPES.FileUploadedEventHandler).to(FileUploadedEventHandler)
-    container.bind<FileRemovedEventHandler>(TYPES.FileRemovedEventHandler).to(FileRemovedEventHandler)
     container
-      .bind<ListedAccountCreatedEventHandler>(TYPES.ListedAccountCreatedEventHandler)
+      .bind<UserEmailChangedEventHandler>(TYPES.Auth_UserEmailChangedEventHandler)
+      .to(UserEmailChangedEventHandler)
+    container.bind<FileUploadedEventHandler>(TYPES.Auth_FileUploadedEventHandler).to(FileUploadedEventHandler)
+    container.bind<FileRemovedEventHandler>(TYPES.Auth_FileRemovedEventHandler).to(FileRemovedEventHandler)
+    container
+      .bind<ListedAccountCreatedEventHandler>(TYPES.Auth_ListedAccountCreatedEventHandler)
       .to(ListedAccountCreatedEventHandler)
     container
-      .bind<ListedAccountDeletedEventHandler>(TYPES.ListedAccountDeletedEventHandler)
+      .bind<ListedAccountDeletedEventHandler>(TYPES.Auth_ListedAccountDeletedEventHandler)
       .to(ListedAccountDeletedEventHandler)
     container
-      .bind<UserDisabledSessionUserAgentLoggingEventHandler>(TYPES.UserDisabledSessionUserAgentLoggingEventHandler)
+      .bind<UserDisabledSessionUserAgentLoggingEventHandler>(TYPES.Auth_UserDisabledSessionUserAgentLoggingEventHandler)
       .to(UserDisabledSessionUserAgentLoggingEventHandler)
     container
-      .bind<SharedSubscriptionInvitationCreatedEventHandler>(TYPES.SharedSubscriptionInvitationCreatedEventHandler)
+      .bind<SharedSubscriptionInvitationCreatedEventHandler>(TYPES.Auth_SharedSubscriptionInvitationCreatedEventHandler)
       .to(SharedSubscriptionInvitationCreatedEventHandler)
     container
-      .bind<PredicateVerificationRequestedEventHandler>(TYPES.PredicateVerificationRequestedEventHandler)
+      .bind<PredicateVerificationRequestedEventHandler>(TYPES.Auth_PredicateVerificationRequestedEventHandler)
       .to(PredicateVerificationRequestedEventHandler)
 
     container
-      .bind<EmailSubscriptionUnsubscribedEventHandler>(TYPES.EmailSubscriptionUnsubscribedEventHandler)
+      .bind<EmailSubscriptionUnsubscribedEventHandler>(TYPES.Auth_EmailSubscriptionUnsubscribedEventHandler)
       .toConstantValue(
         new EmailSubscriptionUnsubscribedEventHandler(
-          container.get(TYPES.UserRepository),
-          container.get(TYPES.SettingService),
+          container.get(TYPES.Auth_UserRepository),
+          container.get(TYPES.Auth_SettingService),
         ),
       )
 
     const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
-      ['USER_REGISTERED', container.get(TYPES.UserRegisteredEventHandler)],
-      ['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.AccountDeletionRequestedEventHandler)],
-      ['SUBSCRIPTION_PURCHASED', container.get(TYPES.SubscriptionPurchasedEventHandler)],
-      ['SUBSCRIPTION_CANCELLED', container.get(TYPES.SubscriptionCancelledEventHandler)],
-      ['SUBSCRIPTION_RENEWED', container.get(TYPES.SubscriptionRenewedEventHandler)],
-      ['SUBSCRIPTION_REFUNDED', container.get(TYPES.SubscriptionRefundedEventHandler)],
-      ['SUBSCRIPTION_EXPIRED', container.get(TYPES.SubscriptionExpiredEventHandler)],
-      ['SUBSCRIPTION_SYNC_REQUESTED', container.get(TYPES.SubscriptionSyncRequestedEventHandler)],
-      ['EXTENSION_KEY_GRANTED', container.get(TYPES.ExtensionKeyGrantedEventHandler)],
-      ['SUBSCRIPTION_REASSIGNED', container.get(TYPES.SubscriptionReassignedEventHandler)],
-      ['USER_EMAIL_CHANGED', container.get(TYPES.UserEmailChangedEventHandler)],
-      ['FILE_UPLOADED', container.get(TYPES.FileUploadedEventHandler)],
-      ['FILE_REMOVED', container.get(TYPES.FileRemovedEventHandler)],
-      ['LISTED_ACCOUNT_CREATED', container.get(TYPES.ListedAccountCreatedEventHandler)],
-      ['LISTED_ACCOUNT_DELETED', container.get(TYPES.ListedAccountDeletedEventHandler)],
+      ['USER_REGISTERED', container.get(TYPES.Auth_UserRegisteredEventHandler)],
+      ['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
+      ['SUBSCRIPTION_PURCHASED', container.get(TYPES.Auth_SubscriptionPurchasedEventHandler)],
+      ['SUBSCRIPTION_CANCELLED', container.get(TYPES.Auth_SubscriptionCancelledEventHandler)],
+      ['SUBSCRIPTION_RENEWED', container.get(TYPES.Auth_SubscriptionRenewedEventHandler)],
+      ['SUBSCRIPTION_REFUNDED', container.get(TYPES.Auth_SubscriptionRefundedEventHandler)],
+      ['SUBSCRIPTION_EXPIRED', container.get(TYPES.Auth_SubscriptionExpiredEventHandler)],
+      ['SUBSCRIPTION_SYNC_REQUESTED', container.get(TYPES.Auth_SubscriptionSyncRequestedEventHandler)],
+      ['EXTENSION_KEY_GRANTED', container.get(TYPES.Auth_ExtensionKeyGrantedEventHandler)],
+      ['SUBSCRIPTION_REASSIGNED', container.get(TYPES.Auth_SubscriptionReassignedEventHandler)],
+      ['USER_EMAIL_CHANGED', container.get(TYPES.Auth_UserEmailChangedEventHandler)],
+      ['FILE_UPLOADED', container.get(TYPES.Auth_FileUploadedEventHandler)],
+      ['FILE_REMOVED', container.get(TYPES.Auth_FileRemovedEventHandler)],
+      ['LISTED_ACCOUNT_CREATED', container.get(TYPES.Auth_ListedAccountCreatedEventHandler)],
+      ['LISTED_ACCOUNT_DELETED', container.get(TYPES.Auth_ListedAccountDeletedEventHandler)],
       [
         'USER_DISABLED_SESSION_USER_AGENT_LOGGING',
-        container.get(TYPES.UserDisabledSessionUserAgentLoggingEventHandler),
+        container.get(TYPES.Auth_UserDisabledSessionUserAgentLoggingEventHandler),
       ],
-      ['SHARED_SUBSCRIPTION_INVITATION_CREATED', container.get(TYPES.SharedSubscriptionInvitationCreatedEventHandler)],
-      ['PREDICATE_VERIFICATION_REQUESTED', container.get(TYPES.PredicateVerificationRequestedEventHandler)],
-      ['EMAIL_SUBSCRIPTION_UNSUBSCRIBED', container.get(TYPES.EmailSubscriptionUnsubscribedEventHandler)],
+      [
+        'SHARED_SUBSCRIPTION_INVITATION_CREATED',
+        container.get(TYPES.Auth_SharedSubscriptionInvitationCreatedEventHandler),
+      ],
+      ['PREDICATE_VERIFICATION_REQUESTED', container.get(TYPES.Auth_PredicateVerificationRequestedEventHandler)],
+      ['EMAIL_SUBSCRIPTION_UNSUBSCRIBED', container.get(TYPES.Auth_EmailSubscriptionUnsubscribedEventHandler)],
     ])
 
     container
-      .bind<DomainEventMessageHandlerInterface>(TYPES.DomainEventMessageHandler)
+      .bind<DomainEventMessageHandlerInterface>(TYPES.Auth_DomainEventMessageHandler)
       .toConstantValue(
         env.get('NEW_RELIC_ENABLED', true) === 'true'
-          ? new SQSNewRelicEventMessageHandler(eventHandlers, container.get(TYPES.Logger))
-          : new SQSEventMessageHandler(eventHandlers, container.get(TYPES.Logger)),
+          ? new SQSNewRelicEventMessageHandler(eventHandlers, container.get(TYPES.Auth_Logger))
+          : new SQSEventMessageHandler(eventHandlers, container.get(TYPES.Auth_Logger)),
       )
     container
-      .bind<DomainEventSubscriberFactoryInterface>(TYPES.DomainEventSubscriberFactory)
+      .bind<DomainEventSubscriberFactoryInterface>(TYPES.Auth_DomainEventSubscriberFactory)
       .toConstantValue(
         new SQSDomainEventSubscriberFactory(
-          container.get(TYPES.SQS),
-          container.get(TYPES.SQS_QUEUE_URL),
-          container.get(TYPES.DomainEventMessageHandler),
+          container.get(TYPES.Auth_SQS),
+          container.get(TYPES.Auth_SQS_QUEUE_URL),
+          container.get(TYPES.Auth_DomainEventMessageHandler),
+        ),
+      )
+
+    container
+      .bind<InversifyExpressAuthController>(TYPES.Auth_InversifyExpressAuthController)
+      .toConstantValue(
+        new InversifyExpressAuthController(
+          container.get(TYPES.Auth_VerifyMFA),
+          container.get(TYPES.Auth_SignIn),
+          container.get(TYPES.Auth_GetUserKeyParams),
+          container.get(TYPES.Auth_ClearLoginAttempts),
+          container.get(TYPES.Auth_IncreaseLoginAttempts),
+          container.get(TYPES.Auth_Logger),
+          container.get(TYPES.Auth_AuthController),
+          container.get(TYPES.Auth_ControllerContainer),
+        ),
+      )
+    container
+      .bind<InversifyExpressAuthenticatorsController>(TYPES.Auth_InversifyExpressAuthenticatorsController)
+      .toConstantValue(
+        new InversifyExpressAuthenticatorsController(
+          container.get(TYPES.Auth_AuthenticatorsController),
+          container.get(TYPES.Auth_ControllerContainer),
+        ),
+      )
+    container
+      .bind<InversifyExpressSubscriptionInvitesController>(TYPES.Auth_InversifyExpressSubscriptionInvitesController)
+      .toConstantValue(
+        new InversifyExpressSubscriptionInvitesController(
+          container.get(TYPES.Auth_SubscriptionInvitesController),
+          container.get(TYPES.Auth_ControllerContainer),
+        ),
+      )
+    container
+      .bind<InversifyExpressUserRequestsController>(TYPES.Auth_InversifyExpressUserRequestsController)
+      .toConstantValue(
+        new InversifyExpressUserRequestsController(
+          container.get(TYPES.Auth_UserRequestsController),
+          container.get(TYPES.Auth_ControllerContainer),
+        ),
+      )
+    container
+      .bind<InversifyExpressWebSocketsController>(TYPES.Auth_InversifyExpressWebSocketsController)
+      .toConstantValue(
+        new InversifyExpressWebSocketsController(
+          container.get(TYPES.Auth_CreateCrossServiceToken),
+          container.get(TYPES.Auth_WebSocketConnectionTokenDecoder),
+          container.get(TYPES.Auth_ControllerContainer),
         ),
       )
 

+ 50 - 43
packages/auth/src/Bootstrap/DataSource.ts

@@ -28,29 +28,6 @@ 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 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),
-      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 commonDataSourceOptions = {
   maxQueryExecutionTime,
   entities: [
@@ -71,29 +48,59 @@ const commonDataSourceOptions = {
     TypeORMEmergencyAccessInvitation,
     TypeORMCacheEntry,
   ],
-  migrations: [`dist/migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
+  migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
   migrationsRun: true,
-  logging: <LoggerOptions>env.get('DB_DEBUG_LEVEL'),
+  logging: <LoggerOptions>env.get('DB_DEBUG_LEVEL', true) ?? 'info',
 }
 
-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'),
-}
+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'),
+    },
+    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`,
+  }
 
-const sqliteDataSourceOptions: SqliteConnectionOptions = {
-  ...commonDataSourceOptions,
-  type: 'sqlite',
-  database: `data/${env.get('DB_DATABASE')}.sqlite`,
+  dataSource = new DataSource(sqliteDataSourceOptions)
 }
 
-export const AppDataSource = new DataSource(isConfiguredForMySQL ? mySQLDataSourceOptions : sqliteDataSourceOptions)
+export const AppDataSource = dataSource

+ 37 - 0
packages/auth/src/Bootstrap/Service.ts

@@ -0,0 +1,37 @@
+import {
+  ControllerContainerInterface,
+  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.Auth).getValue(), this)
+  }
+
+  async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise<unknown> {
+    const method = this.controllerContainer.get(endpointOrMethodIdentifier)
+
+    if (!method) {
+      throw new Error(`Method ${endpointOrMethodIdentifier} not found`)
+    }
+
+    return method(request, response)
+  }
+
+  async getContainer(): Promise<unknown> {
+    const config = new ContainerConfigLoader()
+
+    return config.load(this.controllerContainer)
+  }
+
+  getId(): ServiceIdentifier {
+    return ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue()
+  }
+}

+ 212 - 202
packages/auth/src/Bootstrap/Types.ts

@@ -1,217 +1,227 @@
 const TYPES = {
-  Logger: Symbol.for('Logger'),
-  Redis: Symbol.for('Redis'),
-  SNS: Symbol.for('SNS'),
-  SQS: Symbol.for('SQS'),
+  Auth_Logger: Symbol.for('Auth_Logger'),
+  Auth_Redis: Symbol.for('Auth_Redis'),
+  Auth_SNS: Symbol.for('Auth_SNS'),
+  Auth_SQS: Symbol.for('Auth_SQS'),
   // Mapping
-  SessionTracePersistenceMapper: Symbol.for('SessionTracePersistenceMapper'),
-  AuthenticatorChallengePersistenceMapper: Symbol.for('AuthenticatorChallengePersistenceMapper'),
-  AuthenticatorPersistenceMapper: Symbol.for('AuthenticatorPersistenceMapper'),
-  AuthenticatorHttpMapper: Symbol.for('AuthenticatorHttpMapper'),
-  CacheEntryPersistenceMapper: Symbol.for('CacheEntryPersistenceMapper'),
+  Auth_SessionTracePersistenceMapper: Symbol.for('Auth_SessionTracePersistenceMapper'),
+  Auth_AuthenticatorChallengePersistenceMapper: Symbol.for('Auth_AuthenticatorChallengePersistenceMapper'),
+  Auth_AuthenticatorPersistenceMapper: Symbol.for('Auth_AuthenticatorPersistenceMapper'),
+  Auth_AuthenticatorHttpMapper: Symbol.for('Auth_AuthenticatorHttpMapper'),
+  Auth_CacheEntryPersistenceMapper: Symbol.for('Auth_CacheEntryPersistenceMapper'),
   // Controller
-  AuthController: Symbol.for('AuthController'),
-  AuthenticatorsController: Symbol.for('AuthenticatorsController'),
-  SubscriptionInvitesController: Symbol.for('SubscriptionInvitesController'),
-  UserRequestsController: Symbol.for('UserRequestsController'),
+  Auth_ControllerContainer: Symbol.for('Auth_ControllerContainer'),
+  Auth_AuthController: Symbol.for('Auth_AuthController'),
+  Auth_AuthenticatorsController: Symbol.for('Auth_AuthenticatorsController'),
+  Auth_SubscriptionInvitesController: Symbol.for('Auth_SubscriptionInvitesController'),
+  Auth_UserRequestsController: Symbol.for('Auth_UserRequestsController'),
   // Repositories
-  UserRepository: Symbol.for('UserRepository'),
-  SessionRepository: Symbol.for('SessionRepository'),
-  EphemeralSessionRepository: Symbol.for('EphemeralSessionRepository'),
-  RevokedSessionRepository: Symbol.for('RevokedSessionRepository'),
-  SettingRepository: Symbol.for('SettingRepository'),
-  SubscriptionSettingRepository: Symbol.for('SubscriptionSettingRepository'),
-  OfflineSettingRepository: Symbol.for('OfflineSettingRepository'),
-  LockRepository: Symbol.for('LockRepository'),
-  RoleRepository: Symbol.for('RoleRepository'),
-  UserSubscriptionRepository: Symbol.for('UserSubscriptionRepository'),
-  OfflineUserSubscriptionRepository: Symbol.for('OfflineUserSubscriptionRepository'),
-  SubscriptionTokenRepository: Symbol.for('SubscriptionTokenRepository'),
-  OfflineSubscriptionTokenRepository: Symbol.for('OfflineSubscriptionTokenRepository'),
-  SharedSubscriptionInvitationRepository: Symbol.for('SharedSubscriptionInvitationRepository'),
-  PKCERepository: Symbol.for('PKCERepository'),
-  SessionTraceRepository: Symbol.for('SessionTraceRepository'),
-  AuthenticatorRepository: Symbol.for('AuthenticatorRepository'),
-  AuthenticatorChallengeRepository: Symbol.for('AuthenticatorChallengeRepository'),
-  CacheEntryRepository: Symbol.for('CacheEntryRepository'),
+  Auth_UserRepository: Symbol.for('Auth_UserRepository'),
+  Auth_SessionRepository: Symbol.for('Auth_SessionRepository'),
+  Auth_EphemeralSessionRepository: Symbol.for('Auth_EphemeralSessionRepository'),
+  Auth_RevokedSessionRepository: Symbol.for('Auth_RevokedSessionRepository'),
+  Auth_SettingRepository: Symbol.for('Auth_SettingRepository'),
+  Auth_SubscriptionSettingRepository: Symbol.for('Auth_SubscriptionSettingRepository'),
+  Auth_OfflineSettingRepository: Symbol.for('Auth_OfflineSettingRepository'),
+  Auth_LockRepository: Symbol.for('Auth_LockRepository'),
+  Auth_RoleRepository: Symbol.for('Auth_RoleRepository'),
+  Auth_UserSubscriptionRepository: Symbol.for('Auth_UserSubscriptionRepository'),
+  Auth_OfflineUserSubscriptionRepository: Symbol.for('Auth_OfflineUserSubscriptionRepository'),
+  Auth_SubscriptionTokenRepository: Symbol.for('Auth_SubscriptionTokenRepository'),
+  Auth_OfflineSubscriptionTokenRepository: Symbol.for('Auth_OfflineSubscriptionTokenRepository'),
+  Auth_SharedSubscriptionInvitationRepository: Symbol.for('Auth_SharedSubscriptionInvitationRepository'),
+  Auth_PKCERepository: Symbol.for('Auth_PKCERepository'),
+  Auth_SessionTraceRepository: Symbol.for('Auth_SessionTraceRepository'),
+  Auth_AuthenticatorRepository: Symbol.for('Auth_AuthenticatorRepository'),
+  Auth_AuthenticatorChallengeRepository: Symbol.for('Auth_AuthenticatorChallengeRepository'),
+  Auth_CacheEntryRepository: Symbol.for('Auth_CacheEntryRepository'),
   // ORM
-  ORMOfflineSettingRepository: Symbol.for('ORMOfflineSettingRepository'),
-  ORMOfflineUserSubscriptionRepository: Symbol.for('ORMOfflineUserSubscriptionRepository'),
-  ORMRevokedSessionRepository: Symbol.for('ORMRevokedSessionRepository'),
-  ORMRoleRepository: Symbol.for('ORMRoleRepository'),
-  ORMSessionRepository: Symbol.for('ORMSessionRepository'),
-  ORMSettingRepository: Symbol.for('ORMSettingRepository'),
-  ORMSharedSubscriptionInvitationRepository: Symbol.for('ORMSharedSubscriptionInvitationRepository'),
-  ORMSubscriptionSettingRepository: Symbol.for('ORMSubscriptionSettingRepository'),
-  ORMUserRepository: Symbol.for('ORMUserRepository'),
-  ORMUserSubscriptionRepository: Symbol.for('ORMUserSubscriptionRepository'),
-  ORMSessionTraceRepository: Symbol.for('ORMSessionTraceRepository'),
-  ORMAuthenticatorRepository: Symbol.for('ORMAuthenticatorRepository'),
-  ORMAuthenticatorChallengeRepository: Symbol.for('ORMAuthenticatorChallengeRepository'),
-  ORMCacheEntryRepository: Symbol.for('ORMCacheEntryRepository'),
+  Auth_ORMOfflineSettingRepository: Symbol.for('Auth_ORMOfflineSettingRepository'),
+  Auth_ORMOfflineUserSubscriptionRepository: Symbol.for('Auth_ORMOfflineUserSubscriptionRepository'),
+  Auth_ORMRevokedSessionRepository: Symbol.for('Auth_ORMRevokedSessionRepository'),
+  Auth_ORMRoleRepository: Symbol.for('Auth_ORMRoleRepository'),
+  Auth_ORMSessionRepository: Symbol.for('Auth_ORMSessionRepository'),
+  Auth_ORMSettingRepository: Symbol.for('Auth_ORMSettingRepository'),
+  Auth_ORMSharedSubscriptionInvitationRepository: Symbol.for('Auth_ORMSharedSubscriptionInvitationRepository'),
+  Auth_ORMSubscriptionSettingRepository: Symbol.for('Auth_ORMSubscriptionSettingRepository'),
+  Auth_ORMUserRepository: Symbol.for('Auth_ORMUserRepository'),
+  Auth_ORMUserSubscriptionRepository: Symbol.for('Auth_ORMUserSubscriptionRepository'),
+  Auth_ORMSessionTraceRepository: Symbol.for('Auth_ORMSessionTraceRepository'),
+  Auth_ORMAuthenticatorRepository: Symbol.for('Auth_ORMAuthenticatorRepository'),
+  Auth_ORMAuthenticatorChallengeRepository: Symbol.for('Auth_ORMAuthenticatorChallengeRepository'),
+  Auth_ORMCacheEntryRepository: Symbol.for('Auth_ORMCacheEntryRepository'),
   // Middleware
-  AuthMiddleware: Symbol.for('AuthMiddleware'),
-  ApiGatewayAuthMiddleware: Symbol.for('ApiGatewayAuthMiddleware'),
-  ApiGatewayOfflineAuthMiddleware: Symbol.for('ApiGatewayOfflineAuthMiddleware'),
-  OfflineUserAuthMiddleware: Symbol.for('OfflineUserAuthMiddleware'),
-  AuthMiddlewareWithoutResponse: Symbol.for('AuthMiddlewareWithoutResponse'),
-  LockMiddleware: Symbol.for('LockMiddleware'),
-  SessionMiddleware: Symbol.for('SessionMiddleware'),
+  Auth_AuthMiddleware: Symbol.for('Auth_AuthMiddleware'),
+  Auth_ApiGatewayAuthMiddleware: Symbol.for('Auth_ApiGatewayAuthMiddleware'),
+  Auth_ApiGatewayOfflineAuthMiddleware: Symbol.for('Auth_ApiGatewayOfflineAuthMiddleware'),
+  Auth_OfflineUserAuthMiddleware: Symbol.for('Auth_OfflineUserAuthMiddleware'),
+  Auth_AuthMiddlewareWithoutResponse: Symbol.for('Auth_AuthMiddlewareWithoutResponse'),
+  Auth_LockMiddleware: Symbol.for('Auth_LockMiddleware'),
+  Auth_SessionMiddleware: Symbol.for('Auth_SessionMiddleware'),
   // Projectors
-  SessionProjector: Symbol.for('SessionProjector'),
-  UserProjector: Symbol.for('UserProjector'),
-  RoleProjector: Symbol.for('RoleProjector'),
-  PermissionProjector: Symbol.for('PermissionProjector'),
-  SettingProjector: Symbol.for('SettingProjector'),
-  SubscriptionSettingProjector: Symbol.for('SubscriptionSettingProjector'),
+  Auth_SessionProjector: Symbol.for('Auth_SessionProjector'),
+  Auth_UserProjector: Symbol.for('Auth_UserProjector'),
+  Auth_RoleProjector: Symbol.for('Auth_RoleProjector'),
+  Auth_PermissionProjector: Symbol.for('Auth_PermissionProjector'),
+  Auth_SettingProjector: Symbol.for('Auth_SettingProjector'),
+  Auth_SubscriptionSettingProjector: Symbol.for('Auth_SubscriptionSettingProjector'),
   // Factories
-  SettingFactory: Symbol.for('SettingFactory'),
+  Auth_SettingFactory: Symbol.for('Auth_SettingFactory'),
   // env vars
-  JWT_SECRET: Symbol.for('JWT_SECRET'),
-  LEGACY_JWT_SECRET: Symbol.for('LEGACY_JWT_SECRET'),
-  AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'),
-  AUTH_JWT_TTL: Symbol.for('AUTH_JWT_TTL'),
-  VALET_TOKEN_SECRET: Symbol.for('VALET_TOKEN_SECRET'),
-  VALET_TOKEN_TTL: Symbol.for('VALET_TOKEN_TTL'),
-  WEB_SOCKET_CONNECTION_TOKEN_SECRET: Symbol.for('WEB_SOCKET_CONNECTION_TOKEN_SECRET'),
-  WEB_SOCKET_CONNECTION_TOKEN_TTL: Symbol.for('WEB_SOCKET_CONNECTION_TOKEN_TTL'),
-  ENCRYPTION_SERVER_KEY: Symbol.for('ENCRYPTION_SERVER_KEY'),
-  ACCESS_TOKEN_AGE: Symbol.for('ACCESS_TOKEN_AGE'),
-  REFRESH_TOKEN_AGE: Symbol.for('REFRESH_TOKEN_AGE'),
-  EPHEMERAL_SESSION_AGE: Symbol.for('EPHEMERAL_SESSION_AGE'),
-  MAX_LOGIN_ATTEMPTS: Symbol.for('MAX_LOGIN_ATTEMPTS'),
-  FAILED_LOGIN_LOCKOUT: Symbol.for('FAILED_LOGIN_LOCKOUT'),
-  PSEUDO_KEY_PARAMS_KEY: Symbol.for('PSEUDO_KEY_PARAMS_KEY'),
-  REDIS_URL: Symbol.for('REDIS_URL'),
-  DISABLE_USER_REGISTRATION: Symbol.for('DISABLE_USER_REGISTRATION'),
-  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'),
-  USER_SERVER_REGISTRATION_URL: Symbol.for('USER_SERVER_REGISTRATION_URL'),
-  USER_SERVER_AUTH_KEY: Symbol.for('USER_SERVER_AUTH_KEY'),
-  USER_SERVER_CHANGE_EMAIL_URL: Symbol.for('USER_SERVER_CHANGE_EMAIL_URL'),
-  NEW_RELIC_ENABLED: Symbol.for('NEW_RELIC_ENABLED'),
-  SYNCING_SERVER_URL: Symbol.for('SYNCING_SERVER_URL'),
-  VERSION: Symbol.for('VERSION'),
-  PAYMENTS_SERVER_URL: Symbol.for('PAYMENTS_SERVER_URL'),
-  SESSION_TRACE_DAYS_TTL: Symbol.for('SESSION_TRACE_DAYS_TTL'),
-  U2F_RELYING_PARTY_ID: Symbol.for('U2F_RELYING_PARTY_ID'),
-  U2F_RELYING_PARTY_NAME: Symbol.for('U2F_RELYING_PARTY_NAME'),
-  U2F_EXPECTED_ORIGIN: Symbol.for('U2F_EXPECTED_ORIGIN'),
-  U2F_REQUIRE_USER_VERIFICATION: Symbol.for('U2F_REQUIRE_USER_VERIFICATION'),
-  READONLY_USERS: Symbol.for('READONLY_USERS'),
+  Auth_JWT_SECRET: Symbol.for('Auth_JWT_SECRET'),
+  Auth_LEGACY_JWT_SECRET: Symbol.for('Auth_LEGACY_JWT_SECRET'),
+  Auth_AUTH_JWT_SECRET: Symbol.for('Auth_AUTH_JWT_SECRET'),
+  Auth_AUTH_JWT_TTL: Symbol.for('Auth_AUTH_JWT_TTL'),
+  Auth_VALET_TOKEN_SECRET: Symbol.for('Auth_VALET_TOKEN_SECRET'),
+  Auth_VALET_TOKEN_TTL: Symbol.for('Auth_VALET_TOKEN_TTL'),
+  Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET: Symbol.for('Auth_WEB_SOCKET_CONNECTION_TOKEN_SECRET'),
+  Auth_WEB_SOCKET_CONNECTION_TOKEN_TTL: Symbol.for('Auth_WEB_SOCKET_CONNECTION_TOKEN_TTL'),
+  Auth_ENCRYPTION_SERVER_KEY: Symbol.for('Auth_ENCRYPTION_SERVER_KEY'),
+  Auth_ACCESS_TOKEN_AGE: Symbol.for('Auth_ACCESS_TOKEN_AGE'),
+  Auth_REFRESH_TOKEN_AGE: Symbol.for('Auth_REFRESH_TOKEN_AGE'),
+  Auth_EPHEMERAL_SESSION_AGE: Symbol.for('Auth_EPHEMERAL_SESSION_AGE'),
+  Auth_MAX_LOGIN_ATTEMPTS: Symbol.for('Auth_MAX_LOGIN_ATTEMPTS'),
+  Auth_FAILED_LOGIN_LOCKOUT: Symbol.for('Auth_FAILED_LOGIN_LOCKOUT'),
+  Auth_PSEUDO_KEY_PARAMS_KEY: Symbol.for('Auth_PSEUDO_KEY_PARAMS_KEY'),
+  Auth_REDIS_URL: Symbol.for('Auth_REDIS_URL'),
+  Auth_DISABLE_USER_REGISTRATION: Symbol.for('Auth_DISABLE_USER_REGISTRATION'),
+  Auth_SNS_TOPIC_ARN: Symbol.for('Auth_SNS_TOPIC_ARN'),
+  Auth_SNS_AWS_REGION: Symbol.for('Auth_SNS_AWS_REGION'),
+  Auth_SQS_QUEUE_URL: Symbol.for('Auth_SQS_QUEUE_URL'),
+  Auth_SQS_AWS_REGION: Symbol.for('Auth_SQS_AWS_REGION'),
+  Auth_USER_SERVER_REGISTRATION_URL: Symbol.for('Auth_USER_SERVER_REGISTRATION_URL'),
+  Auth_USER_SERVER_AUTH_KEY: Symbol.for('Auth_USER_SERVER_AUTH_KEY'),
+  Auth_USER_SERVER_CHANGE_EMAIL_URL: Symbol.for('Auth_USER_SERVER_CHANGE_EMAIL_URL'),
+  Auth_NEW_RELIC_ENABLED: Symbol.for('Auth_NEW_RELIC_ENABLED'),
+  Auth_SYNCING_SERVER_URL: Symbol.for('Auth_SYNCING_SERVER_URL'),
+  Auth_VERSION: Symbol.for('Auth_VERSION'),
+  Auth_PAYMENTS_SERVER_URL: Symbol.for('Auth_PAYMENTS_SERVER_URL'),
+  Auth_SESSION_TRACE_DAYS_TTL: Symbol.for('Auth_SESSION_TRACE_DAYS_TTL'),
+  Auth_U2F_RELYING_PARTY_ID: Symbol.for('Auth_U2F_RELYING_PARTY_ID'),
+  Auth_U2F_RELYING_PARTY_NAME: Symbol.for('Auth_U2F_RELYING_PARTY_NAME'),
+  Auth_U2F_EXPECTED_ORIGIN: Symbol.for('Auth_U2F_EXPECTED_ORIGIN'),
+  Auth_U2F_REQUIRE_USER_VERIFICATION: Symbol.for('Auth_U2F_REQUIRE_USER_VERIFICATION'),
+  Auth_READONLY_USERS: Symbol.for('Auth_READONLY_USERS'),
   // use cases
-  AuthenticateUser: Symbol.for('AuthenticateUser'),
-  AuthenticateRequest: Symbol.for('AuthenticateRequest'),
-  RefreshSessionToken: Symbol.for('RefreshSessionToken'),
-  VerifyMFA: Symbol.for('VerifyMFA'),
-  SignIn: Symbol.for('SignIn'),
-  ClearLoginAttempts: Symbol.for('ClearLoginAttempts'),
-  IncreaseLoginAttempts: Symbol.for('IncreaseLoginAttempts'),
-  GetUserKeyParams: Symbol.for('GetUserKeyParams'),
-  UpdateUser: Symbol.for('UpdateUser'),
-  Register: Symbol.for('Register'),
-  GetActiveSessionsForUser: Symbol.for('GetActiveSessionsForUser'),
-  DeletePreviousSessionsForUser: Symbol.for('DeletePreviousSessionsForUser'),
-  DeleteSessionForUser: Symbol.for('DeleteSessionForUser'),
-  ChangeCredentials: Symbol.for('ChangePassword'),
-  GetSettings: Symbol.for('GetSettings'),
-  GetSetting: Symbol.for('GetSetting'),
-  GetUserFeatures: Symbol.for('GetUserFeatures'),
-  UpdateSetting: Symbol.for('UpdateSetting'),
-  DeleteSetting: Symbol.for('DeleteSetting'),
-  DeleteAccount: Symbol.for('DeleteAccount'),
-  GetUserSubscription: Symbol.for('GetUserSubscription'),
-  GetUserOfflineSubscription: Symbol.for('GetUserOfflineSubscription'),
-  CreateSubscriptionToken: Symbol.for('CreateSubscriptionToken'),
-  AuthenticateSubscriptionToken: Symbol.for('AuthenticateSubscriptionToken'),
-  CreateOfflineSubscriptionToken: Symbol.for('CreateOfflineSubscriptionToken'),
-  AuthenticateOfflineSubscriptionToken: Symbol.for('AuthenticateOfflineSubscriptionToken'),
-  CreateValetToken: Symbol.for('CreateValetToken'),
-  CreateListedAccount: Symbol.for('CreateListedAccount'),
-  InviteToSharedSubscription: Symbol.for('InviteToSharedSubscription'),
-  AcceptSharedSubscriptionInvitation: Symbol.for('AcceptSharedSubscriptionInvitation'),
-  DeclineSharedSubscriptionInvitation: Symbol.for('DeclineSharedSubscriptionInvitation'),
-  CancelSharedSubscriptionInvitation: Symbol.for('CancelSharedSubscriptionInvitation'),
-  ListSharedSubscriptionInvitations: Symbol.for('ListSharedSubscriptionInvitations'),
-  VerifyPredicate: Symbol.for('VerifyPredicate'),
-  CreateCrossServiceToken: Symbol.for('CreateCrossServiceToken'),
-  ProcessUserRequest: Symbol.for('ProcessUserRequest'),
-  TraceSession: Symbol.for('TraceSession'),
-  CleanupSessionTraces: Symbol.for('CleanupSessionTraces'),
-  CleanupExpiredSessions: Symbol.for('CleanupExpiredSessions'),
-  PersistStatistics: Symbol.for('PersistStatistics'),
-  GenerateAuthenticatorRegistrationOptions: Symbol.for('GenerateAuthenticatorRegistrationOptions'),
-  VerifyAuthenticatorRegistrationResponse: Symbol.for('VerifyAuthenticatorRegistrationResponse'),
-  GenerateAuthenticatorAuthenticationOptions: Symbol.for('GenerateAuthenticatorAuthenticationOptions'),
-  VerifyAuthenticatorAuthenticationResponse: Symbol.for('VerifyAuthenticatorAuthenticationResponse'),
-  ListAuthenticators: Symbol.for('ListAuthenticators'),
-  DeleteAuthenticator: Symbol.for('DeleteAuthenticator'),
-  GenerateRecoveryCodes: Symbol.for('GenerateRecoveryCodes'),
-  SignInWithRecoveryCodes: Symbol.for('SignInWithRecoveryCodes'),
-  GetUserKeyParamsRecovery: Symbol.for('GetUserKeyParamsRecovery'),
+  Auth_AuthenticateUser: Symbol.for('Auth_AuthenticateUser'),
+  Auth_AuthenticateRequest: Symbol.for('Auth_AuthenticateRequest'),
+  Auth_RefreshSessionToken: Symbol.for('Auth_RefreshSessionToken'),
+  Auth_VerifyMFA: Symbol.for('Auth_VerifyMFA'),
+  Auth_SignIn: Symbol.for('Auth_SignIn'),
+  Auth_ClearLoginAttempts: Symbol.for('Auth_ClearLoginAttempts'),
+  Auth_IncreaseLoginAttempts: Symbol.for('Auth_IncreaseLoginAttempts'),
+  Auth_GetUserKeyParams: Symbol.for('Auth_GetUserKeyParams'),
+  Auth_UpdateUser: Symbol.for('Auth_UpdateUser'),
+  Auth_Register: Symbol.for('Auth_Register'),
+  Auth_GetActiveSessionsForUser: Symbol.for('Auth_GetActiveSessionsForUser'),
+  Auth_DeletePreviousSessionsForUser: Symbol.for('Auth_DeletePreviousSessionsForUser'),
+  Auth_DeleteSessionForUser: Symbol.for('Auth_DeleteSessionForUser'),
+  Auth_ChangeCredentials: Symbol.for('Auth_ChangePassword'),
+  Auth_GetSettings: Symbol.for('Auth_GetSettings'),
+  Auth_GetSetting: Symbol.for('Auth_GetSetting'),
+  Auth_GetUserFeatures: Symbol.for('Auth_GetUserFeatures'),
+  Auth_UpdateSetting: Symbol.for('Auth_UpdateSetting'),
+  Auth_DeleteSetting: Symbol.for('Auth_DeleteSetting'),
+  Auth_DeleteAccount: Symbol.for('Auth_DeleteAccount'),
+  Auth_GetUserSubscription: Symbol.for('Auth_GetUserSubscription'),
+  Auth_GetUserOfflineSubscription: Symbol.for('Auth_GetUserOfflineSubscription'),
+  Auth_CreateSubscriptionToken: Symbol.for('Auth_CreateSubscriptionToken'),
+  Auth_AuthenticateSubscriptionToken: Symbol.for('Auth_AuthenticateSubscriptionToken'),
+  Auth_CreateOfflineSubscriptionToken: Symbol.for('Auth_CreateOfflineSubscriptionToken'),
+  Auth_AuthenticateOfflineSubscriptionToken: Symbol.for('Auth_AuthenticateOfflineSubscriptionToken'),
+  Auth_CreateValetToken: Symbol.for('Auth_CreateValetToken'),
+  Auth_CreateListedAccount: Symbol.for('Auth_CreateListedAccount'),
+  Auth_InviteToSharedSubscription: Symbol.for('Auth_InviteToSharedSubscription'),
+  Auth_AcceptSharedSubscriptionInvitation: Symbol.for('Auth_AcceptSharedSubscriptionInvitation'),
+  Auth_DeclineSharedSubscriptionInvitation: Symbol.for('Auth_DeclineSharedSubscriptionInvitation'),
+  Auth_CancelSharedSubscriptionInvitation: Symbol.for('Auth_CancelSharedSubscriptionInvitation'),
+  Auth_ListSharedSubscriptionInvitations: Symbol.for('Auth_ListSharedSubscriptionInvitations'),
+  Auth_VerifyPredicate: Symbol.for('Auth_VerifyPredicate'),
+  Auth_CreateCrossServiceToken: Symbol.for('Auth_CreateCrossServiceToken'),
+  Auth_ProcessUserRequest: Symbol.for('Auth_ProcessUserRequest'),
+  Auth_TraceSession: Symbol.for('Auth_TraceSession'),
+  Auth_CleanupSessionTraces: Symbol.for('Auth_CleanupSessionTraces'),
+  Auth_CleanupExpiredSessions: Symbol.for('Auth_CleanupExpiredSessions'),
+  Auth_PersistStatistics: Symbol.for('Auth_PersistStatistics'),
+  Auth_GenerateAuthenticatorRegistrationOptions: Symbol.for('Auth_GenerateAuthenticatorRegistrationOptions'),
+  Auth_VerifyAuthenticatorRegistrationResponse: Symbol.for('Auth_VerifyAuthenticatorRegistrationResponse'),
+  Auth_GenerateAuthenticatorAuthenticationOptions: Symbol.for('Auth_GenerateAuthenticatorAuthenticationOptions'),
+  Auth_VerifyAuthenticatorAuthenticationResponse: Symbol.for('Auth_VerifyAuthenticatorAuthenticationResponse'),
+  Auth_ListAuthenticators: Symbol.for('Auth_ListAuthenticators'),
+  Auth_DeleteAuthenticator: Symbol.for('Auth_DeleteAuthenticator'),
+  Auth_GenerateRecoveryCodes: Symbol.for('Auth_GenerateRecoveryCodes'),
+  Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
+  Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
   // Handlers
-  UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
-  AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
-  SubscriptionPurchasedEventHandler: Symbol.for('SubscriptionPurchasedEventHandler'),
-  SubscriptionCancelledEventHandler: Symbol.for('SubscriptionCancelledEventHandler'),
-  SubscriptionReassignedEventHandler: Symbol.for('SubscriptionReassignedEventHandler'),
-  SubscriptionRenewedEventHandler: Symbol.for('SubscriptionRenewedEventHandler'),
-  SubscriptionRefundedEventHandler: Symbol.for('SubscriptionRefundedEventHandler'),
-  SubscriptionExpiredEventHandler: Symbol.for('SubscriptionExpiredEventHandler'),
-  SubscriptionSyncRequestedEventHandler: Symbol.for('SubscriptionSyncRequestedEventHandler'),
-  ExtensionKeyGrantedEventHandler: Symbol.for('ExtensionKeyGrantedEventHandler'),
-  UserEmailChangedEventHandler: Symbol.for('UserEmailChangedEventHandler'),
-  FileUploadedEventHandler: Symbol.for('FileUploadedEventHandler'),
-  FileRemovedEventHandler: Symbol.for('FileRemovedEventHandler'),
-  ListedAccountCreatedEventHandler: Symbol.for('ListedAccountCreatedEventHandler'),
-  ListedAccountDeletedEventHandler: Symbol.for('ListedAccountDeletedEventHandler'),
-  UserDisabledSessionUserAgentLoggingEventHandler: Symbol.for('UserDisabledSessionUserAgentLoggingEventHandler'),
-  SharedSubscriptionInvitationCreatedEventHandler: Symbol.for('SharedSubscriptionInvitationCreatedEventHandler'),
-  PredicateVerificationRequestedEventHandler: Symbol.for('PredicateVerificationRequestedEventHandler'),
-  EmailSubscriptionUnsubscribedEventHandler: Symbol.for('EmailSubscriptionUnsubscribedEventHandler'),
+  Auth_UserRegisteredEventHandler: Symbol.for('Auth_UserRegisteredEventHandler'),
+  Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
+  Auth_SubscriptionPurchasedEventHandler: Symbol.for('Auth_SubscriptionPurchasedEventHandler'),
+  Auth_SubscriptionCancelledEventHandler: Symbol.for('Auth_SubscriptionCancelledEventHandler'),
+  Auth_SubscriptionReassignedEventHandler: Symbol.for('Auth_SubscriptionReassignedEventHandler'),
+  Auth_SubscriptionRenewedEventHandler: Symbol.for('Auth_SubscriptionRenewedEventHandler'),
+  Auth_SubscriptionRefundedEventHandler: Symbol.for('Auth_SubscriptionRefundedEventHandler'),
+  Auth_SubscriptionExpiredEventHandler: Symbol.for('Auth_SubscriptionExpiredEventHandler'),
+  Auth_SubscriptionSyncRequestedEventHandler: Symbol.for('Auth_SubscriptionSyncRequestedEventHandler'),
+  Auth_ExtensionKeyGrantedEventHandler: Symbol.for('Auth_ExtensionKeyGrantedEventHandler'),
+  Auth_UserEmailChangedEventHandler: Symbol.for('Auth_UserEmailChangedEventHandler'),
+  Auth_FileUploadedEventHandler: Symbol.for('Auth_FileUploadedEventHandler'),
+  Auth_FileRemovedEventHandler: Symbol.for('Auth_FileRemovedEventHandler'),
+  Auth_ListedAccountCreatedEventHandler: Symbol.for('Auth_ListedAccountCreatedEventHandler'),
+  Auth_ListedAccountDeletedEventHandler: Symbol.for('Auth_ListedAccountDeletedEventHandler'),
+  Auth_UserDisabledSessionUserAgentLoggingEventHandler: Symbol.for(
+    'Auth_UserDisabledSessionUserAgentLoggingEventHandler',
+  ),
+  Auth_SharedSubscriptionInvitationCreatedEventHandler: Symbol.for(
+    'Auth_SharedSubscriptionInvitationCreatedEventHandler',
+  ),
+  Auth_PredicateVerificationRequestedEventHandler: Symbol.for('Auth_PredicateVerificationRequestedEventHandler'),
+  Auth_EmailSubscriptionUnsubscribedEventHandler: Symbol.for('Auth_EmailSubscriptionUnsubscribedEventHandler'),
   // Services
-  DeviceDetector: Symbol.for('DeviceDetector'),
-  SessionService: Symbol.for('SessionService'),
-  SettingService: Symbol.for('SettingService'),
-  SubscriptionSettingService: Symbol.for('SubscriptionSettingService'),
-  OfflineSettingService: Symbol.for('OfflineSettingService'),
-  AuthResponseFactory20161215: Symbol.for('AuthResponseFactory20161215'),
-  AuthResponseFactory20190520: Symbol.for('AuthResponseFactory20190520'),
-  AuthResponseFactory20200115: Symbol.for('AuthResponseFactory20200115'),
-  AuthResponseFactoryResolver: Symbol.for('AuthResponseFactoryResolver'),
-  KeyParamsFactory: Symbol.for('KeyParamsFactory'),
-  SessionTokenDecoder: Symbol.for('SessionTokenDecoder'),
-  FallbackSessionTokenDecoder: Symbol.for('FallbackSessionTokenDecoder'),
-  CrossServiceTokenDecoder: Symbol.for('CrossServiceTokenDecoder'),
-  OfflineUserTokenDecoder: Symbol.for('OfflineUserTokenDecoder'),
-  OfflineUserTokenEncoder: Symbol.for('OfflineUserTokenEncoder'),
-  CrossServiceTokenEncoder: Symbol.for('CrossServiceTokenEncoder'),
-  SessionTokenEncoder: Symbol.for('SessionTokenEncoder'),
-  ValetTokenEncoder: Symbol.for('ValetTokenEncoder'),
-  WebSocketConnectionTokenDecoder: Symbol.for('WebSocketConnectionTokenDecoder'),
-  AuthenticationMethodResolver: Symbol.for('AuthenticationMethodResolver'),
-  DomainEventPublisher: Symbol.for('DomainEventPublisher'),
-  DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'),
-  DomainEventFactory: Symbol.for('DomainEventFactory'),
-  DomainEventMessageHandler: Symbol.for('DomainEventMessageHandler'),
-  HTTPClient: Symbol.for('HTTPClient'),
-  Crypter: Symbol.for('Crypter'),
-  CryptoNode: Symbol.for('CryptoNode'),
-  Timer: Symbol.for('Timer'),
-  ContenDecoder: Symbol.for('ContenDecoder'),
-  WebSocketsClientService: Symbol.for('WebSocketClientService'),
-  RoleService: Symbol.for('RoleService'),
-  RoleToSubscriptionMap: Symbol.for('RoleToSubscriptionMap'),
-  SettingsAssociationService: Symbol.for('SettingsAssociationService'),
-  SubscriptionSettingsAssociationService: Symbol.for('SubscriptionSettingsAssociationService'),
-  FeatureService: Symbol.for('FeatureService'),
-  SettingDecrypter: Symbol.for('SettingDecrypter'),
-  SettingInterpreter: Symbol.for('SettingInterpreter'),
-  ProtocolVersionSelector: Symbol.for('ProtocolVersionSelector'),
-  BooleanSelector: Symbol.for('BooleanSelector'),
-  UserSubscriptionService: Symbol.for('UserSubscriptionService'),
+  Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
+  Auth_SessionService: Symbol.for('Auth_SessionService'),
+  Auth_SettingService: Symbol.for('Auth_SettingService'),
+  Auth_SubscriptionSettingService: Symbol.for('Auth_SubscriptionSettingService'),
+  Auth_OfflineSettingService: Symbol.for('Auth_OfflineSettingService'),
+  Auth_AuthResponseFactory20161215: Symbol.for('Auth_AuthResponseFactory20161215'),
+  Auth_AuthResponseFactory20190520: Symbol.for('Auth_AuthResponseFactory20190520'),
+  Auth_AuthResponseFactory20200115: Symbol.for('Auth_AuthResponseFactory20200115'),
+  Auth_AuthResponseFactoryResolver: Symbol.for('Auth_AuthResponseFactoryResolver'),
+  Auth_KeyParamsFactory: Symbol.for('Auth_KeyParamsFactory'),
+  Auth_SessionTokenDecoder: Symbol.for('Auth_SessionTokenDecoder'),
+  Auth_FallbackSessionTokenDecoder: Symbol.for('Auth_FallbackSessionTokenDecoder'),
+  Auth_CrossServiceTokenDecoder: Symbol.for('Auth_CrossServiceTokenDecoder'),
+  Auth_OfflineUserTokenDecoder: Symbol.for('Auth_OfflineUserTokenDecoder'),
+  Auth_OfflineUserTokenEncoder: Symbol.for('Auth_OfflineUserTokenEncoder'),
+  Auth_CrossServiceTokenEncoder: Symbol.for('Auth_CrossServiceTokenEncoder'),
+  Auth_SessionTokenEncoder: Symbol.for('Auth_SessionTokenEncoder'),
+  Auth_ValetTokenEncoder: Symbol.for('Auth_ValetTokenEncoder'),
+  Auth_WebSocketConnectionTokenDecoder: Symbol.for('Auth_WebSocketConnectionTokenDecoder'),
+  Auth_AuthenticationMethodResolver: Symbol.for('Auth_AuthenticationMethodResolver'),
+  Auth_DomainEventPublisher: Symbol.for('Auth_DomainEventPublisher'),
+  Auth_DomainEventSubscriberFactory: Symbol.for('Auth_DomainEventSubscriberFactory'),
+  Auth_DomainEventFactory: Symbol.for('Auth_DomainEventFactory'),
+  Auth_DomainEventMessageHandler: Symbol.for('Auth_DomainEventMessageHandler'),
+  Auth_HTTPClient: Symbol.for('Auth_HTTPClient'),
+  Auth_Crypter: Symbol.for('Auth_Crypter'),
+  Auth_CryptoNode: Symbol.for('Auth_CryptoNode'),
+  Auth_Timer: Symbol.for('Auth_Timer'),
+  Auth_ContenDecoder: Symbol.for('Auth_ContenDecoder'),
+  Auth_WebSocketsClientService: Symbol.for('Auth_WebSocketClientService'),
+  Auth_RoleService: Symbol.for('Auth_RoleService'),
+  Auth_RoleToSubscriptionMap: Symbol.for('Auth_RoleToSubscriptionMap'),
+  Auth_SettingsAssociationService: Symbol.for('Auth_SettingsAssociationService'),
+  Auth_SubscriptionSettingsAssociationService: Symbol.for('Auth_SubscriptionSettingsAssociationService'),
+  Auth_FeatureService: Symbol.for('Auth_FeatureService'),
+  Auth_SettingDecrypter: Symbol.for('Auth_SettingDecrypter'),
+  Auth_SettingInterpreter: Symbol.for('Auth_SettingInterpreter'),
+  Auth_ProtocolVersionSelector: Symbol.for('Auth_ProtocolVersionSelector'),
+  Auth_BooleanSelector: Symbol.for('Auth_BooleanSelector'),
+  Auth_UserSubscriptionService: Symbol.for('Auth_UserSubscriptionService'),
+  Auth_InversifyExpressAuthController: Symbol.for('Auth_InversifyExpressAuthController'),
+  Auth_InversifyExpressAuthenticatorsController: Symbol.for('Auth_InversifyExpressAuthenticatorsController'),
+  Auth_InversifyExpressSubscriptionInvitesController: Symbol.for('Auth_InversifyExpressSubscriptionInvitesController'),
+  Auth_InversifyExpressUserRequestsController: Symbol.for('Auth_InversifyExpressUserRequestsController'),
+  Auth_InversifyExpressWebSocketsController: Symbol.for('Auth_InversifyExpressWebSocketsController'),
 }
 
 export default TYPES

+ 1 - 0
packages/auth/src/Bootstrap/index.ts

@@ -0,0 +1 @@
+export * from './Service'

+ 12 - 1
packages/auth/src/Controller/AdminController.spec.ts

@@ -8,6 +8,7 @@ import * as express from 'express'
 import { DeleteSetting } from '../Domain/UseCase/DeleteSetting/DeleteSetting'
 import { CreateSubscriptionToken } from '../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
 import { CreateOfflineSubscriptionToken } from '../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionToken'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('AdminController', () => {
   let deleteSetting: DeleteSetting
@@ -16,9 +17,16 @@ describe('AdminController', () => {
   let createOfflineSubscriptionToken: CreateOfflineSubscriptionToken
   let request: express.Request
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
   const createController = () =>
-    new AdminController(deleteSetting, userRepository, createSubscriptionToken, createOfflineSubscriptionToken)
+    new AdminController(
+      deleteSetting,
+      userRepository,
+      createSubscriptionToken,
+      createOfflineSubscriptionToken,
+      controllerContainer,
+    )
 
   beforeEach(() => {
     user = {} as jest.Mocked<User>
@@ -50,6 +58,9 @@ describe('AdminController', () => {
       body: {},
       params: {},
     } as jest.Mocked<express.Request>
+
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
   })
 
   it('should return error if missing email parameter', async () => {

+ 12 - 5
packages/auth/src/Controller/AdminController.ts

@@ -1,4 +1,4 @@
-import { Username } from '@standardnotes/domain-core'
+import { ControllerContainerInterface, Username } from '@standardnotes/domain-core'
 import { SettingName } from '@standardnotes/settings'
 import { Request } from 'express'
 import { inject } from 'inversify'
@@ -20,13 +20,20 @@ import { UserRepositoryInterface } from '../Domain/User/UserRepositoryInterface'
 @controller('/admin')
 export class AdminController extends BaseHttpController {
   constructor(
-    @inject(TYPES.DeleteSetting) private doDeleteSetting: DeleteSetting,
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
-    @inject(TYPES.CreateOfflineSubscriptionToken)
+    @inject(TYPES.Auth_DeleteSetting) private doDeleteSetting: DeleteSetting,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
+    @inject(TYPES.Auth_CreateOfflineSubscriptionToken)
     private createOfflineSubscriptionToken: CreateOfflineSubscriptionToken,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('admin.getUser', this.getUser.bind(this))
+    this.controllerContainer.register('admin.deleteMFASetting', this.deleteMFASetting.bind(this))
+    this.controllerContainer.register('admin.createToken', this.createToken.bind(this))
+    this.controllerContainer.register('admin.createOfflineToken', this.createOfflineToken.bind(this))
+    this.controllerContainer.register('admin.disableEmailBackups', this.disableEmailBackups.bind(this))
   }
 
   @httpGet('/user/:email')

+ 2 - 2
packages/auth/src/Controller/ApiGatewayAuthMiddleware.ts

@@ -8,8 +8,8 @@ import TYPES from '../Bootstrap/Types'
 @injectable()
 export class ApiGatewayAuthMiddleware extends BaseMiddleware {
   constructor(
-    @inject(TYPES.CrossServiceTokenDecoder) private tokenDecoder: TokenDecoderInterface<CrossServiceTokenData>,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_CrossServiceTokenDecoder) private tokenDecoder: TokenDecoderInterface<CrossServiceTokenData>,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {
     super()
   }

+ 2 - 2
packages/auth/src/Controller/ApiGatewayOfflineAuthMiddleware.ts

@@ -8,8 +8,8 @@ import TYPES from '../Bootstrap/Types'
 @injectable()
 export class ApiGatewayOfflineAuthMiddleware extends BaseMiddleware {
   constructor(
-    @inject(TYPES.OfflineUserTokenDecoder) private tokenDecoder: TokenDecoderInterface<OfflineUserTokenData>,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_OfflineUserTokenDecoder) private tokenDecoder: TokenDecoderInterface<OfflineUserTokenData>,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {
     super()
   }

+ 6 - 0
packages/auth/src/Controller/AuthController.spec.ts

@@ -13,6 +13,7 @@ import { SignInWithRecoveryCodes } from '../Domain/UseCase/SignInWithRecoveryCod
 import { GetUserKeyParamsRecovery } from '../Domain/UseCase/GetUserKeyParamsRecovery/GetUserKeyParamsRecovery'
 import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
 import { Logger } from 'winston'
+import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
 
 describe('AuthController', () => {
   let clearLoginAttempts: ClearLoginAttempts
@@ -25,6 +26,7 @@ describe('AuthController', () => {
   let getUserKeyParamsRecovery: GetUserKeyParamsRecovery
   let doGenerateRecoveryCodes: GenerateRecoveryCodes
   let logger: Logger
+  let sessionService: SessionServiceInterface
 
   const createController = () =>
     new AuthController(
@@ -36,6 +38,7 @@ describe('AuthController', () => {
       getUserKeyParamsRecovery,
       doGenerateRecoveryCodes,
       logger,
+      sessionService,
     )
 
   beforeEach(() => {
@@ -58,6 +61,9 @@ describe('AuthController', () => {
 
     logger = {} as jest.Mocked<Logger>
     logger.debug = jest.fn()
+
+    sessionService = {} as jest.Mocked<SessionServiceInterface>
+    sessionService.deleteSessionByToken = jest.fn().mockReturnValue('1-2-3')
   })
 
   it('should register a user', async () => {

+ 40 - 12
packages/auth/src/Controller/AuthController.ts

@@ -1,4 +1,3 @@
-import { inject, injectable } from 'inversify'
 import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
 import {
   ApiVersion,
@@ -7,10 +6,9 @@ import {
   UserDeletionResponseBody,
   UserRegistrationResponseBody,
 } from '@standardnotes/api'
-import { HttpResponse, HttpStatusCode } from '@standardnotes/responses'
+import { ErrorTag, HttpResponse, HttpStatusCode } from '@standardnotes/responses'
 import { ProtocolVersion } from '@standardnotes/common'
 
-import TYPES from '../Bootstrap/Types'
 import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
 import { Register } from '../Domain/UseCase/Register'
 import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
@@ -24,18 +22,19 @@ import { GenerateRecoveryCodesResponseBody } from '../Infra/Http/Response/Genera
 import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
 import { GenerateRecoveryCodesRequestParams } from '../Infra/Http/Request/GenerateRecoveryCodesRequestParams'
 import { Logger } from 'winston'
+import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
 
-@injectable()
 export class AuthController implements UserServerInterface {
   constructor(
-    @inject(TYPES.ClearLoginAttempts) private clearLoginAttempts: ClearLoginAttempts,
-    @inject(TYPES.Register) private registerUser: Register,
-    @inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
-    @inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
-    @inject(TYPES.SignInWithRecoveryCodes) private doSignInWithRecoveryCodes: SignInWithRecoveryCodes,
-    @inject(TYPES.GetUserKeyParamsRecovery) private getUserKeyParamsRecovery: GetUserKeyParamsRecovery,
-    @inject(TYPES.GenerateRecoveryCodes) private doGenerateRecoveryCodes: GenerateRecoveryCodes,
-    @inject(TYPES.Logger) private logger: Logger,
+    private clearLoginAttempts: ClearLoginAttempts,
+    private registerUser: Register,
+    private domainEventPublisher: DomainEventPublisherInterface,
+    private domainEventFactory: DomainEventFactoryInterface,
+    private doSignInWithRecoveryCodes: SignInWithRecoveryCodes,
+    private getUserKeyParamsRecovery: GetUserKeyParamsRecovery,
+    private doGenerateRecoveryCodes: GenerateRecoveryCodes,
+    private logger: Logger,
+    private sessionService: SessionServiceInterface,
   ) {}
 
   async deleteAccount(_params: never): Promise<HttpResponse<UserDeletionResponseBody>> {
@@ -200,4 +199,33 @@ export class AuthController implements UserServerInterface {
       },
     }
   }
+
+  async signOut(params: Record<string, unknown>): Promise<HttpResponse> {
+    if (params.readOnlyAccess) {
+      return {
+        status: HttpStatusCode.Unauthorized,
+        data: {
+          error: {
+            tag: ErrorTag.ReadOnlyAccess,
+            message: 'Session has read-only access.',
+          },
+        },
+      }
+    }
+
+    const userUuid = await this.sessionService.deleteSessionByToken(
+      (params.authorizationHeader as string).replace('Bearer ', ''),
+    )
+
+    let headers = undefined
+    if (userUuid !== null) {
+      headers = new Map([['x-invalidate-cache', userUuid]])
+    }
+
+    return {
+      status: HttpStatusCode.NoContent,
+      data: {},
+      headers,
+    }
+  }
 }

+ 2 - 2
packages/auth/src/Controller/AuthMiddleware.ts

@@ -8,8 +8,8 @@ import { AuthenticateRequest } from '../Domain/UseCase/AuthenticateRequest'
 @injectable()
 export class AuthMiddleware extends BaseMiddleware {
   constructor(
-    @inject(TYPES.AuthenticateRequest) private authenticateRequest: AuthenticateRequest,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_AuthenticateRequest) private authenticateRequest: AuthenticateRequest,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {
     super()
   }

+ 1 - 1
packages/auth/src/Controller/AuthMiddlewareWithoutResponse.ts

@@ -6,7 +6,7 @@ import { AuthenticateRequest } from '../Domain/UseCase/AuthenticateRequest'
 
 @injectable()
 export class AuthMiddlewareWithoutResponse extends BaseMiddleware {
-  constructor(@inject(TYPES.AuthenticateRequest) private authenticateRequest: AuthenticateRequest) {
+  constructor(@inject(TYPES.Auth_AuthenticateRequest) private authenticateRequest: AuthenticateRequest) {
     super()
   }
 

+ 6 - 1
packages/auth/src/Controller/FeaturesController.spec.ts

@@ -6,6 +6,7 @@ import { FeaturesController } from './FeaturesController'
 import { results } from 'inversify-express-utils'
 import { User } from '../Domain/User/User'
 import { GetUserFeatures } from '../Domain/UseCase/GetUserFeatures/GetUserFeatures'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('FeaturesController', () => {
   let getUserFeatures: GetUserFeatures
@@ -13,10 +14,14 @@ describe('FeaturesController', () => {
   let request: express.Request
   let response: express.Response
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
-  const createController = () => new FeaturesController(getUserFeatures)
+  const createController = () => new FeaturesController(getUserFeatures, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     user = {} as jest.Mocked<User>
     user.uuid = '123'
 

+ 8 - 2
packages/auth/src/Controller/FeaturesController.ts

@@ -9,14 +9,20 @@ import {
 } from 'inversify-express-utils'
 import TYPES from '../Bootstrap/Types'
 import { GetUserFeatures } from '../Domain/UseCase/GetUserFeatures/GetUserFeatures'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/users/:userUuid/features')
 export class FeaturesController extends BaseHttpController {
-  constructor(@inject(TYPES.GetUserFeatures) private doGetUserFeatures: GetUserFeatures) {
+  constructor(
+    @inject(TYPES.Auth_GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
+  ) {
     super()
+
+    this.controllerContainer.register('auth.users.getFeatures', this.getFeatures.bind(this))
   }
 
-  @httpGet('/', TYPES.ApiGatewayAuthMiddleware)
+  @httpGet('/', TYPES.Auth_ApiGatewayAuthMiddleware)
   async getFeatures(request: Request, response: Response): Promise<results.JsonResult> {
     if (request.params.userUuid !== response.locals.user.uuid) {
       return this.json(

+ 2 - 2
packages/auth/src/Controller/InternalController.ts

@@ -14,8 +14,8 @@ import { GetUserFeatures } from '../Domain/UseCase/GetUserFeatures/GetUserFeatur
 @controller('/internal')
 export class InternalController extends BaseHttpController {
   constructor(
-    @inject(TYPES.GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
-    @inject(TYPES.GetSetting) private doGetSetting: GetSetting,
+    @inject(TYPES.Auth_GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
+    @inject(TYPES.Auth_GetSetting) private doGetSetting: GetSetting,
   ) {
     super()
   }

+ 6 - 1
packages/auth/src/Controller/ListedController.spec.ts

@@ -6,6 +6,7 @@ import { results } from 'inversify-express-utils'
 import { ListedController } from './ListedController'
 import { User } from '../Domain/User/User'
 import { CreateListedAccount } from '../Domain/UseCase/CreateListedAccount/CreateListedAccount'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('ListedController', () => {
   let createListedAccount: CreateListedAccount
@@ -13,10 +14,14 @@ describe('ListedController', () => {
   let request: express.Request
   let response: express.Response
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
-  const createController = () => new ListedController(createListedAccount)
+  const createController = () => new ListedController(createListedAccount, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     user = {} as jest.Mocked<User>
     user.uuid = '123'
 

+ 8 - 2
packages/auth/src/Controller/ListedController.ts

@@ -5,14 +5,20 @@ import { Request, Response } from 'express'
 import TYPES from '../Bootstrap/Types'
 import { CreateListedAccount } from '../Domain/UseCase/CreateListedAccount/CreateListedAccount'
 import { ErrorTag } from '@standardnotes/responses'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/listed')
 export class ListedController extends BaseHttpController {
-  constructor(@inject(TYPES.CreateListedAccount) private doCreateListedAccount: CreateListedAccount) {
+  constructor(
+    @inject(TYPES.Auth_CreateListedAccount) private doCreateListedAccount: CreateListedAccount,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
+  ) {
     super()
+
+    this.controllerContainer.register('auth.users.createListedAccount', this.createListedAccount.bind(this))
   }
 
-  @httpPost('/', TYPES.ApiGatewayAuthMiddleware)
+  @httpPost('/', TYPES.Auth_ApiGatewayAuthMiddleware)
   async createListedAccount(_request: Request, response: Response): Promise<results.JsonResult> {
     if (response.locals.readOnlyAccess) {
       return this.json(

+ 2 - 2
packages/auth/src/Controller/LockMiddleware.ts

@@ -10,8 +10,8 @@ import { UserRepositoryInterface } from '../Domain/User/UserRepositoryInterface'
 @injectable()
 export class LockMiddleware extends BaseMiddleware {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.LockRepository) private lockRepository: LockRepositoryInterface,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_LockRepository) private lockRepository: LockRepositoryInterface,
   ) {
     super()
   }

+ 7 - 0
packages/auth/src/Controller/OfflineController.spec.ts

@@ -14,6 +14,7 @@ import { GetUserOfflineSubscription } from '../Domain/UseCase/GetUserOfflineSubs
 import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/security'
 import { SubscriptionName } from '@standardnotes/common'
 import { Logger } from 'winston'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('OfflineController', () => {
   let getUserFeatures: GetUserFeatures
@@ -28,6 +29,8 @@ describe('OfflineController', () => {
   let response: express.Response
   let user: User
 
+  let controllerContainer: ControllerContainerInterface
+
   const createController = () =>
     new OfflineController(
       getUserFeatures,
@@ -37,9 +40,13 @@ describe('OfflineController', () => {
       tokenEncoder,
       jwtTTL,
       logger,
+      controllerContainer,
     )
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     user = {} as jest.Mocked<User>
     user.uuid = '123'
 

+ 16 - 9
packages/auth/src/Controller/OfflineController.ts

@@ -15,23 +15,30 @@ import { CreateOfflineSubscriptionToken } from '../Domain/UseCase/CreateOfflineS
 import { GetUserOfflineSubscription } from '../Domain/UseCase/GetUserOfflineSubscription/GetUserOfflineSubscription'
 import { Logger } from 'winston'
 import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/security'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/offline')
 export class OfflineController extends BaseHttpController {
   constructor(
-    @inject(TYPES.GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
-    @inject(TYPES.GetUserOfflineSubscription) private getUserOfflineSubscription: GetUserOfflineSubscription,
-    @inject(TYPES.CreateOfflineSubscriptionToken)
+    @inject(TYPES.Auth_GetUserFeatures) private doGetUserFeatures: GetUserFeatures,
+    @inject(TYPES.Auth_GetUserOfflineSubscription) private getUserOfflineSubscription: GetUserOfflineSubscription,
+    @inject(TYPES.Auth_CreateOfflineSubscriptionToken)
     private createOfflineSubscriptionToken: CreateOfflineSubscriptionToken,
-    @inject(TYPES.AuthenticateOfflineSubscriptionToken) private authenticateToken: AuthenticateOfflineSubscriptionToken,
-    @inject(TYPES.OfflineUserTokenEncoder) private tokenEncoder: TokenEncoderInterface<OfflineUserTokenData>,
-    @inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_AuthenticateOfflineSubscriptionToken)
+    private authenticateToken: AuthenticateOfflineSubscriptionToken,
+    @inject(TYPES.Auth_OfflineUserTokenEncoder) private tokenEncoder: TokenEncoderInterface<OfflineUserTokenData>,
+    @inject(TYPES.Auth_AUTH_JWT_TTL) private jwtTTL: number,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.offline.features', this.getOfflineFeatures.bind(this))
+    this.controllerContainer.register('auth.offline.subscriptionTokens.create', this.createToken.bind(this))
+    this.controllerContainer.register('auth.users.getOfflineSubscriptionByToken', this.getSubscription.bind(this))
   }
 
-  @httpGet('/features', TYPES.OfflineUserAuthMiddleware)
+  @httpGet('/features', TYPES.Auth_OfflineUserAuthMiddleware)
   async getOfflineFeatures(_request: Request, response: Response): Promise<results.JsonResult> {
     const result = await this.doGetUserFeatures.execute({
       email: response.locals.offlineUserEmail,
@@ -119,7 +126,7 @@ export class OfflineController extends BaseHttpController {
     return this.json({ authToken })
   }
 
-  @httpGet('/users/subscription', TYPES.ApiGatewayOfflineAuthMiddleware)
+  @httpGet('/users/subscription', TYPES.Auth_ApiGatewayOfflineAuthMiddleware)
   async getSubscription(_request: Request, response: Response): Promise<results.JsonResult> {
     const result = await this.getUserOfflineSubscription.execute({
       userEmail: response.locals.userEmail,

+ 2 - 2
packages/auth/src/Controller/OfflineUserAuthMiddleware.ts

@@ -9,8 +9,8 @@ import { OfflineSettingRepositoryInterface } from '../Domain/Setting/OfflineSett
 @injectable()
 export class OfflineUserAuthMiddleware extends BaseMiddleware {
   constructor(
-    @inject(TYPES.OfflineSettingRepository) private offlineSettingRepository: OfflineSettingRepositoryInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_OfflineSettingRepository) private offlineSettingRepository: OfflineSettingRepositoryInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {
     super()
   }

+ 6 - 1
packages/auth/src/Controller/SessionController.spec.ts

@@ -7,6 +7,7 @@ import { results } from 'inversify-express-utils'
 import { RefreshSessionToken } from '../Domain/UseCase/RefreshSessionToken'
 import { DeletePreviousSessionsForUser } from '../Domain/UseCase/DeletePreviousSessionsForUser'
 import { DeleteSessionForUser } from '../Domain/UseCase/DeleteSessionForUser'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('SessionController', () => {
   let deleteSessionForUser: DeleteSessionForUser
@@ -14,11 +15,15 @@ describe('SessionController', () => {
   let refreshSessionToken: RefreshSessionToken
   let request: express.Request
   let response: express.Response
+  let controllerContainer: ControllerContainerInterface
 
   const createController = () =>
-    new SessionController(deleteSessionForUser, deletePreviousSessionsForUser, refreshSessionToken)
+    new SessionController(deleteSessionForUser, deletePreviousSessionsForUser, refreshSessionToken, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     deleteSessionForUser = {} as jest.Mocked<DeleteSessionForUser>
     deleteSessionForUser.execute = jest.fn().mockReturnValue({ success: true })
 

+ 12 - 5
packages/auth/src/Controller/SessionController.ts

@@ -13,18 +13,25 @@ import TYPES from '../Bootstrap/Types'
 import { DeletePreviousSessionsForUser } from '../Domain/UseCase/DeletePreviousSessionsForUser'
 import { DeleteSessionForUser } from '../Domain/UseCase/DeleteSessionForUser'
 import { RefreshSessionToken } from '../Domain/UseCase/RefreshSessionToken'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/session')
 export class SessionController extends BaseHttpController {
   constructor(
-    @inject(TYPES.DeleteSessionForUser) private deleteSessionForUser: DeleteSessionForUser,
-    @inject(TYPES.DeletePreviousSessionsForUser) private deletePreviousSessionsForUser: DeletePreviousSessionsForUser,
-    @inject(TYPES.RefreshSessionToken) private refreshSessionToken: RefreshSessionToken,
+    @inject(TYPES.Auth_DeleteSessionForUser) private deleteSessionForUser: DeleteSessionForUser,
+    @inject(TYPES.Auth_DeletePreviousSessionsForUser)
+    private deletePreviousSessionsForUser: DeletePreviousSessionsForUser,
+    @inject(TYPES.Auth_RefreshSessionToken) private refreshSessionToken: RefreshSessionToken,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.session.delete', this.deleteSession.bind(this))
+    this.controllerContainer.register('auth.session.deleteAll', this.deleteAllSessions.bind(this))
+    this.controllerContainer.register('auth.session.refresh', this.refresh.bind(this))
   }
 
-  @httpDelete('/', TYPES.AuthMiddleware, TYPES.SessionMiddleware)
+  @httpDelete('/', TYPES.Auth_AuthMiddleware, TYPES.Auth_SessionMiddleware)
   async deleteSession(request: Request, response: Response): Promise<results.JsonResult | void> {
     if (response.locals.readOnlyAccess) {
       return this.json(
@@ -80,7 +87,7 @@ export class SessionController extends BaseHttpController {
     response.status(204).send()
   }
 
-  @httpDelete('/all', TYPES.AuthMiddleware, TYPES.SessionMiddleware)
+  @httpDelete('/all', TYPES.Auth_AuthMiddleware, TYPES.Auth_SessionMiddleware)
   async deleteAllSessions(_request: Request, response: Response): Promise<results.JsonResult | void> {
     if (response.locals.readOnlyAccess) {
       return this.json(

+ 12 - 1
packages/auth/src/Controller/SessionsController.spec.ts

@@ -10,6 +10,7 @@ import { GetActiveSessionsForUser } from '../Domain/UseCase/GetActiveSessionsFor
 import { AuthenticateRequest } from '../Domain/UseCase/AuthenticateRequest'
 import { User } from '../Domain/User/User'
 import { CreateCrossServiceToken } from '../Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('SessionsController', () => {
   let getActiveSessionsForUser: GetActiveSessionsForUser
@@ -20,11 +21,21 @@ describe('SessionsController', () => {
   let response: express.Response
   let user: User
   let createCrossServiceToken: CreateCrossServiceToken
+  let controllerContainer: ControllerContainerInterface
 
   const createController = () =>
-    new SessionsController(getActiveSessionsForUser, authenticateRequest, sessionProjector, createCrossServiceToken)
+    new SessionsController(
+      getActiveSessionsForUser,
+      authenticateRequest,
+      sessionProjector,
+      createCrossServiceToken,
+      controllerContainer,
+    )
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     session = {} as jest.Mocked<Session>
 
     user = {} as jest.Mocked<User>

+ 9 - 5
packages/auth/src/Controller/SessionsController.ts

@@ -16,16 +16,20 @@ import { User } from '../Domain/User/User'
 import { ProjectorInterface } from '../Projection/ProjectorInterface'
 import { SessionProjector } from '../Projection/SessionProjector'
 import { CreateCrossServiceToken } from '../Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/sessions')
 export class SessionsController extends BaseHttpController {
   constructor(
-    @inject(TYPES.GetActiveSessionsForUser) private getActiveSessionsForUser: GetActiveSessionsForUser,
-    @inject(TYPES.AuthenticateRequest) private authenticateRequest: AuthenticateRequest,
-    @inject(TYPES.SessionProjector) private sessionProjector: ProjectorInterface<Session>,
-    @inject(TYPES.CreateCrossServiceToken) private createCrossServiceToken: CreateCrossServiceToken,
+    @inject(TYPES.Auth_GetActiveSessionsForUser) private getActiveSessionsForUser: GetActiveSessionsForUser,
+    @inject(TYPES.Auth_AuthenticateRequest) private authenticateRequest: AuthenticateRequest,
+    @inject(TYPES.Auth_SessionProjector) private sessionProjector: ProjectorInterface<Session>,
+    @inject(TYPES.Auth_CreateCrossServiceToken) private createCrossServiceToken: CreateCrossServiceToken,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.sessions.list', this.getSessions.bind(this))
   }
 
   @httpPost('/validate')
@@ -56,7 +60,7 @@ export class SessionsController extends BaseHttpController {
     return this.json({ authToken: result.token })
   }
 
-  @httpGet('/', TYPES.AuthMiddleware, TYPES.SessionMiddleware)
+  @httpGet('/', TYPES.Auth_AuthMiddleware, TYPES.Auth_SessionMiddleware)
   async getSessions(_request: Request, response: Response): Promise<results.JsonResult> {
     if (response.locals.readOnlyAccess) {
       return this.json([])

+ 7 - 1
packages/auth/src/Controller/SettingsController.spec.ts

@@ -10,6 +10,7 @@ import { GetSetting } from '../Domain/UseCase/GetSetting/GetSetting'
 import { UpdateSetting } from '../Domain/UseCase/UpdateSetting/UpdateSetting'
 import { DeleteSetting } from '../Domain/UseCase/DeleteSetting/DeleteSetting'
 import { EncryptionVersion } from '../Domain/Encryption/EncryptionVersion'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('SettingsController', () => {
   let deleteSetting: DeleteSetting
@@ -20,10 +21,15 @@ describe('SettingsController', () => {
   let request: express.Request
   let response: express.Response
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
-  const createController = () => new SettingsController(getSettings, getSetting, updateSetting, deleteSetting)
+  const createController = () =>
+    new SettingsController(getSettings, getSetting, updateSetting, deleteSetting, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     deleteSetting = {} as jest.Mocked<DeleteSetting>
     deleteSetting.execute = jest.fn().mockReturnValue({ success: true })
 

+ 15 - 8
packages/auth/src/Controller/SettingsController.ts

@@ -16,19 +16,26 @@ import { DeleteSetting } from '../Domain/UseCase/DeleteSetting/DeleteSetting'
 import { GetSetting } from '../Domain/UseCase/GetSetting/GetSetting'
 import { GetSettings } from '../Domain/UseCase/GetSettings/GetSettings'
 import { UpdateSetting } from '../Domain/UseCase/UpdateSetting/UpdateSetting'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/users/:userUuid')
 export class SettingsController extends BaseHttpController {
   constructor(
-    @inject(TYPES.GetSettings) private doGetSettings: GetSettings,
-    @inject(TYPES.GetSetting) private doGetSetting: GetSetting,
-    @inject(TYPES.UpdateSetting) private doUpdateSetting: UpdateSetting,
-    @inject(TYPES.DeleteSetting) private doDeleteSetting: DeleteSetting,
+    @inject(TYPES.Auth_GetSettings) private doGetSettings: GetSettings,
+    @inject(TYPES.Auth_GetSetting) private doGetSetting: GetSetting,
+    @inject(TYPES.Auth_UpdateSetting) private doUpdateSetting: UpdateSetting,
+    @inject(TYPES.Auth_DeleteSetting) private doDeleteSetting: DeleteSetting,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.users.getSettings', this.getSettings.bind(this))
+    this.controllerContainer.register('auth.users.getSetting', this.getSetting.bind(this))
+    this.controllerContainer.register('auth.users.updateSetting', this.updateSetting.bind(this))
+    this.controllerContainer.register('auth.users.deleteSetting', this.deleteSetting.bind(this))
   }
 
-  @httpGet('/settings', TYPES.ApiGatewayAuthMiddleware)
+  @httpGet('/settings', TYPES.Auth_ApiGatewayAuthMiddleware)
   async getSettings(request: Request, response: Response): Promise<results.JsonResult> {
     if (request.params.userUuid !== response.locals.user.uuid) {
       return this.json(
@@ -47,7 +54,7 @@ export class SettingsController extends BaseHttpController {
     return this.json(result)
   }
 
-  @httpGet('/settings/:settingName', TYPES.ApiGatewayAuthMiddleware)
+  @httpGet('/settings/:settingName', TYPES.Auth_ApiGatewayAuthMiddleware)
   async getSetting(request: Request, response: Response): Promise<results.JsonResult> {
     if (request.params.userUuid !== response.locals.user.uuid) {
       return this.json(
@@ -70,7 +77,7 @@ export class SettingsController extends BaseHttpController {
     return this.json(result, 400)
   }
 
-  @httpPut('/settings', TYPES.ApiGatewayAuthMiddleware)
+  @httpPut('/settings', TYPES.Auth_ApiGatewayAuthMiddleware)
   async updateSetting(request: Request, response: Response): Promise<results.JsonResult | results.StatusCodeResult> {
     if (response.locals.readOnlyAccess) {
       return this.json(
@@ -117,7 +124,7 @@ export class SettingsController extends BaseHttpController {
     return this.json(result, result.statusCode)
   }
 
-  @httpDelete('/settings/:settingName', TYPES.ApiGatewayAuthMiddleware)
+  @httpDelete('/settings/:settingName', TYPES.Auth_ApiGatewayAuthMiddleware)
   async deleteSetting(request: Request, response: Response): Promise<results.JsonResult> {
     if (response.locals.readOnlyAccess) {
       return this.json(

+ 5 - 5
packages/auth/src/Controller/SubscriptionInvitesController.ts

@@ -26,14 +26,14 @@ import { ListSharedSubscriptionInvitations } from '../Domain/UseCase/ListSharedS
 @injectable()
 export class SubscriptionInvitesController implements SubscriptionServerInterface {
   constructor(
-    @inject(TYPES.InviteToSharedSubscription) private inviteToSharedSubscription: InviteToSharedSubscription,
-    @inject(TYPES.AcceptSharedSubscriptionInvitation)
+    @inject(TYPES.Auth_InviteToSharedSubscription) private inviteToSharedSubscription: InviteToSharedSubscription,
+    @inject(TYPES.Auth_AcceptSharedSubscriptionInvitation)
     private acceptSharedSubscriptionInvitation: AcceptSharedSubscriptionInvitation,
-    @inject(TYPES.DeclineSharedSubscriptionInvitation)
+    @inject(TYPES.Auth_DeclineSharedSubscriptionInvitation)
     private declineSharedSubscriptionInvitation: DeclineSharedSubscriptionInvitation,
-    @inject(TYPES.CancelSharedSubscriptionInvitation)
+    @inject(TYPES.Auth_CancelSharedSubscriptionInvitation)
     private cancelSharedSubscriptionInvitation: CancelSharedSubscriptionInvitation,
-    @inject(TYPES.ListSharedSubscriptionInvitations)
+    @inject(TYPES.Auth_ListSharedSubscriptionInvitations)
     private listSharedSubscriptionInvitations: ListSharedSubscriptionInvitations,
   ) {}
 

+ 6 - 1
packages/auth/src/Controller/SubscriptionSettingsController.spec.ts

@@ -6,6 +6,7 @@ import { results } from 'inversify-express-utils'
 import { User } from '../Domain/User/User'
 import { SubscriptionSettingsController } from './SubscriptionSettingsController'
 import { GetSetting } from '../Domain/UseCase/GetSetting/GetSetting'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('SubscriptionSettingsController', () => {
   let getSetting: GetSetting
@@ -13,10 +14,14 @@ describe('SubscriptionSettingsController', () => {
   let request: express.Request
   let response: express.Response
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
-  const createController = () => new SubscriptionSettingsController(getSetting)
+  const createController = () => new SubscriptionSettingsController(getSetting, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     user = {} as jest.Mocked<User>
     user.uuid = '123'
 

+ 8 - 2
packages/auth/src/Controller/SubscriptionSettingsController.ts

@@ -9,14 +9,20 @@ import {
 } from 'inversify-express-utils'
 import TYPES from '../Bootstrap/Types'
 import { GetSetting } from '../Domain/UseCase/GetSetting/GetSetting'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/users/:userUuid')
 export class SubscriptionSettingsController extends BaseHttpController {
-  constructor(@inject(TYPES.GetSetting) private doGetSetting: GetSetting) {
+  constructor(
+    @inject(TYPES.Auth_GetSetting) private doGetSetting: GetSetting,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
+  ) {
     super()
+
+    this.controllerContainer.register('auth.users.getSubscriptionSetting', this.getSubscriptionSetting.bind(this))
   }
 
-  @httpGet('/subscription-settings/:subscriptionSettingName', TYPES.ApiGatewayAuthMiddleware)
+  @httpGet('/subscription-settings/:subscriptionSettingName', TYPES.Auth_ApiGatewayAuthMiddleware)
   async getSubscriptionSetting(request: Request, response: Response): Promise<results.JsonResult> {
     const result = await this.doGetSetting.execute({
       userUuid: response.locals.user.uuid,

+ 7 - 0
packages/auth/src/Controller/SubscriptionTokensController.spec.ts

@@ -13,6 +13,7 @@ import { Role } from '../Domain/Role/Role'
 import { SettingServiceInterface } from '../Domain/Setting/SettingServiceInterface'
 import { Setting } from '../Domain/Setting/Setting'
 import { CrossServiceTokenData, TokenEncoderInterface } from '@standardnotes/security'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('SubscriptionTokensController', () => {
   let createSubscriptionToken: CreateSubscriptionToken
@@ -29,6 +30,8 @@ describe('SubscriptionTokensController', () => {
   let user: User
   let role: Role
 
+  let controllerContainer: ControllerContainerInterface
+
   const createController = () =>
     new SubscriptionTokensController(
       createSubscriptionToken,
@@ -38,9 +41,13 @@ describe('SubscriptionTokensController', () => {
       roleProjector,
       tokenEncoder,
       jwtTTL,
+      controllerContainer,
     )
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     user = {} as jest.Mocked<User>
     user.uuid = '123'
     user.roles = Promise.resolve([role])

+ 12 - 8
packages/auth/src/Controller/SubscriptionTokensController.ts

@@ -18,22 +18,26 @@ import { AuthenticateSubscriptionToken } from '../Domain/UseCase/AuthenticateSub
 import { CreateSubscriptionToken } from '../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
 import { User } from '../Domain/User/User'
 import { ProjectorInterface } from '../Projection/ProjectorInterface'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/subscription-tokens')
 export class SubscriptionTokensController extends BaseHttpController {
   constructor(
-    @inject(TYPES.CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
-    @inject(TYPES.AuthenticateSubscriptionToken) private authenticateToken: AuthenticateSubscriptionToken,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.UserProjector) private userProjector: ProjectorInterface<User>,
-    @inject(TYPES.RoleProjector) private roleProjector: ProjectorInterface<Role>,
-    @inject(TYPES.CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
-    @inject(TYPES.AUTH_JWT_TTL) private jwtTTL: number,
+    @inject(TYPES.Auth_CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
+    @inject(TYPES.Auth_AuthenticateSubscriptionToken) private authenticateToken: AuthenticateSubscriptionToken,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_UserProjector) private userProjector: ProjectorInterface<User>,
+    @inject(TYPES.Auth_RoleProjector) private roleProjector: ProjectorInterface<Role>,
+    @inject(TYPES.Auth_CrossServiceTokenEncoder) private tokenEncoder: TokenEncoderInterface<CrossServiceTokenData>,
+    @inject(TYPES.Auth_AUTH_JWT_TTL) private jwtTTL: number,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.subscription-tokens.create', this.createToken.bind(this))
   }
 
-  @httpPost('/', TYPES.ApiGatewayAuthMiddleware)
+  @httpPost('/', TYPES.Auth_ApiGatewayAuthMiddleware)
   async createToken(_request: Request, response: Response): Promise<results.JsonResult> {
     if (response.locals.readOnlyAccess) {
       return this.json(

+ 1 - 1
packages/auth/src/Controller/UserRequestsController.ts

@@ -6,7 +6,7 @@ import { ProcessUserRequest } from '../Domain/UseCase/ProcessUserRequest/Process
 
 @injectable()
 export class UserRequestsController implements UserRequestServerInterface {
-  constructor(@inject(TYPES.ProcessUserRequest) private processUserRequest: ProcessUserRequest) {}
+  constructor(@inject(TYPES.Auth_ProcessUserRequest) private processUserRequest: ProcessUserRequest) {}
 
   async submitUserRequest(params: UserRequestRequestParams): Promise<HttpResponse<UserRequestResponseBody>> {
     const result = await this.processUserRequest.execute({

+ 6 - 0
packages/auth/src/Controller/UsersController.spec.ts

@@ -13,6 +13,7 @@ import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
 import { IncreaseLoginAttempts } from '../Domain/UseCase/IncreaseLoginAttempts'
 import { ChangeCredentials } from '../Domain/UseCase/ChangeCredentials/ChangeCredentials'
 import { InviteToSharedSubscription } from '../Domain/UseCase/InviteToSharedSubscription/InviteToSharedSubscription'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('UsersController', () => {
   let updateUser: UpdateUser
@@ -27,6 +28,7 @@ describe('UsersController', () => {
   let request: express.Request
   let response: express.Response
   let user: User
+  let controllerContainer: ControllerContainerInterface
 
   const createController = () =>
     new UsersController(
@@ -37,9 +39,13 @@ describe('UsersController', () => {
       clearLoginAttempts,
       increaseLoginAttempts,
       changeCredentials,
+      controllerContainer,
     )
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     updateUser = {} as jest.Mocked<UpdateUser>
     updateUser.execute = jest.fn()
 

+ 17 - 10
packages/auth/src/Controller/UsersController.ts

@@ -19,22 +19,29 @@ import { GetUserSubscription } from '../Domain/UseCase/GetUserSubscription/GetUs
 import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
 import { IncreaseLoginAttempts } from '../Domain/UseCase/IncreaseLoginAttempts'
 import { ChangeCredentials } from '../Domain/UseCase/ChangeCredentials/ChangeCredentials'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 @controller('/users')
 export class UsersController extends BaseHttpController {
   constructor(
-    @inject(TYPES.UpdateUser) private updateUser: UpdateUser,
-    @inject(TYPES.GetUserKeyParams) private getUserKeyParams: GetUserKeyParams,
-    @inject(TYPES.DeleteAccount) private doDeleteAccount: DeleteAccount,
-    @inject(TYPES.GetUserSubscription) private doGetUserSubscription: GetUserSubscription,
-    @inject(TYPES.ClearLoginAttempts) private clearLoginAttempts: ClearLoginAttempts,
-    @inject(TYPES.IncreaseLoginAttempts) private increaseLoginAttempts: IncreaseLoginAttempts,
-    @inject(TYPES.ChangeCredentials) private changeCredentialsUseCase: ChangeCredentials,
+    @inject(TYPES.Auth_UpdateUser) private updateUser: UpdateUser,
+    @inject(TYPES.Auth_GetUserKeyParams) private getUserKeyParams: GetUserKeyParams,
+    @inject(TYPES.Auth_DeleteAccount) private doDeleteAccount: DeleteAccount,
+    @inject(TYPES.Auth_GetUserSubscription) private doGetUserSubscription: GetUserSubscription,
+    @inject(TYPES.Auth_ClearLoginAttempts) private clearLoginAttempts: ClearLoginAttempts,
+    @inject(TYPES.Auth_IncreaseLoginAttempts) private increaseLoginAttempts: IncreaseLoginAttempts,
+    @inject(TYPES.Auth_ChangeCredentials) private changeCredentialsUseCase: ChangeCredentials,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
   ) {
     super()
+
+    this.controllerContainer.register('auth.users.update', this.update.bind(this))
+    this.controllerContainer.register('auth.users.getKeyParams', this.keyParams.bind(this))
+    this.controllerContainer.register('auth.users.getSubscription', this.getSubscription.bind(this))
+    this.controllerContainer.register('auth.users.updateCredentials', this.changeCredentials.bind(this))
   }
 
-  @httpPatch('/:userId', TYPES.ApiGatewayAuthMiddleware)
+  @httpPatch('/:userId', TYPES.Auth_ApiGatewayAuthMiddleware)
   async update(request: Request, response: Response): Promise<results.JsonResult | void> {
     if (response.locals.readOnlyAccess) {
       return this.json(
@@ -125,7 +132,7 @@ export class UsersController extends BaseHttpController {
     return this.json({ message: result.message }, result.responseCode)
   }
 
-  @httpGet('/:userUuid/subscription', TYPES.ApiGatewayAuthMiddleware)
+  @httpGet('/:userUuid/subscription', TYPES.Auth_ApiGatewayAuthMiddleware)
   async getSubscription(request: Request, response: Response): Promise<results.JsonResult> {
     if (request.params.userUuid !== response.locals.user.uuid) {
       return this.json(
@@ -149,7 +156,7 @@ export class UsersController extends BaseHttpController {
     return this.json(result, 400)
   }
 
-  @httpPut('/:userId/attributes/credentials', TYPES.AuthMiddleware)
+  @httpPut('/:userId/attributes/credentials', TYPES.Auth_AuthMiddleware)
   async changeCredentials(request: Request, response: Response): Promise<results.JsonResult | void> {
     if (response.locals.readOnlyAccess) {
       return this.json(

+ 6 - 1
packages/auth/src/Controller/ValetTokenController.spec.ts

@@ -4,15 +4,20 @@ import { Request, Response } from 'express'
 import { results } from 'inversify-express-utils'
 import { ValetTokenController } from './ValetTokenController'
 import { CreateValetToken } from '../Domain/UseCase/CreateValetToken/CreateValetToken'
+import { ControllerContainerInterface } from '@standardnotes/domain-core'
 
 describe('ValetTokenController', () => {
   let createValetToken: CreateValetToken
   let request: Request
   let response: Response
+  let controllerContainer: ControllerContainerInterface
 
-  const createController = () => new ValetTokenController(createValetToken)
+  const createController = () => new ValetTokenController(createValetToken, controllerContainer)
 
   beforeEach(() => {
+    controllerContainer = {} as jest.Mocked<ControllerContainerInterface>
+    controllerContainer.register = jest.fn()
+
     createValetToken = {} as jest.Mocked<CreateValetToken>
     createValetToken.execute = jest.fn().mockReturnValue({ success: true, valetToken: 'foobar' })
 

+ 8 - 3
packages/auth/src/Controller/ValetTokenController.ts

@@ -9,15 +9,20 @@ import {
 } from 'inversify-express-utils'
 import { CreateValetTokenPayload, ErrorTag } from '@standardnotes/responses'
 import { ValetTokenOperation } from '@standardnotes/security'
-import { Uuid } from '@standardnotes/domain-core'
+import { ControllerContainerInterface, Uuid } from '@standardnotes/domain-core'
 
 import TYPES from '../Bootstrap/Types'
 import { CreateValetToken } from '../Domain/UseCase/CreateValetToken/CreateValetToken'
 
-@controller('/valet-tokens', TYPES.ApiGatewayAuthMiddleware)
+@controller('/valet-tokens', TYPES.Auth_ApiGatewayAuthMiddleware)
 export class ValetTokenController extends BaseHttpController {
-  constructor(@inject(TYPES.CreateValetToken) private createValetKey: CreateValetToken) {
+  constructor(
+    @inject(TYPES.Auth_CreateValetToken) private createValetKey: CreateValetToken,
+    @inject(TYPES.Auth_ControllerContainer) private controllerContainer: ControllerContainerInterface,
+  ) {
     super()
+
+    this.controllerContainer.register('auth.valet-tokens.create', this.create.bind(this))
   }
 
   @httpPost('/')

+ 3 - 3
packages/auth/src/Domain/Auth/AuthResponseFactory20161215.ts

@@ -15,9 +15,9 @@ import { AuthResponseFactoryInterface } from './AuthResponseFactoryInterface'
 @injectable()
 export class AuthResponseFactory20161215 implements AuthResponseFactoryInterface {
   constructor(
-    @inject(TYPES.UserProjector) protected userProjector: ProjectorInterface<User>,
-    @inject(TYPES.SessionTokenEncoder) protected tokenEncoder: TokenEncoderInterface<SessionTokenData>,
-    @inject(TYPES.Logger) protected logger: Logger,
+    @inject(TYPES.Auth_UserProjector) protected userProjector: ProjectorInterface<User>,
+    @inject(TYPES.Auth_SessionTokenEncoder) protected tokenEncoder: TokenEncoderInterface<SessionTokenData>,
+    @inject(TYPES.Auth_Logger) protected logger: Logger,
   ) {}
 
   async createResponse(dto: {

+ 7 - 7
packages/auth/src/Domain/Auth/AuthResponseFactory20200115.ts

@@ -23,13 +23,13 @@ import { AuthResponse20200115 } from './AuthResponse20200115'
 @injectable()
 export class AuthResponseFactory20200115 extends AuthResponseFactory20190520 {
   constructor(
-    @inject(TYPES.SessionService) private sessionService: SessionServiceInterface,
-    @inject(TYPES.KeyParamsFactory) private keyParamsFactory: KeyParamsFactoryInterface,
-    @inject(TYPES.UserProjector) userProjector: ProjectorInterface<User>,
-    @inject(TYPES.SessionTokenEncoder) protected override tokenEncoder: TokenEncoderInterface<SessionTokenData>,
-    @inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
-    @inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
-    @inject(TYPES.Logger) logger: Logger,
+    @inject(TYPES.Auth_SessionService) private sessionService: SessionServiceInterface,
+    @inject(TYPES.Auth_KeyParamsFactory) private keyParamsFactory: KeyParamsFactoryInterface,
+    @inject(TYPES.Auth_UserProjector) userProjector: ProjectorInterface<User>,
+    @inject(TYPES.Auth_SessionTokenEncoder) protected override tokenEncoder: TokenEncoderInterface<SessionTokenData>,
+    @inject(TYPES.Auth_DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
+    @inject(TYPES.Auth_DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
+    @inject(TYPES.Auth_Logger) logger: Logger,
   ) {
     super(userProjector, tokenEncoder, logger)
   }

+ 4 - 4
packages/auth/src/Domain/Auth/AuthResponseFactoryResolver.ts

@@ -11,10 +11,10 @@ import { AuthResponseFactoryResolverInterface } from './AuthResponseFactoryResol
 @injectable()
 export class AuthResponseFactoryResolver implements AuthResponseFactoryResolverInterface {
   constructor(
-    @inject(TYPES.AuthResponseFactory20161215) private authResponseFactory20161215: AuthResponseFactory20161215,
-    @inject(TYPES.AuthResponseFactory20190520) private authResponseFactory20190520: AuthResponseFactory20190520,
-    @inject(TYPES.AuthResponseFactory20200115) private authResponseFactory20200115: AuthResponseFactory20200115,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_AuthResponseFactory20161215) private authResponseFactory20161215: AuthResponseFactory20161215,
+    @inject(TYPES.Auth_AuthResponseFactory20190520) private authResponseFactory20190520: AuthResponseFactory20190520,
+    @inject(TYPES.Auth_AuthResponseFactory20200115) private authResponseFactory20200115: AuthResponseFactory20200115,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   resolveAuthResponseFactoryVersion(apiVersion: string): AuthResponseFactoryInterface {

+ 4 - 4
packages/auth/src/Domain/Auth/AuthenticationMethodResolver.ts

@@ -9,10 +9,10 @@ import { AuthenticationMethodResolverInterface } from './AuthenticationMethodRes
 @injectable()
 export class AuthenticationMethodResolver implements AuthenticationMethodResolverInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.SessionService) private sessionService: SessionServiceInterface,
-    @inject(TYPES.SessionTokenDecoder) private sessionTokenDecoder: TokenDecoderInterface<SessionTokenData>,
-    @inject(TYPES.FallbackSessionTokenDecoder)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_SessionService) private sessionService: SessionServiceInterface,
+    @inject(TYPES.Auth_SessionTokenDecoder) private sessionTokenDecoder: TokenDecoderInterface<SessionTokenData>,
+    @inject(TYPES.Auth_FallbackSessionTokenDecoder)
     private fallbackSessionTokenDecoder: TokenDecoderInterface<SessionTokenData>,
   ) {}
 

+ 3 - 3
packages/auth/src/Domain/Encryption/CrypterNode.ts

@@ -9,9 +9,9 @@ import { CrypterInterface } from './CrypterInterface'
 @injectable()
 export class CrypterNode implements CrypterInterface {
   constructor(
-    @inject(TYPES.ENCRYPTION_SERVER_KEY) private encryptionServerKey: string,
-    @inject(TYPES.CryptoNode) private cryptoNode: CryptoNode,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_ENCRYPTION_SERVER_KEY) private encryptionServerKey: string,
+    @inject(TYPES.Auth_CryptoNode) private cryptoNode: CryptoNode,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {
     const keyBuffer = Buffer.from(encryptionServerKey, 'hex')
     const { byteLength } = keyBuffer

+ 1 - 1
packages/auth/src/Domain/Event/DomainEventFactory.ts

@@ -30,7 +30,7 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
 
 @injectable()
 export class DomainEventFactory implements DomainEventFactoryInterface {
-  constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
+  constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
 
   createSessionCreatedEvent(dto: { userUuid: string }): SessionCreatedEvent {
     return {

+ 3 - 3
packages/auth/src/Domain/Feature/FeatureService.ts

@@ -15,10 +15,10 @@ import { TimerInterface } from '@standardnotes/time'
 @injectable()
 export class FeatureService implements FeatureServiceInterface {
   constructor(
-    @inject(TYPES.RoleToSubscriptionMap) private roleToSubscriptionMap: RoleToSubscriptionMapInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_RoleToSubscriptionMap) private roleToSubscriptionMap: RoleToSubscriptionMapInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.Timer) private timer: TimerInterface,
+    @inject(TYPES.Auth_Timer) private timer: TimerInterface,
   ) {}
 
   async userIsEntitledToFeature(user: User, featureIdentifier: string): Promise<boolean> {

+ 6 - 5
packages/auth/src/Domain/Handler/AccountDeletionRequestedEventHandler.ts

@@ -10,11 +10,12 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 @injectable()
 export class AccountDeletionRequestedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface,
-    @inject(TYPES.EphemeralSessionRepository) private ephemeralSessionRepository: EphemeralSessionRepositoryInterface,
-    @inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_SessionRepository) private sessionRepository: SessionRepositoryInterface,
+    @inject(TYPES.Auth_EphemeralSessionRepository)
+    private ephemeralSessionRepository: EphemeralSessionRepositoryInterface,
+    @inject(TYPES.Auth_RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: AccountDeletionRequestedEvent): Promise<void> {

+ 5 - 5
packages/auth/src/Domain/Handler/ExtensionKeyGrantedEventHandler.ts

@@ -16,11 +16,11 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class ExtensionKeyGrantedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.OfflineSettingService) private offlineSettingService: OfflineSettingServiceInterface,
-    @inject(TYPES.ContenDecoder) private contentDecoder: ContentDecoderInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_OfflineSettingService) private offlineSettingService: OfflineSettingServiceInterface,
+    @inject(TYPES.Auth_ContenDecoder) private contentDecoder: ContentDecoderInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: ExtensionKeyGrantedEvent): Promise<void> {

+ 4 - 3
packages/auth/src/Domain/Handler/FileRemovedEventHandler.ts

@@ -12,9 +12,10 @@ import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscripti
 @injectable()
 export class FileRemovedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
-    @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
+    @inject(TYPES.Auth_SubscriptionSettingService)
+    private subscriptionSettingService: SubscriptionSettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: FileRemovedEvent): Promise<void> {

+ 5 - 4
packages/auth/src/Domain/Handler/FileUploadedEventHandler.ts

@@ -13,10 +13,11 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 @injectable()
 export class FileUploadedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
-    @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
+    @inject(TYPES.Auth_SubscriptionSettingService)
+    private subscriptionSettingService: SubscriptionSettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: FileUploadedEvent): Promise<void> {

+ 3 - 3
packages/auth/src/Domain/Handler/ListedAccountCreatedEventHandler.ts

@@ -11,9 +11,9 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 @injectable()
 export class ListedAccountCreatedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: ListedAccountCreatedEvent): Promise<void> {

+ 3 - 3
packages/auth/src/Domain/Handler/ListedAccountDeletedEventHandler.ts

@@ -11,9 +11,9 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 @injectable()
 export class ListedAccountDeletedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: ListedAccountDeletedEvent): Promise<void> {

+ 5 - 5
packages/auth/src/Domain/Handler/PredicateVerificationRequestedEventHandler.ts

@@ -16,11 +16,11 @@ import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
 @injectable()
 export class PredicateVerificationRequestedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.VerifyPredicate) private verifyPredicate: VerifyPredicate,
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
-    @inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_VerifyPredicate) private verifyPredicate: VerifyPredicate,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
+    @inject(TYPES.Auth_DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: PredicateVerificationRequestedEvent): Promise<void> {

+ 1 - 1
packages/auth/src/Domain/Handler/SharedSubscriptionInvitationCreatedEventHandler.ts

@@ -8,7 +8,7 @@ import { AcceptSharedSubscriptionInvitation } from '../UseCase/AcceptSharedSubsc
 @injectable()
 export class SharedSubscriptionInvitationCreatedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.AcceptSharedSubscriptionInvitation)
+    @inject(TYPES.Auth_AcceptSharedSubscriptionInvitation)
     private acceptSharedSubscriptionInvitation: AcceptSharedSubscriptionInvitation,
   ) {}
 

+ 3 - 2
packages/auth/src/Domain/Handler/SubscriptionCancelledEventHandler.ts

@@ -8,8 +8,9 @@ import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/Offl
 @injectable()
 export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
   ) {}
 

+ 6 - 5
packages/auth/src/Domain/Handler/SubscriptionExpiredEventHandler.ts

@@ -12,12 +12,13 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionExpiredEvent): Promise<void> {

+ 8 - 6
packages/auth/src/Domain/Handler/SubscriptionPurchasedEventHandler.ts

@@ -17,13 +17,15 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_SubscriptionSettingService)
+    private subscriptionSettingService: SubscriptionSettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionPurchasedEvent): Promise<void> {

+ 8 - 6
packages/auth/src/Domain/Handler/SubscriptionReassignedEventHandler.ts

@@ -18,12 +18,14 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionReassignedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_SubscriptionSettingService)
+    private subscriptionSettingService: SubscriptionSettingServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionReassignedEvent): Promise<void> {

+ 6 - 5
packages/auth/src/Domain/Handler/SubscriptionRefundedEventHandler.ts

@@ -12,12 +12,13 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionRefundedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionRefundedEvent): Promise<void> {

+ 6 - 5
packages/auth/src/Domain/Handler/SubscriptionRenewedEventHandler.ts

@@ -13,12 +13,13 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionRenewedEvent): Promise<void> {

+ 11 - 9
packages/auth/src/Domain/Handler/SubscriptionSyncRequestedEventHandler.ts

@@ -24,16 +24,18 @@ import { Username } from '@standardnotes/domain-core'
 @injectable()
 export class SubscriptionSyncRequestedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
-    @inject(TYPES.UserSubscriptionRepository) private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
-    @inject(TYPES.OfflineUserSubscriptionRepository)
+    @inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
+    @inject(TYPES.Auth_UserSubscriptionRepository)
+    private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
+    @inject(TYPES.Auth_OfflineUserSubscriptionRepository)
     private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
-    @inject(TYPES.RoleService) private roleService: RoleServiceInterface,
-    @inject(TYPES.SettingService) private settingService: SettingServiceInterface,
-    @inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
-    @inject(TYPES.OfflineSettingService) private offlineSettingService: OfflineSettingServiceInterface,
-    @inject(TYPES.ContenDecoder) private contentDecoder: ContentDecoderInterface,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_RoleService) private roleService: RoleServiceInterface,
+    @inject(TYPES.Auth_SettingService) private settingService: SettingServiceInterface,
+    @inject(TYPES.Auth_SubscriptionSettingService)
+    private subscriptionSettingService: SubscriptionSettingServiceInterface,
+    @inject(TYPES.Auth_OfflineSettingService) private offlineSettingService: OfflineSettingServiceInterface,
+    @inject(TYPES.Auth_ContenDecoder) private contentDecoder: ContentDecoderInterface,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: SubscriptionSyncRequestedEvent): Promise<void> {

+ 2 - 2
packages/auth/src/Domain/Handler/UserDisabledSessionUserAgentLoggingEventHandler.ts

@@ -8,8 +8,8 @@ import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterfac
 @injectable()
 export class UserDisabledSessionUserAgentLoggingEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface,
-    @inject(TYPES.SessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
+    @inject(TYPES.Auth_SessionRepository) private sessionRepository: SessionRepositoryInterface,
+    @inject(TYPES.Auth_SessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
   ) {}
 
   async handle(event: UserDisabledSessionUserAgentLoggingEvent): Promise<void> {

+ 4 - 4
packages/auth/src/Domain/Handler/UserEmailChangedEventHandler.ts

@@ -8,10 +8,10 @@ import TYPES from '../../Bootstrap/Types'
 @injectable()
 export class UserEmailChangedEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
-    @inject(TYPES.USER_SERVER_CHANGE_EMAIL_URL) private userServerChangeEmailUrl: string,
-    @inject(TYPES.USER_SERVER_AUTH_KEY) private userServerAuthKey: string,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_HTTPClient) private httpClient: AxiosInstance,
+    @inject(TYPES.Auth_USER_SERVER_CHANGE_EMAIL_URL) private userServerChangeEmailUrl: string,
+    @inject(TYPES.Auth_USER_SERVER_AUTH_KEY) private userServerAuthKey: string,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: UserEmailChangedEvent): Promise<void> {

+ 4 - 4
packages/auth/src/Domain/Handler/UserRegisteredEventHandler.ts

@@ -8,10 +8,10 @@ import TYPES from '../../Bootstrap/Types'
 @injectable()
 export class UserRegisteredEventHandler implements DomainEventHandlerInterface {
   constructor(
-    @inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
-    @inject(TYPES.USER_SERVER_REGISTRATION_URL) private userServerRegistrationUrl: string,
-    @inject(TYPES.USER_SERVER_AUTH_KEY) private userServerAuthKey: string,
-    @inject(TYPES.Logger) private logger: Logger,
+    @inject(TYPES.Auth_HTTPClient) private httpClient: AxiosInstance,
+    @inject(TYPES.Auth_USER_SERVER_REGISTRATION_URL) private userServerRegistrationUrl: string,
+    @inject(TYPES.Auth_USER_SERVER_AUTH_KEY) private userServerAuthKey: string,
+    @inject(TYPES.Auth_Logger) private logger: Logger,
   ) {}
 
   async handle(event: UserRegisteredEvent): Promise<void> {

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov