import { type PublicToken, type Token } from '@fluojs/core'; import type { NormalizedProvider, Provider } from './types.js'; /** * Factory provider resolution mode recorded after a factory returns either synchronously or through a promise. */ export type FactoryResolutionKind = 'async' | 'sync'; /** * Controlled cache adoption seam for framework-owned testing and tooling that * need synchronous helpers to preserve container-owned singleton disposal. */ export interface ContainerResolutionCacheOwner { readonly deleteMultiSingleton: (provider: NormalizedProvider) => void; readonly deleteSingleton: (token: Token) => void; readonly recordFactoryResolution: (provider: NormalizedProvider, kind: FactoryResolutionKind) => void; readonly setMultiSingleton: (provider: NormalizedProvider, promise: Promise) => void; readonly setSingleton: (token: Token, promise: Promise) => void; } /** * Read-only factory resolution diagnostics recorded by container-owned factory * instantiation paths. */ export interface ContainerFactoryResolutionState { readonly get: (provider: NormalizedProvider) => FactoryResolutionKind | undefined; readonly has: (provider: NormalizedProvider) => boolean; } /** * Public read-only seam for framework-owned testing and tooling that need to * inspect a container's resolved provider graph without depending on private * field names or structural casts. */ export interface ContainerResolutionState { readonly cacheOwner: ContainerResolutionCacheOwner; readonly factoryResolutionKinds: ContainerFactoryResolutionState; readonly parent?: ContainerResolutionState; readonly registrations: ReadonlyMap; readonly multiRegistrations: ReadonlyMap; readonly multiSingletonCache: ReadonlyMap>; readonly requestScopeEnabled: boolean; readonly singletonCache: ReadonlyMap>; } /** * Scope-aware dependency injection container for Fluo providers. */ export declare class Container { #private; private readonly registrations; private readonly multiRegistrations; private readonly multiOverriddenTokens; private requestCache; private multiRequestCache; private readonly multiSingletonCache; private readonly materializedCachePromises; private readonly pendingDisposables; private readonly staleDisposalTasks; private readonly singletonCache; private readonly forwardRefTokenCache; private readonly factoryResolutionKinds; private readonly providerLookupPlanCache; private readonly multiProviderPlanCache; private readonly requestScopeVerdictPlanCache; private readonly effectiveProviderPlanCache; private childScopes; private disposePromise; private disposed; private trackedByParent; private graphRevision; private readonly parent; private readonly requestScopeEnabled; /** * Creates a root container that owns its own singleton cache. * * Child request scopes are package-owned and must be created with * {@link Container.createRequestScope}; caller-supplied parent, request-scope, * or singleton-cache wiring is rejected. * * @throws {ContainerResolutionError} When any constructor argument is supplied. */ constructor(...construction: never[]); /** * Registers providers in the current container scope. * * @param providers Provider definitions to register in this container. * @returns The same container instance for fluent registration chains. * @throws {ContainerResolutionError} When called after the container was disposed. * @throws {ScopeMismatchError} When registering singleton providers directly on a request scope. * @throws {DuplicateProviderError} When registration conflicts with existing single/multi mappings. * @throws {InvalidProviderError} When a provider definition is structurally invalid. */ register(...providers: Provider[]): this; /** * Override one or more already-registered providers. * * **Multi-provider destructive replacement**: when the incoming provider has `multi: true`, * the entire existing multi-registration array for that token is deleted before the new entry * is added. There is intentionally no way to replace a single entry within a multi-provider * set — the whole set is replaced. If you need to preserve other entries, re-register them * together with the replacement in one `override()` call. * * **Batch atomicity**: the whole batch is validated before any registration or cache is touched, * so a rejected `override()` call leaves every provider, cached instance, and disposal ownership * exactly as it was before the call. * * @param providers Provider definitions that should replace existing registrations for each token. * @returns The same container instance for fluent override chains. * @throws {ContainerResolutionError} When called after the container was disposed. * @throws {ScopeMismatchError} When a request-scope override would introduce a new singleton token. * @throws {InvalidProviderError} When a provider definition is structurally invalid. * @throws {DuplicateProviderError} When one token mixes single and multi replacements or repeats a single replacement. */ override(...providers: Provider[]): this; /** * Returns whether a token is registered in this scope chain. * * @param token Token to check across this container and its ancestors. * @returns `true` when a single or multi provider exists for the token. */ has(token: Token): boolean; /** * Returns the framework-owned resolution state for testing/tooling adapters. * * This method is the supported introspection seam for packages such as * `@fluojs/testing`; callers should prefer ordinary `has(...)` and * `resolve(...)` unless they need read-only graph/cache visibility while * implementing a framework-level helper. Cache adoption for synchronous * helpers goes through `cacheOwner`; the returned maps are not mutable * container internals. * * @returns Read-only provider registrations and resolution caches for this container scope. */ inspectResolutionState(): ContainerResolutionState; private createCacheOwner; private createFactoryResolutionState; /** * Returns whether resolving a token may require a request-scope container. * * @param token Provider token to inspect through aliases, multi providers, and dependencies. * @returns `true` when the provider graph contains request-scoped dependencies or is cyclic. */ hasRequestScopedDependency(token: Token): boolean; /** * Creates a child request-scope container that shares root singleton cache. * * @returns A request-scope child container bound to this container hierarchy. * @throws {ContainerResolutionError} When called after the container was disposed. */ createRequestScope(): Container; /** * Resolves a token to an instance using scope-aware caching rules. * * @param token Token to resolve. * @returns A promise that resolves to the token instance (or multi-provider instance array). * @throws {ContainerResolutionError} When called after disposal or when no provider is registered. * @throws {RequestScopeResolutionError} When request-scoped providers are resolved from root scope. * @throws {ScopeMismatchError} When singleton providers depend on request-scoped providers. * @throws {CircularDependencyError} When provider dependency resolution detects a cycle. */ resolve(token: PublicToken): Promise; resolve(token: Token): Promise; private resolveMultiContribution; /** * Disposes cached instances and nested request scopes. * * Concurrent callers share the active disposal attempt. After a failed attempt, * a later explicit call retries only `onDestroy()` hooks that did not complete; * successfully completed hooks are never repeated. Disposal remains terminal * for registration, resolution, overrides, and child-scope creation. A directly * disposed child owns its remaining retries after that attempt settles, while a * parent-started failed attempt remains owned by the parent hierarchy. * * @returns A promise that settles after all cached disposable instances are torn down. * @throws {Error} Propagates one or more disposal errors (`AggregateError` when multiple failures occur). */ dispose(): Promise; private disposeFromParent; private disposeWithOrigin; private disposeAll; private isDisposedInHierarchy; private hasMulti; private assertNoRegistrationConflict; private hasAncestorSingleRegistration; private hasSingleRegistration; private hasAncestorMultiRegistration; private hasMultiRegistration; private collectMultiProviders; private providerGraphRequiresRequestScope; private unregisteredClassRequiresRequestScope; private normalizedProviderRequiresRequestScope; private dependencyEntryRequiresRequestScope; private resolveWithChain; private resolveFromRegisteredProviders; private requireProvider; private resolveAliasTarget; private resolveForwardRefCircularDependency; private resolveMultiProviderInstances; private resolveMultiProviderInstance; private resolveExistingProviderTarget; private resolveScopedOrSingletonInstance; private getCachedScopedOrSingletonInstance; private cacheOwnerFor; private resolveDepToken; private withTokenInChain; private root; private ensureTrackedRequestScope; private requestCacheForWrite; private multiRequestCacheForWrite; private lookupProvider; /** * Resolve the cache map that should hold the instance for `provider`. * * **Singleton-in-request-scope**: if a provider with `scope: 'singleton'` (the default) is * registered directly on a request-scope child container (rather than the root), it is cached * in the child's `requestCache` instead of the root's `singletonCache`. This means it behaves * as request-scoped despite the singleton scope annotation. This is intentional — it allows * test and override scenarios to inject short-lived values without polluting the global cache * — but the divergence from the declared scope is a known footgun for consumers who * inadvertently register singletons on child containers. */ private cacheFor; private multiCacheFor; private hasLocalMultiProvider; private disposalCacheEntries; private disposeCache; private collectDisposableInstances; private disposeInstancesInReverseOrder; private clearDisposalCaches; private trackCacheMaterialization; private currentLineageRevision; private readCachedPlan; private writePlanCache; private advanceGraphRevision; private clearResolutionPlanCaches; private assertStaleDisposalsSettled; private retainedStaleDisposalTasks; private hasRetainedStaleDisposalTasksInSubtree; private releaseNonOwnerStaleTaskObservers; private releaseNonOwnerStaleTaskObserversInSubtree; private retryFailedStaleDisposals; private scheduleStaleDisposal; private throwDisposalErrors; private collectDisposalError; private isDisposable; private instantiate; private assertSingletonDependencyScopes; private findRequestScopedDependency; private findRequestScopedDependencyToken; private findRequestScopedMultiContribution; private resolveEffectiveProvider; private resolveProviderDependencyToken; private resolveForwardRefToken; private resolveProviderDeps; private invalidateAffectedCachedEntriesInHierarchy; private invalidateAffectedCachedEntries; private shouldInvalidateCachedToken; private shouldInvalidateCachedProvider; private providerDependsOnToken; private dependencyEntryReferencesToken; private dependencyTokenReferencesToken; } //# sourceMappingURL=container.d.ts.map