@navios/di 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/lib/browser/utils/get-injectors.mjs +9 -12
- package/lib/browser/utils/get-injectors.mjs.map +1 -1
- package/lib/{container-8-z89TyQ.mjs → container-Bi0huFQX.mjs} +10 -13
- package/lib/container-Bi0huFQX.mjs.map +1 -0
- package/lib/{container-CaY2fDuk.cjs → container-pmGNCZL_.cjs} +10 -13
- package/lib/container-pmGNCZL_.cjs.map +1 -0
- package/lib/index.cjs +1 -1
- package/lib/index.mjs +1 -1
- package/lib/testing/index.cjs +28 -15
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +6 -5
- package/lib/testing/index.d.cts.map +1 -1
- package/lib/testing/index.d.mts +6 -5
- package/lib/testing/index.d.mts.map +1 -1
- package/lib/testing/index.mjs +28 -15
- package/lib/testing/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/get-injectors.spec.mts +166 -0
- package/src/__tests__/unit-test-container.spec.mts +128 -4
- package/src/testing/test-container.mts +23 -5
- package/src/testing/types.mts +8 -2
- package/src/testing/unit-test-container.mts +120 -28
- package/src/utils/get-injectors.mts +36 -32
- package/lib/container-8-z89TyQ.mjs.map +0 -1
- package/lib/container-CaY2fDuk.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.2] - 2026-01-05
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Wrong Token Order with Pre-cached Dependencies**: Fixed a bug where `inject()` would throw "Wrong token order" error when some dependencies were already instantiated before the service constructor ran
|
|
13
|
+
- The frozen state replay now correctly tracks all injected tokens, including those resolved from cache
|
|
14
|
+
- Refactored `inject()` function to use a single `getRequest()` call path, eliminating duplicate logic and redundant `ctx.inject()` calls
|
|
15
|
+
|
|
16
|
+
## [0.9.1] - 2026-01-05
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **BoundInjectionToken Support in Testing Containers**: `TestContainer` and `UnitTestContainer` now support `BoundInjectionToken` in providers
|
|
21
|
+
- Can override bound token values in tests using `useValue`, `useClass`, or `useFactory`
|
|
22
|
+
- Bound tokens can be registered without overrides (uses bound value)
|
|
23
|
+
- Proper token resolution for bound tokens in both containers
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Test Binding Priority**: Test bindings now use priority 1000 to ensure test overrides take precedence over production registrations
|
|
28
|
+
- **Value Binding Implementation**: Changed from static instance to factory pattern for better consistency
|
|
29
|
+
- **Token Resolution**: Enhanced token resolution in testing containers to properly handle `BoundInjectionToken` instances
|
|
30
|
+
|
|
8
31
|
## [0.9.0] - 2025-12-21
|
|
9
32
|
|
|
10
33
|
### Added
|
|
@@ -87,18 +87,15 @@ function getInjectors() {
|
|
|
87
87
|
const realToken = token[InjectableTokenMeta] ?? token;
|
|
88
88
|
if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
|
|
89
89
|
const ctx = getFactoryContext();
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
ctx.inject(realToken, args).catch(() => {});
|
|
101
|
-
return instance;
|
|
90
|
+
const cachedInstance = !injectState.isFrozen ? ctx.container.tryGetSync(realToken, args) : null;
|
|
91
|
+
const request = getRequest(realToken, args);
|
|
92
|
+
if (cachedInstance) return cachedInstance;
|
|
93
|
+
if (request.error) throw request.error;
|
|
94
|
+
if (request.result) return request.result;
|
|
95
|
+
if (promiseCollector && !injectState.isFrozen) promiseCollector(request.promise);
|
|
96
|
+
return new Proxy({}, { get() {
|
|
97
|
+
throw new Error(`[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`);
|
|
98
|
+
} });
|
|
102
99
|
}
|
|
103
100
|
function optional(token, args) {
|
|
104
101
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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","instance","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 const ctx = getFactoryContext()\n const instance = ctx.container.tryGetSync(realToken, args)\n if (!instance) {\n const request = getRequest(realToken, args)\n if (request.error) {\n throw request.error\n } else if (request.result) {\n return request.result\n }\n if (promiseCollector) {\n promiseCollector(request.promise)\n }\n // Return a dynamic proxy that looks up the instance when accessed\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 // Even when tryGetSync returns an existing instance, we still need to\n // track the dependency for scope upgrade. This ensures that if a Singleton\n // service depends on an already-created Request-scoped service, the\n // Singleton will be properly upgraded to Request scope.\n // The ctx.inject call handles dependency tracking and scope upgrades.\n // We fire-and-forget this since we already have the instance.\n ctx.inject(realToken, args).catch(() => {\n // Ignore errors - we already have the instance\n })\n\n return instance 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":"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"}
|
|
1
|
+
{"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":"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"}
|
|
@@ -1333,18 +1333,15 @@ function getInjectors() {
|
|
|
1333
1333
|
const realToken = token[InjectableTokenMeta] ?? token;
|
|
1334
1334
|
if (!injectState) throw new Error("[Injector] Trying to access inject outside of a injectable context");
|
|
1335
1335
|
const ctx = getFactoryContext();
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
}
|
|
1346
|
-
ctx.inject(realToken, args).catch(() => {});
|
|
1347
|
-
return instance;
|
|
1336
|
+
const cachedInstance = !injectState.isFrozen ? ctx.container.tryGetSync(realToken, args) : null;
|
|
1337
|
+
const request = getRequest(realToken, args);
|
|
1338
|
+
if (cachedInstance) return cachedInstance;
|
|
1339
|
+
if (request.error) throw request.error;
|
|
1340
|
+
if (request.result) return request.result;
|
|
1341
|
+
if (promiseCollector && !injectState.isFrozen) promiseCollector(request.promise);
|
|
1342
|
+
return new Proxy({}, { get() {
|
|
1343
|
+
throw new Error(`[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`);
|
|
1344
|
+
} });
|
|
1348
1345
|
}
|
|
1349
1346
|
function optional$1(token, args) {
|
|
1350
1347
|
try {
|
|
@@ -2252,4 +2249,4 @@ var Container = class extends (_AbstractContainer = AbstractContainer) {
|
|
|
2252
2249
|
|
|
2253
2250
|
//#endregion
|
|
2254
2251
|
export { Registry as A, withResolutionContext as C, DIError as D, isUsingNativeAsyncLocalStorage as E, InjectableTokenMeta as F, InjectableType as I, InjectableScope as L, BoundInjectionToken as M, FactoryInjectionToken as N, DIErrorCode as O, InjectionToken as P, getCurrentResolutionContext as S, createAsyncLocalStorage as T, ScopeTracker as _, UnifiedStorage as a, CircularDetector as b, asyncInject as c, optional as d, provideFactoryContext as f, ServiceInitializer as g, ServiceInvalidator as h, LifecycleEventBus as i, globalRegistry as j, Injectable as k, defaultInjectors as l, getInjectors as m, ScopedContainer as n, TokenResolver as o, wrapSyncInit as p, StubFactoryClass as r, getInjectableToken as s, _Container as t, inject as u, NameResolver as v, withoutResolutionContext as w, InstanceStatus as x, InstanceResolver as y };
|
|
2255
|
-
//# sourceMappingURL=container-
|
|
2252
|
+
//# sourceMappingURL=container-Bi0huFQX.mjs.map
|