/** * Represents value that can be `T` or `null`. * * @template T - The base type. * @group General Types */ type Nullable = T | null; /** * Represents value that can be `T` or `undefined`. * * @template T - The base type. * @group General Types */ type Optional = T | undefined; /** * Represents value that can be `T` or a Promise of `T`. * * @template T - The base type. * @group General Types */ type MaybePromise = T | Promise; /** * Constructor type for a concrete class Wirestate can instantiate. * * @remarks * Used for service classes, class tokens, and instance binding implementations. * * @template T - Instance type the constructor produces. * * @group General Types */ type Newable = new (...args: Array) => T; /** * Abstract class reference that cannot be constructed directly, * but can serve as a binding token. * * @template T - Instance type the abstract class describes. * * @group General Types */ interface AbstractClass { prototype: T; name: string; } /** * Typed reference token for dependencies stored in a container. * * @remarks * Use an `InjectionToken` when a dependency needs a named, collision-free runtime key * that carries the resolved TypeScript type. It works well for configuration, external * objects, interfaces, and service contracts that should be resolved through an explicit key. * The token is identified by object reference, not by its description. * * @group Bind * * @example * ```typescript * import { Container, InjectionToken, Injectable, inject } from "@wirestate/core"; * * interface RuntimeConfig { * readonly apiUrl: string; * } * * const RUNTIME_CONFIG = new InjectionToken("RUNTIME_CONFIG"); * * const container = new Container({ * bindings: [{ token: RUNTIME_CONFIG, value: { apiUrl: "https://api.example.com" } }], * }); * * @Injectable() * class ApiClient { * public constructor(private readonly config = inject(RUNTIME_CONFIG)) {} * } * ``` */ declare class InjectionToken { private readonly description; /** * Phantom field that ties the token to its value type. * It exists so `InjectionToken` is not assignable to `InjectionToken`. */ protected readonly _type?: T; /** * Creates an injection token with a human-readable description. * * @param description - Description used in diagnostics. */ constructor(description: string | symbol); /** * Returns a diagnostic label for this token. * * @returns Human-readable token label. */ toString(): string; } /** * Returns the token a binding resolves under. * * @remarks * A bare service class is its own token, and a descriptor carries an explicit one. * Use it when working with the {@link Binding} union, such as the entries of * `ContainerConfig.bindings`, instead of narrowing the union at each call site. * * @group Bind * * @param binding - Service class or descriptor to inspect. * @returns Token used for container resolution. * * @example * ```typescript * import { getBindingToken, Injectable, InjectionToken } from "@wirestate/core"; * * @Injectable() * class LoggerService {} * * const API_URL = new InjectionToken("API_URL"); * * getBindingToken(LoggerService); // LoggerService * getBindingToken({ token: API_URL, value: "https://api.example.com" }); // API_URL * ``` */ declare function getBindingToken(binding: Binding): ServiceToken; /** * Binding strategy names accepted by binding descriptors. * * @group Bind */ declare const BindingType: { readonly Value: "Value"; readonly Instance: "Instance"; readonly Factory: "Factory"; }; /** * Binding strategy name. * * @group Bind */ type BindingTypeValue = keyof typeof BindingType; /** * Lifetime scope names accepted by binding descriptors: * * - `Singleton` (default): the value is constructed once and reused for every resolution. * - `Transient`: a new value is constructed for every resolution and never cached. * * @group Bind */ declare const BindingScope: { readonly Singleton: "Singleton"; readonly Transient: "Transient"; }; /** * Binding lifetime scope name. * * @group Bind */ type BindingScopeValue = keyof typeof BindingScope; /** * Token accepted by container lookup and injection APIs. * * @remarks * A token can be an injectable class constructor, abstract class token, string, * symbol, or {@link InjectionToken}. Class tokens and `InjectionToken` * carry the resolved value type. Plain strings and symbols resolve as * `unknown` unless the call site supplies a type argument. * * @group Container * * @template T - Value type resolved for the token. */ type ServiceToken = Newable | AbstractClass | string | symbol | InjectionToken; /** * Describes a token-bound value stored directly in the container. * * @remarks * Use a value binding for constants, configuration, already-created objects, * environment data, or external objects that Wirestate should resolve as-is. * Value bindings are always singletons. They are cached as the provided value * and are not wired into service lifecycle, provider lifecycle, or messaging. * `Container` rejects a value bound under a class token that declares * `@OnProvision`, `@OnDeprovision`, or a messaging handler, because it owns no * instance to run them on. * * The `type` field is optional for value bindings. Value-shaped descriptors * do not support transient scope. * * @group Bind * * @template T - Value type resolved for the token. */ interface ValueBindingDescriptor { /** * Binding strategy. Optional for ordinary value descriptors. */ readonly type?: "Value"; /** * Token used to resolve the stored value. */ readonly token: ServiceToken; /** * Value returned when the token is resolved. */ readonly value: T; } /** * Describes a token-bound service instance constructed from an injectable class. * * @remarks * Use an instance binding when the token callers resolve should be explicit: * an interface-shaped {@link InjectionToken}, an abstract class, a base class, * or a class token mapped to a subclass implementation. A bare class binding is * shorthand for an instance binding whose `token` and `value` are the same class. * * Singleton instance bindings are cached, owned by the container, and wired into * service lifecycle, provider lifecycle, and messaging. Transient instance bindings * create a fresh instance for every resolution and are not cached or owned. * `Container` rejects transient instance classes that declare lifecycle or messaging * handlers because those handlers would have no owned lifetime. * * @group Bind * * @template T - Instance type resolved for the token. */ interface InstanceBindingDescriptor { /** * Binding strategy for injectable class construction. */ readonly type: "Instance"; /** * Token used to resolve the constructed instance. */ readonly token: ServiceToken; /** * Injectable service constructor used to create the instance. * * @remarks * The constructor must be assignable to the token's resolved type and must be * decorated with `@Injectable()`. */ readonly value: Newable>; /** * Lifetime scope for the instance. * * @remarks * Defaults to `Singleton`: the value is constructed once, cached, and owned by the * container with full instance lifecycle. A `Transient` value is constructed fresh on * every resolution and is never cached or owned, so its class must declare no wirestate * lifecycle or messaging handlers. The container rejects a transient instance class that * declares handlers at bind time. */ readonly scope?: BindingScopeValue; } /** * Describes a token-bound value produced by a factory function. * * @remarks * Use a factory binding when a dependency should be created on first resolution, * should read other container bindings while it is created, or should create a fresh * value for each resolution with `Transient` scope. Singleton factories are cached * after the first resolution. Factory results are not service instances, so service * lifecycle decorators and messaging handlers are not wired for the returned value. * `Container` rejects a factory bound under a class token that declares * `@OnProvision`, `@OnDeprovision`, or a messaging handler, because it owns no * instance to run them on. * * @group Bind * * @template T - Value returned by the factory. */ interface FactoryBindingDescriptor { /** * Binding strategy. Optional when the descriptor has a `factory` field. */ readonly type?: "Factory"; /** * Token used to resolve the factory result. */ readonly token: ServiceToken; /** * Creates the value for this token. * * @remarks * Receives the current container and runs inside the injection context, so * both `current.get(...)` and `inject(...)` can read other bindings. */ readonly factory: (container: Container) => NoInfer; /** * Lifetime scope for factory results. * * @remarks * Defaults to `Singleton`, which calls the factory once and reuses the result. * `Transient` calls the factory on every resolution and does not cache the result. */ readonly scope?: BindingScopeValue; } /** * Descriptor object that binds a token to a value, class, or factory strategy. * * @remarks * Use a descriptor when a bare service class is not enough: typed values, * factory-created values, or an injectable class registered behind an explicit * token. * * `type: "Instance"` selects class construction. A descriptor with a * `factory` field is a factory binding. A descriptor with a `value` field and * no instance type is a value binding. * * @group Bind * * @template T - Resolved value type. */ type BindingDescriptor = ValueBindingDescriptor | InstanceBindingDescriptor | FactoryBindingDescriptor; /** * Binding entry accepted by container registration APIs. * * @remarks * Pass a bare `@Injectable()` class when the class should be its own singleton * token. Pass a {@link BindingDescriptor} when the binding needs an explicit * token, a stored value, a factory, or non-default scope. `ContainerConfig.bindings` * and `container.bind(...)` both accept this shape. * * @group Bind */ type Binding = Newable | BindingDescriptor; /** * Identifies an event for emitting and subscribing. * * @remarks * Event types are compared by value for strings and numbers, and by reference * for symbols. * * @group Events */ type EventType = string | symbol | number; /** * Event delivered to handlers: its type, optional payload, and optional source. * * @remarks * `payload` and `source` are present only when the emitted value is not * `undefined`. Other falsy values, such as `null`, `0`, and `false`, are * preserved. * * @group Events * * @template P - Payload type. * @template T - Event type. * @template S - Source type. */ interface WireEvent

