{"version":3,"file":"scoped-container.mjs","names":["InjectableScope","UnifiedStorage","AbstractContainer","ScopedContainer","defaultScope","Request","storage","disposed","metadata","parent","registry","requestId","getStorage","getRegistry","getTokenResolver","getNameResolver","getServiceInvalidator","getRequestId","getParent","getMetadata","key","setMetadata","value","get","token","args","Error","tokenResolver","realToken","getRegistryToken","has","record","scope","error","instance","getInstanceResolver","resolveRequestScopedInstance","resolveInstance","invalidate","service","holder","findByInstance","invalidateWithStorage","name","dispose","endRequest","tryGetSync","Singleton","result","tryGetSyncFromStorage","addInstance","clearAllWithStorage","removeRequestId"],"sources":["../../../src/container/scoped-container.mts"],"sourcesContent":["import type { z, ZodType } from 'zod/v4'\n\nimport type { Factorable } from '../interfaces/factory.interface.mjs'\nimport type {\n  ClassType,\n  ClassTypeWithArgument,\n  FactoryInjectionToken,\n  InjectionTokenSchemaType,\n} from '../token/injection-token.mjs'\nimport type { Registry } from '../token/registry.mjs'\nimport type { Join, UnionToArray } from '../utils/types.mjs'\nimport type { NameResolver } from '../internal/core/name-resolver.mjs'\nimport type { ServiceInvalidator } from '../internal/core/service-invalidator.mjs'\nimport type { TokenResolver } from '../internal/core/token-resolver.mjs'\n\nimport { InjectableScope } from '../enums/index.mjs'\nimport { UnifiedStorage } from '../internal/holder/unified-storage.mjs'\nimport {\n  BoundInjectionToken,\n  InjectionToken,\n} from '../token/injection-token.mjs'\nimport { AbstractContainer } from './abstract-container.mjs'\nimport { Container } from './container.mjs'\n\n/**\n * Request-scoped dependency injection container.\n *\n * Wraps a parent Container and provides isolated request-scoped instances\n * while delegating singleton and transient resolution to the parent.\n * This design eliminates race conditions that can occur with async operations\n * when multiple requests are processed concurrently.\n */\nexport class ScopedContainer extends AbstractContainer {\n  protected readonly defaultScope = InjectableScope.Request\n\n  private readonly storage: UnifiedStorage\n  private disposed = false\n  private readonly metadata: Record<string, any>\n\n  constructor(\n    private readonly parent: Container,\n    private readonly registry: Registry,\n    public readonly requestId: string,\n    metadata?: Record<string, any>,\n  ) {\n    super()\n    // Create own unified storage for request-scoped services\n    this.storage = new UnifiedStorage(InjectableScope.Request)\n    this.metadata = metadata || {}\n  }\n\n  // ============================================================================\n  // ABSTRACT METHOD IMPLEMENTATIONS - Delegate to parent\n  // ============================================================================\n\n  getStorage(): UnifiedStorage {\n    return this.storage\n  }\n\n  protected getRegistry(): Registry {\n    return this.registry\n  }\n\n  protected getTokenResolver(): TokenResolver {\n    return this.parent.getTokenResolver()\n  }\n\n  protected getNameResolver(): NameResolver {\n    return this.parent.getNameResolver()\n  }\n\n  protected getServiceInvalidator(): ServiceInvalidator {\n    return this.parent.getServiceInvalidator()\n  }\n\n  // ============================================================================\n  // SCOPED CONTAINER SPECIFIC METHODS\n  // ============================================================================\n\n  /**\n   * Gets the request ID for this scoped container.\n   */\n  getRequestId(): string {\n    return this.requestId\n  }\n\n  /**\n   * Gets the parent container.\n   */\n  getParent(): Container {\n    return this.parent\n  }\n\n  /**\n   * Gets metadata from the request context.\n   */\n  getMetadata(key: string): any | undefined {\n    return this.metadata[key]\n  }\n\n  /**\n   * Sets metadata on the request context.\n   */\n  setMetadata(key: string, value: any): void {\n    this.metadata[key] = value\n  }\n\n  /**\n   * Gets an instance from the container.\n   * Request-scoped services are resolved from this container's storage.\n   * All other services are delegated to the parent container.\n   */\n  // #1 Simple class\n  get<T extends ClassType>(\n    token: T,\n  ): InstanceType<T> extends Factorable<infer R>\n    ? Promise<R>\n    : Promise<InstanceType<T>>\n  // #1.1 Simple class with args\n  get<T extends ClassTypeWithArgument<R>, R>(\n    token: T,\n    args: R,\n  ): Promise<InstanceType<T>>\n  // #2 Token with required Schema\n  get<T, S extends InjectionTokenSchemaType>(\n    token: InjectionToken<T, S>,\n    args: z.input<S>,\n  ): Promise<T>\n  // #3 Token with optional Schema\n  get<T, S extends InjectionTokenSchemaType, R extends boolean>(\n    token: InjectionToken<T, S, R>,\n  ): R extends false\n    ? Promise<T>\n    : S extends ZodType<infer Type>\n      ? `Error: Your token requires args: ${Join<\n          UnionToArray<keyof Type>,\n          ', '\n        >}`\n      : 'Error: Your token requires args'\n  // #4 Token with no Schema\n  get<T>(token: InjectionToken<T, undefined>): Promise<T>\n  get<T>(token: BoundInjectionToken<T, any>): Promise<T>\n  get<T>(token: FactoryInjectionToken<T, any>): Promise<T>\n\n  async get(\n    token:\n      | ClassType\n      | InjectionToken<any>\n      | BoundInjectionToken<any, any>\n      | FactoryInjectionToken<any, any>,\n    args?: unknown,\n  ) {\n    if (this.disposed) {\n      throw new Error('ScopedContainer has been disposed')\n    }\n\n    // Check if this is a request-scoped service\n    const tokenResolver = this.getTokenResolver()\n    const realToken = tokenResolver.getRegistryToken(token)\n\n    if (this.registry.has(realToken)) {\n      const record = this.registry.get(realToken)\n      if (record.scope === InjectableScope.Request) {\n        // Resolve request-scoped service from this container\n        const [error, instance] = await this.parent\n          .getInstanceResolver()\n          .resolveRequestScopedInstance(token, args, this)\n\n        if (error) {\n          throw error\n        }\n\n        return instance\n      }\n    }\n\n    // Delegate singleton/transient services to parent\n    const [error, instance] = await this.parent\n      .getInstanceResolver()\n      .resolveInstance(token, args, this, this.storage, this.requestId)\n\n    if (error) {\n      throw error\n    }\n\n    return instance\n  }\n\n  /**\n   * Invalidates a service and its dependencies.\n   */\n  async invalidate(service: unknown): Promise<void> {\n    // Find the service by instance in request storage\n    const holder = this.storage.findByInstance(service)\n    if (!holder) {\n      // Try parent storage\n      return this.parent.invalidate(service)\n    }\n\n    await this.getServiceInvalidator().invalidateWithStorage(\n      holder.name,\n      this.storage,\n    )\n  }\n\n  /**\n   * Disposes the container and cleans up all resources.\n   * Alias for endRequest().\n   */\n  async dispose(): Promise<void> {\n    return this.endRequest()\n  }\n\n  /**\n   * @internal\n   * Attempts to get an instance synchronously if it already exists.\n   * Checks request storage first, then delegates to parent.\n   */\n  override tryGetSync<T>(token: any, args?: any): T | null {\n    // Check request storage first for request-scoped services\n    const tokenResolver = this.getTokenResolver()\n    const realToken = tokenResolver.getRegistryToken(token)\n    const scope = this.registry.has(realToken)\n      ? this.registry.get(realToken).scope\n      : InjectableScope.Singleton\n\n    if (scope === InjectableScope.Request) {\n      const result = this.tryGetSyncFromStorage<T>(\n        token,\n        args,\n        this.storage,\n        this.requestId,\n      )\n      if (result !== null) {\n        return result\n      }\n    }\n\n    // Delegate to parent for singleton/transient\n    return this.parent.tryGetSync<T>(token, args, this.requestId)\n  }\n\n  /**\n   * Adds an instance to the container.\n   * Overrides base class to check disposed state.\n   */\n  override addInstance<T>(\n    token: ClassType | InjectionToken<T, any> | BoundInjectionToken<T, any>,\n    instance: T,\n  ): void {\n    if (this.disposed) {\n      throw new Error('ScopedContainer has been disposed')\n    }\n\n    super.addInstance(token, instance)\n  }\n\n  /**\n   * Ends the request and cleans up all request-scoped services.\n   */\n  async endRequest(): Promise<void> {\n    if (this.disposed) {\n      return\n    }\n\n    this.disposed = true\n\n    // Clear all request-scoped services\n    await this.getServiceInvalidator().clearAllWithStorage(this.storage)\n\n    // Remove request ID from parent\n    this.parent.removeRequestId(this.requestId)\n  }\n}\n"],"mappings":";;;;;;;;;;;;GAgCA,IAAaG,kBAAb,cAAqCD,kBAAAA;;;;CAChBE,eAAeJ,gBAAgBK;CAEjCC;CACTC,WAAW;CACFC;CAEjB,YACE,QACA,UACA,WACAA,UACA;AACA,SAAK,EAAA,KALYC,SAAAA,QAAAA,KACAC,WAAAA,UAAAA,KACDC,YAAAA;AAKhB,OAAKL,UAAU,IAAIL,eAAeD,gBAAgBK,QAAO;AACzD,OAAKG,WAAWA,YAAY,EAAC;;CAO/BI,aAA6B;AAC3B,SAAO,KAAKN;;CAGJO,cAAwB;AAChC,SAAO,KAAKH;;CAGJI,mBAAkC;AAC1C,SAAO,KAAKL,OAAOK,kBAAgB;;CAG3BC,kBAAgC;AACxC,SAAO,KAAKN,OAAOM,iBAAe;;CAG1BC,wBAA4C;AACpD,SAAO,KAAKP,OAAOO,uBAAqB;;;;IAU1CC,eAAuB;AACrB,SAAO,KAAKN;;;;IAMdO,YAAuB;AACrB,SAAO,KAAKT;;;;IAMdU,YAAYC,KAA8B;AACxC,SAAO,KAAKZ,SAASY;;;;IAMvBC,YAAYD,KAAaE,OAAkB;AACzC,OAAKd,SAASY,OAAOE;;CAwCvB,MAAMC,IACJC,OAKAC,MACA;AACA,MAAI,KAAKlB,SACP,OAAM,IAAImB,MAAM,oCAAA;EAKlB,MAAME,YADgB,KAAKd,kBAAgB,CACXe,iBAAiBL,MAAAA;AAEjD,MAAI,KAAKd,SAASoB,IAAIF,UAAAA,EAEpB;OADe,KAAKlB,SAASa,IAAIK,UAAAA,CACtBI,UAAUhC,gBAAgBK,SAAS;IAE5C,MAAM,CAAC4B,SAAOC,cAAY,MAAM,KAAKzB,OAClC0B,qBAAmB,CACnBC,6BAA6BZ,OAAOC,MAAM,KAAI;AAEjD,QAAIQ,QACF,OAAMA;AAGR,WAAOC;;;EAKX,MAAM,CAACD,OAAOC,YAAY,MAAM,KAAKzB,OAClC0B,qBAAmB,CACnBE,gBAAgBb,OAAOC,MAAM,MAAM,KAAKnB,SAAS,KAAKK,UAAS;AAElE,MAAIsB,MACF,OAAMA;AAGR,SAAOC;;;;IAMT,MAAMI,WAAWC,SAAiC;EAEhD,MAAMC,SAAS,KAAKlC,QAAQmC,eAAeF,QAAAA;AAC3C,MAAI,CAACC,OAEH,QAAO,KAAK/B,OAAO6B,WAAWC,QAAAA;AAGhC,QAAM,KAAKvB,uBAAqB,CAAG0B,sBACjCF,OAAOG,MACP,KAAKrC,QAAO;;;;;IAQhB,MAAMsC,UAAyB;AAC7B,SAAO,KAAKC,YAAU;;;;;;IAQxB,WAAuBrB,OAAYC,MAAsB;EAGvD,MAAMG,YADgB,KAAKd,kBAAgB,CACXe,iBAAiBL,MAAAA;AAKjD,OAJc,KAAKd,SAASoB,IAAIF,UAAAA,GAC5B,KAAKlB,SAASa,IAAIK,UAAAA,CAAWI,QAC7BhC,gBAAgB+C,eAEN/C,gBAAgBK,SAAS;GACrC,MAAM2C,SAAS,KAAKC,sBAClBzB,OACAC,MACA,KAAKnB,SACL,KAAKK,UAAS;AAEhB,OAAIqC,WAAW,KACb,QAAOA;;AAKX,SAAO,KAAKvC,OAAOqC,WAActB,OAAOC,MAAM,KAAKd,UAAS;;;;;IAO9D,YACEa,OACAU,UACM;AACN,MAAI,KAAK3B,SACP,OAAM,IAAImB,MAAM,oCAAA;AAGlB,QAAMwB,YAAY1B,OAAOU,SAAAA;;;;IAM3B,MAAMW,aAA4B;AAChC,MAAI,KAAKtC,SACP;AAGF,OAAKA,WAAW;AAGhB,QAAM,KAAKS,uBAAqB,CAAGmC,oBAAoB,KAAK7C,QAAO;AAGnE,OAAKG,OAAO2C,gBAAgB,KAAKzC,UAAS"}