@navios/di 0.4.2 → 0.5.0

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.
Files changed (120) hide show
  1. package/README.md +211 -1
  2. package/coverage/clover.xml +1912 -1277
  3. package/coverage/coverage-final.json +37 -28
  4. package/coverage/docs/examples/basic-usage.mts.html +1 -1
  5. package/coverage/docs/examples/factory-pattern.mts.html +1 -1
  6. package/coverage/docs/examples/index.html +1 -1
  7. package/coverage/docs/examples/injection-tokens.mts.html +1 -1
  8. package/coverage/docs/examples/request-scope-example.mts.html +1 -1
  9. package/coverage/docs/examples/service-lifecycle.mts.html +1 -1
  10. package/coverage/index.html +71 -41
  11. package/coverage/lib/_tsup-dts-rollup.d.mts.html +682 -43
  12. package/coverage/lib/index.d.mts.html +7 -4
  13. package/coverage/lib/index.html +5 -5
  14. package/coverage/lib/testing/index.d.mts.html +91 -0
  15. package/coverage/lib/testing/index.html +116 -0
  16. package/coverage/src/base-instance-holder-manager.mts.html +589 -0
  17. package/coverage/src/container.mts.html +257 -74
  18. package/coverage/src/decorators/factory.decorator.mts.html +1 -1
  19. package/coverage/src/decorators/index.html +1 -1
  20. package/coverage/src/decorators/index.mts.html +1 -1
  21. package/coverage/src/decorators/injectable.decorator.mts.html +20 -20
  22. package/coverage/src/enums/index.html +1 -1
  23. package/coverage/src/enums/index.mts.html +1 -1
  24. package/coverage/src/enums/injectable-scope.enum.mts.html +1 -1
  25. package/coverage/src/enums/injectable-type.enum.mts.html +1 -1
  26. package/coverage/src/errors/di-error.mts.html +292 -0
  27. package/coverage/src/errors/errors.enum.mts.html +30 -21
  28. package/coverage/src/errors/factory-not-found.mts.html +31 -22
  29. package/coverage/src/errors/factory-token-not-resolved.mts.html +29 -26
  30. package/coverage/src/errors/index.html +56 -41
  31. package/coverage/src/errors/index.mts.html +15 -9
  32. package/coverage/src/errors/instance-destroying.mts.html +31 -22
  33. package/coverage/src/errors/instance-expired.mts.html +31 -22
  34. package/coverage/src/errors/instance-not-found.mts.html +31 -22
  35. package/coverage/src/errors/unknown-error.mts.html +31 -43
  36. package/coverage/src/event-emitter.mts.html +14 -14
  37. package/coverage/src/factory-context.mts.html +1 -1
  38. package/coverage/src/index.html +121 -46
  39. package/coverage/src/index.mts.html +7 -4
  40. package/coverage/src/injection-token.mts.html +28 -28
  41. package/coverage/src/injector.mts.html +1 -1
  42. package/coverage/src/instance-resolver.mts.html +1762 -0
  43. package/coverage/src/interfaces/factory.interface.mts.html +1 -1
  44. package/coverage/src/interfaces/index.html +1 -1
  45. package/coverage/src/interfaces/index.mts.html +1 -1
  46. package/coverage/src/interfaces/on-service-destroy.interface.mts.html +1 -1
  47. package/coverage/src/interfaces/on-service-init.interface.mts.html +1 -1
  48. package/coverage/src/registry.mts.html +28 -28
  49. package/coverage/src/request-context-holder.mts.html +183 -102
  50. package/coverage/src/request-context-manager.mts.html +532 -0
  51. package/coverage/src/service-instantiator.mts.html +49 -49
  52. package/coverage/src/service-invalidator.mts.html +1372 -0
  53. package/coverage/src/service-locator-event-bus.mts.html +48 -48
  54. package/coverage/src/service-locator-instance-holder.mts.html +2 -14
  55. package/coverage/src/service-locator-manager.mts.html +71 -335
  56. package/coverage/src/service-locator.mts.html +240 -2328
  57. package/coverage/src/symbols/index.html +1 -1
  58. package/coverage/src/symbols/index.mts.html +1 -1
  59. package/coverage/src/symbols/injectable-token.mts.html +1 -1
  60. package/coverage/src/testing/index.html +131 -0
  61. package/coverage/src/testing/index.mts.html +88 -0
  62. package/coverage/src/testing/test-container.mts.html +445 -0
  63. package/coverage/src/token-processor.mts.html +607 -0
  64. package/coverage/src/utils/defer.mts.html +28 -214
  65. package/coverage/src/utils/get-injectable-token.mts.html +7 -7
  66. package/coverage/src/utils/get-injectors.mts.html +99 -99
  67. package/coverage/src/utils/index.html +15 -15
  68. package/coverage/src/utils/index.mts.html +4 -7
  69. package/coverage/src/utils/types.mts.html +1 -1
  70. package/docs/injectable.md +51 -11
  71. package/docs/scopes.md +63 -29
  72. package/lib/_tsup-dts-rollup.d.mts +376 -213
  73. package/lib/_tsup-dts-rollup.d.ts +376 -213
  74. package/lib/{chunk-3NLYPYBY.mjs → chunk-44F3LXW5.mjs} +1021 -605
  75. package/lib/chunk-44F3LXW5.mjs.map +1 -0
  76. package/lib/index.d.mts +6 -4
  77. package/lib/index.d.ts +6 -4
  78. package/lib/index.js +1192 -776
  79. package/lib/index.js.map +1 -1
  80. package/lib/index.mjs +2 -2
  81. package/lib/testing/index.js +1258 -840
  82. package/lib/testing/index.js.map +1 -1
  83. package/lib/testing/index.mjs +1 -1
  84. package/package.json +1 -1
  85. package/src/__tests__/container.spec.mts +47 -13
  86. package/src/__tests__/errors.spec.mts +53 -27
  87. package/src/__tests__/injectable.spec.mts +73 -0
  88. package/src/__tests__/request-scope.spec.mts +0 -2
  89. package/src/__tests__/service-locator-manager.spec.mts +12 -82
  90. package/src/__tests__/service-locator.spec.mts +1009 -1
  91. package/src/__type-tests__/inject.spec-d.mts +30 -7
  92. package/src/__type-tests__/injectable.spec-d.mts +76 -37
  93. package/src/base-instance-holder-manager.mts +2 -9
  94. package/src/container.mts +61 -9
  95. package/src/decorators/injectable.decorator.mts +29 -5
  96. package/src/errors/di-error.mts +69 -0
  97. package/src/errors/index.mts +9 -7
  98. package/src/injection-token.mts +1 -0
  99. package/src/injector.mts +2 -0
  100. package/src/instance-resolver.mts +559 -0
  101. package/src/request-context-holder.mts +0 -2
  102. package/src/request-context-manager.mts +149 -0
  103. package/src/service-invalidator.mts +429 -0
  104. package/src/service-locator-instance-holder.mts +0 -4
  105. package/src/service-locator-manager.mts +10 -40
  106. package/src/service-locator.mts +86 -782
  107. package/src/token-processor.mts +174 -0
  108. package/src/utils/get-injectors.mts +161 -24
  109. package/src/utils/index.mts +0 -1
  110. package/src/utils/types.mts +12 -8
  111. package/lib/chunk-3NLYPYBY.mjs.map +0 -1
  112. package/src/__tests__/defer.spec.mts +0 -166
  113. package/src/errors/errors.enum.mts +0 -8
  114. package/src/errors/factory-not-found.mts +0 -8
  115. package/src/errors/factory-token-not-resolved.mts +0 -10
  116. package/src/errors/instance-destroying.mts +0 -8
  117. package/src/errors/instance-expired.mts +0 -8
  118. package/src/errors/instance-not-found.mts +0 -8
  119. package/src/errors/unknown-error.mts +0 -15
  120. package/src/utils/defer.mts +0 -73
