@furystack/inject
Version:
Dependency Injection framework for FuryStack
136 lines • 6.05 kB
TypeScript
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