@zudojs/container 0.1.0 → 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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -8
  3. package/dist/containerCore/containerCore.core.d.ts +105 -14
  4. package/dist/containerCore/containerCore.core.js +211 -44
  5. package/dist/containerCore/containerCore.scope.d.ts +63 -18
  6. package/dist/containerCore/containerCore.scope.js +108 -29
  7. package/dist/containerCore/containerCore.type.d.ts +22 -16
  8. package/dist/containerLifecycle/containerLifecycle.core.d.ts +59 -9
  9. package/dist/containerLifecycle/containerLifecycle.core.js +58 -15
  10. package/dist/containerOptions/containerOptions.type.d.ts +7 -17
  11. package/dist/containerOptions/containerOptions.type.js +0 -19
  12. package/dist/containerProvider/containerProvider.core.d.ts +11 -3
  13. package/dist/containerProvider/containerProvider.core.js +11 -5
  14. package/dist/containerRegistration/containerRegistration.core.d.ts +9 -3
  15. package/dist/containerRegistration/containerRegistration.core.js +0 -6
  16. package/dist/containerRegistry/containerRegistry.core.d.ts +23 -9
  17. package/dist/containerRegistry/containerRegistry.core.js +50 -47
  18. package/dist/containerRegistry/containerRegistry.type.d.ts +3 -1
  19. package/dist/containerRegistry/containerRegistry.type.js +2 -0
  20. package/dist/containerRegistry/index.d.ts +0 -1
  21. package/dist/containerRegistry/index.js +0 -1
  22. package/dist/containerResolution/containerResolution.core.d.ts +42 -10
  23. package/dist/containerResolution/containerResolution.core.js +207 -64
  24. package/dist/containerResolution/containerResolution.error.d.ts +68 -3
  25. package/dist/containerResolution/containerResolution.error.js +107 -3
  26. package/dist/containerResolution/containerResolution.type.d.ts +35 -3
  27. package/dist/containerResolution/index.d.ts +1 -0
  28. package/dist/containerResolution/index.js +1 -0
  29. package/dist/containerToken/containerToken.type.d.ts +26 -1
  30. package/dist/containerToken/containerToken.type.js +18 -0
  31. package/package.json +21 -12
  32. package/dist/.tsbuildinfo +0 -1
  33. package/dist/containerCore/containerCore.core.d.ts.map +0 -1
  34. package/dist/containerCore/containerCore.core.js.map +0 -1
  35. package/dist/containerCore/containerCore.scope.d.ts.map +0 -1
  36. package/dist/containerCore/containerCore.scope.js.map +0 -1
  37. package/dist/containerCore/containerCore.type.d.ts.map +0 -1
  38. package/dist/containerCore/containerCore.type.js.map +0 -1
  39. package/dist/containerCore/index.d.ts.map +0 -1
  40. package/dist/containerCore/index.js.map +0 -1
  41. package/dist/containerLifecycle/containerLifecycle.core.d.ts.map +0 -1
  42. package/dist/containerLifecycle/containerLifecycle.core.js.map +0 -1
  43. package/dist/containerLifecycle/index.d.ts.map +0 -1
  44. package/dist/containerLifecycle/index.js.map +0 -1
  45. package/dist/containerOptions/containerOptions.type.d.ts.map +0 -1
  46. package/dist/containerOptions/containerOptions.type.js.map +0 -1
  47. package/dist/containerOptions/index.d.ts.map +0 -1
  48. package/dist/containerOptions/index.js.map +0 -1
  49. package/dist/containerProvider/containerProvider.core.d.ts.map +0 -1
  50. package/dist/containerProvider/containerProvider.core.js.map +0 -1
  51. package/dist/containerProvider/index.d.ts.map +0 -1
  52. package/dist/containerProvider/index.js.map +0 -1
  53. package/dist/containerRegistration/containerRegistration.core.d.ts.map +0 -1
  54. package/dist/containerRegistration/containerRegistration.core.js.map +0 -1
  55. package/dist/containerRegistration/index.d.ts.map +0 -1
  56. package/dist/containerRegistration/index.js.map +0 -1
  57. package/dist/containerRegistry/containerRegistry.core.d.ts.map +0 -1
  58. package/dist/containerRegistry/containerRegistry.core.js.map +0 -1
  59. package/dist/containerRegistry/containerRegistry.error.d.ts +0 -12
  60. package/dist/containerRegistry/containerRegistry.error.d.ts.map +0 -1
  61. package/dist/containerRegistry/containerRegistry.error.js +0 -22
  62. package/dist/containerRegistry/containerRegistry.error.js.map +0 -1
  63. package/dist/containerRegistry/containerRegistry.type.d.ts.map +0 -1
  64. package/dist/containerRegistry/containerRegistry.type.js.map +0 -1
  65. package/dist/containerRegistry/index.d.ts.map +0 -1
  66. package/dist/containerRegistry/index.js.map +0 -1
  67. package/dist/containerResolution/containerResolution.core.d.ts.map +0 -1
  68. package/dist/containerResolution/containerResolution.core.js.map +0 -1
  69. package/dist/containerResolution/containerResolution.error.d.ts.map +0 -1
  70. package/dist/containerResolution/containerResolution.error.js.map +0 -1
  71. package/dist/containerResolution/containerResolution.type.d.ts.map +0 -1
  72. package/dist/containerResolution/containerResolution.type.js.map +0 -1
  73. package/dist/containerResolution/index.d.ts.map +0 -1
  74. package/dist/containerResolution/index.js.map +0 -1
  75. package/dist/containerScope/containerScope.type.d.ts.map +0 -1
  76. package/dist/containerScope/containerScope.type.js.map +0 -1
  77. package/dist/containerScope/index.d.ts.map +0 -1
  78. package/dist/containerScope/index.js.map +0 -1
  79. package/dist/containerToken/containerToken.type.d.ts.map +0 -1
  80. package/dist/containerToken/containerToken.type.js.map +0 -1
  81. package/dist/containerToken/index.d.ts.map +0 -1
  82. package/dist/containerToken/index.js.map +0 -1
  83. package/dist/index.d.ts.map +0 -1
  84. package/dist/index.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zudojs Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -11,23 +11,220 @@ npm install @zudojs/container
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { createContainer } from "@zudojs/container";
14
+ import {
15
+ createContainer,
16
+ createToken,
17
+ ContainerScope,
18
+ } from "@zudojs/container";
15
19
 
16
20
  const container = createContainer();
17
21
 
18
- container.register("logger", () => createLogger({ name: "app" }), {
19
- lifetime: "singleton",
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
- const logger = container.resolve("logger");
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
- - Automatic dependency resolution
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 { ContainerRegistry } from "../containerRegistry/containerRegistry.core.js";
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 { ContainerScopeOptions } from "./containerCore.type.js";
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
- export declare class Container {
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: new (...args: unknown[]) => T, options?: CreateRegistrationOptions): ContainerRegistration<T>;
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
- resolveMany<T>(tokens: readonly RegistrationToken<T>[]): T[];
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
- clearSingletons(): void;
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;