UNPKG

@furystack/inject

Version:

Dependency Injection framework for FuryStack

136 lines 6.05 kB
import type { AnyToken, AsyncServiceFactory, AsyncToken, CreateScopeOptions, Lifetime, ServiceFactory, SyncToken } from './types.js'; /** * Thrown when a method is called on an injector that has already been disposed. */ export declare class InjectorDisposedError extends Error { constructor(); } /** * Thrown when a factory depends on itself (directly or transitively) during * instantiation. */ export declare class CircularDependencyError extends Error { readonly path: readonly string[]; constructor(path: readonly string[]); } /** * Thrown when a singleton-lifetime service attempts to depend on a non-singleton * service, or a scoped service attempts to depend on a transient. */ export declare class InvalidLifetimeDependencyError extends Error { readonly parentName: string; readonly parentLifetime: Lifetime; readonly childName: string; readonly childLifetime: Lifetime; constructor(parentName: string, parentLifetime: Lifetime, childName: string, childLifetime: Lifetime); } /** * Thrown when attempting to resolve an async token via the synchronous * {@link Injector.get} method. In well-typed call sites this case is caught at * compile time by {@link Injector.get}'s signature; the runtime check exists * as a defense for dynamically-constructed tokens. */ export declare class AsyncTokenInSyncContextError extends Error { readonly tokenName: string; constructor(tokenName: string); } /** * The dependency injection container. Created via {@link createInjector} or * {@link Injector.createScope}. Manages service resolution, caching, and * disposal across a hierarchical scope tree. */ export declare class Injector implements AsyncDisposable { readonly parent: Injector | null; readonly owner: unknown; private readonly cache; private readonly bindings; private readonly disposeCallbacks; private isDisposed; constructor(options?: { parent?: Injector; owner?: unknown; }); private ensureLive; private rootInjector; private ownerForLifetime; private findCached; private findFactory; private buildContext; /** * Resolves a sync token. Throws {@link InjectorDisposedError} if the * injector is already disposed and {@link AsyncTokenInSyncContextError} if * a runtime-async token slips past the compile-time check. */ get<TService>(token: SyncToken<TService>): TService; /** * Resolves a sync or async token. Sync tokens are wrapped in a resolved * promise. Synchronous failures (disposed injector, sync-throwing async * factory) are normalised to a rejected promise so callers can rely on * `.rejects` / `.catch` uniformly. */ getAsync<TService>(token: AnyToken<TService>): Promise<TService>; private resolveSync; private resolveAsync; private consumeCached; private consumeCachedAsync; private pushResolving; private popResolving; private instantiateSync; private instantiateAsync; /** * Installs a factory override for `token` on the injector that would own its * cached instance (root for singleton, this injector for scoped/transient). * Any cached entry for the token on that injector is dropped so the next * resolution uses the new factory. * * Scope caveat: a `scoped` bind applies only to the injector it was called * on. Descendant scopes each own their own cache and resolve scoped tokens * against `token.factory` unless they also call `bind`. Bind at the highest * scope whose cache you want the override to populate — usually the same * scope that will call `injector.get(token)`. */ bind<TService, TLifetime extends Lifetime>(token: SyncToken<TService, TLifetime>, factory: ServiceFactory<TService>): void; bind<TService, TLifetime extends Lifetime>(token: AsyncToken<TService, TLifetime>, factory: AsyncServiceFactory<TService>): void; /** * Drops any cached entry for `token` on the injector that owns its cached * instance. The next resolution will run the factory again. Useful for * recovering from cached factory failures or resetting state between tests. */ invalidate<TService>(token: AnyToken<TService>): void; /** * Returns `true` when `token` has a cache entry (resolved, pending or * failed) on the scope that owns its lifetime -- the root injector for * singletons, the requesting injector for scoped tokens. Transient * tokens are never cached and therefore always report `false`. * * Useful for bootstrap helpers that must run before a service is first * resolved: checking `isResolved` lets them fail loudly instead of * silently leaking the previous instance. */ isResolved<TService>(token: AnyToken<TService>): boolean; /** * Creates a child injector. The child has its own cache and bindings; * singleton resolution still walks up to the root. Disposing the child * leaves the parent untouched. Disposing the parent disposes all * descendants reachable through stored references. */ createScope(options?: CreateScopeOptions): Injector; /** * Disposes the injector: runs registered `onDispose` callbacks in LIFO * order, clears the cache, and marks the injector as disposed. Idempotent — * a second call is a no-op so `await using` and manual teardown paths * don't have to guard. Errors from callbacks are collected and re-thrown * as a single `AggregateError`. */ [Symbol.asyncDispose](): Promise<void>; } /** * Creates a new root {@link Injector}. */ export declare const createInjector: () => Injector; /** * Creates a child scope of `parent`, runs `fn` with it, then disposes the * scope — including when `fn` throws. Returns `fn`'s resolved value. */ export declare const withScope: <TResult>(parent: Injector, fn: (scope: Injector) => Promise<TResult> | TResult, options?: CreateScopeOptions) => Promise<TResult>; //# sourceMappingURL=injector.d.ts.map