@navios/di 0.7.1 → 0.9.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/CHANGELOG.md +110 -0
- package/README.md +117 -17
- package/lib/browser/container/abstract-container.d.mts +112 -0
- package/lib/browser/container/abstract-container.d.mts.map +1 -0
- package/lib/browser/container/abstract-container.mjs +100 -0
- package/lib/browser/container/abstract-container.mjs.map +1 -0
- package/lib/browser/container/container.d.mts +100 -0
- package/lib/browser/container/container.d.mts.map +1 -0
- package/lib/browser/container/container.mjs +424 -0
- package/lib/browser/container/container.mjs.map +1 -0
- package/lib/browser/container/scoped-container.d.mts +93 -0
- package/lib/browser/container/scoped-container.d.mts.map +1 -0
- package/lib/browser/container/scoped-container.mjs +119 -0
- package/lib/browser/container/scoped-container.mjs.map +1 -0
- package/lib/browser/decorators/factory.decorator.d.mts +26 -0
- package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/factory.decorator.mjs +20 -0
- package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
- package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
- package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
- package/lib/browser/decorators/injectable.decorator.mjs +21 -0
- package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
- package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
- package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
- package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
- package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
- package/lib/browser/enums/injectable-type.enum.mjs +10 -0
- package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
- package/lib/browser/errors/di-error.d.mts +43 -0
- package/lib/browser/errors/di-error.d.mts.map +1 -0
- package/lib/browser/errors/di-error.mjs +98 -0
- package/lib/browser/errors/di-error.mjs.map +1 -0
- package/lib/browser/event-emitter.d.mts +16 -0
- package/lib/browser/event-emitter.d.mts.map +1 -0
- package/lib/browser/event-emitter.mjs +320 -0
- package/lib/browser/event-emitter.mjs.map +1 -0
- package/lib/browser/index.d.mts +37 -1508
- package/lib/browser/index.mjs +29 -2650
- package/lib/browser/interfaces/container.interface.d.mts +59 -0
- package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/factory.interface.d.mts +14 -0
- package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
- package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
- package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
- package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
- package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
- package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
- package/lib/browser/internal/context/factory-context.d.mts +23 -0
- package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.d.mts +43 -0
- package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
- package/lib/browser/internal/context/resolution-context.mjs +56 -0
- package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
- package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
- package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
- package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
- package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
- package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/instance-resolver.mjs +306 -0
- package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/name-resolver.d.mts +52 -0
- package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/name-resolver.mjs +118 -0
- package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
- package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
- package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
- package/lib/browser/internal/core/scope-tracker.mjs +120 -0
- package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
- package/lib/browser/internal/core/service-initializer.d.mts +44 -0
- package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
- package/lib/browser/internal/core/service-initializer.mjs +109 -0
- package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
- package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
- package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
- package/lib/browser/internal/core/service-invalidator.mjs +142 -0
- package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
- package/lib/browser/internal/core/token-resolver.d.mts +54 -0
- package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
- package/lib/browser/internal/core/token-resolver.mjs +77 -0
- package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
- package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
- package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
- package/lib/browser/internal/holder/instance-holder.mjs +19 -0
- package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
- package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
- package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
- package/lib/browser/internal/holder/unified-storage.mjs +144 -0
- package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
- package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
- package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
- package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
- package/lib/browser/internal/stub-factory-class.d.mts +14 -0
- package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
- package/lib/browser/internal/stub-factory-class.mjs +18 -0
- package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
- package/lib/browser/symbols/injectable-token.d.mts +5 -0
- package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
- package/lib/browser/symbols/injectable-token.mjs +6 -0
- package/lib/browser/symbols/injectable-token.mjs.map +1 -0
- package/lib/browser/token/injection-token.d.mts +55 -0
- package/lib/browser/token/injection-token.d.mts.map +1 -0
- package/lib/browser/token/injection-token.mjs +100 -0
- package/lib/browser/token/injection-token.mjs.map +1 -0
- package/lib/browser/token/registry.d.mts +37 -0
- package/lib/browser/token/registry.d.mts.map +1 -0
- package/lib/browser/token/registry.mjs +86 -0
- package/lib/browser/token/registry.mjs.map +1 -0
- package/lib/browser/utils/default-injectors.d.mts +12 -0
- package/lib/browser/utils/default-injectors.d.mts.map +1 -0
- package/lib/browser/utils/default-injectors.mjs +13 -0
- package/lib/browser/utils/default-injectors.mjs.map +1 -0
- package/lib/browser/utils/get-injectable-token.d.mts +9 -0
- package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
- package/lib/browser/utils/get-injectable-token.mjs +13 -0
- package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
- package/lib/browser/utils/get-injectors.d.mts +55 -0
- package/lib/browser/utils/get-injectors.d.mts.map +1 -0
- package/lib/browser/utils/get-injectors.mjs +121 -0
- package/lib/browser/utils/get-injectors.mjs.map +1 -0
- package/lib/browser/utils/types.d.mts +23 -0
- package/lib/browser/utils/types.d.mts.map +1 -0
- package/lib/{container-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
- package/lib/container-8-z89TyQ.mjs.map +1 -0
- package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
- package/lib/container-CNiqesCL.d.mts.map +1 -0
- package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
- package/lib/container-CaY2fDuk.cjs.map +1 -0
- package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
- package/lib/container-D-0Ho3qL.d.cts.map +1 -0
- package/lib/index.cjs +13 -15
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +58 -223
- package/lib/index.d.cts.map +1 -1
- package/lib/index.d.mts +62 -222
- package/lib/index.d.mts.map +1 -1
- package/lib/index.mjs +5 -6
- package/lib/index.mjs.map +1 -1
- package/lib/testing/index.cjs +569 -311
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +370 -41
- package/lib/testing/index.d.cts.map +1 -1
- package/lib/testing/index.d.mts +370 -41
- package/lib/testing/index.d.mts.map +1 -1
- package/lib/testing/index.mjs +568 -305
- package/lib/testing/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/__tests__/circular-detector.spec.mts +193 -0
- package/src/__tests__/concurrent.spec.mts +368 -0
- package/src/__tests__/container.spec.mts +32 -30
- package/src/__tests__/di-error.spec.mts +351 -0
- package/src/__tests__/e2e.browser.spec.mts +0 -4
- package/src/__tests__/e2e.spec.mts +10 -19
- package/src/__tests__/event-emitter.spec.mts +232 -109
- package/src/__tests__/get-injectors.spec.mts +250 -39
- package/src/__tests__/injection-token.spec.mts +293 -349
- package/src/__tests__/library-findings.spec.mts +8 -8
- package/src/__tests__/registry.spec.mts +358 -210
- package/src/__tests__/resolution-context.spec.mts +255 -0
- package/src/__tests__/scope-tracker.spec.mts +598 -0
- package/src/__tests__/scope-upgrade.spec.mts +808 -0
- package/src/__tests__/scoped-container.spec.mts +595 -0
- package/src/__tests__/test-container.spec.mts +293 -0
- package/src/__tests__/token-resolver.spec.mts +207 -0
- package/src/__tests__/unified-storage.spec.mts +535 -0
- package/src/__tests__/unit-test-container.spec.mts +405 -0
- package/src/__type-tests__/container.spec-d.mts +180 -0
- package/src/__type-tests__/factory.spec-d.mts +15 -3
- package/src/__type-tests__/inject.spec-d.mts +115 -20
- package/src/__type-tests__/injectable.spec-d.mts +69 -52
- package/src/__type-tests__/injection-token.spec-d.mts +176 -0
- package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
- package/src/container/abstract-container.mts +327 -0
- package/src/container/container.mts +142 -170
- package/src/container/scoped-container.mts +126 -208
- package/src/decorators/factory.decorator.mts +16 -11
- package/src/decorators/injectable.decorator.mts +20 -16
- package/src/enums/index.mts +2 -2
- package/src/enums/injectable-scope.enum.mts +1 -0
- package/src/enums/injectable-type.enum.mts +1 -0
- package/src/errors/di-error.mts +96 -0
- package/src/event-emitter.mts +3 -27
- package/src/index.mts +6 -153
- package/src/interfaces/container.interface.mts +13 -0
- package/src/interfaces/factory.interface.mts +1 -1
- package/src/interfaces/index.mts +1 -1
- package/src/internal/context/async-local-storage.mts +3 -2
- package/src/internal/context/async-local-storage.types.mts +1 -0
- package/src/internal/context/factory-context.mts +1 -0
- package/src/internal/context/index.mts +3 -1
- package/src/internal/context/resolution-context.mts +1 -0
- package/src/internal/context/service-initialization-context.mts +43 -0
- package/src/internal/core/index.mts +5 -4
- package/src/internal/core/instance-resolver.mts +461 -292
- package/src/internal/core/name-resolver.mts +196 -0
- package/src/internal/core/scope-tracker.mts +242 -0
- package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
- package/src/internal/core/service-invalidator.mts +290 -0
- package/src/internal/core/{token-processor.mts → token-resolver.mts} +17 -88
- package/src/internal/holder/holder-storage.interface.mts +11 -5
- package/src/internal/holder/index.mts +2 -5
- package/src/internal/holder/instance-holder.mts +1 -3
- package/src/internal/holder/unified-storage.mts +245 -0
- package/src/internal/index.mts +2 -1
- package/src/internal/lifecycle/circular-detector.mts +1 -0
- package/src/internal/lifecycle/index.mts +1 -1
- package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
- package/src/internal/stub-factory-class.mts +16 -0
- package/src/symbols/injectable-token.mts +3 -1
- package/src/testing/index.mts +2 -0
- package/src/testing/test-container.mts +546 -85
- package/src/testing/types.mts +117 -0
- package/src/testing/unit-test-container.mts +509 -0
- package/src/token/injection-token.mts +41 -4
- package/src/token/registry.mts +75 -9
- package/src/utils/default-injectors.mts +16 -0
- package/src/utils/get-injectable-token.mts +2 -3
- package/src/utils/get-injectors.mts +26 -15
- package/src/utils/index.mts +3 -1
- package/src/utils/types.mts +1 -0
- package/tsdown.config.mts +11 -1
- package/lib/browser/index.d.mts.map +0 -1
- package/lib/browser/index.mjs.map +0 -1
- package/lib/container-BuAutHGg.d.mts.map +0 -1
- package/lib/container-DnzgpfBe.cjs.map +0 -1
- package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
- package/lib/container-oGTgX2iX.d.cts.map +0 -1
- package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
- package/src/__tests__/async-local-storage.spec.mts +0 -333
- package/src/__tests__/errors.spec.mts +0 -87
- package/src/__tests__/factory.spec.mts +0 -137
- package/src/__tests__/injectable.spec.mts +0 -246
- package/src/__tests__/request-scope.spec.mts +0 -416
- package/src/__tests__/service-instantiator.spec.mts +0 -410
- package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
- package/src/__tests__/service-locator-manager.spec.mts +0 -300
- package/src/__tests__/service-locator.spec.mts +0 -966
- package/src/__tests__/unified-api.spec.mts +0 -130
- package/src/browser.mts +0 -11
- package/src/injectors.mts +0 -18
- package/src/internal/context/request-context.mts +0 -214
- package/src/internal/core/invalidator.mts +0 -437
- package/src/internal/core/service-locator.mts +0 -202
- package/src/internal/holder/base-holder-manager.mts +0 -238
- package/src/internal/holder/holder-manager.mts +0 -85
- package/src/internal/holder/request-storage.mts +0 -134
- package/src/internal/holder/singleton-storage.mts +0 -105
- package/src/testing/README.md +0 -80
- package/src/testing/__tests__/test-container.spec.mts +0 -173
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-invalidator.mjs","names":["InstanceStatus","ServiceInvalidator","eventBus","logger","invalidateWithStorage","service","storage","options","emitEvents","onInvalidated","log","result","get","holder","invalidateHolderWithStorage","setupDependencySubscriptions","serviceName","dependencies","dependencyName","unsubscribe","on","catch","error","destroyListeners","push","clearAllWithStorage","waitForSettlement","readyWithStorage","allServiceNames","getAllNames","length","join","clearPromises","map","Promise","all","holders","forEach","_","waitForHolderToSettle","key","invalidateHolderByStatus","context","onDestroy","destroyHolderWithStorage","status","Destroying","destroyPromise","Creating","creationPromise","listener","then","deps","clear","delete","emitInstanceEvent","Created","Error","name","event","resolve","emit"],"sources":["../../../../src/internal/core/service-invalidator.mts"],"sourcesContent":["import type { IHolderStorage } from '../holder/holder-storage.interface.mjs'\nimport type { InstanceHolder } from '../holder/instance-holder.mjs'\nimport type { LifecycleEventBus } from '../lifecycle/lifecycle-event-bus.mjs'\n\nimport { InstanceStatus } from '../holder/instance-holder.mjs'\n\nexport interface ClearAllOptions {\n /** Whether to wait for all services to settle before starting (default: true) */\n waitForSettlement?: boolean\n}\n\nexport interface InvalidationOptions {\n /** Whether to emit events after invalidation (default: true) */\n emitEvents?: boolean\n /** Custom event emitter function */\n onInvalidated?: (instanceName: string) => Promise<void>\n /** Whether to cascade invalidation to dependents (default: false - events handle it) */\n cascade?: boolean\n}\n\n/**\n * Manages graceful service cleanup with event-based invalidation.\n *\n * Uses event subscriptions instead of manual dependent finding.\n * When a service is created, it subscribes to destroy events of its dependencies.\n * When a dependency is destroyed, the event automatically invalidates dependents.\n */\nexport class ServiceInvalidator {\n constructor(\n private readonly eventBus: LifecycleEventBus | null,\n private readonly logger: Console | null = null,\n ) {}\n\n /**\n * Invalidates a service using a specific storage.\n * Event-based invalidation means dependents are automatically invalidated\n * via destroy event subscriptions - no need to manually find dependents.\n *\n * @param service The instance name to invalidate\n * @param storage The storage to use for this invalidation\n * @param options Additional options for invalidation behavior\n */\n async invalidateWithStorage(\n service: string,\n storage: IHolderStorage,\n options: InvalidationOptions = {},\n ): Promise<void> {\n const { emitEvents = true, onInvalidated } = options\n\n this.logger?.log(\n `[ServiceInvalidator] Starting invalidation process for ${service}`,\n )\n\n const result = storage.get(service)\n if (result === null) {\n return\n }\n\n const [, holder] = result\n if (holder) {\n await this.invalidateHolderWithStorage(\n service,\n holder,\n storage,\n emitEvents,\n onInvalidated,\n )\n }\n }\n\n /**\n * Sets up destroy event subscriptions for a service's dependencies.\n * Called when a service is successfully instantiated.\n *\n * @param serviceName The name of the service\n * @param dependencies The set of dependency names\n * @param storage The storage to use for invalidation\n * @param holder The holder for the service (to add unsubscribe to destroy listeners)\n */\n setupDependencySubscriptions(\n serviceName: string,\n dependencies: Set<string>,\n storage: IHolderStorage,\n holder: InstanceHolder,\n ): void {\n if (!this.eventBus) {\n return\n }\n\n for (const dependencyName of dependencies) {\n // Subscribe to the dependency's destroy event\n const unsubscribe = this.eventBus.on(dependencyName, 'destroy', () => {\n this.logger?.log(\n `[ServiceInvalidator] Dependency ${dependencyName} destroyed, invalidating ${serviceName}`,\n )\n // Automatically invalidate this service when dependency is destroyed\n this.invalidateWithStorage(serviceName, storage).catch((error) => {\n this.logger?.error(\n `[ServiceInvalidator] Error invalidating ${serviceName} after dependency ${dependencyName} destroyed:`,\n error,\n )\n })\n })\n\n // Store unsubscribe function in the service's destroy listeners\n // so it's cleaned up when the service is destroyed\n holder.destroyListeners.push(unsubscribe)\n }\n }\n\n /**\n * Gracefully clears all services in a specific storage.\n * This allows clearing request-scoped services using a RequestStorage.\n */\n async clearAllWithStorage(\n storage: IHolderStorage,\n options: ClearAllOptions = {},\n ): Promise<void> {\n const { waitForSettlement = true } = options\n\n this.logger?.log(\n '[ServiceInvalidator] Starting graceful clearing of all services',\n )\n\n // Wait for all services to settle if requested\n if (waitForSettlement) {\n this.logger?.log(\n '[ServiceInvalidator] Waiting for all services to settle...',\n )\n await this.readyWithStorage(storage)\n }\n\n // Get all service names that need to be cleared\n const allServiceNames = storage.getAllNames()\n\n if (allServiceNames.length === 0) {\n this.logger?.log('[ServiceInvalidator] No services to clear')\n } else {\n this.logger?.log(\n `[ServiceInvalidator] Found ${allServiceNames.length} services to clear: ${allServiceNames.join(', ')}`,\n )\n\n // Clear services - events will handle dependent invalidation\n const clearPromises = allServiceNames.map((serviceName) =>\n this.invalidateWithStorage(serviceName, storage),\n )\n\n await Promise.all(clearPromises)\n }\n\n this.logger?.log('[ServiceInvalidator] Graceful clearing completed')\n }\n\n /**\n * Waits for all services in a specific storage to settle.\n */\n async readyWithStorage(storage: IHolderStorage): Promise<void> {\n const holders: InstanceHolder<any>[] = []\n storage.forEach((_: string, holder: InstanceHolder) => holders.push(holder))\n await Promise.all(\n holders.map((holder) => this.waitForHolderToSettle(holder)),\n )\n }\n\n // ============================================================================\n // INTERNAL INVALIDATION HELPERS\n // ============================================================================\n\n /**\n * Invalidates a single holder using a specific storage.\n */\n private async invalidateHolderWithStorage(\n key: string,\n holder: InstanceHolder<any>,\n storage: IHolderStorage,\n emitEvents: boolean,\n onInvalidated?: (instanceName: string) => Promise<void>,\n ): Promise<void> {\n await this.invalidateHolderByStatus(holder, {\n context: key,\n onDestroy: () =>\n this.destroyHolderWithStorage(\n key,\n holder,\n storage,\n emitEvents,\n onInvalidated,\n ),\n })\n }\n\n /**\n * Common invalidation logic for holders based on their status.\n */\n private async invalidateHolderByStatus(\n holder: InstanceHolder<any>,\n options: {\n context: string\n onDestroy: () => Promise<void>\n },\n ): Promise<void> {\n switch (holder.status) {\n case InstanceStatus.Destroying:\n await holder.destroyPromise\n break\n\n case InstanceStatus.Creating:\n // Wait for creation to complete before destroying\n await holder.creationPromise\n await options.onDestroy()\n break\n\n default:\n await options.onDestroy()\n break\n }\n }\n\n /**\n * Destroys a holder using a specific storage.\n */\n private async destroyHolderWithStorage(\n key: string,\n holder: InstanceHolder<any>,\n storage: IHolderStorage,\n emitEvents: boolean,\n onInvalidated?: (instanceName: string) => Promise<void>,\n ): Promise<void> {\n holder.status = InstanceStatus.Destroying\n this.logger?.log(\n `[ServiceInvalidator] Invalidating ${key} and notifying listeners`,\n )\n\n holder.destroyPromise = Promise.all(\n holder.destroyListeners.map((listener) => listener()),\n ).then(async () => {\n holder.destroyListeners = []\n holder.deps.clear()\n storage.delete(key)\n\n // Emit events if enabled and event bus exists\n if (emitEvents && this.eventBus) {\n await this.emitInstanceEvent(key, 'destroy')\n }\n\n // Call custom callback if provided\n if (onInvalidated) {\n await onInvalidated(key)\n }\n })\n\n await holder.destroyPromise\n }\n\n /**\n * Waits for a holder to settle (either created, destroyed, or error state).\n */\n private async waitForHolderToSettle(\n holder: InstanceHolder<any>,\n ): Promise<void> {\n switch (holder.status) {\n case InstanceStatus.Creating:\n await holder.creationPromise\n break\n case InstanceStatus.Destroying:\n await holder.destroyPromise\n break\n // Already settled states\n case InstanceStatus.Created:\n case InstanceStatus.Error:\n break\n }\n }\n\n /**\n * Emits events to listeners for instance lifecycle events.\n */\n private emitInstanceEvent(\n name: string,\n event: 'create' | 'destroy' = 'create',\n ) {\n if (!this.eventBus) {\n return Promise.resolve()\n }\n this.logger?.log(\n `[ServiceInvalidator]#emitInstanceEvent() Notifying listeners for ${name} with event ${event}`,\n )\n return this.eventBus.emit(name, event)\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AnyInjectableType, InjectionToken, InjectionTokenType } from "../../token/injection-token.mjs";
|
|
2
|
+
import { DIError } from "../../errors/di-error.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/internal/core/token-resolver.d.mts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles token validation and resolution.
|
|
8
|
+
*
|
|
9
|
+
* Focuses on token validation, normalization, and argument validation.
|
|
10
|
+
* Name generation is handled by NameResolver.
|
|
11
|
+
*/
|
|
12
|
+
declare class TokenResolver {
|
|
13
|
+
private readonly logger;
|
|
14
|
+
constructor(logger?: Console | null);
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a token to an InjectionToken.
|
|
17
|
+
* Handles class constructors by getting their injectable token.
|
|
18
|
+
*
|
|
19
|
+
* @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
|
|
20
|
+
* @returns The normalized InjectionTokenType
|
|
21
|
+
*/
|
|
22
|
+
normalizeToken(token: AnyInjectableType): InjectionTokenType;
|
|
23
|
+
/**
|
|
24
|
+
* Gets the underlying "real" token from wrapped tokens.
|
|
25
|
+
* For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.
|
|
26
|
+
* For other tokens, returns the token itself.
|
|
27
|
+
*
|
|
28
|
+
* @param token The token to unwrap
|
|
29
|
+
* @returns The underlying InjectionToken
|
|
30
|
+
*/
|
|
31
|
+
getRealToken<T = unknown>(token: InjectionTokenType): InjectionToken<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Convenience method that normalizes a token and then gets the real token.
|
|
34
|
+
* Useful for checking registry entries where you need the actual registered token.
|
|
35
|
+
*
|
|
36
|
+
* @param token Any injectable type
|
|
37
|
+
* @returns The underlying InjectionToken
|
|
38
|
+
*/
|
|
39
|
+
getRegistryToken<T = unknown>(token: AnyInjectableType): InjectionToken<T>;
|
|
40
|
+
/**
|
|
41
|
+
* Validates and resolves token arguments, handling factory token resolution and validation.
|
|
42
|
+
*
|
|
43
|
+
* @param token The token to validate
|
|
44
|
+
* @param args Optional arguments
|
|
45
|
+
* @returns [error, { actualToken, validatedArgs }]
|
|
46
|
+
*/
|
|
47
|
+
validateAndResolveTokenArgs(token: AnyInjectableType, args?: any): [DIError | undefined, {
|
|
48
|
+
actualToken: InjectionTokenType;
|
|
49
|
+
validatedArgs?: any;
|
|
50
|
+
}];
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { TokenResolver };
|
|
54
|
+
//# sourceMappingURL=token-resolver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-resolver.d.mts","names":[],"sources":["../../../../src/internal/core/token-resolver.mts"],"sourcesContent":[],"mappings":";;;;;;AAmBA;;;;;AA6BuE,cA7B1D,aAAA,CA6B0D;EAAf,iBAAA,MAAA;EAiBjB,WAAA,CAAA,MAAA,CAAA,EA7CA,OA6CA,GAAA,IAAA;EAAmC;;;;;;;wBAhClD,oBAAoB;;;;;;;;;mCAeT,qBAAqB,eAAe;;;;;;;;uCAiBhC,oBAAoB,eAAe;;;;;;;;qCAgB/D,iCAGP;iBACe"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BoundInjectionToken, FactoryInjectionToken } from "../../token/injection-token.mjs";
|
|
2
|
+
import { DIError } from "../../errors/di-error.mjs";
|
|
3
|
+
import { getInjectableToken } from "../../utils/get-injectable-token.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/internal/core/token-resolver.mts
|
|
6
|
+
/**
|
|
7
|
+
* Handles token validation and resolution.
|
|
8
|
+
*
|
|
9
|
+
* Focuses on token validation, normalization, and argument validation.
|
|
10
|
+
* Name generation is handled by NameResolver.
|
|
11
|
+
*/ var TokenResolver = class {
|
|
12
|
+
logger;
|
|
13
|
+
constructor(logger = null) {
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes a token to an InjectionToken.
|
|
18
|
+
* Handles class constructors by getting their injectable token.
|
|
19
|
+
*
|
|
20
|
+
* @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken
|
|
21
|
+
* @returns The normalized InjectionTokenType
|
|
22
|
+
*/ normalizeToken(token) {
|
|
23
|
+
if (typeof token === "function") return getInjectableToken(token);
|
|
24
|
+
return token;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Gets the underlying "real" token from wrapped tokens.
|
|
28
|
+
* For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.
|
|
29
|
+
* For other tokens, returns the token itself.
|
|
30
|
+
*
|
|
31
|
+
* @param token The token to unwrap
|
|
32
|
+
* @returns The underlying InjectionToken
|
|
33
|
+
*/ getRealToken(token) {
|
|
34
|
+
if (token instanceof BoundInjectionToken || token instanceof FactoryInjectionToken) return token.token;
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Convenience method that normalizes a token and then gets the real token.
|
|
39
|
+
* Useful for checking registry entries where you need the actual registered token.
|
|
40
|
+
*
|
|
41
|
+
* @param token Any injectable type
|
|
42
|
+
* @returns The underlying InjectionToken
|
|
43
|
+
*/ getRegistryToken(token) {
|
|
44
|
+
return this.getRealToken(this.normalizeToken(token));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validates and resolves token arguments, handling factory token resolution and validation.
|
|
48
|
+
*
|
|
49
|
+
* @param token The token to validate
|
|
50
|
+
* @param args Optional arguments
|
|
51
|
+
* @returns [error, { actualToken, validatedArgs }]
|
|
52
|
+
*/ validateAndResolveTokenArgs(token, args) {
|
|
53
|
+
let actualToken = token;
|
|
54
|
+
if (typeof token === "function") actualToken = getInjectableToken(token);
|
|
55
|
+
let realArgs = args;
|
|
56
|
+
if (actualToken instanceof BoundInjectionToken) realArgs = actualToken.value;
|
|
57
|
+
else if (actualToken instanceof FactoryInjectionToken) if (actualToken.resolved) realArgs = actualToken.value;
|
|
58
|
+
else return [DIError.factoryTokenNotResolved(token.name), { actualToken }];
|
|
59
|
+
if (!actualToken.schema) return [void 0, {
|
|
60
|
+
actualToken,
|
|
61
|
+
validatedArgs: realArgs
|
|
62
|
+
}];
|
|
63
|
+
const validatedArgs = actualToken.schema?.safeParse(realArgs);
|
|
64
|
+
if (validatedArgs && !validatedArgs.success) {
|
|
65
|
+
this.logger?.error(`[TokenResolver]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`, validatedArgs.error);
|
|
66
|
+
return [DIError.tokenValidationError(`Validation failed for ${actualToken.name.toString()}`, actualToken.schema, realArgs), { actualToken }];
|
|
67
|
+
}
|
|
68
|
+
return [void 0, {
|
|
69
|
+
actualToken,
|
|
70
|
+
validatedArgs: validatedArgs?.data
|
|
71
|
+
}];
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
export { TokenResolver };
|
|
77
|
+
//# sourceMappingURL=token-resolver.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-resolver.mjs","names":["DIError","BoundInjectionToken","FactoryInjectionToken","getInjectableToken","TokenResolver","logger","normalizeToken","token","getRealToken","getRegistryToken","validateAndResolveTokenArgs","args","actualToken","realArgs","value","resolved","factoryTokenNotResolved","name","schema","undefined","validatedArgs","safeParse","success","error","toString","tokenValidationError","data"],"sources":["../../../../src/internal/core/token-resolver.mts"],"sourcesContent":["import type {\n AnyInjectableType,\n InjectionTokenType,\n} from '../../token/injection-token.mjs'\n\nimport { DIError } from '../../errors/index.mjs'\nimport {\n BoundInjectionToken,\n FactoryInjectionToken,\n InjectionToken,\n} from '../../token/injection-token.mjs'\nimport { getInjectableToken } from '../../utils/index.mjs'\n\n/**\n * Handles token validation and resolution.\n *\n * Focuses on token validation, normalization, and argument validation.\n * Name generation is handled by NameResolver.\n */\nexport class TokenResolver {\n constructor(private readonly logger: Console | null = null) {}\n\n // ============================================================================\n // TOKEN NORMALIZATION\n // ============================================================================\n\n /**\n * Normalizes a token to an InjectionToken.\n * Handles class constructors by getting their injectable token.\n *\n * @param token A class constructor, InjectionToken, BoundInjectionToken, or FactoryInjectionToken\n * @returns The normalized InjectionTokenType\n */\n normalizeToken(token: AnyInjectableType): InjectionTokenType {\n if (typeof token === 'function') {\n return getInjectableToken(token)\n }\n return token as InjectionTokenType\n }\n\n /**\n * Gets the underlying \"real\" token from wrapped tokens.\n * For BoundInjectionToken and FactoryInjectionToken, returns the wrapped token.\n * For other tokens, returns the token itself.\n *\n * @param token The token to unwrap\n * @returns The underlying InjectionToken\n */\n getRealToken<T = unknown>(token: InjectionTokenType): InjectionToken<T> {\n if (\n token instanceof BoundInjectionToken ||\n token instanceof FactoryInjectionToken\n ) {\n return token.token as InjectionToken<T>\n }\n return token as InjectionToken<T>\n }\n\n /**\n * Convenience method that normalizes a token and then gets the real token.\n * Useful for checking registry entries where you need the actual registered token.\n *\n * @param token Any injectable type\n * @returns The underlying InjectionToken\n */\n getRegistryToken<T = unknown>(token: AnyInjectableType): InjectionToken<T> {\n return this.getRealToken(this.normalizeToken(token))\n }\n\n // ============================================================================\n // TOKEN VALIDATION\n // ============================================================================\n\n /**\n * Validates and resolves token arguments, handling factory token resolution and validation.\n *\n * @param token The token to validate\n * @param args Optional arguments\n * @returns [error, { actualToken, validatedArgs }]\n */\n validateAndResolveTokenArgs(\n token: AnyInjectableType,\n args?: any,\n ): [\n DIError | undefined,\n { actualToken: InjectionTokenType; validatedArgs?: any },\n ] {\n let actualToken = token as InjectionToken<any, any>\n if (typeof token === 'function') {\n actualToken = getInjectableToken(token)\n }\n let realArgs = args\n if (actualToken instanceof BoundInjectionToken) {\n realArgs = actualToken.value\n } else if (actualToken instanceof FactoryInjectionToken) {\n if (actualToken.resolved) {\n realArgs = actualToken.value\n } else {\n return [DIError.factoryTokenNotResolved(token.name), { actualToken }]\n }\n }\n if (!actualToken.schema) {\n return [undefined, { actualToken, validatedArgs: realArgs }]\n }\n const validatedArgs = actualToken.schema?.safeParse(realArgs)\n if (validatedArgs && !validatedArgs.success) {\n this.logger?.error(\n `[TokenResolver]#validateAndResolveTokenArgs(): Error validating args for ${actualToken.name.toString()}`,\n validatedArgs.error,\n )\n return [\n DIError.tokenValidationError(\n `Validation failed for ${actualToken.name.toString()}`,\n actualToken.schema,\n realArgs,\n ),\n { actualToken },\n ]\n }\n return [undefined, { actualToken, validatedArgs: validatedArgs?.data }]\n }\n}\n"],"mappings":";;;;;;;;;;GAmBA,IAAaI,gBAAb,MAAaA;;CACX,YAAY,SAA0C,MAAM;OAA/BC,SAAAA;;;;;;;;IAa7BC,eAAeC,OAA8C;AAC3D,MAAI,OAAOA,UAAU,WACnB,QAAOJ,mBAAmBI,MAAAA;AAE5B,SAAOA;;;;;;;;;IAWTC,aAA0BD,OAA8C;AACtE,MACEA,iBAAiBN,uBACjBM,iBAAiBL,sBAEjB,QAAOK,MAAMA;AAEf,SAAOA;;;;;;;;IAUTE,iBAA8BF,OAA6C;AACzE,SAAO,KAAKC,aAAa,KAAKF,eAAeC,MAAAA,CAAAA;;;;;;;;IAc/CG,4BACEH,OACAI,MAIA;EACA,IAAIC,cAAcL;AAClB,MAAI,OAAOA,UAAU,WACnBK,eAAcT,mBAAmBI,MAAAA;EAEnC,IAAIM,WAAWF;AACf,MAAIC,uBAAuBX,oBACzBY,YAAWD,YAAYE;WACdF,uBAAuBV,sBAChC,KAAIU,YAAYG,SACdF,YAAWD,YAAYE;MAEvB,QAAO,CAACd,QAAQgB,wBAAwBT,MAAMU,KAAI,EAAG,EAAEL,aAAY,CAAE;AAGzE,MAAI,CAACA,YAAYM,OACf,QAAO,CAACC,QAAW;GAAEP;GAAaQ,eAAeP;GAAS,CAAE;EAE9D,MAAMO,gBAAgBR,YAAYM,QAAQG,UAAUR,SAAAA;AACpD,MAAIO,iBAAiB,CAACA,cAAcE,SAAS;AAC3C,QAAKjB,QAAQkB,MACX,4EAA4EX,YAAYK,KAAKO,UAAQ,IACrGJ,cAAcG,MAAK;AAErB,UAAO,CACLvB,QAAQyB,qBACN,yBAAyBb,YAAYK,KAAKO,UAAQ,IAClDZ,YAAYM,QACZL,SAAAA,EAEF,EAAED,aAAY,CACf;;AAEH,SAAO,CAACO,QAAW;GAAEP;GAAaQ,eAAeA,eAAeM;GAAK,CAAE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
|
|
2
|
+
import { InjectableType } from "../../enums/injectable-type.enum.mjs";
|
|
3
|
+
import { DIError } from "../../errors/di-error.mjs";
|
|
4
|
+
import { InstanceHolder } from "./instance-holder.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/internal/holder/holder-storage.interface.d.mts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Result type for holder retrieval operations.
|
|
10
|
+
* - [undefined, holder] - Holder found successfully
|
|
11
|
+
* - [DIError, holder?] - Error occurred (holder may be available for waiting)
|
|
12
|
+
* - null - No holder exists
|
|
13
|
+
*/
|
|
14
|
+
type HolderGetResult<T = unknown> = [undefined, InstanceHolder<T>] | [DIError, InstanceHolder<T>?] | null;
|
|
15
|
+
/**
|
|
16
|
+
* Interface for abstracting holder storage operations.
|
|
17
|
+
*
|
|
18
|
+
* Enables unified instance resolution logic regardless of where
|
|
19
|
+
* holders are stored. This is the key abstraction for the unified storage pattern.
|
|
20
|
+
*/
|
|
21
|
+
interface IHolderStorage {
|
|
22
|
+
/**
|
|
23
|
+
* The scope this storage handles.
|
|
24
|
+
*/
|
|
25
|
+
readonly scope: InjectableScope;
|
|
26
|
+
/**
|
|
27
|
+
* Retrieves an existing holder by instance name.
|
|
28
|
+
*
|
|
29
|
+
* @param instanceName The unique identifier for the instance
|
|
30
|
+
* @returns
|
|
31
|
+
* - [undefined, holder] if found and ready/creating
|
|
32
|
+
* - [DIError, holder?] if found but in error/destroying state
|
|
33
|
+
* - null if not found
|
|
34
|
+
*/
|
|
35
|
+
get<T = unknown>(instanceName: string): HolderGetResult<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Stores a holder by instance name.
|
|
38
|
+
*
|
|
39
|
+
* @param instanceName The unique identifier for the instance
|
|
40
|
+
* @param holder The holder to store
|
|
41
|
+
*/
|
|
42
|
+
set(instanceName: string, holder: InstanceHolder): void;
|
|
43
|
+
/**
|
|
44
|
+
* Deletes a holder by instance name.
|
|
45
|
+
*
|
|
46
|
+
* @param instanceName The unique identifier for the instance
|
|
47
|
+
* @returns true if the holder was deleted, false if it didn't exist
|
|
48
|
+
*/
|
|
49
|
+
delete(instanceName: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new holder in "Creating" state with a deferred promise.
|
|
52
|
+
* The holder is NOT automatically stored - call set() to store it.
|
|
53
|
+
*
|
|
54
|
+
* @param instanceName The unique identifier for the instance
|
|
55
|
+
* @param type The injectable type
|
|
56
|
+
* @param deps The set of dependency names
|
|
57
|
+
* @returns A tuple containing the deferred promise resolver and the holder
|
|
58
|
+
*/
|
|
59
|
+
createHolder<T>(instanceName: string, type: InjectableType, deps: Set<string>): [ReturnType<typeof Promise.withResolvers<[undefined, T]>>, InstanceHolder<T>];
|
|
60
|
+
/**
|
|
61
|
+
* Checks if this storage should be used for the given scope.
|
|
62
|
+
*/
|
|
63
|
+
handles(scope: InjectableScope): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Gets all instance names in this storage.
|
|
66
|
+
*/
|
|
67
|
+
getAllNames(): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Iterates over all holders with a callback.
|
|
70
|
+
*
|
|
71
|
+
* @param callback Function called for each holder with (name, holder)
|
|
72
|
+
*/
|
|
73
|
+
forEach(callback: (name: string, holder: InstanceHolder) => void): void;
|
|
74
|
+
/**
|
|
75
|
+
* Finds a holder by its instance value (reverse lookup).
|
|
76
|
+
*
|
|
77
|
+
* @param instance The instance to search for
|
|
78
|
+
* @returns The holder if found, null otherwise
|
|
79
|
+
*/
|
|
80
|
+
findByInstance(instance: unknown): InstanceHolder | null;
|
|
81
|
+
/**
|
|
82
|
+
* Finds all instance names that depend on the given instance name.
|
|
83
|
+
*
|
|
84
|
+
* @param instanceName The instance name to find dependents for
|
|
85
|
+
* @returns Array of instance names that have this instance as a dependency
|
|
86
|
+
*/
|
|
87
|
+
findDependents(instanceName: string): string[];
|
|
88
|
+
/**
|
|
89
|
+
* Updates dependency references when instance names change.
|
|
90
|
+
* Used during scope upgrades when instance names are regenerated with requestId.
|
|
91
|
+
*
|
|
92
|
+
* @param oldName The old instance name
|
|
93
|
+
* @param newName The new instance name
|
|
94
|
+
*/
|
|
95
|
+
updateDependencyReference(oldName: string, newName: string): void;
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
export { HolderGetResult, IHolderStorage };
|
|
99
|
+
//# sourceMappingURL=holder-storage.interface.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holder-storage.interface.d.mts","names":[],"sources":["../../../../src/internal/holder/holder-storage.interface.mts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAUA;;;AAEK,KAFO,eAEP,CAAA,IAAA,OAAA,CAAA,GAAA,CAAA,SAAA,EADW,cACX,CAD0B,CAC1B,CAAA,CAAA,GAAA,CAAA,OAAA,EAAS,cAAT,CAAwB,CAAxB,CAAA,CAAA,CAAA,GAAA,IAAA;;;;AASL;;;AAmB0C,UAnBzB,cAAA,CAmByB;EAQN;;;EAwBoB,SAAA,KAAA,EA/CtC,eA+CsC;EAAlC;;;;;;;;;0CAhCoB,gBAAgB;;;;;;;oCAQtB;;;;;;;;;;;;;;;;;8CAqB1B,sBACA,eAEN,kBAAkB,OAAA,CAAQ,0BAA0B,MACpD,eAAe;;;;iBAMF;;;;;;;;;;2CAgB0B;;;;;;;qCAQN"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
|
|
2
|
+
import { InjectableType } from "../../enums/injectable-type.enum.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/internal/holder/instance-holder.d.mts
|
|
5
|
+
/**
|
|
6
|
+
* Represents the lifecycle status of an instance holder.
|
|
7
|
+
*/
|
|
8
|
+
declare enum InstanceStatus {
|
|
9
|
+
/** Instance has been successfully created and is ready for use */
|
|
10
|
+
Created = "created",
|
|
11
|
+
/** Instance is currently being created (async initialization in progress) */
|
|
12
|
+
Creating = "creating",
|
|
13
|
+
/** Instance is being destroyed (cleanup in progress) */
|
|
14
|
+
Destroying = "destroying",
|
|
15
|
+
/** Instance creation failed with an error */
|
|
16
|
+
Error = "error",
|
|
17
|
+
}
|
|
18
|
+
/** Callback function for instance destruction listeners */
|
|
19
|
+
type InstanceDestroyListener = () => void | Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Instance holder in the Creating state.
|
|
22
|
+
* The instance is null while creation is in progress.
|
|
23
|
+
*/
|
|
24
|
+
interface InstanceHolderCreating<Instance> {
|
|
25
|
+
status: InstanceStatus.Creating;
|
|
26
|
+
name: string;
|
|
27
|
+
instance: null;
|
|
28
|
+
creationPromise: Promise<[undefined, Instance]> | null;
|
|
29
|
+
destroyPromise: null;
|
|
30
|
+
type: InjectableType;
|
|
31
|
+
scope: InjectableScope;
|
|
32
|
+
deps: Set<string>;
|
|
33
|
+
destroyListeners: InstanceDestroyListener[];
|
|
34
|
+
createdAt: number;
|
|
35
|
+
/** Tracks which services this holder is currently waiting for (for circular dependency detection) */
|
|
36
|
+
waitingFor: Set<string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Instance holder in the Created state.
|
|
40
|
+
* The instance is available and ready for use.
|
|
41
|
+
*/
|
|
42
|
+
interface InstanceHolderCreated<Instance> {
|
|
43
|
+
status: InstanceStatus.Created;
|
|
44
|
+
name: string;
|
|
45
|
+
instance: Instance;
|
|
46
|
+
creationPromise: null;
|
|
47
|
+
destroyPromise: null;
|
|
48
|
+
type: InjectableType;
|
|
49
|
+
scope: InjectableScope;
|
|
50
|
+
deps: Set<string>;
|
|
51
|
+
destroyListeners: InstanceDestroyListener[];
|
|
52
|
+
createdAt: number;
|
|
53
|
+
/** Tracks which services this holder is currently waiting for (for circular dependency detection) */
|
|
54
|
+
waitingFor: Set<string>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Instance holder in the Destroying state.
|
|
58
|
+
* The instance may still be available but is being cleaned up.
|
|
59
|
+
*/
|
|
60
|
+
interface InstanceHolderDestroying<Instance> {
|
|
61
|
+
status: InstanceStatus.Destroying;
|
|
62
|
+
name: string;
|
|
63
|
+
instance: Instance | null;
|
|
64
|
+
creationPromise: null;
|
|
65
|
+
destroyPromise: Promise<void>;
|
|
66
|
+
type: InjectableType;
|
|
67
|
+
scope: InjectableScope;
|
|
68
|
+
deps: Set<string>;
|
|
69
|
+
destroyListeners: InstanceDestroyListener[];
|
|
70
|
+
createdAt: number;
|
|
71
|
+
/** Tracks which services this holder is currently waiting for (for circular dependency detection) */
|
|
72
|
+
waitingFor: Set<string>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Instance holder in the Error state.
|
|
76
|
+
* The instance field contains the error that occurred during creation.
|
|
77
|
+
*/
|
|
78
|
+
interface InstanceHolderError {
|
|
79
|
+
status: InstanceStatus.Error;
|
|
80
|
+
name: string;
|
|
81
|
+
instance: Error;
|
|
82
|
+
creationPromise: null;
|
|
83
|
+
destroyPromise: null;
|
|
84
|
+
type: InjectableType;
|
|
85
|
+
scope: InjectableScope;
|
|
86
|
+
deps: Set<string>;
|
|
87
|
+
destroyListeners: InstanceDestroyListener[];
|
|
88
|
+
createdAt: number;
|
|
89
|
+
/** Tracks which services this holder is currently waiting for (for circular dependency detection) */
|
|
90
|
+
waitingFor: Set<string>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Holds the state of a service instance throughout its lifecycle.
|
|
94
|
+
*
|
|
95
|
+
* Tracks creation/destruction promises, dependency relationships,
|
|
96
|
+
* destroy listeners, and current status (Creating, Created, Destroying, Error).
|
|
97
|
+
*/
|
|
98
|
+
type InstanceHolder<Instance = unknown> = InstanceHolderCreating<Instance> | InstanceHolderCreated<Instance> | InstanceHolderDestroying<Instance> | InstanceHolderError;
|
|
99
|
+
//#endregion
|
|
100
|
+
export { InstanceDestroyListener, InstanceHolder, InstanceHolderCreated, InstanceHolderCreating, InstanceHolderDestroying, InstanceHolderError, InstanceStatus };
|
|
101
|
+
//# sourceMappingURL=instance-holder.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-holder.d.mts","names":[],"sources":["../../../../src/internal/holder/instance-holder.mts"],"sourcesContent":[],"mappings":";;;;;;;AAKY,aAAA,cAAA;EAYA;EAMK,OAAA,GAAA,SAAA;EACP;EAG6B,QAAA,GAAA,UAAA;EAApB;EAEX,UAAA,GAAA,YAAA;EACC;EACD,KAAA,GAAA,OAAA;;;AAIS,KAlBL,uBAAA,GAkBK,GAAA,GAAA,IAAA,GAlBkC,OAkBlC,CAAA,IAAA,CAAA;AAOjB;;;;AAOS,UA1BQ,sBA0BR,CAAA,QAAA,CAAA,CAAA;EACD,MAAA,EA1BE,cAAA,CAAe,QA0BjB;EACY,IAAA,EAAA,MAAA;EAGN,QAAA,EAAA,IAAA;EAAG,eAAA,EA3BE,OA2BF,CAAA,CAAA,SAAA,EA3BsB,QA2BtB,CAAA,CAAA,GAAA,IAAA;EAOA,cAAA,EAAA,IAAA;EACP,IAAA,EAjCF,cAiCiB;EAEb,KAAA,EAlCH,eAkCG;EAEM,IAAA,EAnCV,GAmCU,CAAA,MAAA,CAAA;EACV,gBAAA,EAnCY,uBAmCZ,EAAA;EACC,SAAA,EAAA,MAAA;EACD;EACY,UAAA,EAnCN,GAmCM,CAAA,MAAA,CAAA;;;AAUpB;;;AAMQ,UA5CS,qBA4CT,CAAA,QAAA,CAAA,CAAA;EACC,MAAA,EA5CC,cAAA,CAAe,OA4ChB;EACD,IAAA,EAAA,MAAA;EACY,QAAA,EA5CR,QA4CQ;EAGN,eAAA,EAAA,IAAA;EAAG,cAAA,EAAA,IAAA;EASL,IAAA,EArDJ,cAqDkB;EACC,KAAA,EArDlB,eAqDkB;EAAvB,IAAA,EApDI,GAoDJ,CAAA,MAAA,CAAA;EACsB,gBAAA,EApDN,uBAoDM,EAAA;EAAtB,SAAA,EAAA,MAAA;EACyB;EAAzB,UAAA,EAlDU,GAkDV,CAAA,MAAA,CAAA;;;;;;UA3Ca;UACP,cAAA,CAAe;;YAEb;;kBAEM;QACV;SACC;QACD;oBACY;;;cAGN;;;;;;UAOG,mBAAA;UACP,cAAA,CAAe;;YAEb;;;QAGJ;SACC;QACD;oBACY;;;cAGN;;;;;;;;KASF,qCACR,uBAAuB,YACvB,sBAAsB,YACtB,yBAAyB,YACzB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/internal/holder/instance-holder.mts
|
|
2
|
+
/**
|
|
3
|
+
* Represents the lifecycle status of an instance holder.
|
|
4
|
+
*/
|
|
5
|
+
let InstanceStatus = /* @__PURE__ */ function(InstanceStatus$1) {
|
|
6
|
+
/** Instance has been successfully created and is ready for use */
|
|
7
|
+
InstanceStatus$1["Created"] = "created";
|
|
8
|
+
/** Instance is currently being created (async initialization in progress) */
|
|
9
|
+
InstanceStatus$1["Creating"] = "creating";
|
|
10
|
+
/** Instance is being destroyed (cleanup in progress) */
|
|
11
|
+
InstanceStatus$1["Destroying"] = "destroying";
|
|
12
|
+
/** Instance creation failed with an error */
|
|
13
|
+
InstanceStatus$1["Error"] = "error";
|
|
14
|
+
return InstanceStatus$1;
|
|
15
|
+
}({});
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { InstanceStatus };
|
|
19
|
+
//# sourceMappingURL=instance-holder.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-holder.mjs","names":[],"sources":["../../../../src/internal/holder/instance-holder.mts"],"sourcesContent":["import type { InjectableScope, InjectableType } from '../../enums/index.mjs'\n\n/**\n * Represents the lifecycle status of an instance holder.\n */\nexport enum InstanceStatus {\n /** Instance has been successfully created and is ready for use */\n Created = 'created',\n /** Instance is currently being created (async initialization in progress) */\n Creating = 'creating',\n /** Instance is being destroyed (cleanup in progress) */\n Destroying = 'destroying',\n /** Instance creation failed with an error */\n Error = 'error',\n}\n\n/** Callback function for instance destruction listeners */\nexport type InstanceDestroyListener = () => void | Promise<void>\n\n/**\n * Instance holder in the Creating state.\n * The instance is null while creation is in progress.\n */\nexport interface InstanceHolderCreating<Instance> {\n status: InstanceStatus.Creating\n name: string\n instance: null\n creationPromise: Promise<[undefined, Instance]> | null\n destroyPromise: null\n type: InjectableType\n scope: InjectableScope\n deps: Set<string>\n destroyListeners: InstanceDestroyListener[]\n createdAt: number\n /** Tracks which services this holder is currently waiting for (for circular dependency detection) */\n waitingFor: Set<string>\n}\n\n/**\n * Instance holder in the Created state.\n * The instance is available and ready for use.\n */\nexport interface InstanceHolderCreated<Instance> {\n status: InstanceStatus.Created\n name: string\n instance: Instance\n creationPromise: null\n destroyPromise: null\n type: InjectableType\n scope: InjectableScope\n deps: Set<string>\n destroyListeners: InstanceDestroyListener[]\n createdAt: number\n /** Tracks which services this holder is currently waiting for (for circular dependency detection) */\n waitingFor: Set<string>\n}\n\n/**\n * Instance holder in the Destroying state.\n * The instance may still be available but is being cleaned up.\n */\nexport interface InstanceHolderDestroying<Instance> {\n status: InstanceStatus.Destroying\n name: string\n instance: Instance | null\n creationPromise: null\n destroyPromise: Promise<void>\n type: InjectableType\n scope: InjectableScope\n deps: Set<string>\n destroyListeners: InstanceDestroyListener[]\n createdAt: number\n /** Tracks which services this holder is currently waiting for (for circular dependency detection) */\n waitingFor: Set<string>\n}\n\n/**\n * Instance holder in the Error state.\n * The instance field contains the error that occurred during creation.\n */\nexport interface InstanceHolderError {\n status: InstanceStatus.Error\n name: string\n instance: Error\n creationPromise: null\n destroyPromise: null\n type: InjectableType\n scope: InjectableScope\n deps: Set<string>\n destroyListeners: InstanceDestroyListener[]\n createdAt: number\n /** Tracks which services this holder is currently waiting for (for circular dependency detection) */\n waitingFor: Set<string>\n}\n\n/**\n * Holds the state of a service instance throughout its lifecycle.\n *\n * Tracks creation/destruction promises, dependency relationships,\n * destroy listeners, and current status (Creating, Created, Destroying, Error).\n */\nexport type InstanceHolder<Instance = unknown> =\n | InstanceHolderCreating<Instance>\n | InstanceHolderCreated<Instance>\n | InstanceHolderDestroying<Instance>\n | InstanceHolderError\n\n"],"mappings":";;;;AAKA,IAAY,4DAAL;;AAEL;;AAEA;;AAEA;;AAEA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
|
|
2
|
+
import { InjectableType } from "../../enums/injectable-type.enum.mjs";
|
|
3
|
+
import { InstanceHolder } from "./instance-holder.mjs";
|
|
4
|
+
import { HolderGetResult, IHolderStorage } from "./holder-storage.interface.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/internal/holder/unified-storage.d.mts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Unified storage implementation that works the same way regardless of scope.
|
|
10
|
+
* Replaces RequestContext, HolderManager, SingletonStorage, RequestStorage.
|
|
11
|
+
*
|
|
12
|
+
* Scope is just metadata - storage operations are identical for all scopes.
|
|
13
|
+
* Different storage instances are just isolated storage spaces.
|
|
14
|
+
*/
|
|
15
|
+
declare class UnifiedStorage implements IHolderStorage {
|
|
16
|
+
readonly scope: InjectableScope;
|
|
17
|
+
private readonly holders;
|
|
18
|
+
/**
|
|
19
|
+
* Reverse dependency index: maps a dependency name to the set of holder names that depend on it.
|
|
20
|
+
* This allows O(1) lookup of dependents instead of O(n) iteration.
|
|
21
|
+
*/
|
|
22
|
+
private readonly dependents;
|
|
23
|
+
constructor(scope?: InjectableScope);
|
|
24
|
+
get<T = unknown>(instanceName: string): HolderGetResult<T>;
|
|
25
|
+
set(instanceName: string, holder: InstanceHolder): void;
|
|
26
|
+
delete(instanceName: string): boolean;
|
|
27
|
+
createHolder<T>(instanceName: string, type: InjectableType, deps: Set<string>): [ReturnType<typeof Promise.withResolvers<[undefined, T]>>, InstanceHolder<T>];
|
|
28
|
+
storeInstance(instanceName: string, instance: unknown): void;
|
|
29
|
+
handles(scope: InjectableScope): boolean;
|
|
30
|
+
getAllNames(): string[];
|
|
31
|
+
forEach(callback: (name: string, holder: InstanceHolder) => void): void;
|
|
32
|
+
findByInstance(instance: unknown): InstanceHolder | null;
|
|
33
|
+
findDependents(instanceName: string): string[];
|
|
34
|
+
/**
|
|
35
|
+
* Updates dependency references when instance names change.
|
|
36
|
+
* Used during scope upgrades when instance names are regenerated with requestId.
|
|
37
|
+
*
|
|
38
|
+
* @param oldName The old instance name
|
|
39
|
+
* @param newName The new instance name
|
|
40
|
+
*/
|
|
41
|
+
updateDependencyReference(oldName: string, newName: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Registers a holder's dependencies in the reverse index.
|
|
44
|
+
*/
|
|
45
|
+
private registerDependencies;
|
|
46
|
+
/**
|
|
47
|
+
* Removes a holder from the reverse dependency index.
|
|
48
|
+
*/
|
|
49
|
+
private removeFromDependentsIndex;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { UnifiedStorage };
|
|
53
|
+
//# sourceMappingURL=unified-storage.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-storage.d.mts","names":[],"sources":["../../../../src/internal/holder/unified-storage.mts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkBA;;;;AAc0C,cAd7B,cAAA,YAA0B,cAcG,CAAA;EA8BN,SAAA,KAAA,EA3ClB,eA2CkB;EAmB1B,iBAAA,OAAA;EACA;;;;EAGS,iBAAA,UAAA;EAAf,WAAA,CAAA,KAAA,CAAA,EAzDiB,eAyDjB;EAkDa,GAAA,CAAA,IAAA,OAAA,CAAA,CAAA,YAAA,EAAA,MAAA,CAAA,EAvGyB,eAuGzB,CAvGyC,CAuGzC,CAAA;EAY0B,GAAA,CAAA,YAAA,EAAA,MAAA,EAAA,MAAA,EArFP,cAqFO,CAAA,EAAA,IAAA;EAMN,MAAA,CAAA,YAAA,EAAA,MAAA,CAAA,EAAA,OAAA;EAvIE,YAAA,CAAA,CAAA,CAAA,CAAA,YAAA,EAAA,MAAA,EAAA,IAAA,EA+D7B,cA/D6B,EAAA,IAAA,EAgE7B,GAhE6B,CAAA,MAAA,CAAA,CAAA,EAAA,CAkEnC,UAlEiD,CAAA,OAkE/B,OAAA,CAAQ,aAlEuB,CAAA,CAAA,SAAA,EAkEG,CAlEH,CAAA,CAAA,CAAA,EAmEjD,eAAe;;iBAkDF;;2CAY0B;qCAMN"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { InjectableScope } from "../../enums/injectable-scope.enum.mjs";
|
|
2
|
+
import { InjectableType } from "../../enums/injectable-type.enum.mjs";
|
|
3
|
+
import { DIError } from "../../errors/di-error.mjs";
|
|
4
|
+
import { InstanceStatus } from "./instance-holder.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/internal/holder/unified-storage.mts
|
|
7
|
+
/**
|
|
8
|
+
* Unified storage implementation that works the same way regardless of scope.
|
|
9
|
+
* Replaces RequestContext, HolderManager, SingletonStorage, RequestStorage.
|
|
10
|
+
*
|
|
11
|
+
* Scope is just metadata - storage operations are identical for all scopes.
|
|
12
|
+
* Different storage instances are just isolated storage spaces.
|
|
13
|
+
*/ var UnifiedStorage = class {
|
|
14
|
+
scope;
|
|
15
|
+
holders = /* @__PURE__ */ new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Reverse dependency index: maps a dependency name to the set of holder names that depend on it.
|
|
18
|
+
* This allows O(1) lookup of dependents instead of O(n) iteration.
|
|
19
|
+
*/ dependents = /* @__PURE__ */ new Map();
|
|
20
|
+
constructor(scope = InjectableScope.Singleton) {
|
|
21
|
+
this.scope = scope;
|
|
22
|
+
}
|
|
23
|
+
get(instanceName) {
|
|
24
|
+
const holder = this.holders.get(instanceName);
|
|
25
|
+
if (!holder) return null;
|
|
26
|
+
switch (holder.status) {
|
|
27
|
+
case InstanceStatus.Destroying: return [DIError.instanceDestroying(instanceName), holder];
|
|
28
|
+
case InstanceStatus.Error: return [holder.instance, holder];
|
|
29
|
+
case InstanceStatus.Creating:
|
|
30
|
+
case InstanceStatus.Created: return [void 0, holder];
|
|
31
|
+
default: return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
set(instanceName, holder) {
|
|
35
|
+
this.holders.set(instanceName, holder);
|
|
36
|
+
if (holder.deps.size > 0) this.registerDependencies(instanceName, holder.deps);
|
|
37
|
+
}
|
|
38
|
+
delete(instanceName) {
|
|
39
|
+
const holder = this.holders.get(instanceName);
|
|
40
|
+
if (holder) this.removeFromDependentsIndex(instanceName, holder.deps);
|
|
41
|
+
return this.holders.delete(instanceName);
|
|
42
|
+
}
|
|
43
|
+
createHolder(instanceName, type, deps) {
|
|
44
|
+
const deferred = Promise.withResolvers();
|
|
45
|
+
return [deferred, {
|
|
46
|
+
status: InstanceStatus.Creating,
|
|
47
|
+
name: instanceName,
|
|
48
|
+
instance: null,
|
|
49
|
+
creationPromise: deferred.promise,
|
|
50
|
+
destroyPromise: null,
|
|
51
|
+
type,
|
|
52
|
+
scope: this.scope,
|
|
53
|
+
deps,
|
|
54
|
+
destroyListeners: [],
|
|
55
|
+
createdAt: Date.now(),
|
|
56
|
+
waitingFor: /* @__PURE__ */ new Set()
|
|
57
|
+
}];
|
|
58
|
+
}
|
|
59
|
+
storeInstance(instanceName, instance) {
|
|
60
|
+
if (this.holders.get(instanceName)) throw DIError.storageError("Instance already stored", "storeInstance", instanceName);
|
|
61
|
+
this.set(instanceName, {
|
|
62
|
+
status: InstanceStatus.Created,
|
|
63
|
+
name: instanceName,
|
|
64
|
+
instance,
|
|
65
|
+
creationPromise: null,
|
|
66
|
+
destroyPromise: null,
|
|
67
|
+
type: InjectableType.Class,
|
|
68
|
+
scope: this.scope,
|
|
69
|
+
deps: /* @__PURE__ */ new Set(),
|
|
70
|
+
destroyListeners: typeof instance === "object" && instance !== null && "onServiceDestroy" in instance ? [instance.onServiceDestroy] : [],
|
|
71
|
+
createdAt: Date.now(),
|
|
72
|
+
waitingFor: /* @__PURE__ */ new Set()
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
handles(scope) {
|
|
76
|
+
return scope === this.scope;
|
|
77
|
+
}
|
|
78
|
+
getAllNames() {
|
|
79
|
+
return Array.from(this.holders.keys());
|
|
80
|
+
}
|
|
81
|
+
forEach(callback) {
|
|
82
|
+
for (const [name, holder] of this.holders) callback(name, holder);
|
|
83
|
+
}
|
|
84
|
+
findByInstance(instance) {
|
|
85
|
+
for (const holder of this.holders.values()) if (holder.instance === instance) return holder;
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
findDependents(instanceName) {
|
|
89
|
+
const dependents = this.dependents.get(instanceName);
|
|
90
|
+
return dependents ? Array.from(dependents) : [];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Updates dependency references when instance names change.
|
|
94
|
+
* Used during scope upgrades when instance names are regenerated with requestId.
|
|
95
|
+
*
|
|
96
|
+
* @param oldName The old instance name
|
|
97
|
+
* @param newName The new instance name
|
|
98
|
+
*/ updateDependencyReference(oldName, newName) {
|
|
99
|
+
for (const holder of this.holders.values()) if (holder.deps.has(oldName)) {
|
|
100
|
+
holder.deps.delete(oldName);
|
|
101
|
+
holder.deps.add(newName);
|
|
102
|
+
}
|
|
103
|
+
const oldDependents = this.dependents.get(oldName);
|
|
104
|
+
if (oldDependents) {
|
|
105
|
+
const newDependents = this.dependents.get(newName) || /* @__PURE__ */ new Set();
|
|
106
|
+
for (const dependent of oldDependents) newDependents.add(dependent);
|
|
107
|
+
this.dependents.set(newName, newDependents);
|
|
108
|
+
this.dependents.delete(oldName);
|
|
109
|
+
}
|
|
110
|
+
for (const [depName, dependents] of this.dependents.entries()) if (depName === oldName) {
|
|
111
|
+
const newDependents = this.dependents.get(newName) || /* @__PURE__ */ new Set();
|
|
112
|
+
for (const dependent of dependents) newDependents.add(dependent);
|
|
113
|
+
this.dependents.set(newName, newDependents);
|
|
114
|
+
this.dependents.delete(oldName);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Registers a holder's dependencies in the reverse index.
|
|
119
|
+
*/ registerDependencies(holderName, deps) {
|
|
120
|
+
for (const dep of deps) {
|
|
121
|
+
let dependents = this.dependents.get(dep);
|
|
122
|
+
if (!dependents) {
|
|
123
|
+
dependents = /* @__PURE__ */ new Set();
|
|
124
|
+
this.dependents.set(dep, dependents);
|
|
125
|
+
}
|
|
126
|
+
dependents.add(holderName);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Removes a holder from the reverse dependency index.
|
|
131
|
+
*/ removeFromDependentsIndex(holderName, deps) {
|
|
132
|
+
for (const dep of deps) {
|
|
133
|
+
const dependents = this.dependents.get(dep);
|
|
134
|
+
if (dependents) {
|
|
135
|
+
dependents.delete(holderName);
|
|
136
|
+
if (dependents.size === 0) this.dependents.delete(dep);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
export { UnifiedStorage };
|
|
144
|
+
//# sourceMappingURL=unified-storage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-storage.mjs","names":["InjectableScope","InjectableType","DIError","InstanceStatus","UnifiedStorage","scope","holders","Map","dependents","Singleton","get","instanceName","holder","status","Destroying","instanceDestroying","Error","instance","Creating","Created","undefined","set","deps","size","registerDependencies","delete","removeFromDependentsIndex","createHolder","type","deferred","Promise","withResolvers","name","creationPromise","promise","destroyPromise","destroyListeners","createdAt","Date","now","waitingFor","Set","storeInstance","storageError","Class","onServiceDestroy","handles","getAllNames","Array","from","keys","forEach","callback","findByInstance","values","findDependents","updateDependencyReference","oldName","newName","has","add","oldDependents","newDependents","dependent","depName","entries","holderName","dep"],"sources":["../../../../src/internal/holder/unified-storage.mts"],"sourcesContent":["import type { OnServiceDestroy } from '../../interfaces/index.mjs'\nimport type {\n HolderGetResult,\n IHolderStorage,\n} from './holder-storage.interface.mjs'\nimport type { InstanceHolder } from './instance-holder.mjs'\n\nimport { InjectableScope, InjectableType } from '../../enums/index.mjs'\nimport { DIError } from '../../errors/index.mjs'\nimport { InstanceStatus } from './instance-holder.mjs'\n\n/**\n * Unified storage implementation that works the same way regardless of scope.\n * Replaces RequestContext, HolderManager, SingletonStorage, RequestStorage.\n *\n * Scope is just metadata - storage operations are identical for all scopes.\n * Different storage instances are just isolated storage spaces.\n */\nexport class UnifiedStorage implements IHolderStorage {\n readonly scope: InjectableScope\n\n private readonly holders = new Map<string, InstanceHolder>()\n /**\n * Reverse dependency index: maps a dependency name to the set of holder names that depend on it.\n * This allows O(1) lookup of dependents instead of O(n) iteration.\n */\n private readonly dependents = new Map<string, Set<string>>()\n\n constructor(scope: InjectableScope = InjectableScope.Singleton) {\n this.scope = scope\n }\n\n get<T = unknown>(instanceName: string): HolderGetResult<T> {\n const holder = this.holders.get(instanceName)\n\n if (!holder) {\n return null\n }\n\n // Check holder status for error states\n switch (holder.status) {\n case InstanceStatus.Destroying:\n return [\n DIError.instanceDestroying(instanceName),\n holder as InstanceHolder<T>,\n ]\n\n case InstanceStatus.Error:\n return [\n holder.instance as unknown as DIError,\n holder as InstanceHolder<T>,\n ]\n\n case InstanceStatus.Creating:\n case InstanceStatus.Created:\n return [undefined, holder as InstanceHolder<T>]\n\n default:\n return null\n }\n }\n\n set(instanceName: string, holder: InstanceHolder): void {\n this.holders.set(instanceName, holder)\n // Register dependencies in reverse index\n if (holder.deps.size > 0) {\n this.registerDependencies(instanceName, holder.deps)\n }\n }\n\n delete(instanceName: string): boolean {\n const holder = this.holders.get(instanceName)\n if (holder) {\n // Remove this holder from the reverse index for all its dependencies\n this.removeFromDependentsIndex(instanceName, holder.deps)\n }\n return this.holders.delete(instanceName)\n }\n\n createHolder<T>(\n instanceName: string,\n type: InjectableType,\n deps: Set<string>,\n ): [\n ReturnType<typeof Promise.withResolvers<[undefined, T]>>,\n InstanceHolder<T>,\n ] {\n const deferred = Promise.withResolvers<[undefined, T]>()\n\n const holder: InstanceHolder<T> = {\n status: InstanceStatus.Creating,\n name: instanceName,\n instance: null,\n creationPromise: deferred.promise,\n destroyPromise: null,\n type,\n scope: this.scope,\n deps,\n destroyListeners: [],\n createdAt: Date.now(),\n waitingFor: new Set(),\n }\n\n return [deferred, holder]\n }\n\n storeInstance(instanceName: string, instance: unknown): void {\n const holder = this.holders.get(instanceName)\n if (holder) {\n throw DIError.storageError(\n 'Instance already stored',\n 'storeInstance',\n instanceName,\n )\n }\n this.set(instanceName, {\n status: InstanceStatus.Created,\n name: instanceName,\n instance,\n creationPromise: null,\n destroyPromise: null,\n type: InjectableType.Class,\n scope: this.scope,\n deps: new Set(),\n destroyListeners:\n typeof instance === 'object' &&\n instance !== null &&\n 'onServiceDestroy' in instance\n ? [(instance as OnServiceDestroy).onServiceDestroy]\n : [],\n createdAt: Date.now(),\n waitingFor: new Set(),\n })\n }\n\n handles(scope: InjectableScope): boolean {\n return scope === this.scope\n }\n\n // ============================================================================\n // ITERATION AND QUERY\n // ============================================================================\n\n getAllNames(): string[] {\n return Array.from(this.holders.keys())\n }\n\n forEach(callback: (name: string, holder: InstanceHolder) => void): void {\n for (const [name, holder] of this.holders) {\n callback(name, holder)\n }\n }\n\n findByInstance(instance: unknown): InstanceHolder | null {\n for (const holder of this.holders.values()) {\n if (holder.instance === instance) {\n return holder\n }\n }\n return null\n }\n\n findDependents(instanceName: string): string[] {\n const dependents = this.dependents.get(instanceName)\n return dependents ? Array.from(dependents) : []\n }\n\n /**\n * Updates dependency references when instance names change.\n * Used during scope upgrades when instance names are regenerated with requestId.\n *\n * @param oldName The old instance name\n * @param newName The new instance name\n */\n updateDependencyReference(oldName: string, newName: string): void {\n // Update all holders that reference oldName in their deps Set\n for (const holder of this.holders.values()) {\n if (holder.deps.has(oldName)) {\n holder.deps.delete(oldName)\n holder.deps.add(newName)\n }\n }\n\n // Update reverse dependency index\n const oldDependents = this.dependents.get(oldName)\n if (oldDependents) {\n // Move dependents from old name to new name\n const newDependents = this.dependents.get(newName) || new Set<string>()\n for (const dependent of oldDependents) {\n newDependents.add(dependent)\n }\n this.dependents.set(newName, newDependents)\n this.dependents.delete(oldName)\n }\n\n // Update reverse index entries - if oldName was a dependency, update all holders that depend on it\n for (const [depName, dependents] of this.dependents.entries()) {\n if (depName === oldName) {\n // This shouldn't happen, but handle it just in case\n const newDependents = this.dependents.get(newName) || new Set<string>()\n for (const dependent of dependents) {\n newDependents.add(dependent)\n }\n this.dependents.set(newName, newDependents)\n this.dependents.delete(oldName)\n }\n }\n }\n\n // ============================================================================\n // INTERNAL HELPERS\n // ============================================================================\n\n /**\n * Registers a holder's dependencies in the reverse index.\n */\n private registerDependencies(holderName: string, deps: Set<string>): void {\n for (const dep of deps) {\n let dependents = this.dependents.get(dep)\n if (!dependents) {\n dependents = new Set()\n this.dependents.set(dep, dependents)\n }\n dependents.add(holderName)\n }\n }\n\n /**\n * Removes a holder from the reverse dependency index.\n */\n private removeFromDependentsIndex(\n holderName: string,\n deps: Set<string>,\n ): void {\n for (const dep of deps) {\n const dependents = this.dependents.get(dep)\n if (dependents) {\n dependents.delete(holderName)\n if (dependents.size === 0) {\n this.dependents.delete(dep)\n }\n }\n }\n }\n}\n"],"mappings":"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"}
|