@navios/di 0.3.0 → 0.3.1
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/lib/_tsup-dts-rollup.d.mts +5 -1
- package/lib/_tsup-dts-rollup.d.ts +5 -1
- package/lib/index.js +31 -11
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +31 -11
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/request-scope.spec.mts +164 -0
- package/src/request-context-holder.mts +33 -4
|
@@ -4,6 +4,7 @@ import { Container } from '../container.mjs'
|
|
|
4
4
|
import { Injectable } from '../decorators/injectable.decorator.mjs'
|
|
5
5
|
import { InjectableScope } from '../enums/index.mjs'
|
|
6
6
|
import { inject } from '../index.mjs'
|
|
7
|
+
import { InjectionToken } from '../injection-token.mjs'
|
|
7
8
|
import { Registry } from '../registry.mjs'
|
|
8
9
|
import { createRequestContextHolder } from '../request-context-holder.mjs'
|
|
9
10
|
|
|
@@ -259,5 +260,168 @@ describe('Request Scope', () => {
|
|
|
259
260
|
holder.clear()
|
|
260
261
|
expect(holder.getMetadata('key1')).toBeUndefined()
|
|
261
262
|
})
|
|
263
|
+
|
|
264
|
+
it('should store instances by InjectionToken', () => {
|
|
265
|
+
const holder = createRequestContextHolder('test-request')
|
|
266
|
+
const token = InjectionToken.create<string>('TestService')
|
|
267
|
+
const instance = { id: 'test-instance', data: 'test-data' }
|
|
268
|
+
|
|
269
|
+
// Store instance by InjectionToken
|
|
270
|
+
holder.addInstance(token, instance)
|
|
271
|
+
|
|
272
|
+
// Verify instance is stored and retrievable
|
|
273
|
+
expect(holder.hasInstance(token.toString())).toBe(true)
|
|
274
|
+
expect(holder.getInstance(token.toString())).toBe(instance)
|
|
275
|
+
|
|
276
|
+
// Verify holder is created with correct properties
|
|
277
|
+
const holderInfo = holder.getHolder(token.toString())
|
|
278
|
+
expect(holderInfo).toBeDefined()
|
|
279
|
+
expect(holderInfo?.instance).toBe(instance)
|
|
280
|
+
expect(holderInfo?.name).toBe(token.toString())
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it('should store multiple instances by different InjectionTokens', () => {
|
|
284
|
+
const holder = createRequestContextHolder('test-request')
|
|
285
|
+
|
|
286
|
+
const token1 = InjectionToken.create<string>('Service1')
|
|
287
|
+
const token2 = InjectionToken.create<number>('Service2')
|
|
288
|
+
const token3 = InjectionToken.create<boolean>('Service3')
|
|
289
|
+
|
|
290
|
+
const instance1 = { id: 'instance1', type: 'string' }
|
|
291
|
+
const instance2 = { id: 'instance2', type: 'number' }
|
|
292
|
+
const instance3 = { id: 'instance3', type: 'boolean' }
|
|
293
|
+
|
|
294
|
+
// Store multiple instances
|
|
295
|
+
holder.addInstance(token1, instance1)
|
|
296
|
+
holder.addInstance(token2, instance2)
|
|
297
|
+
holder.addInstance(token3, instance3)
|
|
298
|
+
|
|
299
|
+
// Verify all instances are stored correctly
|
|
300
|
+
expect(holder.hasInstance(token1.toString())).toBe(true)
|
|
301
|
+
expect(holder.hasInstance(token2.toString())).toBe(true)
|
|
302
|
+
expect(holder.hasInstance(token3.toString())).toBe(true)
|
|
303
|
+
|
|
304
|
+
expect(holder.getInstance(token1.toString())).toBe(instance1)
|
|
305
|
+
expect(holder.getInstance(token2.toString())).toBe(instance2)
|
|
306
|
+
expect(holder.getInstance(token3.toString())).toBe(instance3)
|
|
307
|
+
|
|
308
|
+
// Verify each has its own holder
|
|
309
|
+
const holder1 = holder.getHolder(token1.toString())
|
|
310
|
+
const holder2 = holder.getHolder(token2.toString())
|
|
311
|
+
const holder3 = holder.getHolder(token3.toString())
|
|
312
|
+
|
|
313
|
+
expect(holder1?.instance).toBe(instance1)
|
|
314
|
+
expect(holder2?.instance).toBe(instance2)
|
|
315
|
+
expect(holder3?.instance).toBe(instance3)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('should override instances stored by InjectionToken', () => {
|
|
319
|
+
const holder = createRequestContextHolder('test-request')
|
|
320
|
+
const token = InjectionToken.create<string>('TestService')
|
|
321
|
+
|
|
322
|
+
const originalInstance = { id: 'original', data: 'original-data' }
|
|
323
|
+
const newInstance = { id: 'new', data: 'new-data' }
|
|
324
|
+
|
|
325
|
+
// Store original instance
|
|
326
|
+
holder.addInstance(token, originalInstance)
|
|
327
|
+
expect(holder.getInstance(token.toString())).toBe(originalInstance)
|
|
328
|
+
|
|
329
|
+
// Override with new instance
|
|
330
|
+
holder.addInstance(token, newInstance)
|
|
331
|
+
expect(holder.getInstance(token.toString())).toBe(newInstance)
|
|
332
|
+
expect(holder.getInstance(token.toString())).not.toBe(originalInstance)
|
|
333
|
+
|
|
334
|
+
// Verify holder is updated
|
|
335
|
+
const holderInfo = holder.getHolder(token.toString())
|
|
336
|
+
expect(holderInfo?.instance).toBe(newInstance)
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('should handle InjectionToken with different name types', () => {
|
|
340
|
+
const holder = createRequestContextHolder('test-request')
|
|
341
|
+
|
|
342
|
+
// Test with string name
|
|
343
|
+
const stringToken = InjectionToken.create<string>('StringService')
|
|
344
|
+
const stringInstance = { type: 'string' }
|
|
345
|
+
|
|
346
|
+
// Test with symbol name
|
|
347
|
+
const symbolToken = InjectionToken.create<number>(Symbol('SymbolService'))
|
|
348
|
+
const symbolInstance = { type: 'symbol' }
|
|
349
|
+
|
|
350
|
+
// Test with class name
|
|
351
|
+
class TestClass {}
|
|
352
|
+
const classToken = InjectionToken.create(TestClass)
|
|
353
|
+
const classInstance = { type: 'class' }
|
|
354
|
+
|
|
355
|
+
holder.addInstance(stringToken, stringInstance)
|
|
356
|
+
holder.addInstance(symbolToken, symbolInstance)
|
|
357
|
+
holder.addInstance(classToken, classInstance)
|
|
358
|
+
|
|
359
|
+
expect(holder.getInstance(stringToken.toString())).toBe(stringInstance)
|
|
360
|
+
expect(holder.getInstance(symbolToken.toString())).toBe(symbolInstance)
|
|
361
|
+
expect(holder.getInstance(classToken.toString())).toBe(classInstance)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
it('should clear instances stored by InjectionToken', () => {
|
|
365
|
+
const holder = createRequestContextHolder('test-request')
|
|
366
|
+
const token1 = InjectionToken.create<string>('Service1')
|
|
367
|
+
const token2 = InjectionToken.create<number>('Service2')
|
|
368
|
+
|
|
369
|
+
const instance1 = { id: 'instance1' }
|
|
370
|
+
const instance2 = { id: 'instance2' }
|
|
371
|
+
|
|
372
|
+
holder.addInstance(token1, instance1)
|
|
373
|
+
holder.addInstance(token2, instance2)
|
|
374
|
+
|
|
375
|
+
expect(holder.hasInstance(token1.toString())).toBe(true)
|
|
376
|
+
expect(holder.hasInstance(token2.toString())).toBe(true)
|
|
377
|
+
|
|
378
|
+
// Clear all instances
|
|
379
|
+
holder.clear()
|
|
380
|
+
|
|
381
|
+
expect(holder.hasInstance(token1.toString())).toBe(false)
|
|
382
|
+
expect(holder.hasInstance(token2.toString())).toBe(false)
|
|
383
|
+
expect(holder.getInstance(token1.toString())).toBeUndefined()
|
|
384
|
+
expect(holder.getInstance(token2.toString())).toBeUndefined()
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
it('should handle mixed storage by InjectionToken and string name', () => {
|
|
388
|
+
const holder = createRequestContextHolder('test-request')
|
|
389
|
+
|
|
390
|
+
const token = InjectionToken.create<string>('TokenService')
|
|
391
|
+
const tokenInstance = { id: 'token-instance' }
|
|
392
|
+
|
|
393
|
+
const stringName = 'string-service'
|
|
394
|
+
const stringInstance = { id: 'string-instance' }
|
|
395
|
+
|
|
396
|
+
// Store by InjectionToken
|
|
397
|
+
holder.addInstance(token, tokenInstance)
|
|
398
|
+
|
|
399
|
+
// Store by string name (requires holder)
|
|
400
|
+
const mockHolder = {
|
|
401
|
+
status: 'Created' as any,
|
|
402
|
+
name: stringName,
|
|
403
|
+
instance: stringInstance,
|
|
404
|
+
creationPromise: null,
|
|
405
|
+
destroyPromise: null,
|
|
406
|
+
type: 'Class' as any,
|
|
407
|
+
scope: 'Singleton' as any,
|
|
408
|
+
deps: new Set<string>(),
|
|
409
|
+
destroyListeners: [],
|
|
410
|
+
createdAt: Date.now(),
|
|
411
|
+
ttl: Infinity,
|
|
412
|
+
}
|
|
413
|
+
holder.addInstance(stringName, stringInstance, mockHolder)
|
|
414
|
+
|
|
415
|
+
// Verify both are stored correctly
|
|
416
|
+
expect(holder.hasInstance(token.toString())).toBe(true)
|
|
417
|
+
expect(holder.hasInstance(stringName)).toBe(true)
|
|
418
|
+
|
|
419
|
+
expect(holder.getInstance(token.toString())).toBe(tokenInstance)
|
|
420
|
+
expect(holder.getInstance(stringName)).toBe(stringInstance)
|
|
421
|
+
|
|
422
|
+
// Verify holders
|
|
423
|
+
expect(holder.getHolder(token.toString())?.instance).toBe(tokenInstance)
|
|
424
|
+
expect(holder.getHolder(stringName)?.instance).toBe(stringInstance)
|
|
425
|
+
})
|
|
262
426
|
})
|
|
263
427
|
})
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ServiceLocatorInstanceHolder } from './service-locator-instance-holder.mjs'
|
|
2
2
|
|
|
3
|
+
import { InjectableScope, InjectableType } from './enums/index.mjs'
|
|
4
|
+
import { InjectionToken } from './injection-token.mjs'
|
|
5
|
+
import { ServiceLocatorInstanceHolderStatus } from './service-locator-instance-holder.mjs'
|
|
6
|
+
|
|
3
7
|
/**
|
|
4
8
|
* Request context holder that manages pre-prepared instances for a specific request.
|
|
5
9
|
* This allows for efficient instantiation of request-scoped services.
|
|
@@ -45,6 +49,11 @@ export interface RequestContextHolder {
|
|
|
45
49
|
holder: ServiceLocatorInstanceHolder,
|
|
46
50
|
): void
|
|
47
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Adds a pre-prepared instance to this context.
|
|
54
|
+
*/
|
|
55
|
+
addInstance(token: InjectionToken<any, undefined>, instance: any): void
|
|
56
|
+
|
|
48
57
|
/**
|
|
49
58
|
* Gets a pre-prepared instance from this context.
|
|
50
59
|
*/
|
|
@@ -98,12 +107,32 @@ export class DefaultRequestContextHolder implements RequestContextHolder {
|
|
|
98
107
|
}
|
|
99
108
|
|
|
100
109
|
addInstance(
|
|
101
|
-
instanceName: string,
|
|
110
|
+
instanceName: string | InjectionToken<any, undefined>,
|
|
102
111
|
instance: any,
|
|
103
|
-
holder
|
|
112
|
+
holder?: ServiceLocatorInstanceHolder,
|
|
104
113
|
): void {
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
if (instanceName instanceof InjectionToken) {
|
|
115
|
+
this.instances.set(instanceName.toString(), instance)
|
|
116
|
+
this.holders.set(instanceName.toString(), {
|
|
117
|
+
instance,
|
|
118
|
+
status: ServiceLocatorInstanceHolderStatus.Created,
|
|
119
|
+
creationPromise: null,
|
|
120
|
+
destroyPromise: null,
|
|
121
|
+
destroyListeners: [],
|
|
122
|
+
deps: new Set(),
|
|
123
|
+
name: instanceName.toString(),
|
|
124
|
+
type: InjectableType.Class,
|
|
125
|
+
scope: InjectableScope.Singleton,
|
|
126
|
+
createdAt: Date.now(),
|
|
127
|
+
ttl: Infinity,
|
|
128
|
+
})
|
|
129
|
+
} else {
|
|
130
|
+
if (!holder) {
|
|
131
|
+
throw new Error('Holder is required when adding an instance by name')
|
|
132
|
+
}
|
|
133
|
+
this.instances.set(instanceName, instance)
|
|
134
|
+
this.holders.set(instanceName, holder)
|
|
135
|
+
}
|
|
107
136
|
}
|
|
108
137
|
|
|
109
138
|
getInstance(instanceName: string): any | undefined {
|