@vielzeug/conduit 2.1.0 → 2.1.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/README.md CHANGED
@@ -59,7 +59,7 @@ container.validate();
59
59
 
60
60
  ## Errors
61
61
 
62
- All errors extend `ConduitError`. Use `ConduitError.is(error)` for package-boundary guards.
62
+ All errors extend `ConduitError`. Use `instanceof ConduitError` for package-boundary guards.
63
63
 
64
64
  - `ConduitError`
65
65
  - `ConduitProviderNotFoundError`
@@ -1 +1 @@
1
- {"version":3,"file":"conduit.cjs","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: never) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<any>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<any>, Registration<any>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value as never);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value as never);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conduit.cjs","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: unknown) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<unknown>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<unknown>, Registration<unknown>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose as Disposer, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"conduit.iife.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: never) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<any>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<any>, Registration<any>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value as never);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value as never);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conduit.iife.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: unknown) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<unknown>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<unknown>, Registration<unknown>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose as Disposer, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"conduit.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: never) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<any>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<any>, Registration<any>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value as never);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value as never);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conduit.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/errors.ts","../src/container.ts","../src/types.ts"],"sourcesContent":["import type { ScopeToken, Token } from './types.js';\n\nexport function tokenName(token: Token<unknown>): string {\n return token.description ?? 'anonymous';\n}\n\nexport class ConduitError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n readonly cycle: Token<unknown>[];\n\n constructor(cycle: Token<unknown>[]) {\n super(`Circular dependency detected: ${cycle.map(tokenName).join(' -> ')}`);\n this.cycle = cycle;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n readonly containerName: string;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, containerName: string) {\n super(`No provider registered for token: ${tokenName(token)} (in container '${containerName}')`);\n this.containerName = containerName;\n this.token = token;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>) {\n super(`Token \"${tokenName(token)}\" is already registered.`);\n this.token = token;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n readonly requiredScope: ScopeToken;\n readonly token: Token<unknown>;\n\n constructor(token: Token<unknown>, requiredScope: ScopeToken) {\n super(`Token \"${tokenName(token)}\" requires scope \"${requiredScope.description ?? 'anonymous'}\".`);\n this.requiredScope = requiredScope;\n this.token = token;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Cannot use disposed container '${containerName}'.`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDisposeError extends ConduitError {\n readonly errors: unknown[];\n\n constructor(errors: unknown[]) {\n super(`Container disposal failed with ${errors.length} cleanup error${errors.length === 1 ? '' : 's'}.`);\n this.errors = errors;\n }\n}\n","import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: unknown) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<unknown>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<unknown>, Registration<unknown>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose as Disposer, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n","declare const tokenBrand: unique symbol;\ndeclare const scopeBrand: unique symbol;\n\nexport type Token<T = unknown> = symbol & { readonly [tokenBrand]: T };\nexport type ScopeToken = symbol & { readonly [scopeBrand]: true };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n}>;\n\nexport type FactoryOptions<T> = Readonly<{\n dispose?: (value: T) => Promise<void> | void;\n lifetime?: Lifetime;\n}>;\n\nexport type InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\nexport interface Container {\n createScope(scope?: ScopeToken, options?: { name?: string }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n ): this;\n\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n validate(): this;\n\n value<T>(token: Token<T>, value: T, options?: ValueOptions<T>): this;\n [Symbol.asyncDispose](): Promise<void>;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"container.cjs","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/container.ts"],"sourcesContent":["import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: never) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<any>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<any>, Registration<any>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value as never);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value as never);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"container.cjs","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/container.ts"],"sourcesContent":["import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: unknown) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<unknown>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<unknown>, Registration<unknown>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose as Disposer, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/container.ts"],"sourcesContent":["import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: never) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<any>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<any>, Registration<any>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value as never);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value as never);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"container.js","names":["#parent","#scope","#children","#disposalController","#lifecycle","#assertActive","#assertUnregistered","#registry","#owned","#lookup","#resolve","#factories","#validatePath","#disposePromise","#finishDisposal","#inFlight","#cleanupFailures","#cache","#ownerFor","#create","#scopeOwner"],"sources":["../src/container.ts"],"sourcesContent":["import {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nimport type { Container, FactoryOptions, InferTokens, Lifetime, ScopeToken, Token, ValueOptions } from './types.js';\n\ntype Disposer = (value: unknown) => Promise<void> | void;\n\ntype ValueRegistration<T> = Readonly<{\n dispose?: Disposer;\n kind: 'value';\n value: T;\n}>;\n\ntype FactoryRegistration<T = unknown> = Readonly<{\n create: (...values: unknown[]) => Promise<T> | T;\n dependencies: readonly Token<unknown>[];\n dispose?: Disposer;\n kind: 'factory';\n lifetime: Lifetime;\n}>;\n\ntype Registration<T = unknown> = FactoryRegistration<T> | ValueRegistration<T>;\ntype OwnedResource = Readonly<{ dispose?: Disposer; value: unknown }>;\ntype CacheEntry = { promise?: Promise<unknown>; value?: unknown };\ntype Lifecycle = 'active' | 'disposed' | 'disposing';\n\nclass ContainerImpl implements Container {\n #cache = new Map<FactoryRegistration<unknown>, CacheEntry>();\n #children = new Set<ContainerImpl>();\n #cleanupFailures: unknown[] = [];\n #disposalController = new AbortController();\n #inFlight = new Set<Promise<unknown>>();\n #lifecycle: Lifecycle = 'active';\n #disposePromise?: Promise<void>;\n #owned: OwnedResource[] = [];\n #parent?: ContainerImpl;\n #registry = new Map<Token<unknown>, Registration<unknown>>();\n #scope?: ScopeToken;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, options: { name?: string; scope?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scope = options.scope;\n\n if (parent) parent.#children.add(this);\n\n this.name = options.name ?? (parent ? `${parent.name}:${options.scope?.description ?? 'child'}` : 'root');\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposalController.signal;\n }\n\n get disposed(): boolean {\n return this.#lifecycle === 'disposed';\n }\n\n value<T>(token: Token<T>, value: T, options: ValueOptions<T> = {}): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: ValueRegistration<T> = {\n dispose: options.dispose as Disposer | undefined,\n kind: 'value',\n value,\n };\n\n this.#registry.set(token, registration);\n\n if (options.dispose) this.#owned.push({ dispose: options.dispose as Disposer, value });\n\n return this;\n }\n\n factory<T, Dependencies extends readonly Token<unknown>[]>(\n token: Token<T>,\n dependencies: Dependencies,\n create: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options: FactoryOptions<T> = {},\n ): this {\n this.#assertActive();\n this.#assertUnregistered(token);\n\n const registration: FactoryRegistration<T> = {\n create: create as (...values: unknown[]) => Promise<T> | T,\n dependencies: Object.freeze([...dependencies]),\n dispose: options.dispose as Disposer | undefined,\n kind: 'factory',\n lifetime: options.lifetime ?? 'singleton',\n };\n\n this.#registry.set(token, registration);\n\n return this;\n }\n\n has<T>(token: Token<T>): boolean {\n this.#assertActive();\n\n return this.#lookup(token) !== undefined;\n }\n\n async resolve<T>(token: Token<T>): Promise<T> {\n this.#assertActive();\n\n return this.#resolve(token, []);\n }\n\n validate(): this {\n this.#assertActive();\n\n for (const { owner, registration, token } of this.#factories()) {\n owner.#validatePath(token, registration, new Set(), []);\n }\n\n return this;\n }\n\n createScope(scope?: ScopeToken, options?: { name?: string }): Container {\n this.#assertActive();\n\n return new ContainerImpl(this, { name: options?.name, scope });\n }\n\n dispose(): Promise<void> {\n if (this.#lifecycle === 'disposed') return Promise.resolve();\n\n if (this.#disposePromise) return this.#disposePromise;\n\n this.#lifecycle = 'disposing';\n this.#disposalController.abort();\n this.#disposePromise = this.#finishDisposal();\n\n return this.#disposePromise;\n }\n\n async #finishDisposal(): Promise<void> {\n const childOutcomes = await Promise.allSettled([...this.#children].map((child) => child.dispose()));\n\n await Promise.allSettled([...this.#inFlight]);\n\n const failures = [\n ...this.#cleanupFailures,\n ...childOutcomes.flatMap((outcome) => {\n if (outcome.status !== 'rejected') return [];\n\n return outcome.reason instanceof ConduitDisposeError ? outcome.reason.errors : [outcome.reason];\n }),\n ];\n\n for (const resource of [...this.#owned].reverse()) {\n if (!resource.dispose) continue;\n\n try {\n await resource.dispose(resource.value);\n } catch (error) {\n failures.push(error);\n }\n }\n\n this.#cache.clear();\n this.#children.clear();\n this.#cleanupFailures = [];\n this.#owned = [];\n this.#registry.clear();\n\n if (this.#parent) this.#parent.#children.delete(this);\n\n this.#lifecycle = 'disposed';\n\n if (failures.length) throw new ConduitDisposeError(failures);\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.dispose();\n }\n\n #assertActive(): void {\n if (this.#lifecycle !== 'active') throw new ConduitDisposedError(this.name);\n }\n\n #assertUnregistered(token: Token<unknown>): void {\n if (this.#registry.has(token)) throw new ConduitDuplicateRegistrationError(token);\n }\n\n #lookup<T>(token: Token<T>): { owner: ContainerImpl; registration: Registration<T> } | undefined {\n const local = this.#registry.get(token) as Registration<T> | undefined;\n\n if (local) return { owner: this, registration: local };\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#lookup(token);\n }\n\n #factories(): { owner: ContainerImpl; registration: FactoryRegistration; token: Token<unknown> }[] {\n const parentFactories = this.#parent ? this.#parent.#factories() : [];\n const localFactories = [...this.#registry].flatMap(([token, registration]) =>\n registration.kind === 'factory' ? [{ owner: this, registration, token }] : [],\n );\n\n return [...parentFactories, ...localFactories];\n }\n\n #validatePath(\n token: Token<unknown>,\n registration: FactoryRegistration,\n visiting: Set<Token<unknown>>,\n path: Token<unknown>[],\n ): void {\n if (visiting.has(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n visiting.add(token);\n\n for (const dependency of registration.dependencies) {\n const found = this.#lookup(dependency);\n\n if (!found) throw new ConduitProviderNotFoundError(dependency, this.name);\n\n if (found.registration.kind === 'factory') {\n found.owner.#validatePath(dependency, found.registration, visiting, [...path, token]);\n }\n }\n\n visiting.delete(token);\n }\n\n async #resolve<T>(token: Token<T>, path: Token<unknown>[]): Promise<T> {\n if (path.includes(token)) throw new ConduitCircularDependencyError([...path, token]);\n\n const found = this.#lookup(token);\n\n if (!found) throw new ConduitProviderNotFoundError(token, this.name);\n\n if (found.registration.kind === 'value') return found.registration.value as T;\n\n const owner = this.#ownerFor(found.owner, found.registration, token);\n\n if (found.registration.lifetime === 'transient') {\n return this.#create(found.registration, owner, [...path, token]) as Promise<T>;\n }\n\n const existing = owner.#cache.get(found.registration);\n\n if (existing?.value !== undefined) return existing.value as T;\n\n if (existing?.promise) return existing.promise as Promise<T>;\n\n const entry: CacheEntry = {};\n const promise = owner.#create(found.registration, owner, [...path, token]).then((value) => {\n entry.value = value;\n\n return value;\n });\n\n entry.promise = promise;\n owner.#cache.set(found.registration, entry);\n\n return promise as Promise<T>;\n }\n\n #ownerFor(owner: ContainerImpl, registration: FactoryRegistration, token: Token<unknown>): ContainerImpl {\n if (registration.lifetime === 'singleton') return owner;\n\n if (registration.lifetime === 'transient') return this;\n\n const scope = this.#scopeOwner(registration.lifetime);\n\n if (!scope) throw new ConduitScopedResolutionError(token, registration.lifetime);\n\n return scope;\n }\n\n #scopeOwner(scope: ScopeToken): ContainerImpl | undefined {\n if (this.#scope === scope) return this;\n\n return this.#parent ? this.#parent.#scopeOwner(scope) : undefined;\n }\n\n async #create(registration: FactoryRegistration, owner: ContainerImpl, path: Token<unknown>[]): Promise<unknown> {\n const promise = Promise.all(registration.dependencies.map((dependency) => owner.#resolve(dependency, path))).then(\n (dependencies) => registration.create(...dependencies),\n );\n\n owner.#inFlight.add(promise);\n\n try {\n const value = await promise;\n\n if (owner.#lifecycle !== 'active') {\n if (registration.dispose) {\n try {\n await registration.dispose(value);\n } catch (error) {\n owner.#cleanupFailures.push(error);\n }\n }\n\n throw new ConduitDisposedError(owner.name);\n }\n\n if (registration.dispose) owner.#owned.push({ dispose: registration.dispose, value });\n\n return value;\n } finally {\n owner.#inFlight.delete(promise);\n }\n }\n}\n\nexport function createContainer(options?: { name?: string }): Container {\n return new ContainerImpl(undefined, options);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/conduit",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Lightweight dependency injection container — singletons, transient instances, factories, and named scopes",
5
5
  "repository": {
6
6
  "type": "git",