di-bag 0.1.0
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/LICENSE +21 -0
- package/README.md +280 -0
- package/dist/acquisition-context.d.ts +42 -0
- package/dist/acquisition-context.js +19 -0
- package/dist/acquisition-family.d.ts +32 -0
- package/dist/acquisition-family.js +135 -0
- package/dist/acquisition-mode.d.ts +34 -0
- package/dist/acquisition-mode.js +35 -0
- package/dist/acquisition.d.ts +44 -0
- package/dist/acquisition.js +395 -0
- package/dist/alias-types.d.ts +22 -0
- package/dist/alias-types.js +2 -0
- package/dist/aliases.d.ts +4 -0
- package/dist/aliases.js +24 -0
- package/dist/composition.d.ts +41 -0
- package/dist/composition.js +45 -0
- package/dist/contribution-types.d.ts +57 -0
- package/dist/contribution-types.js +2 -0
- package/dist/contributions.d.ts +3 -0
- package/dist/contributions.js +11 -0
- package/dist/dependency-references.d.ts +52 -0
- package/dist/dependency-references.js +53 -0
- package/dist/di-bag.d.ts +247 -0
- package/dist/di-bag.js +211 -0
- package/dist/errors.d.ts +66 -0
- package/dist/errors.js +89 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +10 -0
- package/dist/inspection.d.ts +36 -0
- package/dist/inspection.js +2 -0
- package/dist/lifetime-types.d.ts +214 -0
- package/dist/lifetime-types.js +2 -0
- package/dist/lifetime.d.ts +42 -0
- package/dist/lifetime.js +31 -0
- package/dist/module-types.d.ts +182 -0
- package/dist/module-types.js +2 -0
- package/dist/module.d.ts +45 -0
- package/dist/module.js +118 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.js +22 -0
- package/dist/observers.d.ts +71 -0
- package/dist/observers.js +58 -0
- package/dist/persistent-map.d.ts +29 -0
- package/dist/persistent-map.js +146 -0
- package/dist/persistent-sequence.d.ts +9 -0
- package/dist/persistent-sequence.js +20 -0
- package/dist/plugins.d.ts +32 -0
- package/dist/plugins.js +82 -0
- package/dist/provider-execution.d.ts +59 -0
- package/dist/provider-execution.js +271 -0
- package/dist/provider-operations.d.ts +59 -0
- package/dist/provider-operations.js +38 -0
- package/dist/provider.d.ts +199 -0
- package/dist/provider.js +158 -0
- package/dist/registration.d.ts +32 -0
- package/dist/registration.js +45 -0
- package/dist/replacement-types.d.ts +30 -0
- package/dist/replacement-types.js +2 -0
- package/dist/runtime.d.ts +90 -0
- package/dist/runtime.js +428 -0
- package/dist/scope-selection.d.ts +6 -0
- package/dist/scope-selection.js +62 -0
- package/dist/scope-types.d.ts +58 -0
- package/dist/scope-types.js +2 -0
- package/dist/startup.d.ts +14 -0
- package/dist/startup.js +141 -0
- package/dist/token-types.d.ts +67 -0
- package/dist/token-types.js +2 -0
- package/dist/tokens.d.ts +47 -0
- package/dist/tokens.js +69 -0
- package/dist/types.d.ts +174 -0
- package/dist/types.js +2 -0
- package/package.json +64 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TokenBase, TokenService } from './tokens';
|
|
2
|
+
import type { TokenTupleAdmission, ValidToken } from './token-types';
|
|
3
|
+
declare const referenceInvariant: unique symbol;
|
|
4
|
+
declare class ReferenceBase {
|
|
5
|
+
private readonly nominal;
|
|
6
|
+
}
|
|
7
|
+
declare class DependencyHandle<T extends TokenBase, K extends 'optional' | 'lazy' | 'all'> extends ReferenceBase {
|
|
8
|
+
readonly [referenceInvariant]: (value: [T, K]) => [T, K];
|
|
9
|
+
}
|
|
10
|
+
/** A positional dependency that yields the token service or `undefined` when unbound. */
|
|
11
|
+
export type OptionalDependency<T extends TokenBase> = DependencyHandle<T, 'optional'>;
|
|
12
|
+
/** A positional dependency that yields all contributions for a token as a readonly array. */
|
|
13
|
+
export type CollectionDependency<T extends TokenBase> = DependencyHandle<T, 'all'>;
|
|
14
|
+
/** A positional dependency that yields a function which resolves the token on demand. */
|
|
15
|
+
export type LazyDependency<T extends TokenBase> = DependencyHandle<T, 'lazy'>;
|
|
16
|
+
/** A typed token or one of the positional dependency-reference handles. */
|
|
17
|
+
export type DependencyReference = TokenBase | ReferenceBase;
|
|
18
|
+
type ReferenceParts<R> = R extends {
|
|
19
|
+
readonly [referenceInvariant]: (...args: never[]) => [infer T extends TokenBase, infer K];
|
|
20
|
+
} ? [T, K] : never;
|
|
21
|
+
export type DependencyToken<R> = R extends TokenBase ? R : ReferenceParts<R>[0];
|
|
22
|
+
export type DependencyKind<R> = R extends TokenBase ? 'required' : ReferenceParts<R>[1];
|
|
23
|
+
export type DependencyValue<R> = R extends TokenBase ? TokenService<R> : ReferenceParts<R> extends [infer T, infer K] ? K extends 'optional' ? TokenService<T> | undefined : K extends 'lazy' ? () => TokenService<T> : K extends 'all' ? ReadonlyArray<TokenService<T>> : never : never;
|
|
24
|
+
export type ValidDependency<R> = [R] extends [never] ? false : ValidToken<R> extends true ? true : R extends ReferenceBase ? ValidToken<DependencyToken<R>> : false;
|
|
25
|
+
export interface ArgumentReference {
|
|
26
|
+
readonly slot: symbol;
|
|
27
|
+
readonly key: symbol;
|
|
28
|
+
readonly kind: 'required' | 'optional' | 'lazy' | 'all';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Describe a positional dependency that supplies `undefined` only when the token is unbound.
|
|
32
|
+
* A present `undefined` value and acquisition failures remain present dependency results.
|
|
33
|
+
* @param token - The genuine typed token to read optionally.
|
|
34
|
+
* @returns An immutable reference accepted by positional provider adapters.
|
|
35
|
+
*/
|
|
36
|
+
export declare function optional<T extends TokenBase>(token: T & TokenTupleAdmission<readonly [T]>, ...invalid: [T] extends [never] ? [TokenTupleAdmission<readonly [T]>] : []): OptionalDependency<T>;
|
|
37
|
+
/**
|
|
38
|
+
* Describe a positional dependency supplied as an on-demand lookup function.
|
|
39
|
+
* Each invocation follows the target lifetime and records its dependency edge then.
|
|
40
|
+
* @param token - The genuine typed token to resolve lazily.
|
|
41
|
+
* @returns An immutable lazy reference accepted by positional provider adapters.
|
|
42
|
+
*/
|
|
43
|
+
export declare function lazy<T extends TokenBase>(token: T & TokenTupleAdmission<readonly [T]>, ...invalid: [T] extends [never] ? [TokenTupleAdmission<readonly [T]>] : []): LazyDependency<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Describe a positional dependency containing every contribution for a token.
|
|
46
|
+
* @param token - The genuine collection token.
|
|
47
|
+
* @returns An immutable reference that supplies a fresh frozen array, including when empty.
|
|
48
|
+
*/
|
|
49
|
+
export declare function all<T extends TokenBase>(token: T & TokenTupleAdmission<readonly [T]>, ...invalid: [T] extends [never] ? [TokenTupleAdmission<readonly [T]>] : []): CollectionDependency<T>;
|
|
50
|
+
/** Indexed snapshots ignore tuple iterators and retain only authenticated records. */
|
|
51
|
+
export declare function snapshotReferences(value: unknown): readonly ArgumentReference[];
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.optional = optional;
|
|
4
|
+
exports.lazy = lazy;
|
|
5
|
+
exports.all = all;
|
|
6
|
+
exports.snapshotReferences = snapshotReferences;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
const tokens_1 = require("./tokens");
|
|
9
|
+
class ReferenceBase {
|
|
10
|
+
}
|
|
11
|
+
class DependencyHandle extends ReferenceBase {
|
|
12
|
+
}
|
|
13
|
+
const references = new WeakMap();
|
|
14
|
+
function reference(token, kind) {
|
|
15
|
+
const key = (0, tokens_1.readTokenKey)(token);
|
|
16
|
+
const handle = new DependencyHandle();
|
|
17
|
+
references.set(handle, Object.freeze({ key, kind }));
|
|
18
|
+
Object.freeze(handle);
|
|
19
|
+
return handle;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Describe a positional dependency that supplies `undefined` only when the token is unbound.
|
|
23
|
+
* A present `undefined` value and acquisition failures remain present dependency results.
|
|
24
|
+
* @param token - The genuine typed token to read optionally.
|
|
25
|
+
* @returns An immutable reference accepted by positional provider adapters.
|
|
26
|
+
*/
|
|
27
|
+
function optional(token, ...invalid) { return reference(token, 'optional'); }
|
|
28
|
+
/**
|
|
29
|
+
* Describe a positional dependency supplied as an on-demand lookup function.
|
|
30
|
+
* Each invocation follows the target lifetime and records its dependency edge then.
|
|
31
|
+
* @param token - The genuine typed token to resolve lazily.
|
|
32
|
+
* @returns An immutable lazy reference accepted by positional provider adapters.
|
|
33
|
+
*/
|
|
34
|
+
function lazy(token, ...invalid) { return reference(token, 'lazy'); }
|
|
35
|
+
/**
|
|
36
|
+
* Describe a positional dependency containing every contribution for a token.
|
|
37
|
+
* @param token - The genuine collection token.
|
|
38
|
+
* @returns An immutable reference that supplies a fresh frozen array, including when empty.
|
|
39
|
+
*/
|
|
40
|
+
function all(token, ...invalid) { return reference(token, 'all'); }
|
|
41
|
+
/** Indexed snapshots ignore tuple iterators and retain only authenticated records. */
|
|
42
|
+
function snapshotReferences(value) {
|
|
43
|
+
if (!Array.isArray(value))
|
|
44
|
+
throw (0, errors_1.libraryError)('DI_BAG_INVALID_TOKEN', 'tokens must be a tuple', { operation: 'token' });
|
|
45
|
+
const selected = [];
|
|
46
|
+
const length = value.length;
|
|
47
|
+
for (let index = 0; index < length; index++)
|
|
48
|
+
selected[index] = value[index];
|
|
49
|
+
return Object.freeze(selected.map(handle => {
|
|
50
|
+
const retained = typeof handle === 'object' && handle !== null ? references.get(handle) : undefined;
|
|
51
|
+
return Object.freeze({ slot: Symbol('argument'), key: retained?.key ?? (0, tokens_1.readTokenKey)(handle), kind: retained?.kind ?? 'required' });
|
|
52
|
+
}));
|
|
53
|
+
}
|
package/dist/di-bag.d.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import type { ObserverOptions } from './observers';
|
|
2
|
+
import type { BuilderContribute, CollectionMember } from './contribution-types';
|
|
3
|
+
import type { AliasSelection, AliasAdmission, AliasTarget, AliasDestination, AliasEntry, AliasEntries } from './alias-types';
|
|
4
|
+
import { optional, lazy, all } from './dependency-references';
|
|
5
|
+
import { withDisposal } from './registration';
|
|
6
|
+
import type { FactoryWithDisposal, Factory, Registration, Registrations } from './registration';
|
|
7
|
+
import { BindingGraph, BagRuntime } from './runtime';
|
|
8
|
+
import type { Module } from './module';
|
|
9
|
+
import type { CheckedConstraints, CompleteConstraints, ExternalRequirements, IncrementalConstraints, ModulePublicProviders, ModuleSealedConstraints, NeedConstraint } from './module-types';
|
|
10
|
+
import type { CheckedLifetimes } from './lifetime-types';
|
|
11
|
+
import { withLifetime } from './lifetime';
|
|
12
|
+
import { fromFactory } from './acquisition-context';
|
|
13
|
+
import type { ScopeOptions, DisjointScopeSelection, UnsharedAliases, ScopedAliases } from './scope-types';
|
|
14
|
+
import type { CheckedScopeLifetimes } from './lifetime-types';
|
|
15
|
+
import type { StartupOptions } from './startup';
|
|
16
|
+
import { withMetadata, transformService } from './provider';
|
|
17
|
+
import { fromFunction, fromClass } from './composition';
|
|
18
|
+
import type { RuntimeContext, RuntimeOptions } from './acquisition-mode';
|
|
19
|
+
import type { ProviderRegistrationMetadata, ProviderAcquisitionMetadata } from './provider';
|
|
20
|
+
import type { RegistrationSnapshot } from './inspection';
|
|
21
|
+
import { token } from './tokens';
|
|
22
|
+
import type { PluginProviderFactory } from './plugins';
|
|
23
|
+
import type { TokenBase, TokenKey, TokenService } from './tokens';
|
|
24
|
+
import type { TokenBinding, BindingOutput, TokenMember, TokenTupleAdmission, SelectionKey, ReboundSelection } from './token-types';
|
|
25
|
+
import type { BuilderReplacementRegistration, ReplacementAdmission, ReplacedEntries, ZeroDependencyAdmission } from './replacement-types';
|
|
26
|
+
import type { CheckDependencyCompatibility, CheckDependencyCompleteness, RegistrationEntries, Entry, EntryKeys, OverrideFactoryContext, RegistrationsFromEntries, IncrementalChecked, Introduces, IntroducesKeys, OverrideRegistrations, Overrides, ServicesOf, ReplacementKeyOf, ReplacementOutput, SelectedRegistrations, Selection, NamedAdmission } from './types';
|
|
27
|
+
type ReplacementFactory<O> = (this: void) => O;
|
|
28
|
+
declare const constraintInvariant: unique symbol;
|
|
29
|
+
/**
|
|
30
|
+
* A resolving container with lazy acquisition, caching, and independent resource ownership.
|
|
31
|
+
*
|
|
32
|
+
* Create bags through {@link DiBagApi.createBuilder} followed by {@link Builder.build} or
|
|
33
|
+
* {@link Builder.buildAndStart}; the class is exported as a type and has no public constructor.
|
|
34
|
+
*/
|
|
35
|
+
declare class Bag<R extends Registrations, C extends NeedConstraint = never> {
|
|
36
|
+
#private;
|
|
37
|
+
private readonly context;
|
|
38
|
+
/** @internal */
|
|
39
|
+
readonly [constraintInvariant]: (value: C) => C;
|
|
40
|
+
constructor(graph: BindingGraph, context: RuntimeContext, runtime?: BagRuntime);
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a named or typed-token service, acquiring it lazily when needed.
|
|
43
|
+
* Scoped and root services are cached according to their lifetime; transient services
|
|
44
|
+
* create a new acquisition for each call. Promise-valued services keep their identity.
|
|
45
|
+
* @param token - An existing public string name or typed token.
|
|
46
|
+
* @returns The service exposed by the selected registration.
|
|
47
|
+
* @throws If the bag is closing, the token is invalid, acquisition fails, or a runtime cycle is found.
|
|
48
|
+
*/
|
|
49
|
+
resolve<K extends (keyof R & string) | TokenBase>(token: K & ([K] extends [string] ? unknown : TokenMember<R, K>)): ServicesOf<R>[SelectionKey<K> & keyof R];
|
|
50
|
+
/**
|
|
51
|
+
* Resolve every contribution for a typed token in declaration and installation order.
|
|
52
|
+
* @param token - The collection token whose contributions to acquire.
|
|
53
|
+
* @returns A fresh frozen array; an unpopulated collection returns an empty array.
|
|
54
|
+
* @throws If the bag is closing, the token is invalid, or a contribution fails.
|
|
55
|
+
*/
|
|
56
|
+
resolveAll<T extends TokenBase>(token: T & TokenTupleAdmission<readonly [T]> & CollectionMember<T, C>, ...invalid: [T] extends [never] ? [never] : []): ReadonlyArray<TokenService<T>>;
|
|
57
|
+
/**
|
|
58
|
+
* Inspect every contribution for a token without running its factories.
|
|
59
|
+
* @param token - The collection token to inspect.
|
|
60
|
+
* @returns Frozen snapshots in contribution order.
|
|
61
|
+
*/
|
|
62
|
+
inspectAll<T extends TokenBase>(token: T & TokenTupleAdmission<readonly [T]> & CollectionMember<T, C>, ...invalid: [T] extends [never] ? [never] : []): readonly RegistrationSnapshot<object, readonly unknown[]>[];
|
|
63
|
+
/**
|
|
64
|
+
* Inspect static metadata and copied acquisition state without resolving a service.
|
|
65
|
+
* @param token - An existing public string name or typed token.
|
|
66
|
+
* @returns A frozen point-in-time snapshot. Application-owned metadata payloads are not frozen.
|
|
67
|
+
*/
|
|
68
|
+
inspect<K extends (keyof R & string) | TokenBase>(token: K & ([K] extends [string] ? unknown : TokenMember<R, K>)): RegistrationSnapshot<ProviderRegistrationMetadata<R[SelectionKey<K> & keyof R]>, ProviderAcquisitionMetadata<R[SelectionKey<K> & keyof R]>>;
|
|
69
|
+
/**
|
|
70
|
+
* Create a tracked child that borrows selected parent acquisitions.
|
|
71
|
+
* @param options - A checked selection of non-transient services to share lazily.
|
|
72
|
+
* @returns A child owned by this bag; closing the parent closes the child first.
|
|
73
|
+
*/
|
|
74
|
+
createScope<const S extends readonly unknown[]>(options: ScopeOptions<R, S>): Bag<ScopedAliases<R, R, S>, C>;
|
|
75
|
+
/**
|
|
76
|
+
* Create a tracked child with selected replacements and optional parent sharing.
|
|
77
|
+
* @param keys - Existing names or tokens to replace in the child.
|
|
78
|
+
* @param overrides - Own registration properties for every selected key.
|
|
79
|
+
* @param options - A disjoint selection of non-transient parent acquisitions to share.
|
|
80
|
+
* @returns A child with fresh scoped acquisitions and ownership for unshared services.
|
|
81
|
+
* @throws If the runtime selections, overrides, or sharing options are invalid.
|
|
82
|
+
*/
|
|
83
|
+
createScope<const K extends readonly unknown[], O extends OverrideFactoryContext<R, K, O>, const S extends readonly unknown[] = readonly []>(keys: K & Selection<R, K, 'createScope'>, overrides: O & object & Record<SelectionKey<K[number]>, Registration> & Overrides<R, SelectedRegistrations<K, O>> & CheckDependencyCompatibility<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckDependencyCompleteness<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckedConstraints<C, OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CompleteConstraints<C, OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckedScopeLifetimes<NoInfer<ScopedAliases<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>, R, S>>, NoInfer<SelectedRegistrations<K, O>>, C>, options?: ScopeOptions<R, S> & DisjointScopeSelection<K, S>): Bag<ScopedAliases<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>, R, S>, C>;
|
|
84
|
+
/**
|
|
85
|
+
* Create a tracked child with the same graph and fresh scoped acquisitions.
|
|
86
|
+
* @returns A child that is closed before its parent finishes closing.
|
|
87
|
+
*/
|
|
88
|
+
createScope(): Bag<UnsharedAliases<R>, C>;
|
|
89
|
+
/**
|
|
90
|
+
* Create an independent bag with the same graph and fresh instances.
|
|
91
|
+
* @returns A new ownership family that must be closed separately.
|
|
92
|
+
*/
|
|
93
|
+
fork(this: Bag<R, C> & CheckedLifetimes<UnsharedAliases<R>, C>): Bag<UnsharedAliases<R>, C>;
|
|
94
|
+
/**
|
|
95
|
+
* Create an independent bag with selected replacements.
|
|
96
|
+
* @param keys - Existing names or tokens to replace.
|
|
97
|
+
* @param overrides - Own registration properties for every selected key.
|
|
98
|
+
* @returns A fresh ownership family whose graph uses the checked replacements.
|
|
99
|
+
* @throws If a selected key is absent or lacks an own override.
|
|
100
|
+
*/
|
|
101
|
+
fork<const K extends readonly unknown[], O extends OverrideFactoryContext<R, K, O>>(keys: K & Selection<R, K>, overrides: O & object & Record<SelectionKey<K[number]>, Registration> & Overrides<R, SelectedRegistrations<K, O>> & CheckDependencyCompatibility<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckDependencyCompleteness<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckedConstraints<C, OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CompleteConstraints<C, OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>> & CheckedLifetimes<UnsharedAliases<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>>, C>): Bag<UnsharedAliases<OverrideRegistrations<R, ReboundSelection<R, SelectedRegistrations<K, O>>>>, C>;
|
|
102
|
+
/**
|
|
103
|
+
* Close this bag, drain in-flight work, and dispose owned resources once.
|
|
104
|
+
* Dependents are disposed before dependencies; remaining independent acquisitions use
|
|
105
|
+
* reverse acquisition order. Repeated calls return the same promise.
|
|
106
|
+
* @returns The shared shutdown promise.
|
|
107
|
+
* @throws {@link DiBagCleanupError} when one or more disposers fail after all cleanup is attempted.
|
|
108
|
+
*/
|
|
109
|
+
close(): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* An immutable, type-checked graph builder. Every operation returns a new builder.
|
|
113
|
+
* Create one with {@link DiBagApi.createBuilder}. The same builder value can
|
|
114
|
+
* {@link Builder.build} a bag once its graph is complete, or
|
|
115
|
+
* {@link Builder.buildModule} a reusable module whose unmet dependencies become
|
|
116
|
+
* requirements the installing host must satisfy.
|
|
117
|
+
*/
|
|
118
|
+
declare class Builder<E extends Entry, C extends NeedConstraint = never> {
|
|
119
|
+
#private;
|
|
120
|
+
private readonly context;
|
|
121
|
+
/** @internal */
|
|
122
|
+
readonly [constraintInvariant]: (value: readonly [E, C]) => readonly [E, C];
|
|
123
|
+
constructor(graph: BindingGraph, context: RuntimeContext);
|
|
124
|
+
/**
|
|
125
|
+
* Add new string-named registrations.
|
|
126
|
+
* @param more - A finite object whose own string keys are service names and values are registrations.
|
|
127
|
+
* @returns A new builder containing snapshots of the supplied registrations.
|
|
128
|
+
* @throws If the input is malformed, contains a non-string key, or duplicates a public name.
|
|
129
|
+
*/
|
|
130
|
+
register<N extends {
|
|
131
|
+
[K in keyof N]: Registration;
|
|
132
|
+
}>(more: N & Registrations & ([N] extends [never] ? never : NamedAdmission<N> & IntroducesKeys<EntryKeys<E>, keyof N> & IncrementalChecked<E, N> & CheckedConstraints<C, OverrideRegistrations<RegistrationsFromEntries<E>, N>>)): Builder<E | RegistrationEntries<N>, C>;
|
|
133
|
+
/**
|
|
134
|
+
* Register a provider to a typed token.
|
|
135
|
+
* @param token - A new typed token identity.
|
|
136
|
+
* @param registration - A registration whose exposed output satisfies the token service type.
|
|
137
|
+
* @returns A new builder retaining the provider's metadata, lifetime, dependencies, and ownership stages.
|
|
138
|
+
*/
|
|
139
|
+
register<T extends TokenBase, V extends Registration>(token: T & TokenTupleAdmission<readonly [T]> & IntroducesKeys<EntryKeys<E>, TokenKey<T>>, registration: V & Registration & BindingOutput<NoInfer<T>, NoInfer<V>> & IncrementalChecked<E, Record<TokenKey<T>, TokenBinding<NoInfer<T>, NoInfer<V>>>> & CheckedConstraints<C, OverrideRegistrations<RegistrationsFromEntries<E>, Record<TokenKey<T>, TokenBinding<NoInfer<T>, NoInfer<V>>>>>): Builder<E | {
|
|
140
|
+
key: TokenKey<T>;
|
|
141
|
+
registration: TokenBinding<T, V>;
|
|
142
|
+
}, C>;
|
|
143
|
+
/**
|
|
144
|
+
* Add another lookup name or token for an existing service.
|
|
145
|
+
* @param destination - A new string name or typed token.
|
|
146
|
+
* @param target - The existing name or token whose canonical acquisition is reused.
|
|
147
|
+
* @returns A new builder; aliases add no cache or ownership of their own.
|
|
148
|
+
*/
|
|
149
|
+
alias<const D extends AliasSelection, const T extends AliasSelection>(destination: D & (unknown extends AliasAdmission<D> ? Introduces<RegistrationsFromEntries<E>, AliasEntries<RegistrationsFromEntries<E>, D, T>> : AliasAdmission<D>), target: T & AliasAdmission<T> & (unknown extends AliasAdmission<T> ? AliasTarget<RegistrationsFromEntries<E>, T> & AliasDestination<RegistrationsFromEntries<E>, NoInfer<D>, T> : unknown) & (unknown extends AliasAdmission<D> & AliasAdmission<T> ? IncrementalChecked<E, AliasEntries<RegistrationsFromEntries<E>, NoInfer<D>, NoInfer<T>>> & CheckedConstraints<C, OverrideRegistrations<RegistrationsFromEntries<E>, AliasEntries<RegistrationsFromEntries<E>, NoInfer<D>, NoInfer<T>>>> : unknown), ...invalid: [D] extends [never] ? [never] : [T] extends [never] ? [never] : []): Builder<E | AliasEntry<RegistrationsFromEntries<E>, D, T>, C>;
|
|
150
|
+
/**
|
|
151
|
+
* Append a provider to a typed-token collection.
|
|
152
|
+
* @param token - The collection's typed token.
|
|
153
|
+
* @param registration - A registration whose output satisfies the token service type.
|
|
154
|
+
* @returns A new builder preserving contribution order.
|
|
155
|
+
*/
|
|
156
|
+
readonly contribute: BuilderContribute<E, C>;
|
|
157
|
+
/**
|
|
158
|
+
* Replace an existing string-named registration with a dependency-free factory.
|
|
159
|
+
* @param key - One existing string-literal service name.
|
|
160
|
+
* @param registration - The replacement, checked against every surviving consumer.
|
|
161
|
+
* @returns A new builder with the replacement.
|
|
162
|
+
* @typeParam V - The exact replacement factory or disposable-factory type.
|
|
163
|
+
*/
|
|
164
|
+
replace<const K extends string, V extends (ReplacementFactory<ReplacementOutput<NoInfer<RegistrationsFromEntries<E>>, K, C>>) | FactoryWithDisposal<ReplacementFactory<ReplacementOutput<NoInfer<RegistrationsFromEntries<E>>, K, C>>>>(key: K & ReplacementKeyOf<EntryKeys<E>, K>, registration: V & (Factory | FactoryWithDisposal<Factory>) & ZeroDependencyAdmission<NoInfer<V>> & CheckedConstraints<C, OverrideRegistrations<RegistrationsFromEntries<E>, Record<K, NoInfer<V>>>>): Builder<Exclude<E, {
|
|
165
|
+
key: K;
|
|
166
|
+
}> | {
|
|
167
|
+
key: K;
|
|
168
|
+
registration: V;
|
|
169
|
+
}, C>;
|
|
170
|
+
/**
|
|
171
|
+
* Replace an existing named or typed-token registration.
|
|
172
|
+
* @param key - The single existing name or token to replace.
|
|
173
|
+
* @param registration - A replacement compatible with the token and known consumers.
|
|
174
|
+
* @returns A new builder with the replacement and its inferred service type.
|
|
175
|
+
*/
|
|
176
|
+
replace<const K extends string | TokenBase, V extends Registration>(key: K & NoInfer<ReplacementAdmission<RegistrationsFromEntries<E>, K>>, registration: V & Registration & BuilderReplacementRegistration<E, C, NoInfer<K>, V>): Builder<ReplacedEntries<E, K, V>, C>;
|
|
177
|
+
/**
|
|
178
|
+
* Install a sealed module, allocating fresh private bindings for this installation.
|
|
179
|
+
* @param module - A module whose public names do not collide and whose external requirements remain checkable.
|
|
180
|
+
* @returns A new builder exposing only the module's selected exports.
|
|
181
|
+
*/
|
|
182
|
+
installModule<P extends object, R extends object, MC extends NeedConstraint, D extends Registrations>(module: Module<P, R, MC, D> & IntroducesKeys<EntryKeys<E>, keyof D> & IncrementalChecked<E, D> & IncrementalConstraints<C, MC, RegistrationsFromEntries<E>, D>): Builder<E | RegistrationEntries<D>, C | MC>;
|
|
183
|
+
/**
|
|
184
|
+
* Seal this graph as a reusable module and select its public names and typed tokens.
|
|
185
|
+
* Unselected registrations stay private to each installation; unmet dependencies
|
|
186
|
+
* become requirements of the module. Installed modules nest: their private
|
|
187
|
+
* bindings and retained constraints are re-scoped inside this module.
|
|
188
|
+
* @param keys - A finite tuple of existing names or tokens; an empty tuple is allowed.
|
|
189
|
+
* @returns An immutable module that can be renamed or installed in another builder.
|
|
190
|
+
* @throws If the selection is not a tuple or contains an absent name or token.
|
|
191
|
+
*/
|
|
192
|
+
buildModule<const K extends readonly unknown[]>(keys: K & Selection<RegistrationsFromEntries<E>, K, 'buildModule'>): Module<Pick<ServicesOf<RegistrationsFromEntries<E>>, Extract<SelectionKey<K[number]>, keyof RegistrationsFromEntries<E>>>, ExternalRequirements<ModuleSealedConstraints<E, C, Extract<SelectionKey<K[number]>, keyof RegistrationsFromEntries<E>>>>, ModuleSealedConstraints<E, C, Extract<SelectionKey<K[number]>, keyof RegistrationsFromEntries<E>>>, ModulePublicProviders<RegistrationsFromEntries<E>, Extract<SelectionKey<K[number]>, keyof RegistrationsFromEntries<E>>>>;
|
|
193
|
+
/**
|
|
194
|
+
* Finish a complete graph as a lazy bag.
|
|
195
|
+
* @returns A fresh bag that owns the acquisitions it creates.
|
|
196
|
+
* @throws At runtime if automatic acquisition is used without a configured Promise classifier.
|
|
197
|
+
*/
|
|
198
|
+
build(this: Builder<E, C> & CheckDependencyCompleteness<RegistrationsFromEntries<E>> & CompleteConstraints<C, RegistrationsFromEntries<E>> & CheckedLifetimes<RegistrationsFromEntries<E>, C>): Bag<RegistrationsFromEntries<E>, C>;
|
|
199
|
+
/**
|
|
200
|
+
* Create a fresh bag and acquire selected services before returning it.
|
|
201
|
+
* @param keys - A finite tuple of existing names or typed tokens to make ready.
|
|
202
|
+
* @param options - Optional cancellation signal, positive timeout, and parallel, sequential, or positive safe integer bounded scheduling.
|
|
203
|
+
* @returns A promise for the new bag after every selected final stage is ready.
|
|
204
|
+
* @throws {@link DiBagStartupError} after rollback on acquisition failure, or
|
|
205
|
+
* {@link DiBagStartupCancelledError} promptly on abort or timeout.
|
|
206
|
+
*/
|
|
207
|
+
buildAndStart<const K extends readonly unknown[]>(this: Builder<E, C> & CheckDependencyCompleteness<RegistrationsFromEntries<E>> & CompleteConstraints<C, RegistrationsFromEntries<E>> & CheckedLifetimes<RegistrationsFromEntries<E>, C>, keys: K & Selection<RegistrationsFromEntries<E>, K, 'buildAndStart'>, options?: StartupOptions): Promise<Bag<RegistrationsFromEntries<E>, C>>;
|
|
208
|
+
}
|
|
209
|
+
export type { Bag, Builder };
|
|
210
|
+
/** Immutable facade configuration. Observers append in the supplied order. */
|
|
211
|
+
export interface ConfigurationOptions {
|
|
212
|
+
readonly runtime?: RuntimeOptions;
|
|
213
|
+
readonly observers?: readonly ObserverOptions[];
|
|
214
|
+
}
|
|
215
|
+
/** The immutable public entry surface used by {@link DiBag} and derived facades. */
|
|
216
|
+
export interface DiBagApi {
|
|
217
|
+
/** Return a facade with inherited runtime settings and appended observers. */
|
|
218
|
+
withConfiguration: (options: ConfigurationOptions) => DiBagApi;
|
|
219
|
+
/** Describe a named-dependency factory, optionally receiving acquisition context. */
|
|
220
|
+
fromFactory: typeof fromFactory;
|
|
221
|
+
/** Create a nominal typed token with a diagnostic label. */
|
|
222
|
+
token: typeof token;
|
|
223
|
+
/** Create a positional dependency that yields undefined only when unregistered. */
|
|
224
|
+
optional: typeof optional;
|
|
225
|
+
/** Create a positional dependency resolved on demand by the receiving service. */
|
|
226
|
+
lazy: typeof lazy;
|
|
227
|
+
/** Create a positional dependency containing ordered collection contributions. */
|
|
228
|
+
all: typeof all;
|
|
229
|
+
/** Validate an unknown plugin descriptor and its acquired output at a checked boundary. */
|
|
230
|
+
fromPlugin: PluginProviderFactory;
|
|
231
|
+
/** Adapt a positional function with strict dependency tuple and argument checking. */
|
|
232
|
+
fromFunction: typeof fromFunction;
|
|
233
|
+
/** Adapt a concrete constructor with positional dependency injection. */
|
|
234
|
+
fromClass: typeof fromClass;
|
|
235
|
+
/** Begin an empty immutable graph; build creates its owning bag, buildModule seals a reusable module. */
|
|
236
|
+
createBuilder: () => Builder<never>;
|
|
237
|
+
/** Attach owned-value cleanup while retaining earlier disposal stages. */
|
|
238
|
+
withDisposal: typeof withDisposal;
|
|
239
|
+
/** Select root, scoped, or transient caching within an ownership family. */
|
|
240
|
+
withLifetime: typeof withLifetime;
|
|
241
|
+
/** Attach registration metadata and ordered acquisition metadata in direct or awaited mode. */
|
|
242
|
+
withMetadata: typeof withMetadata;
|
|
243
|
+
/** Transform the exposed service while retaining dependencies, metadata, lifetime, and existing ownership. */
|
|
244
|
+
transformService: typeof transformService;
|
|
245
|
+
}
|
|
246
|
+
/** The portable, immutable DI Bag facade. Configure `auto` acquisition or use explicit modes. */
|
|
247
|
+
export declare const DiBag: DiBagApi;
|
package/dist/di-bag.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiBag = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const observers_1 = require("./observers");
|
|
6
|
+
const contributions_1 = require("./contributions");
|
|
7
|
+
const aliases_1 = require("./aliases");
|
|
8
|
+
const dependency_references_1 = require("./dependency-references");
|
|
9
|
+
const registration_1 = require("./registration");
|
|
10
|
+
const runtime_1 = require("./runtime");
|
|
11
|
+
const module_1 = require("./module");
|
|
12
|
+
const lifetime_1 = require("./lifetime");
|
|
13
|
+
const acquisition_context_1 = require("./acquisition-context");
|
|
14
|
+
const startup_1 = require("./startup");
|
|
15
|
+
const scope_selection_1 = require("./scope-selection");
|
|
16
|
+
const provider_1 = require("./provider");
|
|
17
|
+
const composition_1 = require("./composition");
|
|
18
|
+
const acquisition_mode_1 = require("./acquisition-mode");
|
|
19
|
+
const tokens_1 = require("./tokens");
|
|
20
|
+
const plugins_1 = require("./plugins");
|
|
21
|
+
/**
|
|
22
|
+
* A resolving container with lazy acquisition, caching, and independent resource ownership.
|
|
23
|
+
*
|
|
24
|
+
* Create bags through {@link DiBagApi.createBuilder} followed by {@link Builder.build} or
|
|
25
|
+
* {@link Builder.buildAndStart}; the class is exported as a type and has no public constructor.
|
|
26
|
+
*/
|
|
27
|
+
class Bag {
|
|
28
|
+
context;
|
|
29
|
+
#graph;
|
|
30
|
+
#runtime;
|
|
31
|
+
constructor(graph, context, runtime) {
|
|
32
|
+
this.context = context;
|
|
33
|
+
this.#graph = graph;
|
|
34
|
+
this.#runtime = runtime ?? new runtime_1.BagRuntime(graph, context);
|
|
35
|
+
}
|
|
36
|
+
resolve(token) {
|
|
37
|
+
return this.#runtime.resolve(typeof token === 'string' ? token : (0, tokens_1.readTokenKey)(token));
|
|
38
|
+
}
|
|
39
|
+
resolveAll(token) { return this.#runtime.resolveAll((0, tokens_1.readTokenKey)(token)); }
|
|
40
|
+
inspectAll(token) { return this.#runtime.inspectAll((0, tokens_1.readTokenKey)(token)); }
|
|
41
|
+
inspect(token) {
|
|
42
|
+
return this.#runtime.inspect(typeof token === 'string' ? token : (0, tokens_1.readTokenKey)(token));
|
|
43
|
+
}
|
|
44
|
+
createScope(...args) {
|
|
45
|
+
this.#runtime.assertOpen();
|
|
46
|
+
const { graph, shared } = (0, scope_selection_1.selectScope)(this.#graph, args, key => this.#runtime.isTransient(key));
|
|
47
|
+
return new Bag(graph, this.context, this.#runtime.scope(graph, shared));
|
|
48
|
+
}
|
|
49
|
+
fork(keys, overrides) {
|
|
50
|
+
this.#runtime.assertOpen();
|
|
51
|
+
if (keys === undefined && overrides === undefined) {
|
|
52
|
+
return new Bag(this.#graph, this.context);
|
|
53
|
+
}
|
|
54
|
+
if (!Array.isArray(keys) ||
|
|
55
|
+
typeof overrides !== 'object' ||
|
|
56
|
+
overrides === null) {
|
|
57
|
+
throw (0, errors_1.libraryError)('DI_BAG_INVALID_OVERRIDE', 'fork requires selected keys and an override object', { operation: 'fork' });
|
|
58
|
+
}
|
|
59
|
+
// Snapshot indexed entries before override getters can mutate the tuple.
|
|
60
|
+
// A tuple's custom iterator need not enumerate its declared indexed keys.
|
|
61
|
+
const selectedKeys = [];
|
|
62
|
+
const length = keys.length;
|
|
63
|
+
for (let index = 0; index < length; index++) {
|
|
64
|
+
selectedKeys[index] = keys[index];
|
|
65
|
+
}
|
|
66
|
+
if (selectedKeys.length === 0)
|
|
67
|
+
return new Bag(this.#graph, this.context);
|
|
68
|
+
const publicKeys = selectedKeys.map(value => typeof value === 'string' ? value : (0, tokens_1.readTokenKey)(value));
|
|
69
|
+
for (const token of publicKeys) {
|
|
70
|
+
if (!this.#graph.hasPublic(token)) {
|
|
71
|
+
throw (0, errors_1.libraryError)('DI_BAG_INVALID_OVERRIDE', `fork accepts existing names or typed tokens only: ${String(token)}`, { operation: 'fork' });
|
|
72
|
+
}
|
|
73
|
+
if (!Object.hasOwn(overrides, token)) {
|
|
74
|
+
throw (0, errors_1.libraryError)('DI_BAG_INVALID_OVERRIDE', `missing override: ${String(token)}`, { operation: 'fork' });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const selectedBindings = [];
|
|
78
|
+
for (const token of publicKeys) {
|
|
79
|
+
const registration = Reflect.get(overrides, token);
|
|
80
|
+
(0, registration_1.normalize)(registration);
|
|
81
|
+
selectedBindings.push([token, registration]);
|
|
82
|
+
}
|
|
83
|
+
return new Bag(this.#graph.withPublicBindings(selectedBindings), this.context);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Close this bag, drain in-flight work, and dispose owned resources once.
|
|
87
|
+
* Dependents are disposed before dependencies; remaining independent acquisitions use
|
|
88
|
+
* reverse acquisition order. Repeated calls return the same promise.
|
|
89
|
+
* @returns The shared shutdown promise.
|
|
90
|
+
* @throws {@link DiBagCleanupError} when one or more disposers fail after all cleanup is attempted.
|
|
91
|
+
*/
|
|
92
|
+
close() {
|
|
93
|
+
return this.#runtime.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* An immutable, type-checked graph builder. Every operation returns a new builder.
|
|
98
|
+
* Create one with {@link DiBagApi.createBuilder}. The same builder value can
|
|
99
|
+
* {@link Builder.build} a bag once its graph is complete, or
|
|
100
|
+
* {@link Builder.buildModule} a reusable module whose unmet dependencies become
|
|
101
|
+
* requirements the installing host must satisfy.
|
|
102
|
+
*/
|
|
103
|
+
class Builder {
|
|
104
|
+
context;
|
|
105
|
+
#graph;
|
|
106
|
+
constructor(graph, context) {
|
|
107
|
+
this.context = context;
|
|
108
|
+
this.#graph = graph;
|
|
109
|
+
}
|
|
110
|
+
register(moreOrToken, registration) {
|
|
111
|
+
if (arguments.length === 1) {
|
|
112
|
+
const snapshot = (0, registration_1.snapshotAdd)(moreOrToken, key => this.#graph.hasPublic(key));
|
|
113
|
+
return new Builder(this.#graph.withPublicRegistrations(snapshot), this.context);
|
|
114
|
+
}
|
|
115
|
+
const key = (0, tokens_1.readTokenKey)(moreOrToken);
|
|
116
|
+
if (this.#graph.hasPublic(key))
|
|
117
|
+
throw (0, errors_1.libraryError)('DI_BAG_DUPLICATE_REGISTRATION', `duplicate registration: ${String(key)}`, { operation: 'register', key });
|
|
118
|
+
return new Builder(this.#graph.withPublicBinding(key, (0, provider_1.withTokenBinding)(moreOrToken, registration)), this.context);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Add another lookup name or token for an existing service.
|
|
122
|
+
* @param destination - A new string name or typed token.
|
|
123
|
+
* @param target - The existing name or token whose canonical acquisition is reused.
|
|
124
|
+
* @returns A new builder; aliases add no cache or ownership of their own.
|
|
125
|
+
*/
|
|
126
|
+
alias(destination, target, ...invalid) {
|
|
127
|
+
const [key, registration] = (0, aliases_1.aliasEntry)(destination, target, key => this.#graph.hasPublic(key));
|
|
128
|
+
return new Builder(this.#graph.withPublicBinding(key, registration), this.context);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Append a provider to a typed-token collection.
|
|
132
|
+
* @param token - The collection's typed token.
|
|
133
|
+
* @param registration - A registration whose output satisfies the token service type.
|
|
134
|
+
* @returns A new builder preserving contribution order.
|
|
135
|
+
*/
|
|
136
|
+
// A named callable keeps extracted generic methods nameable in consumer declarations.
|
|
137
|
+
contribute = ((token, registration) => {
|
|
138
|
+
const [key, value] = (0, contributions_1.contributionEntry)(token, registration);
|
|
139
|
+
return new Builder(this.#graph.withContribution(key, value), this.context);
|
|
140
|
+
});
|
|
141
|
+
replace(selection, registration) {
|
|
142
|
+
const key = typeof selection === 'string' ? selection : (0, tokens_1.readTokenKey)(selection);
|
|
143
|
+
if (!this.#graph.hasPublic(key)) {
|
|
144
|
+
throw (0, errors_1.libraryError)('DI_BAG_INVALID_REPLACEMENT', `replace accepts existing names or typed tokens only: ${String(key)}`, { operation: 'replace', key });
|
|
145
|
+
}
|
|
146
|
+
(0, registration_1.normalize)(registration);
|
|
147
|
+
return new Builder(this.#graph.withPublicBinding(key, registration), this.context);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Install a sealed module, allocating fresh private bindings for this installation.
|
|
151
|
+
* @param module - A module whose public names do not collide and whose external requirements remain checkable.
|
|
152
|
+
* @returns A new builder exposing only the module's selected exports.
|
|
153
|
+
*/
|
|
154
|
+
installModule(module) {
|
|
155
|
+
return new Builder(this.#graph.withInstallation((0, module_1.moduleGraph)(module)), this.context);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Seal this graph as a reusable module and select its public names and typed tokens.
|
|
159
|
+
* Unselected registrations stay private to each installation; unmet dependencies
|
|
160
|
+
* become requirements of the module. Installed modules nest: their private
|
|
161
|
+
* bindings and retained constraints are re-scoped inside this module.
|
|
162
|
+
* @param keys - A finite tuple of existing names or tokens; an empty tuple is allowed.
|
|
163
|
+
* @returns An immutable module that can be renamed or installed in another builder.
|
|
164
|
+
* @throws If the selection is not a tuple or contains an absent name or token.
|
|
165
|
+
*/
|
|
166
|
+
buildModule(keys) {
|
|
167
|
+
return (0, module_1.sealModule)(this.#graph, keys);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Finish a complete graph as a lazy bag.
|
|
171
|
+
* @returns A fresh bag that owns the acquisitions it creates.
|
|
172
|
+
* @throws At runtime if automatic acquisition is used without a configured Promise classifier.
|
|
173
|
+
*/
|
|
174
|
+
build() {
|
|
175
|
+
return new Bag(this.#graph, this.context);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Create a fresh bag and acquire selected services before returning it.
|
|
179
|
+
* @param keys - A finite tuple of existing names or typed tokens to make ready.
|
|
180
|
+
* @param options - Optional cancellation signal, positive timeout, and parallel, sequential, or positive safe integer bounded scheduling.
|
|
181
|
+
* @returns A promise for the new bag after every selected final stage is ready.
|
|
182
|
+
* @throws {@link DiBagStartupError} after rollback on acquisition failure, or
|
|
183
|
+
* {@link DiBagStartupCancelledError} promptly on abort or timeout.
|
|
184
|
+
*/
|
|
185
|
+
async buildAndStart(keys, options) {
|
|
186
|
+
const runtime = await (0, startup_1.startRuntime)(this.#graph, this.context, keys, options);
|
|
187
|
+
return new Bag(this.#graph, this.context, runtime);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function facade(context) {
|
|
191
|
+
return Object.freeze({
|
|
192
|
+
withConfiguration: (options) => {
|
|
193
|
+
if (typeof options !== 'object' || options === null || Array.isArray(options))
|
|
194
|
+
throw (0, errors_1.libraryTypeError)('DI_BAG_INVALID_CONFIGURATION', 'withConfiguration requires an options object', { operation: 'withConfiguration' });
|
|
195
|
+
const { runtime, observers } = options;
|
|
196
|
+
let configured = runtime === undefined ? context : (0, acquisition_mode_1.runtimeContext)(runtime, context);
|
|
197
|
+
if (observers !== undefined) {
|
|
198
|
+
if (!Array.isArray(observers))
|
|
199
|
+
throw (0, errors_1.libraryTypeError)('DI_BAG_INVALID_CONFIGURATION', 'withConfiguration observers must be an array', { operation: 'withConfiguration' });
|
|
200
|
+
for (const observer of observers)
|
|
201
|
+
configured = Object.freeze({ ...configured, observers: observers_1.LifecycleObservers.append(configured.observers, observer) });
|
|
202
|
+
}
|
|
203
|
+
return facade(configured);
|
|
204
|
+
},
|
|
205
|
+
fromFactory: acquisition_context_1.fromFactory, token: tokens_1.token, optional: dependency_references_1.optional, lazy: dependency_references_1.lazy, all: dependency_references_1.all, fromPlugin: plugins_1.fromPlugin, fromFunction: composition_1.fromFunction, fromClass: composition_1.fromClass,
|
|
206
|
+
createBuilder: () => new Builder(new runtime_1.BindingGraph(), context),
|
|
207
|
+
withDisposal: registration_1.withDisposal, withLifetime: lifetime_1.withLifetime, withMetadata: provider_1.withMetadata, transformService: provider_1.transformService,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/** The portable, immutable DI Bag facade. Configure `auto` acquisition or use explicit modes. */
|
|
211
|
+
exports.DiBag = facade(acquisition_mode_1.unconfigured);
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Stable category for a diagnostic created by DI Bag itself. */
|
|
2
|
+
export type DiBagErrorCode = `DI_BAG_${string}`;
|
|
3
|
+
/** Structured library diagnostics. Application-owned payloads retain their identity. */
|
|
4
|
+
export interface DiBagDiagnostic {
|
|
5
|
+
readonly code: DiBagErrorCode;
|
|
6
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
7
|
+
}
|
|
8
|
+
/** Attach only at library-owned error creation sites; never modify application errors. */
|
|
9
|
+
export declare function diagnostic<E extends Error>(error: E, code: DiBagErrorCode, details?: Readonly<Record<string, unknown>>): E & DiBagDiagnostic;
|
|
10
|
+
export declare function libraryError(code: DiBagErrorCode, message: string, details?: Readonly<Record<string, unknown>>): Error & DiBagDiagnostic;
|
|
11
|
+
export declare function libraryTypeError(code: DiBagErrorCode, message: string, details?: Readonly<Record<string, unknown>>): TypeError & DiBagDiagnostic;
|
|
12
|
+
/** One disposer failure, associated with the acquisition that owned it. */
|
|
13
|
+
export interface CleanupFailure {
|
|
14
|
+
readonly acquisitionId: symbol;
|
|
15
|
+
readonly bindingId: symbol;
|
|
16
|
+
readonly label: string;
|
|
17
|
+
readonly error: unknown;
|
|
18
|
+
}
|
|
19
|
+
/** A plugin descriptor or produced value crossed the checked plugin boundary. */
|
|
20
|
+
export declare class DiBagPluginValidationError extends Error {
|
|
21
|
+
readonly phase: 'descriptor' | 'output';
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
readonly code: 'DI_BAG_PLUGIN_VALIDATION';
|
|
24
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* @param phase - Whether descriptor authentication or output validation failed.
|
|
27
|
+
* @param reason - A stable description of the rejected boundary condition.
|
|
28
|
+
*/
|
|
29
|
+
constructor(phase: 'descriptor' | 'output', reason: string);
|
|
30
|
+
}
|
|
31
|
+
/** Original cleanup causes and detached acquisition diagnostics, in attempt order. */
|
|
32
|
+
export declare class DiBagCleanupError extends AggregateError {
|
|
33
|
+
readonly code: 'DI_BAG_CLEANUP_FAILED';
|
|
34
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
35
|
+
/** Frozen cleanup failures in finalizer invocation order. */
|
|
36
|
+
readonly failures: readonly CleanupFailure[];
|
|
37
|
+
/** @param failures - Structured failures whose original errors also populate `AggregateError.errors`. */
|
|
38
|
+
constructor(failures: readonly CleanupFailure[]);
|
|
39
|
+
}
|
|
40
|
+
/** Acquisition failure after the new bag has finished releasing its resources. */
|
|
41
|
+
export declare class DiBagStartupError extends Error {
|
|
42
|
+
readonly cleanupError?: unknown | undefined;
|
|
43
|
+
readonly code: 'DI_BAG_STARTUP_FAILED';
|
|
44
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
45
|
+
/** Frozen rollback disposal failures in invocation order. */
|
|
46
|
+
readonly cleanupFailures: readonly CleanupFailure[];
|
|
47
|
+
/**
|
|
48
|
+
* @param cause - The original selected-service acquisition failure.
|
|
49
|
+
* @param cleanupFailures - Structured failures collected while rolling back the new bag.
|
|
50
|
+
* @param cleanupError - The complete shutdown error, when rollback itself rejected.
|
|
51
|
+
*/
|
|
52
|
+
constructor(cause: unknown, cleanupFailures: readonly CleanupFailure[], cleanupError?: unknown | undefined);
|
|
53
|
+
}
|
|
54
|
+
/** Prompt cancellation; cleanup remains awaitable for uncooperative factories. */
|
|
55
|
+
export declare class DiBagStartupCancelledError extends Error {
|
|
56
|
+
readonly reason: 'aborted' | 'timeout';
|
|
57
|
+
readonly cleanupPromise: Promise<void>;
|
|
58
|
+
readonly code: 'DI_BAG_STARTUP_CANCELLED';
|
|
59
|
+
readonly details: Readonly<Record<string, unknown>>;
|
|
60
|
+
/**
|
|
61
|
+
* @param reason - Whether an external abort or startup timeout cancelled the wait.
|
|
62
|
+
* @param cause - The abort reason or generated timeout error.
|
|
63
|
+
* @param cleanupPromise - Eventual shutdown of the partially started bag; cancellation does not await it.
|
|
64
|
+
*/
|
|
65
|
+
constructor(reason: 'aborted' | 'timeout', cause: unknown, cleanupPromise: Promise<void>);
|
|
66
|
+
}
|