Stratal API Reference
    Preparing search index...

    Class Container

    Unified Container for DI management

    Manages the two-tier container hierarchy:

    • Global scope: Singletons, base instances of request-scoped services
    • Request scope: Context-enriched instances per HTTP request
    import { container as tsyringeRootContainer } from 'tsyringe'

    const container = new Container({
    env,
    ctx,
    container: tsyringeRootContainer.createChildContainer()
    })

    // Auto-extract token and scope from decorator
    container.register(I18nService)

    // Explicit token with auto-scope detection
    container.register(MY_TOKEN, MyService)

    // Explicit singleton registration
    container.registerSingleton(ConfigService)

    // Register a value
    container.registerValue(MY_TOKEN, myInstance)
    // Resolves from container
    const service = container.resolve(MY_TOKEN)
    await container.runInRequestScope(routerContext, async () => {
    const i18n = container.resolve(I18N_TOKEN)
    // i18n is context-enriched for this request
    })
    const reqContainer = container.createRequestScope(routerContext)
    await reqContainer.runWithContextStore(async () => {
    // use reqContainer...
    })
    // Cleanup is automatic
    Index

    Constructors

    Accessors

    Methods

    • Create request scope container

      Use when you need manual control over the request container lifecycle, typically in middleware. Returns a new Container instance wrapping a request-scoped child container.

      Can only be called on global container (not request-scoped).

      Parameters

      • routerContext: RouterContext

        RouterContext for the current request

      Returns Container

      Request-scoped Container instance

      const reqContainer = container.createRequestScope(routerContext)
      await reqContainer.runWithContextStore(async () => {
      // use reqContainer...
      })
      // Cleanup is automatic
    • Replace a service registration with a decorated version

      Resolves the current instance, applies the decorator, and re-registers the decorated instance. This is a one-time operation at initialization time.

      IMPORTANT: This method can only be used in a module's onInitialize() method. The onInitialize() hook runs after all modules have registered their services via the @Module decorator, ensuring all dependencies are available for resolution.

      Type Parameters

      • T

      Parameters

      Returns void

      // In your module's onInitialize() method:
      import type { OnInitialize, ModuleContext } from 'stratal/module'

      @Module({ providers: [...] })
      export class MyModule implements OnInitialize {
      onInitialize({ container }: ModuleContext): void {
      container.extend(DI_TOKENS.Database, (db, c) => {
      const logger = c.resolve(LOGGER_TOKENS.LoggerService)
      return new LoggingDatabaseDecorator(db, logger)
      })
      }
      }
      // DI_TOKENS.Database now resolves to LoggingDatabaseDecorator
      // In onInitialize()
      container.extend(SERVICE_TOKEN, (svc) => new LoggingDecorator(svc))
      container.extend(SERVICE_TOKEN, (svc) => new CachingDecorator(svc))
      // SERVICE_TOKEN now resolves to CachingDecorator(LoggingDecorator(original))
    • Check if currently in request context

      Returns boolean

      true if in request context (inside runInRequestScope or runWithContextStore)

    • Register a service with optional explicit token and scope

      Lifecycle is controlled via the scope parameter, which maps to tsyringe's Lifecycle. If no scope is provided, defaults to Transient (new instance per resolution).

      register(serviceClass, scope?) - Use class as token register(token, serviceClass, scope?) - Explicit token

      Type Parameters

      • T extends object

      Parameters

      Returns void

      container.register(MyService)  // Transient by default
      container.register(MyService, Scope.Singleton) // Singleton
      container.register(MY_TOKEN, MyService, Scope.Request) // Request-scoped with token
    • Register a service with optional explicit token and scope

      Lifecycle is controlled via the scope parameter, which maps to tsyringe's Lifecycle. If no scope is provided, defaults to Transient (new instance per resolution).

      register(serviceClass, scope?) - Use class as token register(token, serviceClass, scope?) - Explicit token

      Type Parameters

      • T extends object

      Parameters

      Returns void

      container.register(MyService)  // Transient by default
      container.register(MyService, Scope.Singleton) // Singleton
      container.register(MY_TOKEN, MyService, Scope.Request) // Request-scoped with token
    • Register an alias to an existing token

      Creates a redirect so that resolving the alias token returns the same instance as the target token. This is useful for:

      • Interface tokens that alias concrete implementations
      • Multiple entry points to the same service

      Type Parameters

      • T

      Parameters

      Returns void

      // Register concrete implementation
      container.register(UserService)

      // Create alias for interface token
      container.registerExisting(I_USER_SERVICE, UserService)

      // Both resolve to the same instance
      const a = container.resolve(UserService)
      const b = container.resolve(I_USER_SERVICE)
      // a === b (same instance)
    • Register with factory function

      Use when instance creation requires custom logic or other resolved dependencies.

      Type Parameters

      • T

      Parameters

      • token: InjectionToken<T>

        DI token for resolution

      • factory: (container: Container) => T

        Factory function that receives the Container

      Returns void

      container.registerFactory(FORMATTER_TOKEN, (c) => {
      const config = c.resolve(CONFIG_TOKEN)
      return config.get('logging').formatter === 'pretty'
      ? new PrettyFormatter()
      : new JsonFormatter()
      }, Scope.Singleton)
    • Register a service as singleton

      Passthrough to tsyringe's registerSingleton method.

      registerSingleton(serviceClass) - Use class as token registerSingleton(token, serviceClass) - Explicit token

      Type Parameters

      • T extends object

      Parameters

      Returns void

      container.registerSingleton(LoggerService)  // Uses class as token
      container.registerSingleton(CONFIG_TOKEN, ConfigService) // Explicit token
    • Register a service as singleton

      Passthrough to tsyringe's registerSingleton method.

      registerSingleton(serviceClass) - Use class as token registerSingleton(token, serviceClass) - Explicit token

      Type Parameters

      • T extends object

      Parameters

      Returns void

      container.registerSingleton(LoggerService)  // Uses class as token
      container.registerSingleton(CONFIG_TOKEN, ConfigService) // Explicit token
    • Register a value (instance) directly

      Use for registering pre-created instances or primitive values.

      Type Parameters

      • T

      Parameters

      Returns void

      container.registerValue(CONFIG_TOKEN, configInstance)
      container.registerValue(DI_TOKENS.Application, app)
    • Resolve a service from the container

      Type Parameters

      • T

      Parameters

      Returns T

      Resolved service instance

      const logger = container.resolve(LOGGER_TOKEN)
      const config = container.resolve<IConfigService>(CONFIG_TOKEN)
    • Run callback within request scope

      Creates a child container with fresh instances for services registered with scope: Scope.Request. Automatically handles lifecycle (setup and cleanup).

      Also wraps with RequestContextStore for Zod i18n validation support.

      Can only be called on global container (not request-scoped).

      Type Parameters

      • T

      Parameters

      • routerContext: RouterContext

        RouterContext for the current request

      • callback: () => T | Promise<T>

        Async operation to run with request context

      Returns Promise<T>

      Result of callback execution

      await container.runInRequestScope(routerContext, async () => {
      const i18n = container.resolve(I18N_TOKEN)
      const message = i18n.t('common.welcome')
      // ...
      })
    • Run callback within request scope context store

      Wraps callback with RequestContextStore (for Zod i18n validation) and automatically handles cleanup after callback completes.

      Can only be called on request-scoped container (not global).

      Type Parameters

      • T

      Parameters

      • callback: () => T | Promise<T>

        Async operation to run with context

      Returns Promise<T>

      Result of callback execution

      const reqContainer = container.createRequestScope(routerContext)
      await reqContainer.runWithContextStore(async () => {
      const i18n = reqContainer.resolve(I18N_TOKENS.I18nService)
      // ...
      })
      // Cleanup is automatic
    • Start a conditional binding with predicate evaluation

      Creates a fluent builder for registering a service that chooses between two implementations based on a predicate evaluated at resolution time.

      Parameters

      • predicate: (container: PredicateContainer) => boolean

        Function that returns true/false to determine implementation. Receives a container with resolve() method for resolving dependencies.

      • options: WhenOptions = {}

        Optional configuration (cache: whether to cache predicate result)

      Returns ConditionalBindingBuilder

      Fluent builder for specifying token and implementations

      container
      .when((c) => c.resolve(CONFIG_TOKEN).get('env') === 'development')
      .use(FORMATTER_TOKEN)
      .give(PrettyFormatter)
      .otherwise(JsonFormatter)
      container
      .when((c) => c.resolve(FEATURE_FLAGS_TOKEN).isEnabled('newPaymentGateway'), { cache: true })
      .use(PAYMENT_TOKEN)
      .give(StripePaymentService)
      .otherwise(LegacyPaymentService)