@zudojs/container 0.0.1 → 1.0.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/README.md +205 -8
- package/dist/containerCore/containerCore.core.d.ts +105 -14
- package/dist/containerCore/containerCore.core.js +211 -44
- package/dist/containerCore/containerCore.scope.d.ts +63 -18
- package/dist/containerCore/containerCore.scope.js +108 -29
- package/dist/containerCore/containerCore.type.d.ts +22 -16
- package/dist/containerLifecycle/containerLifecycle.core.d.ts +59 -9
- package/dist/containerLifecycle/containerLifecycle.core.js +58 -15
- package/dist/containerOptions/containerOptions.type.d.ts +7 -17
- package/dist/containerOptions/containerOptions.type.js +0 -19
- package/dist/containerProvider/containerProvider.core.d.ts +11 -3
- package/dist/containerProvider/containerProvider.core.js +11 -5
- package/dist/containerRegistration/containerRegistration.core.d.ts +9 -3
- package/dist/containerRegistration/containerRegistration.core.js +0 -6
- package/dist/containerRegistry/containerRegistry.core.d.ts +23 -9
- package/dist/containerRegistry/containerRegistry.core.js +50 -47
- package/dist/containerRegistry/containerRegistry.type.d.ts +3 -1
- package/dist/containerRegistry/containerRegistry.type.js +2 -0
- package/dist/containerRegistry/index.d.ts +0 -1
- package/dist/containerRegistry/index.js +0 -1
- package/dist/containerResolution/containerResolution.core.d.ts +42 -10
- package/dist/containerResolution/containerResolution.core.js +207 -64
- package/dist/containerResolution/containerResolution.error.d.ts +68 -3
- package/dist/containerResolution/containerResolution.error.js +107 -3
- package/dist/containerResolution/containerResolution.type.d.ts +35 -3
- package/dist/containerResolution/index.d.ts +1 -0
- package/dist/containerResolution/index.js +1 -0
- package/dist/containerToken/containerToken.type.d.ts +26 -1
- package/dist/containerToken/containerToken.type.js +18 -0
- package/package.json +17 -8
- package/dist/.tsbuildinfo +0 -1
- package/dist/containerCore/containerCore.core.d.ts.map +0 -1
- package/dist/containerCore/containerCore.core.js.map +0 -1
- package/dist/containerCore/containerCore.scope.d.ts.map +0 -1
- package/dist/containerCore/containerCore.scope.js.map +0 -1
- package/dist/containerCore/containerCore.type.d.ts.map +0 -1
- package/dist/containerCore/containerCore.type.js.map +0 -1
- package/dist/containerCore/index.d.ts.map +0 -1
- package/dist/containerCore/index.js.map +0 -1
- package/dist/containerLifecycle/containerLifecycle.core.d.ts.map +0 -1
- package/dist/containerLifecycle/containerLifecycle.core.js.map +0 -1
- package/dist/containerLifecycle/index.d.ts.map +0 -1
- package/dist/containerLifecycle/index.js.map +0 -1
- package/dist/containerOptions/containerOptions.type.d.ts.map +0 -1
- package/dist/containerOptions/containerOptions.type.js.map +0 -1
- package/dist/containerOptions/index.d.ts.map +0 -1
- package/dist/containerOptions/index.js.map +0 -1
- package/dist/containerProvider/containerProvider.core.d.ts.map +0 -1
- package/dist/containerProvider/containerProvider.core.js.map +0 -1
- package/dist/containerProvider/index.d.ts.map +0 -1
- package/dist/containerProvider/index.js.map +0 -1
- package/dist/containerRegistration/containerRegistration.core.d.ts.map +0 -1
- package/dist/containerRegistration/containerRegistration.core.js.map +0 -1
- package/dist/containerRegistration/index.d.ts.map +0 -1
- package/dist/containerRegistration/index.js.map +0 -1
- package/dist/containerRegistry/containerRegistry.core.d.ts.map +0 -1
- package/dist/containerRegistry/containerRegistry.core.js.map +0 -1
- package/dist/containerRegistry/containerRegistry.error.d.ts +0 -12
- package/dist/containerRegistry/containerRegistry.error.d.ts.map +0 -1
- package/dist/containerRegistry/containerRegistry.error.js +0 -22
- package/dist/containerRegistry/containerRegistry.error.js.map +0 -1
- package/dist/containerRegistry/containerRegistry.type.d.ts.map +0 -1
- package/dist/containerRegistry/containerRegistry.type.js.map +0 -1
- package/dist/containerRegistry/index.d.ts.map +0 -1
- package/dist/containerRegistry/index.js.map +0 -1
- package/dist/containerResolution/containerResolution.core.d.ts.map +0 -1
- package/dist/containerResolution/containerResolution.core.js.map +0 -1
- package/dist/containerResolution/containerResolution.error.d.ts.map +0 -1
- package/dist/containerResolution/containerResolution.error.js.map +0 -1
- package/dist/containerResolution/containerResolution.type.d.ts.map +0 -1
- package/dist/containerResolution/containerResolution.type.js.map +0 -1
- package/dist/containerResolution/index.d.ts.map +0 -1
- package/dist/containerResolution/index.js.map +0 -1
- package/dist/containerScope/containerScope.type.d.ts.map +0 -1
- package/dist/containerScope/containerScope.type.js.map +0 -1
- package/dist/containerScope/index.d.ts.map +0 -1
- package/dist/containerScope/index.js.map +0 -1
- package/dist/containerToken/containerToken.type.d.ts.map +0 -1
- package/dist/containerToken/containerToken.type.js.map +0 -1
- package/dist/containerToken/index.d.ts.map +0 -1
- package/dist/containerToken/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,23 +11,220 @@ npm install @zudojs/container
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
createContainer,
|
|
16
|
+
createToken,
|
|
17
|
+
ContainerScope,
|
|
18
|
+
} from "@zudojs/container";
|
|
15
19
|
|
|
16
20
|
const container = createContainer();
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
const LOGGER = createToken<Logger>("logger");
|
|
23
|
+
|
|
24
|
+
// Registration takes a provider object plus options:
|
|
25
|
+
container.register(
|
|
26
|
+
LOGGER,
|
|
27
|
+
{ useFactory: () => createLogger({ name: "app" }) },
|
|
28
|
+
{ scope: ContainerScope.SINGLETON },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const logger = container.resolve(LOGGER);
|
|
32
|
+
const [log, db] = container.resolveMany([LOGGER, DB]); // typed [Logger, Db]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Convenience helpers wrap the provider-object form:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
container.registerValue("config", { port: 3000 }); // always SINGLETON
|
|
39
|
+
container.registerClass(DB, PostgresDb, { scope: ContainerScope.SINGLETON });
|
|
40
|
+
container.registerFactory(API, (db) => new Api(db), [DB]); // deps via inject list
|
|
41
|
+
container.registerExisting("db-alias", DB); // alias to another token
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Tokens
|
|
45
|
+
|
|
46
|
+
Tokens can be strings, symbols, classes, or `InjectionToken`s from
|
|
47
|
+
`createToken<T>()` / `createGlobalToken<T>()`.
|
|
48
|
+
|
|
49
|
+
- Plain string/symbol tokens are **untyped casts** — the compiler cannot
|
|
50
|
+
verify that what you registered under `"logger"` matches the type you
|
|
51
|
+
request later. Prefer `InjectionToken`s or class tokens.
|
|
52
|
+
- `createGlobalToken(key)` uses `Symbol.for(key)`: any other call with the
|
|
53
|
+
same key anywhere in the process yields the **same** token. That is by
|
|
54
|
+
design for cross-package sharing; namespace your keys (e.g. `"myapp:db"`).
|
|
55
|
+
|
|
56
|
+
## Lifetimes (`scope` option)
|
|
57
|
+
|
|
58
|
+
The default scope is **`ContainerScope.TRANSIENT`**.
|
|
59
|
+
|
|
60
|
+
| Scope | Cache | Disposal |
|
|
61
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
62
|
+
| `SINGLETON` | One instance in the container's root cache — the same instance is returned at the root and inside every scope | Disposed by `container.dispose()` (or when its registration is replaced/removed) |
|
|
63
|
+
| `SCOPED` | One instance per scope created with `container.createScope()` (nested scopes see their ancestors' instances) | Disposed by `scope.dispose()` |
|
|
64
|
+
| `TRANSIENT` | Never cached — a new instance per resolution | **Never tracked — the caller owns disposal** |
|
|
65
|
+
|
|
66
|
+
Resolving a `SCOPED` token at the container root **throws** a
|
|
67
|
+
`ScopedResolutionError` ("Scoped token X cannot be resolved outside a
|
|
68
|
+
scope"). A `SINGLETON` whose dependency chain contains a `SCOPED`
|
|
69
|
+
registration throws a `CaptiveDependencyError` — a longer-lived consumer must
|
|
70
|
+
not capture a shorter-lived dependency.
|
|
71
|
+
|
|
72
|
+
`registerValue()` always registers as `SINGLETON`, overriding any
|
|
73
|
+
`options.scope` you pass — a value provider can only ever return the one
|
|
74
|
+
instance you gave it.
|
|
75
|
+
|
|
76
|
+
Tracking covers **every** `SINGLETON`/`SCOPED` instance the container
|
|
77
|
+
creates — including ones created transitively as dependencies of another
|
|
78
|
+
resolution — not just the value returned by the `resolve()` call.
|
|
79
|
+
|
|
80
|
+
### Async factories are not supported for cached lifetimes
|
|
81
|
+
|
|
82
|
+
The container is synchronous. A factory registered as `SINGLETON` or
|
|
83
|
+
`SCOPED` that returns a `Promise` throws an `AsyncProviderError` — otherwise
|
|
84
|
+
the Promise itself would be cached as "the instance" and the eventual value
|
|
85
|
+
would never be disposal-tracked. Await the resource first and register the
|
|
86
|
+
result (`registerValue`), or make the registration `TRANSIENT` and let
|
|
87
|
+
callers await it themselves. There is no `resolveAsync`.
|
|
88
|
+
|
|
89
|
+
## Scopes
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const scope = container.createScope({ name: "request-42" });
|
|
93
|
+
const service = scope.resolve(REQUEST_SERVICE); // SCOPED: cached per scope
|
|
94
|
+
await scope.dispose(); // disposes SCOPED instances only
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- Singletons resolved through a scope come from (and stay owned by) the
|
|
98
|
+
container; `scope.dispose()` never touches them.
|
|
99
|
+
- `scope.createScope()` creates a **nested child** scope:
|
|
100
|
+
- the child sees `SCOPED` instances already created by its ancestors
|
|
101
|
+
(lookups chain upward), while instances it creates itself are private to
|
|
102
|
+
the child and disposed with it;
|
|
103
|
+
- disposing a scope disposes its children first (most recent first);
|
|
104
|
+
- `child.getParent()` returns the parent scope (`getParent()` on a
|
|
105
|
+
top-level scope returns the container); `getContainer()` always returns
|
|
106
|
+
the container.
|
|
107
|
+
- The container keeps track of its live scopes: `container.dispose()`
|
|
108
|
+
disposes them (and their children) first, and resolving from any scope
|
|
109
|
+
after it or one of its ancestors is disposed throws.
|
|
110
|
+
|
|
111
|
+
## Constructor and factory injection
|
|
112
|
+
|
|
113
|
+
Providers declare dependencies with an `inject` token list:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
class Api {
|
|
117
|
+
constructor(
|
|
118
|
+
private db: Db,
|
|
119
|
+
private logger: Logger,
|
|
120
|
+
) {}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
container.registerClass(API, Api, { inject: [DB, LOGGER] });
|
|
124
|
+
// or
|
|
125
|
+
container.register(API, { useClass: Api, inject: [DB, LOGGER] });
|
|
126
|
+
container.register(API, {
|
|
127
|
+
useFactory: (db, log) => new Api(db, log),
|
|
128
|
+
inject: [DB, LOGGER],
|
|
20
129
|
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Classes without an `inject` list are constructed with zero arguments. There
|
|
133
|
+
is no reflection/decorator magic — dependencies are exactly the tokens you
|
|
134
|
+
list, resolved in order.
|
|
135
|
+
|
|
136
|
+
## Duplicate registrations
|
|
137
|
+
|
|
138
|
+
Registering a token twice throws `DuplicateRegistrationError` unless the
|
|
139
|
+
container was created with `{ registry: { allowDuplicates: true } }`, in
|
|
140
|
+
which case the later registration wins. Use `container.replace()` to
|
|
141
|
+
intentionally swap a registration.
|
|
142
|
+
|
|
143
|
+
Replacing or removing a registration **evicts and disposes** its cached
|
|
144
|
+
singleton, so the next `resolve()` uses the new provider.
|
|
145
|
+
|
|
146
|
+
## Resolution options
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const container = createContainer({
|
|
150
|
+
resolution: {
|
|
151
|
+
autoRegisterClasses: true, // default
|
|
152
|
+
detectCircularDependencies: true, // default
|
|
153
|
+
maxResolutionDepth: 100, // default
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- `autoRegisterClasses` — resolving an unregistered **class** token
|
|
159
|
+
registers it on the fly as `TRANSIENT`. When registrations are frozen the
|
|
160
|
+
class is instantiated _ephemerally_ without being registered. Set to
|
|
161
|
+
`false` to require explicit registration (`canResolve`/`resolveOptional`
|
|
162
|
+
respect this).
|
|
163
|
+
- `detectCircularDependencies` — circular chains throw
|
|
164
|
+
`CircularDependencyError` with the full chain. When disabled,
|
|
165
|
+
`maxResolutionDepth` still stops runaway recursion.
|
|
166
|
+
- `maxResolutionDepth` — chains deeper than this throw
|
|
167
|
+
`MaxResolutionDepthError` naming the token and depth.
|
|
21
168
|
|
|
22
|
-
|
|
169
|
+
Resolution failures are wrapped in `DependencyResolutionError` (a subclass of
|
|
170
|
+
`ProviderResolutionError` from `@zudojs/errors`) carrying the failing
|
|
171
|
+
`token`, the resolution `chain`, and the original error as `cause`. The
|
|
172
|
+
message includes all three:
|
|
173
|
+
`Failed to resolve db: connect ECONNREFUSED (chain: api -> repo -> db)`.
|
|
174
|
+
|
|
175
|
+
`resolveOptional(token)` returns `undefined` when the token has no
|
|
176
|
+
registration; other failures (broken factories, missing dependencies of a
|
|
177
|
+
registered token, captive dependencies) still throw.
|
|
178
|
+
|
|
179
|
+
## Start semantics
|
|
180
|
+
|
|
181
|
+
`container.start()` is optional — the first `resolve()`/`createScope()`
|
|
182
|
+
auto-starts the container. With `freezeRegistrations: true`, starting
|
|
183
|
+
(including that implicit start) freezes the registration set: `register`,
|
|
184
|
+
`replace`, `remove`, `clearRegistrations`, and `restoreSnapshot` throw from
|
|
185
|
+
then on.
|
|
186
|
+
|
|
187
|
+
## Disposal
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
await container.dispose();
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
- Disposes all live scopes, then all tracked singletons in **reverse
|
|
194
|
+
creation order** (a dependency is created before its dependents, so it is
|
|
195
|
+
disposed after them). Instances are disposable if they
|
|
196
|
+
have a `dispose()` method or implement `Symbol.dispose` /
|
|
197
|
+
`Symbol.asyncDispose`.
|
|
198
|
+
- `TRANSIENT` instances are never tracked; dispose them yourself.
|
|
199
|
+
- With `autoDispose: false`, `dispose()` releases tracked references
|
|
200
|
+
**without disposing them** — disposal becomes your responsibility.
|
|
201
|
+
- Disposal is terminal: the container is marked disposed even if some
|
|
202
|
+
instances fail to dispose, and every failure is reported in the thrown
|
|
203
|
+
`AggregateError`. `dispose()` is idempotent; any use after disposal throws.
|
|
204
|
+
- `clearSingletons()` evicts and disposes cached singletons without
|
|
205
|
+
disposing the container.
|
|
206
|
+
|
|
207
|
+
## Snapshots (testing)
|
|
208
|
+
|
|
209
|
+
`snapshot()` captures the current **registrations** (not instances);
|
|
210
|
+
`restoreSnapshot(snap)` wholesale-replaces the registration set with a
|
|
211
|
+
snapshot, evicting and disposing cached singletons from the old set. Both are
|
|
212
|
+
refused once registrations are frozen or the container is disposed.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const snap = container.snapshot();
|
|
216
|
+
container.replace(DB, { useValue: fakeDb });
|
|
217
|
+
// ... test ...
|
|
218
|
+
container.restoreSnapshot(snap);
|
|
23
219
|
```
|
|
24
220
|
|
|
25
221
|
## Features
|
|
26
222
|
|
|
27
|
-
- Token-based registration (string, symbol, class)
|
|
28
|
-
- Singleton, scoped, and transient lifetimes
|
|
29
|
-
-
|
|
30
|
-
- Circular dependency detection
|
|
223
|
+
- Token-based registration (string, symbol, class, `InjectionToken`)
|
|
224
|
+
- Singleton, scoped, and transient lifetimes with strict cache coherence
|
|
225
|
+
- Explicit dependency injection via `inject` lists (classes and factories)
|
|
226
|
+
- Circular dependency detection and resolution depth limiting
|
|
227
|
+
- Lifecycle tracking with deterministic reverse-order disposal
|
|
31
228
|
- Container snapshots for testing
|
|
32
229
|
|
|
33
230
|
## Use Cases
|
|
@@ -1,48 +1,139 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core dependency injection container for Zudojs.
|
|
3
|
+
*
|
|
4
|
+
* Lifetime and disposal model:
|
|
5
|
+
* - SINGLETON instances are cached in the container's root singleton cache
|
|
6
|
+
* and tracked by the container lifecycle — including singletons created
|
|
7
|
+
* transitively as dependencies of another resolution; they are disposed
|
|
8
|
+
* when the container is disposed (or when their registration is
|
|
9
|
+
* replaced/removed).
|
|
10
|
+
* - SCOPED instances only exist inside a scope created with `createScope()`;
|
|
11
|
+
* resolving a SCOPED token at the root throws.
|
|
12
|
+
* - TRANSIENT instances are never cached and never tracked — callers own
|
|
13
|
+
* their disposal.
|
|
3
14
|
*/
|
|
4
15
|
import type { ContainerProvider, ProviderToken } from "../containerProvider/containerProvider.core.js";
|
|
5
|
-
import type { ContainerRegistration, CreateRegistrationOptions, RegistrationToken } from "../containerRegistration/containerRegistration.core.js";
|
|
6
|
-
import {
|
|
7
|
-
import { ContainerResolver } from "../containerResolution/containerResolution.core.js";
|
|
8
|
-
import { ContainerLifecycle } from "../containerLifecycle/containerLifecycle.core.js";
|
|
16
|
+
import type { ContainerRegistration, CreateRegistrationOptions, RegistrationToken, ResolvedTokens } from "../containerRegistration/containerRegistration.core.js";
|
|
17
|
+
import type { ResolutionCache, ResolutionResult } from "../containerResolution/containerResolution.type.js";
|
|
9
18
|
import type { ContainerOptions, ResolvedContainerOptions } from "../containerOptions/containerOptions.type.js";
|
|
10
|
-
import type {
|
|
19
|
+
import type { Constructor, Token } from "../containerToken/containerToken.type.js";
|
|
20
|
+
import type { ContainerLike, ContainerScopeOptions } from "./containerCore.type.js";
|
|
11
21
|
import { ContainerScopeContext } from "./containerCore.scope.js";
|
|
12
|
-
|
|
22
|
+
/** Options accepted by {@link Container.registerClass}. */
|
|
23
|
+
export interface RegisterClassOptions extends CreateRegistrationOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Tokens resolved and passed to the constructor, in order.
|
|
26
|
+
* Omit for zero-argument constructors.
|
|
27
|
+
*/
|
|
28
|
+
readonly inject?: readonly ProviderToken[];
|
|
29
|
+
}
|
|
30
|
+
export declare class Container implements ContainerLike {
|
|
31
|
+
#private;
|
|
13
32
|
readonly name: string;
|
|
14
33
|
readonly options: ResolvedContainerOptions;
|
|
15
|
-
readonly registry: ContainerRegistry;
|
|
16
|
-
readonly resolver: ContainerResolver;
|
|
17
|
-
readonly lifecycle: ContainerLifecycle;
|
|
18
|
-
private started;
|
|
19
|
-
private disposed;
|
|
20
34
|
constructor(options?: ContainerOptions);
|
|
35
|
+
/**
|
|
36
|
+
* Marks the container as started.
|
|
37
|
+
*
|
|
38
|
+
* Calling `start()` explicitly is optional: `resolve()` (and
|
|
39
|
+
* `createScope()`) auto-start the container on first use. Note that with
|
|
40
|
+
* `freezeRegistrations: true`, starting — including the implicit start
|
|
41
|
+
* performed by the first `resolve()` — freezes the registration set.
|
|
42
|
+
*/
|
|
21
43
|
start(): this;
|
|
22
44
|
register<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
23
|
-
registerClass<T>(token: RegistrationToken<T>, ctor:
|
|
45
|
+
registerClass<T>(token: RegistrationToken<T>, ctor: Constructor<T>, options?: RegisterClassOptions): ContainerRegistration<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Registers a pre-built value.
|
|
48
|
+
*
|
|
49
|
+
* Note: the scope is forcibly set to SINGLETON (overriding any
|
|
50
|
+
* `options.scope`) — a value provider always returns the same instance, so
|
|
51
|
+
* any other lifetime would be misleading.
|
|
52
|
+
*/
|
|
24
53
|
registerValue<T>(token: RegistrationToken<T>, value: T, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
25
54
|
registerFactory<T>(token: RegistrationToken<T>, factory: (...deps: unknown[]) => T, inject?: readonly ProviderToken[], options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
26
55
|
registerExisting<T>(token: RegistrationToken<T>, existing: ProviderToken<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
56
|
+
/**
|
|
57
|
+
* Resolves a dependency at the container root.
|
|
58
|
+
*
|
|
59
|
+
* Auto-starts the container on first use. SCOPED registrations cannot be
|
|
60
|
+
* resolved here — create a scope with {@link createScope} instead.
|
|
61
|
+
*/
|
|
27
62
|
resolve<T>(token: RegistrationToken<T>): T;
|
|
28
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Resolves several tokens at once. The result is a tuple typed per token,
|
|
65
|
+
* so heterogeneous token lists keep their individual types.
|
|
66
|
+
*/
|
|
67
|
+
resolveMany<const Tokens extends readonly RegistrationToken[]>(tokens: Tokens): ResolvedTokens<Tokens>;
|
|
68
|
+
/**
|
|
69
|
+
* Like {@link resolve} but returns `undefined` when the token has no
|
|
70
|
+
* registration (and cannot be auto-registered). Other resolution failures
|
|
71
|
+
* — broken factories, missing dependencies, captive dependencies — still
|
|
72
|
+
* throw.
|
|
73
|
+
*/
|
|
29
74
|
resolveOptional<T>(token: RegistrationToken<T>): T | undefined;
|
|
30
75
|
canResolve<T>(token: RegistrationToken<T>): boolean;
|
|
31
76
|
has<T>(token: RegistrationToken<T>): boolean;
|
|
32
77
|
getRegistration<T>(token: RegistrationToken<T>): ContainerRegistration<T> | undefined;
|
|
78
|
+
replace<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
|
|
33
79
|
remove<T>(token: RegistrationToken<T>): boolean;
|
|
80
|
+
/** Removes every registration (evicting and disposing cached singletons). */
|
|
81
|
+
clearRegistrations(): void;
|
|
34
82
|
createScope(options?: ContainerScopeOptions): ContainerScopeContext;
|
|
35
83
|
getRegistrations(): readonly ContainerRegistration[];
|
|
84
|
+
getTokens(): readonly Token<unknown>[];
|
|
36
85
|
get registrationCount(): number;
|
|
86
|
+
/**
|
|
87
|
+
* Returns an immutable snapshot of the current registrations, suitable for
|
|
88
|
+
* later {@link restoreSnapshot}. Cached instances are NOT part of the
|
|
89
|
+
* snapshot — only the registrations.
|
|
90
|
+
*/
|
|
91
|
+
snapshot(): readonly ContainerRegistration[];
|
|
92
|
+
/**
|
|
93
|
+
* Wholesale-replaces the registration set with a previous snapshot.
|
|
94
|
+
* Entries are validated, cached singletons for the old set are evicted and
|
|
95
|
+
* disposed, and the operation is refused when registrations are frozen.
|
|
96
|
+
*/
|
|
97
|
+
restoreSnapshot(registrations: readonly ContainerRegistration[]): void;
|
|
37
98
|
isStarted(): boolean;
|
|
38
99
|
isDisposed(): boolean;
|
|
39
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Evicts all cached singleton instances and disposes the tracked ones.
|
|
102
|
+
* Fails with an AggregateError listing every disposal failure.
|
|
103
|
+
*/
|
|
104
|
+
clearSingletons(): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Disposes the container: all live scopes first, then (with
|
|
107
|
+
* `autoDispose: true`, the default) every tracked singleton in reverse
|
|
108
|
+
* creation order.
|
|
109
|
+
*
|
|
110
|
+
* With `autoDispose: false` tracked instances are NOT disposed — their
|
|
111
|
+
* references are simply released and disposal becomes the caller's
|
|
112
|
+
* responsibility.
|
|
113
|
+
*
|
|
114
|
+
* Disposal is terminal: the container is marked disposed even when some
|
|
115
|
+
* instances fail to dispose; every failure is reported in the thrown
|
|
116
|
+
* AggregateError. Idempotent.
|
|
117
|
+
*/
|
|
40
118
|
dispose(): Promise<void>;
|
|
41
119
|
get resolutionOptions(): {
|
|
42
120
|
autoRegisterClasses: boolean;
|
|
43
121
|
detectCircularDependencies: boolean;
|
|
44
122
|
maxResolutionDepth: number;
|
|
45
123
|
};
|
|
124
|
+
/** @internal Creates a fresh scoped-instance cache for a scope. */
|
|
125
|
+
createScopeCache(parent?: ResolutionCache): ResolutionCache;
|
|
126
|
+
/** @internal Resolves on behalf of a scope, tracking singleton results. */
|
|
127
|
+
resolveInScope<T>(token: RegistrationToken<T>, cache: ResolutionCache, onInstanceCreated?: (result: ResolutionResult<unknown>) => void): ResolutionResult<T>;
|
|
128
|
+
/** @internal Unregisters a top-level scope from the live-scope set. */
|
|
129
|
+
releaseScope(scope: ContainerScopeContext): void;
|
|
130
|
+
private buildResolutionOptions;
|
|
131
|
+
/**
|
|
132
|
+
* Tracks every freshly created SINGLETON instance — top-level results and
|
|
133
|
+
* transitively created dependencies alike — in the container lifecycle.
|
|
134
|
+
* SCOPED instances are owned by scopes and TRANSIENT ones by callers.
|
|
135
|
+
*/
|
|
136
|
+
private trackCreated;
|
|
46
137
|
private ensureActive;
|
|
47
138
|
private ensureNotDisposed;
|
|
48
139
|
private ensureMutable;
|