decorator-dependency-injection 1.0.7 → 1.1.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.
package/src/Container.js CHANGED
@@ -17,48 +17,27 @@ export class Container {
17
17
  /** @type {Map<string|Function, InstanceContext>} */
18
18
  #instances = new Map()
19
19
 
20
- /** @type {boolean} Enable debug logging */
21
20
  #debug = false
22
21
 
23
- /**
24
- * Custom string tag for better debugging.
25
- * Shows as [object Container] in console.
26
- */
27
22
  get [Symbol.toStringTag]() {
28
23
  return 'Container'
29
24
  }
30
25
 
31
- /**
32
- * Make the container iterable.
33
- * Yields registration info for each registered class.
34
- * @yields {RegistrationInfo}
35
- */
26
+ /** @yields {RegistrationInfo} */
36
27
  *[Symbol.iterator]() {
37
28
  yield* this.list()
38
29
  }
39
30
 
40
- /**
41
- * Get the number of registrations in the container.
42
- * @returns {number}
43
- */
31
+ /** @returns {number} */
44
32
  get size() {
45
33
  return this.#instances.size
46
34
  }
47
35
 
48
- /**
49
- * Enable or disable debug logging.
50
- * When enabled, logs when instances are created.
51
- * @param {boolean} enabled Whether to enable debug mode
52
- */
36
+ /** @param {boolean} enabled */
53
37
  setDebug(enabled) {
54
38
  this.#debug = enabled
55
39
  }
56
40
 
57
- /**
58
- * Log a debug message if debug mode is enabled.
59
- * @param {string} message The message to log
60
- * @private
61
- */
62
41
  #log(message) {
63
42
  if (this.#debug) {
64
43
  console.log(`[DI] ${message}`)
@@ -66,30 +45,21 @@ export class Container {
66
45
  }
67
46
 
68
47
  /**
69
- * Register a class as a singleton.
70
- * @param {Function} clazz The class constructor
71
- * @param {string} [name] Optional name key
48
+ * @param {Function} clazz
49
+ * @param {string} [name]
72
50
  */
73
51
  registerSingleton(clazz, name) {
74
52
  this.#register(clazz, 'singleton', name)
75
53
  }
76
54
 
77
55
  /**
78
- * Register a class as a factory.
79
- * @param {Function} clazz The class constructor
80
- * @param {string} [name] Optional name key
56
+ * @param {Function} clazz
57
+ * @param {string} [name]
81
58
  */
82
59
  registerFactory(clazz, name) {
83
60
  this.#register(clazz, 'factory', name)
84
61
  }
85
62
 
86
- /**
87
- * Internal registration logic.
88
- * @param {Function} clazz The class constructor
89
- * @param {'singleton'|'factory'} type The registration type
90
- * @param {string} [name] Optional name key
91
- * @private
92
- */
93
63
  #register(clazz, type, name) {
94
64
  const key = name ?? clazz
95
65
  if (this.#instances.has(key)) {
@@ -103,68 +73,52 @@ export class Container {
103
73
  }
104
74
 
105
75
  /**
106
- * Get the context for a given class or name.
107
- * @param {string|Function} clazzOrName The class or name to look up
76
+ * @param {string|Function} clazzOrName
108
77
  * @returns {InstanceContext}
109
- * @throws {Error} If the context is not found
78
+ * @throws {Error} If not found
110
79
  */
111
80
  getContext(clazzOrName) {
112
81
  const context = this.#instances.get(clazzOrName)
113
82
  if (context) {
114
83
  return context
115
84
  }
85
+
86
+ const name = clazzOrName?.name ?? clazzOrName
87
+ const nameStr = String(name)
116
88
  const available = [...this.#instances.keys()]
117
89
  .map(k => typeof k === 'string' ? k : k.name)
118
90
  .join(', ')
119
91
 
120
- const name = clazzOrName?.name || clazzOrName
121
- const nameStr = String(name)
122
-
123
92
  // Detect if this looks like a mock class from a module mocking system
124
93
  const looksLikeMock = /^Mock[A-Z]|mock/i.test(nameStr) ||
125
94
  nameStr.includes('Mock') ||
126
95
  nameStr.startsWith('vi_') ||
127
96
  nameStr.startsWith('jest_')
128
97
 
129
- let errorMessage = `Cannot find injection source for "${name}". ` +
130
- `Available: [${available}]`
131
-
132
- if (looksLikeMock) {
133
- errorMessage += `\n\nHint: The class name "${name}" suggests this may be a mock created by a module mocking system. ` +
98
+ const hint = looksLikeMock
99
+ ? `\n\nHint: The class name "${name}" suggests this may be a mock created by a module mocking system. ` +
134
100
  `If you're using module mocking (e.g., vi.mock() or jest.mock()), consider using @Mock(OriginalService) instead, ` +
135
101
  `which properly registers with the DI container.`
136
- }
102
+ : ''
137
103
 
138
- throw new Error(errorMessage)
104
+ throw new Error(
105
+ `Cannot find injection source for "${name}". Available: [${available}]${hint}`
106
+ )
139
107
  }
140
108
 
141
- /**
142
- * Check if a class or name is registered.
143
- * @param {string|Function} clazzOrName The class or name to check
144
- * @returns {boolean}
145
- */
109
+ /** @param {string|Function} clazzOrName */
146
110
  has(clazzOrName) {
147
111
  return this.#instances.has(clazzOrName)
148
112
  }
149
113
 
150
- /**
151
- * Check if a class or name has a mock registered.
152
- * @param {string|Function} clazzOrName The class or name to check
153
- * @returns {boolean} true if a mock is registered, false otherwise
154
- */
114
+ /** @param {string|Function} clazzOrName */
155
115
  isMocked(clazzOrName) {
156
116
  return !!this.#instances.get(clazzOrName)?.originalClazz
157
117
  }
158
118
 
159
119
  /**
160
- * Unregister a class or name from the container.
161
- * This removes the registration entirely, including any mock.
162
- *
163
- * @param {string|Function} clazzOrName The class or name to unregister
164
- * @returns {boolean} true if the registration was removed, false if it wasn't registered
165
- *
166
- * @example
167
- * container.unregister(MyService) // Returns true if was registered
120
+ * @param {string|Function} clazzOrName
121
+ * @returns {boolean} true if removed
168
122
  */
169
123
  unregister(clazzOrName) {
170
124
  const removed = this.#instances.delete(clazzOrName)
@@ -174,17 +128,7 @@ export class Container {
174
128
  return removed
175
129
  }
176
130
 
177
- /**
178
- * List all registrations in the container.
179
- * Useful for debugging and introspection.
180
- *
181
- * @returns {Array<{key: string|Function, type: 'singleton'|'factory', isMocked: boolean, hasInstance: boolean}>}
182
- *
183
- * @example
184
- * container.list().forEach(reg => {
185
- * console.log(`${reg.key}: ${reg.type}, mocked: ${reg.isMocked}`)
186
- * })
187
- */
131
+ /** @returns {Array<{key: string|Function, name: string, type: 'singleton'|'factory', isMocked: boolean, hasInstance: boolean}>} */
188
132
  list() {
189
133
  return [...this.#instances.entries()].map(([key, context]) => ({
190
134
  key,
@@ -196,13 +140,10 @@ export class Container {
196
140
  }
197
141
 
198
142
  /**
199
- * Resolve and return an instance by class or name.
200
- * This allows non-decorator code to retrieve instances from the container.
201
143
  * @template T
202
- * @param {string|Function} clazzOrName The class or name to resolve
203
- * @param {...*} params Parameters to pass to the constructor
204
- * @returns {T} The resolved instance
205
- * @throws {Error} If the class or name is not registered
144
+ * @param {string|Function} clazzOrName
145
+ * @param {...*} params
146
+ * @returns {T}
206
147
  */
207
148
  resolve(clazzOrName, ...params) {
208
149
  const instanceContext = this.getContext(clazzOrName)
@@ -210,10 +151,9 @@ export class Container {
210
151
  }
211
152
 
212
153
  /**
213
- * Get or create an instance based on the context.
214
- * @param {InstanceContext} instanceContext The instance context
215
- * @param {Array} params Constructor parameters
216
- * @returns {Object} The instance
154
+ * @param {InstanceContext} instanceContext
155
+ * @param {Array} params
156
+ * @returns {Object}
217
157
  */
218
158
  getInstance(instanceContext, params) {
219
159
  if (instanceContext.type === 'singleton' && instanceContext.instance) {
@@ -221,14 +161,14 @@ export class Container {
221
161
  return instanceContext.instance
222
162
  }
223
163
 
164
+ this.#log(`Creating ${instanceContext.type}: ${instanceContext.clazz.name}`)
224
165
  let instance
225
166
  try {
226
- this.#log(`Creating ${instanceContext.type}: ${instanceContext.clazz.name}`)
227
167
  instance = new instanceContext.clazz(...params)
228
168
  } catch (err) {
229
169
  if (err instanceof RangeError) {
230
170
  throw new Error(
231
- `Circular dependency detected for ${instanceContext.clazz.name || instanceContext.clazz}. ` +
171
+ `Circular dependency detected for ${instanceContext.clazz.name ?? instanceContext.clazz}. ` +
232
172
  `Use @InjectLazy to break the cycle.`
233
173
  )
234
174
  }
@@ -248,10 +188,9 @@ export class Container {
248
188
  }
249
189
 
250
190
  /**
251
- * Register a mock for an existing class.
252
- * @param {string|Function} targetClazzOrName The class or name to mock
253
- * @param {Function} mockClazz The mock class
254
- * @param {boolean} [useProxy=false] Whether to proxy unmocked methods to original
191
+ * @param {string|Function} targetClazzOrName
192
+ * @param {Function} mockClazz
193
+ * @param {boolean} [useProxy=false]
255
194
  */
256
195
  registerMock(targetClazzOrName, mockClazz, useProxy = false) {
257
196
  const instanceContext = this.getContext(targetClazzOrName)
@@ -262,48 +201,20 @@ export class Container {
262
201
  originalClazz: instanceContext.clazz,
263
202
  clazz: mockClazz,
264
203
  proxy: useProxy,
265
- instance: undefined // Clear cached instance so the mock takes effect on next resolve
204
+ instance: undefined
266
205
  })
267
206
  this.#log(`Mocked ${targetClazzOrName?.name ?? targetClazzOrName} with ${mockClazz.name}${useProxy ? ' (proxy)' : ''}`)
268
207
  }
269
208
 
270
209
  /**
271
- * Remove a specific mock and restore the original class.
272
- * This completely removes the mock - it does NOT just clear mock call history.
273
- *
274
- * @param {string|Function} clazzOrName The class or name to restore
275
- * @throws {Error} If the class or name is not registered
276
- *
277
- * @example
278
- * // After this call, resolve(MyService) returns the original class, not the mock
279
- * container.removeMock(MyService)
210
+ * Remove mock and restore original. Does NOT clear mock call history.
211
+ * @param {string|Function} clazzOrName
280
212
  */
281
213
  removeMock(clazzOrName) {
282
214
  this.#restoreOriginal(this.#instances.get(clazzOrName), clazzOrName)
283
215
  }
284
216
 
285
- /**
286
- * @deprecated Use removeMock() instead. This method will be removed in a future version.
287
- *
288
- * Note: This does NOT reset mock call history like vi.fn().mockClear().
289
- * It completely removes the mock and restores the original class.
290
- *
291
- * @param {string|Function} clazzOrName The class or name to restore
292
- * @throws {Error} If the class or name is not registered
293
- */
294
- resetMock(clazzOrName) {
295
- console.warn(
296
- '[DI] resetMock() is deprecated and will be removed in a future version. ' +
297
- 'Use removeMock() instead. Note: This removes the mock entirely, ' +
298
- 'it does NOT clear mock call history.'
299
- )
300
- this.removeMock(clazzOrName)
301
- }
302
-
303
- /**
304
- * Remove all mocks and restore original classes.
305
- * This completely removes all mocks - it does NOT just clear mock call history.
306
- */
217
+ /** Remove all mocks. Does NOT clear mock call history. */
307
218
  removeAllMocks() {
308
219
  for (const instanceContext of this.#instances.values()) {
309
220
  this.#restoreOriginal(instanceContext)
@@ -311,44 +222,15 @@ export class Container {
311
222
  }
312
223
 
313
224
  /**
314
- * @deprecated Use removeAllMocks() instead. This method will be removed in a future version.
315
- *
316
- * Note: This does NOT reset mock call history.
317
- * It completely removes all mocks and restores original classes.
318
- */
319
- resetAllMocks() {
320
- console.warn(
321
- '[DI] resetAllMocks() is deprecated and will be removed in a future version. ' +
322
- 'Use removeAllMocks() instead. Note: This removes all mocks entirely, ' +
323
- 'it does NOT clear mock call history.'
324
- )
325
- this.removeAllMocks()
326
- }
327
-
328
- /**
329
- * Reset singleton instances without removing registrations.
330
- * This clears cached singleton instances so they will be recreated on next resolve.
331
- * Mock registrations are preserved by default.
332
- *
333
- * @param {Object} [options] Options for resetting
334
- * @param {boolean} [options.preserveMocks=true] If true, keeps mock registrations intact.
335
- * If false, also removes mocks (same as clear()).
336
- *
337
- * @example
338
- * // Clear singleton instances but keep mocks registered
339
- * container.resetSingletons()
340
- *
341
- * // Clear singleton instances AND remove mocks
342
- * container.resetSingletons({ preserveMocks: false })
225
+ * Clear cached singleton instances. They'll be recreated on next resolve.
226
+ * @param {Object} [options]
227
+ * @param {boolean} [options.preserveMocks=true]
343
228
  */
344
229
  resetSingletons(options = {}) {
345
230
  const { preserveMocks = true } = options
346
231
 
347
232
  for (const instanceContext of this.#instances.values()) {
348
- // Clear the cached singleton instance
349
233
  delete instanceContext.instance
350
-
351
- // Optionally remove mock registrations
352
234
  if (!preserveMocks && instanceContext.originalClazz) {
353
235
  this.#restoreOriginal(instanceContext)
354
236
  }
@@ -357,27 +239,14 @@ export class Container {
357
239
  }
358
240
 
359
241
  /**
360
- * Clear all registered instances and mocks.
361
- * Useful for complete test isolation between test suites.
362
- *
363
- * Note: By default this removes ALL registrations including @Singleton and @Factory classes.
364
- * For clearing just singleton instances while keeping registrations, use resetSingletons().
365
- *
366
- * @param {Object} [options] Options for clearing
367
- * @param {boolean} [options.preserveRegistrations=false] If true, keeps all registrations but clears cached instances.
368
- *
369
- * @example
370
- * // Remove everything (full reset)
371
- * container.clear()
372
- *
373
- * // Clear cached instances but keep all registrations (including mocks)
374
- * container.clear({ preserveRegistrations: true })
242
+ * Clear all registrations. Use resetSingletons() to keep registrations.
243
+ * @param {Object} [options]
244
+ * @param {boolean} [options.preserveRegistrations=false]
375
245
  */
376
246
  clear(options = {}) {
377
247
  const { preserveRegistrations = false } = options
378
248
 
379
249
  if (preserveRegistrations) {
380
- // Just clear cached instances, keep all registrations
381
250
  for (const instanceContext of this.#instances.values()) {
382
251
  delete instanceContext.instance
383
252
  }
@@ -389,25 +258,11 @@ export class Container {
389
258
  }
390
259
 
391
260
  /**
392
- * Get the mock instance for a mocked class.
393
- * This is useful when you need to configure mock behavior dynamically in tests.
394
- *
395
261
  * @template T
396
- * @param {string|Function} clazzOrName The original class or name that was mocked
397
- * @param {...*} params Parameters to pass to the constructor
398
- * @returns {T} The mock instance
399
- * @throws {Error} If the class is not registered
400
- * @throws {Error} If the class is not mocked
401
- *
402
- * @example
403
- * @Mock(UserService)
404
- * class MockUserService {
405
- * getUser = vi.fn()
406
- * }
407
- *
408
- * // In test:
409
- * const mockInstance = container.getMockInstance(UserService)
410
- * mockInstance.getUser.mockReturnValue({ id: 1, name: 'Test' })
262
+ * @param {string|Function} clazzOrName
263
+ * @param {...*} params
264
+ * @returns {T}
265
+ * @throws {Error} If not mocked
411
266
  */
412
267
  getMockInstance(clazzOrName, ...params) {
413
268
  const instanceContext = this.getContext(clazzOrName)
@@ -422,13 +277,6 @@ export class Container {
422
277
  return this.getInstance(instanceContext, params)
423
278
  }
424
279
 
425
- /**
426
- * Internal function to restore an instance context to its original.
427
- * @param {InstanceContext} instanceContext The instance context to reset
428
- * @param {string|Function} [clazzOrName] Optional identifier for error messages
429
- * @throws {Error} If instanceContext is null or undefined
430
- * @private
431
- */
432
280
  #restoreOriginal(instanceContext, clazzOrName) {
433
281
  if (!instanceContext) {
434
282
  const name = clazzOrName?.name || clazzOrName || 'unknown'
@@ -439,7 +287,6 @@ export class Container {
439
287
  clazz: instanceContext.originalClazz,
440
288
  instance: undefined,
441
289
  originalClazz: undefined,
442
- originalInstance: undefined,
443
290
  proxy: undefined
444
291
  })
445
292
  }
@@ -0,0 +1,40 @@
1
+ import { Container, InjectionToken } from '../../index'
2
+
3
+ export type ContainerScope = 'request' | 'global'
4
+
5
+ export function getGlobalContainer(): Container
6
+ export function getContainer(): Container
7
+
8
+ export interface ResolveOptions {
9
+ scope?: ContainerScope
10
+ params?: any[]
11
+ }
12
+
13
+ export function resolve<T>(clazzOrName: InjectionToken<T>, options?: ResolveOptions): T
14
+
15
+ export function runWithContainer<T>(
16
+ container: Container,
17
+ fn: () => T,
18
+ options?: { scope?: ContainerScope }
19
+ ): T
20
+
21
+ export interface MiddlewareOptions {
22
+ scope?: ContainerScope
23
+ debug?: boolean
24
+ }
25
+
26
+ export interface ContainerRequest {
27
+ di: Container
28
+ }
29
+
30
+ export function containerMiddleware(
31
+ options?: MiddlewareOptions
32
+ ): (req: any, res: any, next: () => void) => void
33
+
34
+ export function koaContainerMiddleware(
35
+ options?: MiddlewareOptions
36
+ ): (ctx: any, next: () => Promise<void>) => Promise<void>
37
+
38
+ export function withContainer<T extends (...args: any[]) => any>(
39
+ options?: MiddlewareOptions
40
+ ): (handler: T) => T
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Server middleware integration for decorator-dependency-injection.
3
+ *
4
+ * Provides request-scoped containers using AsyncLocalStorage, enabling
5
+ * automatic per-request isolation without manual container management.
6
+ *
7
+ * IMPORTANT: When using this module, `resolve()` behaves differently than
8
+ * the main module's resolve:
9
+ * - Inside a request: Returns instances from the request-scoped container
10
+ * (singletons are isolated per-request, preventing data leaks between users)
11
+ * - Outside a request: Falls back to the global container
12
+ *
13
+ * @module decorator-dependency-injection/middleware
14
+ */
15
+
16
+ import { AsyncLocalStorage } from 'node:async_hooks'
17
+ import { Container } from '../Container.js'
18
+ import { defaultContainer as mainDefaultContainer } from '../../index.js'
19
+
20
+ /** @type {AsyncLocalStorage<{container: Container, scope: string}>} */
21
+ const requestContext = new AsyncLocalStorage()
22
+
23
+ /** @type {Container} */
24
+ const globalContainer = mainDefaultContainer
25
+
26
+ /** @returns {Container|null} */
27
+ export function getGlobalContainer() {
28
+ return globalContainer
29
+ }
30
+
31
+ function getRequestContext() {
32
+ return requestContext.getStore()
33
+ }
34
+
35
+ /** @returns {Container} */
36
+ export function getContainer() {
37
+ return getRequestContext()?.container ?? globalContainer
38
+ }
39
+
40
+ /**
41
+ * Request-aware resolve. Uses request-scoped container inside requests,
42
+ * falls back to global container outside. Auto-registers from global container.
43
+ *
44
+ * @template T
45
+ * @param {string|Function} clazzOrName
46
+ * @param {Object} [options]
47
+ * @param {'request'|'global'} [options.scope]
48
+ * @param {Array} [options.params]
49
+ * @returns {T}
50
+ */
51
+ export function resolve(clazzOrName, options = {}) {
52
+ const { scope, params = [] } = options
53
+ const ctx = getRequestContext()
54
+
55
+ if (scope === 'global' || ctx?.scope === 'global') {
56
+ return globalContainer.resolve(clazzOrName, ...params)
57
+ }
58
+
59
+ if (!ctx) {
60
+ if (scope === 'request') {
61
+ console.warn(
62
+ `[DI] resolve() called with scope='request' but no request context exists. ` +
63
+ `Did you forget to use containerMiddleware()? Falling back to global container.`
64
+ )
65
+ }
66
+ return globalContainer.resolve(clazzOrName, ...params)
67
+ }
68
+
69
+ const requestContainer = ctx.container
70
+
71
+ if (!requestContainer.has(clazzOrName) && globalContainer?.has(clazzOrName)) {
72
+ const globalContext = globalContainer.getContext(clazzOrName)
73
+ if (globalContext.type === 'singleton') {
74
+ requestContainer.registerSingleton(globalContext.clazz,
75
+ typeof clazzOrName === 'string' ? clazzOrName : undefined)
76
+ } else {
77
+ requestContainer.registerFactory(globalContext.clazz,
78
+ typeof clazzOrName === 'string' ? clazzOrName : undefined)
79
+ }
80
+ }
81
+
82
+ return requestContainer.resolve(clazzOrName, ...params)
83
+ }
84
+
85
+ /**
86
+ * @template T
87
+ * @param {Container} container
88
+ * @param {function(): T} fn
89
+ * @param {Object} [options]
90
+ * @param {'request'|'global'} [options.scope='request']
91
+ * @returns {T}
92
+ */
93
+ export function runWithContainer(container, fn, options = {}) {
94
+ const { scope = 'request' } = options
95
+ return requestContext.run({ container, scope }, fn)
96
+ }
97
+
98
+ /**
99
+ * @typedef {Object} MiddlewareOptions
100
+ * @property {'request'|'global'} [scope='request'] - Container scope mode:
101
+ * - 'request': Each request gets its own container with isolated singletons (default, SSR-safe)
102
+ * - 'global': All requests share the global container (use only for stateless services)
103
+ * @property {boolean} [debug=false] - Enable debug logging
104
+ */
105
+
106
+ /**
107
+ * Express/Connect middleware. scope='request' gives each request isolated singletons (SSR-safe).
108
+ * @param {MiddlewareOptions} [options={}]
109
+ * @returns {function(req, res, next): void}
110
+ */
111
+ export function containerMiddleware(options = {}) {
112
+ const { scope = 'request', debug = false } = options
113
+
114
+ return (req, res, next) => {
115
+ if (scope === 'global') {
116
+ requestContext.run({ container: globalContainer, scope: 'global' }, () => {
117
+ req.di = globalContainer
118
+ next()
119
+ })
120
+ return
121
+ }
122
+
123
+ const container = new Container()
124
+ if (debug) container.setDebug(true)
125
+ req.di = container
126
+ requestContext.run({ container, scope: 'request' }, () => next())
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Koa middleware. See containerMiddleware() for scope behavior.
132
+ * @param {MiddlewareOptions} [options={}]
133
+ * @returns {function(ctx, next): Promise<void>}
134
+ */
135
+ export function koaContainerMiddleware(options = {}) {
136
+ const { scope = 'request', debug = false } = options
137
+
138
+ return async (ctx, next) => {
139
+ if (scope === 'global') {
140
+ await requestContext.run({ container: globalContainer, scope: 'global' }, async () => {
141
+ ctx.di = globalContainer
142
+ await next()
143
+ })
144
+ return
145
+ }
146
+
147
+ const container = new Container()
148
+ if (debug) container.setDebug(true)
149
+ ctx.di = container
150
+ await requestContext.run({ container, scope: 'request' }, () => next())
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Hono/Fastify-style handler wrapper. See containerMiddleware() for scope behavior.
156
+ * @param {MiddlewareOptions} [options={}]
157
+ * @returns {function(handler): function}
158
+ */
159
+ export function withContainer(options = {}) {
160
+ const { scope = 'request', debug = false } = options
161
+
162
+ return (handler) => (...args) => {
163
+ if (scope === 'global') {
164
+ return requestContext.run({ container: globalContainer, scope: 'global' }, () => handler(...args))
165
+ }
166
+
167
+ const container = new Container()
168
+ if (debug) container.setDebug(true)
169
+ return requestContext.run({ container, scope: 'request' }, () => handler(...args))
170
+ }
171
+ }