@@ -0,0 +1,174 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
3
+
4
+ import type { FactoryContext } from './factory-context.mjs'
5
+ import type {
6
+ AnyInjectableType,
7
+ InjectionTokenType,
8
+ } from './injection-token.mjs'
9
+ import type { RequestContextHolder } from './request-context-holder.mjs'
10
+ import type { ServiceLocator } from './service-locator.mjs'
11
+
12
+ import { DIError } from './errors/index.mjs'
13
+ import {
14
+ BoundInjectionToken,
15
+ FactoryInjectionToken,
16
+ InjectionToken,
17
+ } from './injection-token.mjs'
18
+ import { getInjectableToken } from './utils/index.mjs'
19
+
20
+ /**
21
+ * TokenProcessor handles token validation, resolution, and instance name generation.
22
+ * Extracted from ServiceLocator to improve separation of concerns.
23
+ */
24
+ export class TokenProcessor {
25
+ constructor(private readonly logger: Console | null = null) {}
26
+
27
+ /**
28
+ * Validates and resolves token arguments, handling factory token resolution and validation.
29
+ */
30
+ validateAndResolveTokenArgs(
31
+ token: AnyInjectableType,
32
+ args?: any,
33
+ ): [
34
+ DIError | undefined,
35
+ { actualToken: InjectionTokenType; validatedArgs?: any },
36
+ ] {
37
+ let actualToken = token as InjectionToken<any, any>
38
+ if (typeof token === 'function') {
39
+ actualToken = getInjectableToken(token)
40
+ }
41
+ let realArgs = args
42
+ if (actualToken instanceof BoundInjectionToken) {
43
+ realArgs = actualToken.value
44
+ } else if (actualToken instanceof FactoryInjectionToken) {
45
+ if (actualToken.resolved) {
46
+ realArgs = actualToken.value
47
+ } else {
48
+ return [DIError.factoryTokenNotResolved(token.name), { actualToken }]
49
+ }
50
+ }
51
+ if (!actualToken.schema) {
52
+ return [undefined, { actualToken, validatedArgs: realArgs }]
53
+ }
54
+ const validatedArgs = actualToken.schema?.safeParse(realArgs)
55
+ if (validatedArgs && !validatedArgs.success) {
56
+ this.logger?.error(
57
+ `[TokenProcessor]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`,
58
+ validatedArgs.error,
59
+ )
60
+ return [DIError.unknown(validatedArgs.error), { actualToken }]
61
+ }
62
+ return [undefined, { actualToken, validatedArgs: validatedArgs?.data }]
63
+ }
64
+
65
+ /**
66
+ * Generates a unique instance name based on token and arguments.
67
+ */
68
+ generateInstanceName(token: InjectionTokenType, args: any): string {
69
+ if (!args) {
70
+ return token.toString()
71
+ }
72
+
73
+ const formattedArgs = Object.entries(args)
74
+ .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
75
+ .map(([key, value]) => `${key}=${this.formatArgValue(value)}`)
76
+ .join(',')
77
+
78
+ return `${token.toString()}:${formattedArgs.replaceAll(/"/g, '').replaceAll(/:/g, '=')}`
79
+ }
80
+
81
+ /**
82
+ * Formats a single argument value for instance name generation.
83
+ */
84
+ formatArgValue(value: any): string {
85
+ if (typeof value === 'function') {
86
+ return `fn_${value.name}(${value.length})`
87
+ }
88
+ if (typeof value === 'symbol') {
89
+ return value.toString()
90
+ }
91
+ return JSON.stringify(value).slice(0, 40)
92
+ }
93
+
94
+ /**
95
+ * Creates a factory context for dependency injection during service instantiation.
96
+ * @param serviceLocator Reference to the service locator for dependency resolution
97
+ */
98
+ createFactoryContext(
99
+ serviceLocator: ServiceLocator, // ServiceLocator reference for dependency resolution
100
+ ): FactoryContext & {
101
+ getDestroyListeners: () => (() => void)[]
102
+ deps: Set<string>
103
+ } {
104
+ const destroyListeners = new Set<() => void>()
105
+ const deps = new Set<string>()
106
+
107
+ function addDestroyListener(listener: () => void) {
108
+ destroyListeners.add(listener)
109
+ }
110
+
111
+ function getDestroyListeners() {
112
+ return Array.from(destroyListeners)
113
+ }
114
+
115
+ return {
116
+ // @ts-expect-error This is correct type
117
+ async inject(token, args) {
118
+ // Fall back to normal resolution
119
+ const [error, instance] = await serviceLocator.getInstance(
120
+ token,
121
+ args,
122
+ ({ instanceName }: { instanceName: string }) => {
123
+ deps.add(instanceName)
124
+ },
125
+ )
126
+ if (error) {
127
+ throw error
128
+ }
129
+ return instance
130
+ },
131
+ addDestroyListener,
132
+ getDestroyListeners,
133
+ locator: serviceLocator,
134
+ deps,
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Tries to get a pre-prepared instance from request contexts.
140
+ */
141
+ tryGetPrePreparedInstance(
142
+ instanceName: string,
143
+ contextHolder: RequestContextHolder | undefined,
144
+ deps: Set<string>,
145
+ currentRequestContext: RequestContextHolder | null,
146
+ ): any {
147
+ // Check provided context holder first (if has higher priority)
148
+ if (contextHolder && contextHolder.priority > 0) {
149
+ const prePreparedInstance = contextHolder.get(instanceName)?.instance
150
+ if (prePreparedInstance !== undefined) {
151
+ this.logger?.debug(
152
+ `[TokenProcessor] Using pre-prepared instance ${instanceName} from request context ${contextHolder.requestId}`,
153
+ )
154
+ deps.add(instanceName)
155
+ return prePreparedInstance
156
+ }
157
+ }
158
+
159
+ // Check current request context (if different from provided contextHolder)
160
+ if (currentRequestContext && currentRequestContext !== contextHolder) {
161
+ const prePreparedInstance =
162
+ currentRequestContext.get(instanceName)?.instance
163
+ if (prePreparedInstance !== undefined) {
164
+ this.logger?.debug(
165
+ `[TokenProcessor] Using pre-prepared instance ${instanceName} from current request context ${currentRequestContext.requestId}`,
166
+ )
167
+ deps.add(instanceName)
168
+ return prePreparedInstance
169
+ }
170
+ }
171
+
172
+ return undefined
173
+ }
174
+ }
@@ -4,22 +4,45 @@ import type { FactoryContext } from '../factory-context.mjs'
4
4
  import type {
5
5
  BoundInjectionToken,
6
6
  ClassType,
7
+ ClassTypeWithArgument,
8
+ ClassTypeWithoutArguments,
7
9
  FactoryInjectionToken,
8
10
  InjectionToken,
9
11
  InjectionTokenSchemaType,
10
12
  } from '../injection-token.mjs'
11
- import type { Factorable } from '../interfaces/factory.interface.mjs'
12
- import type { InjectState, Join, UnionToArray } from './types.mjs'
13
+ import type {
14
+ Factorable,
15
+ FactorableWithArgs,
16
+ } from '../interfaces/factory.interface.mjs'
17
+ import type {
18
+ InjectRequest,
19
+ InjectState,
20
+ Join,
21
+ UnionToArray,
22
+ } from './types.mjs'
13
23
 
14
24
  import { InjectableTokenMeta } from '../symbols/index.mjs'
15
25
 
16
26
  export interface Injectors {
17
27
  // #1 Simple class
18
- asyncInject<T extends ClassType>(
28
+ asyncInject<T extends ClassTypeWithoutArguments>(
19
29
  token: T,
20
30
  ): InstanceType<T> extends Factorable<infer R>
21
31
  ? Promise<R>
22
32
  : Promise<InstanceType<T>>
33
+ asyncInject<Args, T extends ClassTypeWithArgument<Args>>(
34
+ token: T,
35
+ args: Args,
36
+ ): Promise<InstanceType<T>>
37
+ asyncInject<
38
+ Schema extends InjectionTokenSchemaType,
39
+ R,
40
+ T extends FactorableWithArgs<R, Schema>,
41
+ >(
42
+ token: T,
43
+ args: z.input<Schema>,
44
+ ): Promise<R>
45
+
23
46
  // #2 Token with required Schema
24
47
  asyncInject<T, S extends InjectionTokenSchemaType>(
25
48
  token: InjectionToken<T, S>,
@@ -41,9 +64,22 @@ export interface Injectors {
41
64
  asyncInject<T>(token: BoundInjectionToken<T, any>): Promise<T>
42
65
  asyncInject<T>(token: FactoryInjectionToken<T, any>): Promise<T>
43
66
 
44
- inject<T extends ClassType>(
67
+ inject<T extends ClassTypeWithoutArguments>(
45
68
  token: T,
46
69
  ): InstanceType<T> extends Factorable<infer R> ? R : InstanceType<T>
70
+ inject<Args, T extends ClassTypeWithArgument<Args>>(
71
+ token: T,
72
+ args: Args,
73
+ ): InstanceType<T>
74
+ inject<
75
+ Schema extends InjectionTokenSchemaType,
76
+ R,
77
+ T extends FactorableWithArgs<R, Schema>,
78
+ >(
79
+ token: T,
80
+ args: z.input<Schema>,
81
+ ): R
82
+
47
83
  inject<T, S extends InjectionTokenSchemaType>(
48
84
  token: InjectionToken<T, S>,
49
85
  args: z.input<S>,
@@ -63,6 +99,45 @@ export interface Injectors {
63
99
  inject<T>(token: BoundInjectionToken<T, any>): T
64
100
  inject<T>(token: FactoryInjectionToken<T, any>): T
65
101
 
102
+ /**
103
+ * Optional injection that returns null if the service fails to initialize
104
+ * or is not available. This is useful when you want to inject a service
105
+ * that may not be configured or may fail gracefully.
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * class MyService {
110
+ * constructor() {
111
+ * const optionalService = optional(OptionalServiceToken)
112
+ * // optionalService will be null if initialization fails
113
+ * if (optionalService) {
114
+ * optionalService.doSomething()
115
+ * }
116
+ * }
117
+ * }
118
+ * ```
119
+ */
120
+ optional<T extends ClassType>(
121
+ token: T,
122
+ ): (InstanceType<T> extends Factorable<infer R> ? R : InstanceType<T>) | null
123
+ optional<T, S extends InjectionTokenSchemaType>(
124
+ token: InjectionToken<T, S>,
125
+ args: z.input<S>,
126
+ ): T | null
127
+ optional<T, S extends InjectionTokenSchemaType, R extends boolean>(
128
+ token: InjectionToken<T, S, R>,
129
+ ): R extends false
130
+ ? T | null
131
+ : S extends ZodType<infer Type>
132
+ ? `Error: Your token requires args: ${Join<
133
+ UnionToArray<keyof Type>,
134
+ ', '
135
+ >}`
136
+ : 'Error: Your token requires args'
137
+ optional<T>(token: InjectionToken<T, undefined>): T | null
138
+ optional<T>(token: BoundInjectionToken<T, any>): T | null
139
+ optional<T>(token: FactoryInjectionToken<T, any>): T | null
140
+
66
141
  wrapSyncInit(
67
142
  cb: () => any,
68
143
  ): (injectState?: InjectState) => [any, Promise<any>[], InjectState]
@@ -92,17 +167,10 @@ export function getInjectors() {
92
167
  let promiseCollector: null | ((promise: Promise<any>) => void) = null
93
168
  let injectState: InjectState | null = null
94
169
 
95
- function asyncInject(
96
- token:
97
- | ClassType
98
- | InjectionToken<any>
99
- | BoundInjectionToken<any, any>
100
- | FactoryInjectionToken<any, any>,
101
- args?: unknown,
102
- ) {
170
+ function getRequest(token: InjectionToken<any>, args?: unknown) {
103
171
  if (!injectState) {
104
172
  throw new Error(
105
- '[Injector] Trying to access inject outside of a injectable context',
173
+ '[Injector] Trying to make a request outside of a injectable context',
106
174
  )
107
175
  }
108
176
  if (injectState.isFrozen) {
@@ -113,17 +181,59 @@ export function getInjectors() {
113
181
  `[Injector] Wrong token order. Expected ${request.token.toString()} but got ${token.toString()}`,
114
182
  )
115
183
  }
116
- return request.promise
184
+ return request
117
185
  }
118
-
119
- const promise = getFactoryContext().inject(token as any, args as any)
120
- injectState.requests.push({
186
+ let result: any = null
187
+ let error: Error | null = null
188
+ const promise = getFactoryContext()
189
+ .inject(token as any, args as any)
190
+ .then((r) => {
191
+ result = r
192
+ return r
193
+ })
194
+ .catch((e) => {
195
+ // We don't throw here because we have a mechanism to handle errors
196
+ error = e
197
+ })
198
+ const request: InjectRequest = {
121
199
  token,
122
200
  promise,
123
- })
201
+ get result() {
202
+ return result
203
+ },
204
+ get error() {
205
+ return error
206
+ },
207
+ }
208
+ injectState.requests.push(request)
124
209
  injectState.currentIndex++
125
210
 
126
- return promise
211
+ return request
212
+ }
213
+
214
+ function asyncInject(
215
+ token:
216
+ | ClassType
217
+ | InjectionToken<any>
218
+ | BoundInjectionToken<any, any>
219
+ | FactoryInjectionToken<any, any>,
220
+ args?: unknown,
221
+ ) {
222
+ if (!injectState) {
223
+ throw new Error(
224
+ '[Injector] Trying to access inject outside of a injectable context',
225
+ )
226
+ }
227
+ // @ts-expect-error In case we have a class
228
+ const realToken = token[InjectableTokenMeta] ?? token
229
+ const request = getRequest(realToken, args)
230
+ return request.promise.then((result) => {
231
+ if (request.error) {
232
+ // We throw here because we want to fail the asyncInject call if the dependency fails to initialize
233
+ throw request.error
234
+ }
235
+ return result
236
+ })
127
237
  }
128
238
 
129
239
  function wrapSyncInit(cb: () => any) {
@@ -166,23 +276,33 @@ export function getInjectors() {
166
276
  // @ts-expect-error In case we have a class
167
277
  const realToken = token[InjectableTokenMeta] ?? token
168
278
 
279
+ if (!injectState) {
280
+ throw new Error(
281
+ '[Injector] Trying to access inject outside of a injectable context',
282
+ )
283
+ }
284
+
169
285
  const instance = getFactoryContext().locator.getSyncInstance(
170
286
  realToken,
171
287
  args,
172
288
  )
173
289
  if (!instance) {
290
+ const request = getRequest(realToken, args)
291
+ if (request.error) {
292
+ throw request.error
293
+ } else if (request.result) {
294
+ return request.result
295
+ }
174
296
  if (promiseCollector) {
175
- const promise = getFactoryContext().inject(realToken, args)
176
- promiseCollector(promise)
177
- } else {
178
- throw new Error(`[Injector] Cannot initiate ${realToken.toString()}`)
297
+ promiseCollector(request.promise)
179
298
  }
299
+ // Return a dynamic proxy that looks up the instance when accessed
180
300
  return new Proxy(
181
301
  {},
182
302
  {
183
303
  get() {
184
304
  throw new Error(
185
- `[Injector] Trying to access ${realToken.toString()} before it's initialized, please use asyncInject() instead of inject() or do not use the value outside of class methods`,
305
+ `[Injector] Trying to access ${realToken.toString()} before it's initialized, please move the code to a onServiceInit method`,
186
306
  )
187
307
  },
188
308
  },
@@ -191,9 +311,26 @@ export function getInjectors() {
191
311
  return instance as unknown as T
192
312
  }
193
313
 
314
+ function optional<
315
+ T,
316
+ Token extends
317
+ | InjectionToken<T>
318
+ | BoundInjectionToken<T, any>
319
+ | FactoryInjectionToken<T, any>,
320
+ S extends ZodObject | unknown = Token['schema'],
321
+ >(token: Token, args?: S extends ZodObject ? z.input<S> : never): T | null {
322
+ try {
323
+ return inject(token, args)
324
+ } catch {
325
+ // If injection fails, return null instead of throwing
326
+ return null
327
+ }
328
+ }
329
+
194
330
  const injectors: Injectors = {
195
331
  asyncInject,
196
332
  inject,
333
+ optional,
197
334
  wrapSyncInit,
198
335
  provideFactoryContext,
199
336
  } as Injectors
@@ -1,4 +1,3 @@
1
1
  export * from './get-injectors.mjs'
2
2
  export * from './get-injectable-token.mjs'
3
- export * from './defer.mjs'
4
3
  export * from './types.mjs'
@@ -37,16 +37,20 @@ export type UnionToArray<T, A extends unknown[] = []> =
37
37
  ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
38
38
  : [T, ...A]
39
39
 
40
+ export type InjectRequest = {
41
+ token:
42
+ | InjectionToken<any>
43
+ | BoundInjectionToken<any, any>
44
+ | FactoryInjectionToken<any, any>
45
+ | ClassType
46
+ promise: Promise<any>
47
+ readonly result: any
48
+ readonly error: Error | null
49
+ }
50
+
40
51
  // InjectState interface for managing injection state
41
52
  export interface InjectState {
42
53
  currentIndex: number
43
54
  isFrozen: boolean
44
- requests: {
45
- token:
46
- | InjectionToken<any>
47
- | BoundInjectionToken<any, any>
48
- | FactoryInjectionToken<any, any>
49
- | ClassType
50
- promise: Promise<any>
51
- }[]
55
+ requests: InjectRequest[]
52
56
  }