{ /** * Event type used for matching subscriptions. */ readonly type: T; /** * Payload supplied by the emitter, when one was provided. */ readonly payload?: P; /** * Source supplied by the emitter, when one was provided. */ readonly source?: S; } /** * Options for emitting an event. * * @group Events * * @template S - Source type. */ interface EventEmitOptions { /** * Source attached to the emitted event. * * @remarks * Use this for diagnostics or caller context. */ readonly source?: S; } /** * Receives an emitted event from the bus. * * @remarks * May start asynchronous work. The bus does not await a returned promise, and * reports a rejection through the container error handler. * * @template E - Event shape delivered to the handler. * * @group Events */ type EventHandler = (event: E) => void; /** * Removes the event subscription it was returned for. * * @remarks * Each subscription has its own unsubscriber. Calling it removes only that * subscription, even when the same handler function was subscribed more than * once. * * @group Events */ type EventUnsubscribe = () => void; /** * @remarks * Use it to group logs by failure category. It is diagnostic context, not a * recovery instruction. * * @group Error */ type WirestateErrorSource = "event-handler" | "instance-event-handler" | "instance-activation" | "instance-deactivation" | "provider-provision" | "provider-deprovision"; /** * Describes an isolated failure reported through a container error handler. * * @remarks * Carries the original thrown or rejected value plus what Wirestate knew at * the catch site. Some fields are present only for specific sources, such as * `event` for event handler failures. * * @group Error */ interface WirestateErrorContext { /** * Container that owns the failed work, when known. */ readonly container?: Container; /** * Extra diagnostic values from the failing subsystem. */ readonly details?: ReadonlyArray; /** * Event being dispatched when an event handler failed. */ readonly event?: WireEvent; /** * Original thrown or rejected value. */ readonly error: unknown; /** * Human-readable failure summary. */ readonly message: string; /** * Service method that failed, when known. */ readonly methodName?: string | symbol; /** * Instance that owns the failed handler, when known. */ readonly instance?: object; /** * Instance class name, when known. */ readonly instanceName?: string; /** * Subsystem that caught the failure. */ readonly source: WirestateErrorSource; } /** * Handles isolated Wirestate errors for a container. * * @remarks * Register it as `new Container({ onError })`. If it throws, Wirestate falls * back to {@link defaultWirestateErrorHandler} and reports both failures. * * @param context - Isolated failure context. * * @group Error */ type WirestateErrorHandler = (context: WirestateErrorContext) => void; /** * Reports isolated Wirestate errors to `console.error`. * * @remarks * This is the fallback used when a container has no `onError` handler, or when * a custom handler throws. * * @group Error * * @param context - Isolated failure context. */ declare function defaultWirestateErrorHandler(context: WirestateErrorContext): void; /** * A container lifecycle plugin. * * @remarks * Register plugins on a {@link Container} via `config.plugins`. A plugin is a * class instance, so it can hold per-instance state, and every hook is optional. * * Plugins bracket the user layer (`@OnActivation` / `@OnProvision`): setup hooks * run before the matching user hook, teardown hooks run after it. Setup hooks * (`install`, `onActivate`, `onContainerProvision`, `onProvision`) are atomic, so * a throw unwinds the activation/provision cycle. Teardown hooks (`onDeactivate`, * `onDeprovision`, `onContainerDeprovision`) and disposers are failsafe, so a * throw is swallowed and teardown continues. Plugin teardown failures are not * reported through the container error handler. * * A plugin reaches its container and every descendant (plugins resolve up the * parent chain, nearest first), so one registered on the root observes the whole * subtree unless a nearer built-in messaging plugin shadows the same kind. * * @group Plugins * * @example * ```typescript * import { Container, WirestatePlugin } from "@wirestate/core"; * * class LogPlugin implements WirestatePlugin { * public onActivate(instance: object): void { * console.log("activated", instance.constructor.name); * } * } * * new Container({ plugins: [new LogPlugin()] }); * ``` */ interface WirestatePlugin { /** * Contributes bindings (or other one-time setup) when the plugin is registered. * * @remarks * Runs once, on the container the plugin is registered on (not on inheriting children), * before any binding activates. * * Register cleanup for install-time side effects with `addRollback`. Rollbacks run in reverse * order if this or a later install throws, or if container construction fails afterwards. * They are failsafe and do not run during normal container teardown. * * @param container - Container the plugin is registered on. * @param addRollback - Registers cleanup for a failed container construction. */ install?(container: Container, addRollback: (rollback: () => void) => void): void; /** * Declares whether a binding token is a participant this plugin wires. * * @remarks * Token/class-level so it can drive force-activation: a token this returns * `true` for is resolved (activated) at provision even if nothing injected it, * and the instance is then delivered to {@link WirestatePlugin.onProvision}. * Omit for a pure observer that force-activates nothing. * * @param token - Binding token to inspect. * @returns Whether the plugin participates in this token. */ participates?(token: ServiceToken): boolean; /** * Runs once at the start of a container provision cycle, before instance wiring. * * @param container - Container being provisioned. */ onContainerProvision?(container: Container): void; /** * Runs once at the end of a container deprovision cycle, after all teardown. * * @param container - Container being deprovisioned. */ onContainerDeprovision?(container: Container): void; /** * Runs after a service instance is activated, before its `@OnActivation`. * * @param instance - The activated instance. * @param container - Container that activated it. */ onActivate?(instance: object, container: Container): void; /** * Runs as a service instance is deactivated, after its `@OnDeactivation`. * * @param instance - The instance being deactivated. * @param container - Container that owns it. */ onDeactivate?(instance: object, container: Container): void; /** * Wires a provisioned instance, before any user `@OnProvision`. * * @remarks * Register teardown with `addDisposer`. Disposers run (reverse order, failsafe) * at deprovision. A throw here unwinds the whole provision cycle. * * @param instance - The provisioned instance. * @param container - Container being provisioned. * @param addDisposer - Registers a teardown callback for this provision cycle. */ onProvision?(instance: object, container: Container, addDisposer: (dispose: () => void) => void): void; /** * Runs as a provisioned instance is deprovisioned, after its `@OnDeprovision`. * * @param instance - The instance being deprovisioned. * @param container - Container that owns it. */ onDeprovision?(instance: object, container: Container): void; } /** * Internal dependency injection (DI) engine: tracks bindings and holds the * resolved instances of your services. * * @remarks * This is the base class that {@link Container} extends. The public * {@link Container} adds messaging and scope support on top. Application * code interacts with `Container`, not `ContainerKernel` directly. * * All bindings are explicit: services are constructed synchronously and * only when a binding descriptor was registered with `bind`. */ declare class ContainerKernel { /** * Parent container when this container was created as a child container. */ readonly parent?: ContainerKernel; /** * Tokens the container owns rather than the caller, so `unbindAll` keeps them. * * @remarks * A bare kernel retains nothing. {@link Container} marks its own self-binding and every * binding a plugin's `install` contributed. */ private readonly retained; private readonly bindings; private readonly instances; private readonly activated; private readonly factory; private destroyed; /** * Whether {@link ContainerKernel.destroy} is running its deactivation pass. */ private destroying; constructor(parent?: ContainerKernel); /** * Binds a service class or a binding descriptor to this container, replacing * any binding previously registered for the same token. * * @remarks * A bare class is its own token and binds as a singleton instance binding: * `container.bind(MyService)` is equivalent to * `container.bind({ token: MyService, type: "Instance", value: MyService })`. * * The descriptor is validated structurally, then handed to the protected `assertBindable` hook so a * composition root can add the ownership rules of its lifecycle layer. * * @param binding - Service class or binding descriptor to register. * @returns The same container for chaining. * * @throws {@link WirestateError} If the binding is invalid, the token's existing binding already * constructed values, or a composition root rejects the binding kind. */ bind(binding: Newable | BindingDescriptor): this; /** * Unbinds a token, deactivating every container-owned value it constructed. * * @param token - Token to unbind. * @returns The same container for chaining. */ unbind(token: ServiceToken): this; /** * Resets the container by unbinding every caller-registered binding, deactivating the values * they constructed in reverse creation order, so a dependent's `@OnDeactivation` runs before * its dependencies tear down. Bindings stay resolvable until every deactivation handler has * run, so deactivating services can still talk to each other. * * @remarks * The container stays usable: bindings it owns rather than the caller survive, so * `inject(Container)` and any bus a plugin installed keep resolving and the container can be * re-populated and re-provisioned. A bare {@link ContainerKernel} owns nothing, so every * binding is removed. Use {@link destroy} to tear the container down for good. * * @returns The same container for chaining. * * @throws {@link WirestateError} If the container was destroyed. */ unbindAll(): this; /** * Tears the container down for good, deactivating every value it constructed - retained * bindings included - in reverse creation order. * * @remarks * Terminal, unlike {@link unbindAll}: a destroyed container throws on `bind`, `unbind`, * `unbindAll`, and every `get`, including `{ optional: true }`. Enforcing that is the point - * a destroyed container that still answered lookups would resolve its parent's bindings and * hand callers the wrong scope. * * Inspection stays available so teardown code can still read the container: `has`, `hasOwn`, * `getOwnBindings`, and `getActiveInstances` do not throw, and `has` reports `false` rather than * an ancestor's binding. Idempotent, so teardown paths can call it freely - including * re-entrantly from an `@OnDeactivation` hook this very call is running, where the nested call * returns without starting a second teardown. * * @returns The same container for chaining. */ destroy(): this; /** * Retrieves a service from this container. * * Resolution options can make a lookup optional or lazy. Optional lookups * resolve `undefined` instead of throwing. Lazy lookups return a thunk that * resolves on first call. * * @param token - Token to resolve. * @returns The resolved value, thunk, or `undefined` for optional misses. * * @throws {@link WirestateError} If the token is not bound and not optional, * or if a circular dependency is detected while constructing the value. * Errors thrown by a binding's constructor or factory propagate unchanged. */ get(token: ServiceToken): T; get(token: ServiceToken, options: { optional: true; }): Optional; get(token: ServiceToken, options: { lazy: true; }): () => T; get(token: ServiceToken, options: { lazy: true; optional: true; }): () => Optional; get(token: ServiceToken, options?: { optional?: boolean; lazy?: false; }): Optional; get(token: ServiceToken, options?: { optional?: boolean; lazy?: boolean; }): Optional | (() => Optional); /** * Returns whether this container or one of its parents has a binding for this token. * * @param token - Token to check. * @returns Whether the token can be resolved from this container. */ has(token: ServiceToken): boolean; /** * Returns whether this container itself has a binding for this token, * ignoring parent containers. * * @param token - Token to check. * @returns Whether this container owns a binding for the token. */ hasOwn(token: ServiceToken): boolean; /** * Returns the binding descriptors registered on this container in registration order, * ignoring parent containers. * * @returns Snapshot of this container's own binding descriptors. */ getOwnBindings(): ReadonlyArray>; /** * Returns the service instances this container constructed for singleton instance * bindings, in creation order. Values constructed for value and factory bindings are * not service instances and are not included. Transient instances are excluded too. They * are construct-and-forget and never owned or tracked by the container. * * @returns Snapshot of this container's active service instances. */ getActiveInstances(): ReadonlyArray; /** * Accepts or rejects a structurally valid descriptor before it is registered. * * @remarks * The extension point a composition root uses to enforce the rules of the lifecycle layer it * adds on top of pure DI, such as rejecting a binding kind whose class declares handlers that * kind can never run. The bare kernel accepts everything: it owns no lifecycle. * * @param descriptor - Descriptor about to be registered, already normalized and validated. * * @throws {@link WirestateError} If the composition root rejects the binding. */ protected assertBindable(descriptor: BindingDescriptor): void; /** * Marks a token as container-owned, so {@link unbindAll} keeps its binding and instance. * * @remarks * For composition roots to declare the infrastructure a reset must not take away. Only * {@link destroy} removes a retained binding. * * @internal * * @param token - Token the container owns. */ protected retainBinding(token: ServiceToken): void; /** * Rewrites a token to the newest generation of a hot-replaced class. * * @remarks * Development-only, and the single place that decision is made: every public API taking a * token routes through it, so hot-reload support cannot drift between them. Modules that were * not part of a hot update keep referencing an older generation of a replaced class, and this * keeps those references answerable after a container hot swap. * * The newest generation is used only when it is actually bound in this chain. Containers bound * before the update, such as external containers no provider owns, keep the original token. * * In production the guard folds away and this returns its argument. * * @param token - Token supplied by the caller. * @returns Token to look the binding up by. */ protected getHotToken(token: ServiceToken): ServiceToken; /** * Rewrites a binding to the newest generations of the classes it references. * * @remarks * The registration counterpart of {@link ContainerKernel.getHotToken}, keeping registration keys * consistent with lookups no matter which code path constructed the container. In production * the guard folds away and this returns its argument. * * @template T - Bound value type. * * @param binding - Binding supplied by the caller. * @returns Binding to register. */ protected getHotBinding(binding: Newable | BindingDescriptor): Newable | BindingDescriptor; /** * Throws when the container was destroyed. * * @remarks * A destroyed container is a precondition failure rather than a structural miss, so this * throws for `{ optional: true }` lookups too - the same rule `inject()` applies outside an * injection context. Without it a destroyed child would silently resolve its parent's * bindings, handing callers the wrong scope. * * @throws {@link WirestateError} If the container was destroyed. */ protected assertUsable(): void; /** * Checks the parent chain for a binding, without hot-reload rewriting. * * @remarks * Separate from {@link ContainerKernel.has} so {@link ContainerKernel.getHotToken} can test a * candidate token without recursing back through the rewrite. * * @param token - Token to look up as given. * @returns Whether the token is bound on this container or an ancestor. */ private hasBinding; /** * Resolves the value for a binding descriptor, applying scope caching and * instance lifecycle wiring. * * @param binding - Binding descriptor to resolve. * @returns The resolved value. */ private resolve; /** * Caches the singleton value of a binding descriptor and records it for later deactivation. * * @param record - Activation record holding the constructed value. */ private commit; /** * Removes a record committed before activation when that activation fails, undoing {@link commit} * so a failed instance is never cached or scheduled for deactivation. * * @param record - Activation record to evict. */ private evict; /** * Deactivates the container-owned value of a token. * * @remarks * A token holds at most one activation record - `commit` is guarded by the instance cache, and * `bind` rejects rebinding a token whose binding already constructed - so this needs no teardown * ordering of its own. Ordering across several instances belongs to {@link drainRecords}. * * @param token - Token to deactivate. */ private deactivate; /** * Deactivates every matching activation record in reverse creation order, until none is left. * * @remarks * Records are detached before dispatching, not after: an `@OnDeactivation` that re-enters * teardown would otherwise still find them and run them a second time, and a hook re-entering * `unbindAll` itself would recurse without end. * * Teardown is a transaction over everything the container owns, including what teardown itself * creates: a hook that resolves a lazy singleton commits a new record after the pass began. The * loop keeps draining until a pass finds nothing new, so no instance is left active with its * binding gone. * * @param matches - Selects the records to deactivate. */ private drainRecords; /** * Deactivates one container-owned value. * Instance bindings run the installed activation adapter's cleanup. * Other binding kinds are dropped from the active record map. * * @param record - Activation record being deactivated. */ private deactivateRecord; /** * Checks whether the binding registered for the token has already constructed values. * * @param token - Token to check. * @returns Whether a constructed value exists for the token. */ private hasConstructedBinding; } /** * Defines one {@link Container} scope at construction time. * * @remarks * Bind services and values here when they belong to the container from the * start. Use {@link validateContainerConfig} when a framework adapter stores * config before it creates the container. * * @group Container */ interface ContainerConfig { /** * Controls which configured bindings are resolved during construction. * * @remarks * Pass `true` to resolve every entry in `bindings`. Pass an array to * resolve selected tokens from `bindings`. Omit it, or pass `false`, to keep * services lazy. */ readonly activate?: boolean | ReadonlyArray; /** * Services or binding descriptors registered on this container. * * @remarks * Bare service classes bind as singleton instance bindings keyed by the * class itself. Descriptors can bind tokens to instances, factories, or * values. */ readonly bindings?: ReadonlyArray; /** * Parent container used for inherited bindings. * * @remarks * A child checks its own bindings first, then walks the parent chain. Local * bindings can replace parent bindings for the child scope. */ readonly parent?: Container; /** * Handles isolated internal errors that Wirestate catches instead of * rethrowing, such as event handler failures and lifecycle rejections. * * @remarks * Child containers inherit the nearest parent handler when they do not * provide their own. */ readonly onError?: WirestateErrorHandler; /** * Plugins registered on this container. * * @remarks * Own plugins may install bindings, such as message buses, during * construction. Plugin lifecycle observers are effective for descendant * containers through the parent chain. */ readonly plugins?: ReadonlyArray; } /** * Dependency injection container for one Wirestate scope. * * @remarks * A container owns its local bindings and the instances created from them. * It also owns provider lifecycle state and the plugin bindings installed on * that container. Child containers inherit parent bindings while keeping their * own local registrations and lifecycle state. * * @group Container * * @throws {@link WirestateError} If the config is invalid or `activate` names a token missing from `bindings`. * * @example * ```typescript * import { Container, Injectable } from "@wirestate/core"; * * @Injectable() * class LoggerService {} * * @Injectable() * class CounterService {} * * const container: Container = new Container({ * bindings: [CounterService, LoggerService], * }); * * const loggerService: LoggerService = container.get(LoggerService); * ``` */ declare class Container extends ContainerKernel { /** * Parent container when this container was created as a child container. */ readonly parent?: Container; /** * Creates a Wirestate container. * * @param config - Container setup config. * * @throws {@link WirestateError} If the config is invalid. */ constructor(config?: ContainerConfig); /** * Provisions this container for a framework provider. * * @remarks * Resolves provider lifecycle participants and runs `@OnProvision` once for * this provision cycle, in creation order: a dependency provisions before the dependent that * injected it. Participants unrelated by injection keep the order their bindings were * registered in. A container is provisioned by at most one provider at a time. * Provisioning an already provisioned container throws. Deprovision it first. * * @returns The same container for chaining. * * @throws {@link WirestateError} If the container is already provisioned. */ provision(): this; /** * Deprovisions this container for a framework provider. * * @remarks * Runs `@OnDeprovision` in the exact reverse of provision order, so the first instance * provisioned is the last one deprovisioned and a dependent tears down before the dependencies * it injected. Idempotent: deprovisioning a container that is not currently provisioned is a * no-op. Teardown methods called on this container from `@OnDeprovision` are also no-ops because * the active transaction owns cleanup until every hook and disposer has finished. * * @returns The same container for chaining. */ deprovision(): this; /** * Unbinds a local token and deactivates values created from it. * * @remarks * If the binding owns a provisioned provider lifecycle instance, * `@OnDeprovision` runs before `@OnDeactivation`. * * @param token - Token to unbind. * @returns The same container for chaining. */ override unbind(token: ServiceToken): this; /** * Resets the container: unbinds every binding registered by the caller and deactivates the * instances they created. * * @remarks * The container survives and can be re-populated and re-provisioned. Its own infrastructure * stays bound - the `Container` self-binding and every binding a plugin's `install` * contributed - so `inject(Container)` and the message buses keep resolving. Provider * lifecycle instances are deprovisioned before they deactivate. Parent bindings and parent * instances are not changed. * * Use {@link destroy} to tear the container down for good. * * @returns The same container for chaining. * * @throws {@link WirestateError} If the container was destroyed. */ override unbindAll(): this; /** * Tears the container down for good: deprovisions it, then deactivates every instance it * created, its own infrastructure included. * * @remarks * Terminal, unlike {@link unbindAll}: a destroyed container throws on any later `bind`, * `unbind`, `unbindAll`, `provision`, or `get`, `{ optional: true }` included. Inspection * still works - `has`, `hasOwn`, `getOwnBindings`, and `getActiveInstances` do not throw. * Call it when a provider unmounts or a test ends and the container will never be used again. * Idempotent, and it deprovisions first, so teardown paths can call it on its own. * * @returns The same container for chaining. * * @example * ```typescript * const container: Container = new Container({ bindings: [CounterService] }); * * container.provision(); * container.destroy(); * ``` */ override destroy(): this; /** * Enforces the ownership rules of the Wirestate lifecycle layer on a binding. * * @remarks * Runs after structural validation, so a malformed descriptor reports its own error instead of * a lifecycle one. An instance binding has its lifecycle declarations read here, which rejects a * class hierarchy declaring two methods for one hook before the class can activate. A transient * instance binding and a value or factory binding are rejected when their class declares * handlers the container could never run for them. Finally, a handler-bearing binding cannot * join a container that is already provisioned. * * @param descriptor - Descriptor about to be registered. * * @throws {@link WirestateError} If the binding kind cannot run the handlers its class declares, * the class declares conflicting lifecycle hooks, or the container is provisioned. */ protected override assertBindable(descriptor: BindingDescriptor): void; } export { InjectionToken as C, Newable as D, MaybePromise as E, Nullable as O, ValueBindingDescriptor as S, AbstractClass as T, BindingType as _, WirestateErrorHandler as a, InstanceBindingDescriptor as b, EventEmitOptions as c, EventUnsubscribe as d, WireEvent as f, BindingScopeValue as g, BindingScope as h, WirestateErrorContext as i, Optional as k, EventHandler as l, BindingDescriptor as m, ContainerConfig as n, WirestateErrorSource as o, Binding as p, WirestatePlugin as r, defaultWirestateErrorHandler as s, Container as t, EventType as u, BindingTypeValue as v, getBindingToken as w, ServiceToken as x, FactoryBindingDescriptor as y };