{"version":3,"file":"get-injectors.mjs","names":["withoutResolutionContext","InjectableTokenMeta","getInjectors","currentFactoryContext","provideFactoryContext","context","original","getFactoryContext","Error","promiseCollector","injectState","getRequest","token","args","skipCycleTracking","isFrozen","idx","currentIndex","request","requests","toString","result","error","doInject","inject","then","r","catch","e","promise","push","asyncInject","realToken","wrapSyncInit","cb","previousState","promises","originalPromiseCollector","originalInjectState","newInjectState","ctx","cachedInstance","container","tryGetSync","Proxy","get","optional","injectors"],"sources":["../../../src/utils/get-injectors.mts"],"sourcesContent":["import type { z, ZodObject, ZodType } from 'zod/v4'\n\nimport type {\n  Factorable,\n  FactorableWithArgs,\n} from '../interfaces/factory.interface.mjs'\nimport type { ServiceInitializationContext } from '../internal/context/service-initialization-context.mjs'\nimport type {\n  BoundInjectionToken,\n  ClassType,\n  ClassTypeWithArgument,\n  ClassTypeWithoutArguments,\n  FactoryInjectionToken,\n  InjectionToken,\n  InjectionTokenSchemaType,\n} from '../token/injection-token.mjs'\nimport type {\n  InjectRequest,\n  InjectState,\n  Join,\n  UnionToArray,\n} from './types.mjs'\n\nimport { withoutResolutionContext } from '../internal/context/resolution-context.mjs'\nimport { InjectableTokenMeta } from '../symbols/index.mjs'\n\nexport interface Injectors {\n  // #1 Simple class\n  asyncInject<T extends ClassTypeWithoutArguments>(\n    token: T,\n  ): InstanceType<T> extends Factorable<infer R>\n    ? Promise<R>\n    : Promise<InstanceType<T>>\n  asyncInject<Args, T extends ClassTypeWithArgument<Args>>(\n    token: T,\n    args: Args,\n  ): Promise<InstanceType<T>>\n  asyncInject<\n    Schema extends InjectionTokenSchemaType,\n    R,\n    T extends FactorableWithArgs<R, Schema>,\n  >(\n    token: T,\n    args: z.input<Schema>,\n  ): Promise<R>\n\n  // #2 Token with required Schema\n  asyncInject<T, S extends InjectionTokenSchemaType>(\n    token: InjectionToken<T, S>,\n    args: z.input<S>,\n  ): Promise<T>\n  // #3 Token with optional Schema\n  asyncInject<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  asyncInject<T>(token: InjectionToken<T, undefined>): Promise<T>\n  asyncInject<T>(token: BoundInjectionToken<T, any>): Promise<T>\n  asyncInject<T>(token: FactoryInjectionToken<T, any>): Promise<T>\n\n  inject<T extends ClassTypeWithoutArguments>(\n    token: T,\n  ): InstanceType<T> extends Factorable<infer R> ? R : InstanceType<T>\n  inject<Args, T extends ClassTypeWithArgument<Args>>(\n    token: T,\n    args: Args,\n  ): InstanceType<T>\n  inject<\n    Schema extends InjectionTokenSchemaType,\n    R,\n    T extends FactorableWithArgs<R, Schema>,\n  >(\n    token: T,\n    args: z.input<Schema>,\n  ): R\n\n  inject<T, S extends InjectionTokenSchemaType>(\n    token: InjectionToken<T, S>,\n    args: z.input<S>,\n  ): T\n  // #3 Token with optional Schema\n  inject<T, S extends InjectionTokenSchemaType, R extends boolean>(\n    token: InjectionToken<T, S, R>,\n  ): R extends false\n    ? 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  inject<T>(token: InjectionToken<T, undefined>): T\n  inject<T>(token: BoundInjectionToken<T, any>): T\n  inject<T>(token: FactoryInjectionToken<T, any>): T\n\n  /**\n   * Optional injection that returns null if the service fails to initialize\n   * or is not available. This is useful when you want to inject a service\n   * that may not be configured or may fail gracefully.\n   *\n   * @example\n   * ```ts\n   * class MyService {\n   *   constructor() {\n   *     const optionalService = optional(OptionalServiceToken)\n   *     // optionalService will be null if initialization fails\n   *     if (optionalService) {\n   *       optionalService.doSomething()\n   *     }\n   *   }\n   * }\n   * ```\n   */\n  optional<T extends ClassType>(\n    token: T,\n  ): (InstanceType<T> extends Factorable<infer R> ? R : InstanceType<T>) | null\n  optional<T, S extends InjectionTokenSchemaType>(\n    token: InjectionToken<T, S>,\n    args: z.input<S>,\n  ): T | null\n  optional<T, S extends InjectionTokenSchemaType, R extends boolean>(\n    token: InjectionToken<T, S, R>,\n  ): R extends false\n    ? T | null\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  optional<T>(token: InjectionToken<T, undefined>): T | null\n  optional<T>(token: BoundInjectionToken<T, any>): T | null\n  optional<T>(token: FactoryInjectionToken<T, any>): T | null\n\n  wrapSyncInit(\n    cb: () => any,\n  ): (injectState?: InjectState) => [any, Promise<any>[], InjectState]\n\n  provideFactoryContext(\n    context: ServiceInitializationContext | null,\n  ): ServiceInitializationContext | null\n}\n\nexport function getInjectors() {\n  let currentFactoryContext: ServiceInitializationContext | null = null\n\n  function provideFactoryContext(\n    context: ServiceInitializationContext | null,\n  ): ServiceInitializationContext | null {\n    const original = currentFactoryContext\n    currentFactoryContext = context\n    return original\n  }\n  function getFactoryContext(): ServiceInitializationContext {\n    if (!currentFactoryContext) {\n      throw new Error(\n        '[Injector] Trying to access injection context outside of a injectable context',\n      )\n    }\n    return currentFactoryContext\n  }\n\n  let promiseCollector: null | ((promise: Promise<any>) => void) = null\n  let injectState: InjectState | null = null\n\n  function getRequest(\n    token: InjectionToken<any>,\n    args?: unknown,\n    skipCycleTracking = false,\n  ) {\n    if (!injectState) {\n      throw new Error(\n        '[Injector] Trying to make a request outside of a injectable context',\n      )\n    }\n    if (injectState.isFrozen) {\n      const idx = injectState.currentIndex++\n      const request = injectState.requests[idx]\n      if (request.token !== token) {\n        throw new Error(\n          `[Injector] Wrong token order. Expected ${request.token.toString()} but got ${token.toString()}`,\n        )\n      }\n      return request\n    }\n    let result: any = null\n    let error: Error | null = null\n\n    // For async inject, we run outside the resolution context to skip cycle tracking.\n    // This is because asyncInject returns a promise that doesn't block the constructor,\n    // so it cannot cause a deadlock even with circular dependencies.\n    const doInject = () =>\n      getFactoryContext()\n        .inject(token as any, args as any)\n        .then((r) => {\n          result = r\n          return r\n        })\n        .catch((e) => {\n          // We don't throw here because we have a mechanism to handle errors\n          error = e\n        })\n\n    const promise = skipCycleTracking\n      ? withoutResolutionContext(doInject)\n      : doInject()\n\n    const request: InjectRequest = {\n      token,\n      promise,\n      get result() {\n        return result\n      },\n      get error() {\n        return error\n      },\n    }\n    injectState.requests.push(request)\n    injectState.currentIndex++\n\n    return request\n  }\n\n  function asyncInject(\n    token:\n      | ClassType\n      | InjectionToken<any>\n      | BoundInjectionToken<any, any>\n      | FactoryInjectionToken<any, any>,\n    args?: unknown,\n  ) {\n    if (!injectState) {\n      throw new Error(\n        '[Injector] Trying to access inject outside of a injectable context',\n      )\n    }\n    // @ts-expect-error In case we have a class\n    const realToken = token[InjectableTokenMeta] ?? token\n    // Pass skipCycleTracking=true because asyncInject returns a promise that doesn't\n    // block the constructor, so it cannot cause a deadlock even with circular dependencies.\n    const request = getRequest(realToken, args, true)\n    return request.promise.then((result) => {\n      if (request.error) {\n        // We throw here because we want to fail the asyncInject call if the dependency fails to initialize\n        throw request.error\n      }\n      return result\n    })\n  }\n\n  function wrapSyncInit(cb: () => any) {\n    return (previousState?: InjectState) => {\n      const promises: Promise<any>[] = []\n      const originalPromiseCollector = promiseCollector\n      const originalInjectState = injectState\n      injectState = previousState\n        ? {\n            ...previousState,\n            currentIndex: 0,\n          }\n        : {\n            currentIndex: 0,\n            isFrozen: false,\n            requests: [],\n          }\n      promiseCollector = (promise) => {\n        promises.push(promise)\n      }\n      const result = cb()\n      promiseCollector = originalPromiseCollector\n      const newInjectState = {\n        ...injectState,\n        isFrozen: true,\n      }\n      injectState = originalInjectState\n      return [result, promises, newInjectState]\n    }\n  }\n\n  function inject<\n    T,\n    Token extends\n      | InjectionToken<T>\n      | BoundInjectionToken<T, any>\n      | FactoryInjectionToken<T, any>,\n    S extends ZodObject | unknown = Token['schema'],\n  >(token: Token, args?: S extends ZodObject ? z.input<S> : never): T {\n    // @ts-expect-error In case we have a class\n    const realToken = token[InjectableTokenMeta] ?? token\n\n    if (!injectState) {\n      throw new Error(\n        '[Injector] Trying to access inject outside of a injectable context',\n      )\n    }\n\n    // Try to get cached instance synchronously (only on first run, not frozen replay)\n    const ctx = getFactoryContext()\n    const cachedInstance = !injectState.isFrozen\n      ? ctx.container.tryGetSync(realToken, args)\n      : null\n\n    // getRequest handles both frozen replay and first run:\n    // - Frozen: validates token order and returns cached request\n    // - First run: creates new request with ctx.inject promise\n    const request = getRequest(realToken, args)\n\n    // If we have a cached instance, return it directly\n    if (cachedInstance) {\n      return cachedInstance as unknown as T\n    }\n\n    // Check for errors or already-resolved results\n    if (request.error) {\n      throw request.error\n    }\n    if (request.result) {\n      return request.result as T\n    }\n\n    // Collect promise for awaiting (first run only, frozen state already has results)\n    if (promiseCollector && !injectState.isFrozen) {\n      promiseCollector(request.promise)\n    }\n\n    // Return a proxy that throws if accessed before initialization\n    return new Proxy(\n      {},\n      {\n        get() {\n          throw new Error(\n            `[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`,\n          )\n        },\n      },\n    ) as unknown as T\n  }\n\n  function optional<\n    T,\n    Token extends\n      | InjectionToken<T>\n      | BoundInjectionToken<T, any>\n      | FactoryInjectionToken<T, any>,\n    S extends ZodObject | unknown = Token['schema'],\n  >(token: Token, args?: S extends ZodObject ? z.input<S> : never): T | null {\n    try {\n      return inject(token, args)\n    } catch {\n      // If injection fails, return null instead of throwing\n      return null\n    }\n  }\n\n  const injectors: Injectors = {\n    asyncInject,\n    inject,\n    optional,\n    wrapSyncInit,\n    provideFactoryContext,\n  } as Injectors\n\n  return injectors\n}\n"],"mappings":";;;;AAsJA,SAAgBE,eAAAA;CACd,IAAIC,wBAA6D;CAEjE,SAASC,sBACPC,SAA4C;EAE5C,MAAMC,WAAWH;AACjBA,0BAAwBE;AACxB,SAAOC;;CAET,SAASC,oBAAAA;AACP,MAAI,CAACJ,sBACH,OAAM,IAAIK,MACR,gFAAA;AAGJ,SAAOL;;CAGT,IAAIM,mBAA6D;CACjE,IAAIC,cAAkC;CAEtC,SAASC,WACPC,OACAC,MACAC,oBAAoB,OAAK;AAEzB,MAAI,CAACJ,YACH,OAAM,IAAIF,MACR,sEAAA;AAGJ,MAAIE,YAAYK,UAAU;GACxB,MAAMC,MAAMN,YAAYO;GACxB,MAAMC,YAAUR,YAAYS,SAASH;AACrC,OAAIE,UAAQN,UAAUA,MACpB,OAAM,IAAIJ,MACR,0CAA0CU,UAAQN,MAAMQ,UAAQ,CAAG,WAAWR,MAAMQ,UAAQ,GAAI;AAGpG,UAAOF;;EAET,IAAIG,SAAc;EAClB,IAAIC,QAAsB;EAK1B,MAAMC,iBACJhB,mBAAAA,CACGiB,OAAOZ,OAAcC,KAAAA,CACrBY,MAAMC,MAAAA;AACLL,YAASK;AACT,UAAOA;IACT,CACCC,OAAOC,MAAAA;AAENN,WAAQM;IACV;EAMJ,MAAMV,UAAyB;GAC7BN;GACAiB,SANcf,oBACZd,yBAAyBuB,SAAAA,GACzBA,UAAAA;GAKF,IAAIF,SAAS;AACX,WAAOA;;GAET,IAAIC,QAAQ;AACV,WAAOA;;GAEX;AACAZ,cAAYS,SAASW,KAAKZ,QAAAA;AAC1BR,cAAYO;AAEZ,SAAOC;;CAGT,SAASa,YACPnB,OAKAC,MAAc;AAEd,MAAI,CAACH,YACH,OAAM,IAAIF,MACR,qEAAA;EAOJ,MAAMU,UAAUP,WAHEC,MAAMX,wBAAwBW,OAGVC,MAAM,KAAA;AAC5C,SAAOK,QAAQW,QAAQJ,MAAMJ,WAAAA;AAC3B,OAAIH,QAAQI,MAEV,OAAMJ,QAAQI;AAEhB,UAAOD;IACT;;CAGF,SAASY,aAAaC,IAAa;AACjC,UAAQC,kBAAAA;GACN,MAAMC,WAA2B,EAAE;GACnC,MAAMC,2BAA2B5B;GACjC,MAAM6B,sBAAsB5B;AAC5BA,iBAAcyB,gBACV;IACE,GAAGA;IACHlB,cAAc;IAChB,GACA;IACEA,cAAc;IACdF,UAAU;IACVI,UAAU,EAAE;IACd;AACJV,uBAAoBoB,YAAAA;AAClBO,aAASN,KAAKD,QAAAA;;GAEhB,MAAMR,SAASa,IAAAA;AACfzB,sBAAmB4B;GACnB,MAAME,iBAAiB;IACrB,GAAG7B;IACHK,UAAU;IACZ;AACAL,iBAAc4B;AACd,UAAO;IAACjB;IAAQe;IAAUG;IAAe;;;CAI7C,SAASf,OAOPZ,OAAcC,MAA+C;EAE7D,MAAMmB,YAAYpB,MAAMX,wBAAwBW;AAEhD,MAAI,CAACF,YACH,OAAM,IAAIF,MACR,qEAAA;EAKJ,MAAMgC,MAAMjC,mBAAAA;EACZ,MAAMkC,iBAAiB,CAAC/B,YAAYK,WAChCyB,IAAIE,UAAUC,WAAWX,WAAWnB,KAAAA,GACpC;EAKJ,MAAMK,UAAUP,WAAWqB,WAAWnB,KAAAA;AAGtC,MAAI4B,eACF,QAAOA;AAIT,MAAIvB,QAAQI,MACV,OAAMJ,QAAQI;AAEhB,MAAIJ,QAAQG,OACV,QAAOH,QAAQG;AAIjB,MAAIZ,oBAAoB,CAACC,YAAYK,SACnCN,kBAAiBS,QAAQW,QAAO;AAIlC,SAAO,IAAIe,MACT,EAAC,EACD,EACEC,MAAAA;AACE,SAAM,IAAIrC,MACR,+BAA+BwB,UAAUZ,UAAQ,CAAG,0EAAyE;KAGnI,CAAA;;CAIJ,SAAS0B,SAOPlC,OAAcC,MAA+C;AAC7D,MAAI;AACF,UAAOW,OAAOZ,OAAOC,KAAAA;UACf;AAEN,UAAO;;;AAYX,QAR6B;EAC3BkB;EACAP;EACAsB;EACAb;EACA7B;EACF"}