@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.
Files changed (83) hide show
  1. package/README.md +205 -8
  2. package/dist/containerCore/containerCore.core.d.ts +105 -14
  3. package/dist/containerCore/containerCore.core.js +211 -44
  4. package/dist/containerCore/containerCore.scope.d.ts +63 -18
  5. package/dist/containerCore/containerCore.scope.js +108 -29
  6. package/dist/containerCore/containerCore.type.d.ts +22 -16
  7. package/dist/containerLifecycle/containerLifecycle.core.d.ts +59 -9
  8. package/dist/containerLifecycle/containerLifecycle.core.js +58 -15
  9. package/dist/containerOptions/containerOptions.type.d.ts +7 -17
  10. package/dist/containerOptions/containerOptions.type.js +0 -19
  11. package/dist/containerProvider/containerProvider.core.d.ts +11 -3
  12. package/dist/containerProvider/containerProvider.core.js +11 -5
  13. package/dist/containerRegistration/containerRegistration.core.d.ts +9 -3
  14. package/dist/containerRegistration/containerRegistration.core.js +0 -6
  15. package/dist/containerRegistry/containerRegistry.core.d.ts +23 -9
  16. package/dist/containerRegistry/containerRegistry.core.js +50 -47
  17. package/dist/containerRegistry/containerRegistry.type.d.ts +3 -1
  18. package/dist/containerRegistry/containerRegistry.type.js +2 -0
  19. package/dist/containerRegistry/index.d.ts +0 -1
  20. package/dist/containerRegistry/index.js +0 -1
  21. package/dist/containerResolution/containerResolution.core.d.ts +42 -10
  22. package/dist/containerResolution/containerResolution.core.js +207 -64
  23. package/dist/containerResolution/containerResolution.error.d.ts +68 -3
  24. package/dist/containerResolution/containerResolution.error.js +107 -3
  25. package/dist/containerResolution/containerResolution.type.d.ts +35 -3
  26. package/dist/containerResolution/index.d.ts +1 -0
  27. package/dist/containerResolution/index.js +1 -0
  28. package/dist/containerToken/containerToken.type.d.ts +26 -1
  29. package/dist/containerToken/containerToken.type.js +18 -0
  30. package/package.json +17 -8
  31. package/dist/.tsbuildinfo +0 -1
  32. package/dist/containerCore/containerCore.core.d.ts.map +0 -1
  33. package/dist/containerCore/containerCore.core.js.map +0 -1
  34. package/dist/containerCore/containerCore.scope.d.ts.map +0 -1
  35. package/dist/containerCore/containerCore.scope.js.map +0 -1
  36. package/dist/containerCore/containerCore.type.d.ts.map +0 -1
  37. package/dist/containerCore/containerCore.type.js.map +0 -1
  38. package/dist/containerCore/index.d.ts.map +0 -1
  39. package/dist/containerCore/index.js.map +0 -1
  40. package/dist/containerLifecycle/containerLifecycle.core.d.ts.map +0 -1
  41. package/dist/containerLifecycle/containerLifecycle.core.js.map +0 -1
  42. package/dist/containerLifecycle/index.d.ts.map +0 -1
  43. package/dist/containerLifecycle/index.js.map +0 -1
  44. package/dist/containerOptions/containerOptions.type.d.ts.map +0 -1
  45. package/dist/containerOptions/containerOptions.type.js.map +0 -1
  46. package/dist/containerOptions/index.d.ts.map +0 -1
  47. package/dist/containerOptions/index.js.map +0 -1
  48. package/dist/containerProvider/containerProvider.core.d.ts.map +0 -1
  49. package/dist/containerProvider/containerProvider.core.js.map +0 -1
  50. package/dist/containerProvider/index.d.ts.map +0 -1
  51. package/dist/containerProvider/index.js.map +0 -1
  52. package/dist/containerRegistration/containerRegistration.core.d.ts.map +0 -1
  53. package/dist/containerRegistration/containerRegistration.core.js.map +0 -1
  54. package/dist/containerRegistration/index.d.ts.map +0 -1
  55. package/dist/containerRegistration/index.js.map +0 -1
  56. package/dist/containerRegistry/containerRegistry.core.d.ts.map +0 -1
  57. package/dist/containerRegistry/containerRegistry.core.js.map +0 -1
  58. package/dist/containerRegistry/containerRegistry.error.d.ts +0 -12
  59. package/dist/containerRegistry/containerRegistry.error.d.ts.map +0 -1
  60. package/dist/containerRegistry/containerRegistry.error.js +0 -22
  61. package/dist/containerRegistry/containerRegistry.error.js.map +0 -1
  62. package/dist/containerRegistry/containerRegistry.type.d.ts.map +0 -1
  63. package/dist/containerRegistry/containerRegistry.type.js.map +0 -1
  64. package/dist/containerRegistry/index.d.ts.map +0 -1
  65. package/dist/containerRegistry/index.js.map +0 -1
  66. package/dist/containerResolution/containerResolution.core.d.ts.map +0 -1
  67. package/dist/containerResolution/containerResolution.core.js.map +0 -1
  68. package/dist/containerResolution/containerResolution.error.d.ts.map +0 -1
  69. package/dist/containerResolution/containerResolution.error.js.map +0 -1
  70. package/dist/containerResolution/containerResolution.type.d.ts.map +0 -1
  71. package/dist/containerResolution/containerResolution.type.js.map +0 -1
  72. package/dist/containerResolution/index.d.ts.map +0 -1
  73. package/dist/containerResolution/index.js.map +0 -1
  74. package/dist/containerScope/containerScope.type.d.ts.map +0 -1
  75. package/dist/containerScope/containerScope.type.js.map +0 -1
  76. package/dist/containerScope/index.d.ts.map +0 -1
  77. package/dist/containerScope/index.js.map +0 -1
  78. package/dist/containerToken/containerToken.type.d.ts.map +0 -1
  79. package/dist/containerToken/containerToken.type.js.map +0 -1
  80. package/dist/containerToken/index.d.ts.map +0 -1
  81. package/dist/containerToken/index.js.map +0 -1
  82. package/dist/index.d.ts.map +0 -1
  83. package/dist/index.js.map +0 -1
@@ -2,6 +2,8 @@
2
2
  * Types for the core container.
3
3
  */
4
4
  import type { RegistrationToken } from "../containerRegistration/containerRegistration.core.js";
5
+ import type { ResolutionCache, ResolutionResult } from "../containerResolution/containerResolution.type.js";
6
+ import type { ContainerScopeContext } from "./containerCore.scope.js";
5
7
  /**
6
8
  * Options used when creating a child container scope.
7
9
  */
@@ -16,25 +18,29 @@ export interface ContainerScopeOptions {
16
18
  readonly metadata?: Readonly<Record<string, unknown>>;
17
19
  }
18
20
  /**
19
- * Full Container interface including mixin methods.
20
- * Used by ContainerScopeContext to reference the parent container.
21
+ * The surface a ContainerScopeContext needs from its owning container.
22
+ * Implemented by Container; the `resolveInScope` / `createScopeCache` /
23
+ * `releaseScope` members are internal plumbing for scopes and should not be
24
+ * called by application code.
21
25
  */
22
26
  export interface ContainerLike {
23
27
  readonly name: string;
24
- readonly resolver: {
25
- createScope(): import("../containerResolution/containerResolution.type.js").ResolutionCache;
26
- resolveDetailed(token: unknown, options: unknown): {
27
- token: unknown;
28
- value: unknown;
29
- };
30
- canResolve(token: unknown): boolean;
31
- };
32
- readonly resolutionOptions: {
33
- autoRegisterClasses: boolean;
34
- detectCircularDependencies: boolean;
35
- maxResolutionDepth: number;
36
- };
37
28
  has<T>(token: RegistrationToken<T>): boolean;
38
- createScope(options?: ContainerScopeOptions): import("./containerCore.scope.js").ContainerScopeContext;
29
+ canResolve<T>(token: RegistrationToken<T>): boolean;
30
+ isDisposed(): boolean;
31
+ createScope(options?: ContainerScopeOptions): ContainerScopeContext;
32
+ /**
33
+ * @internal Creates a fresh scoped-instance cache, optionally chained to a
34
+ * parent scope's cache (nested scopes).
35
+ */
36
+ createScopeCache(parent?: ResolutionCache): ResolutionCache;
37
+ /**
38
+ * @internal Resolves a token using the given scope cache. `onInstanceCreated`
39
+ * is invoked for every instance created during the resolution (including
40
+ * transitively created dependencies) so the scope can track SCOPED ones.
41
+ */
42
+ resolveInScope<T>(token: RegistrationToken<T>, cache: ResolutionCache, onInstanceCreated?: (result: ResolutionResult<unknown>) => void): ResolutionResult<T>;
43
+ /** @internal Unregisters a top-level scope from the container's live-scope set. */
44
+ releaseScope(scope: ContainerScopeContext): void;
39
45
  }
40
46
  //# sourceMappingURL=containerCore.type.d.ts.map
@@ -1,16 +1,41 @@
1
1
  /**
2
2
  * Lifecycle management for resolved container instances.
3
- * Tracks instances that need cleanup and disposes them when a container or scope is destroyed.
3
+ *
4
+ * Tracks SINGLETON instances (container-owned) and SCOPED instances
5
+ * (scope-owned) that need cleanup and disposes them when their owner is
6
+ * destroyed, in reverse creation order.
7
+ *
8
+ * TRANSIENT instances are deliberately NOT tracked: the container creates a
9
+ * new transient per resolution, so tracking them per token would either leak
10
+ * (unbounded growth) or silently drop all but the last instance. Callers own
11
+ * the disposal of transient instances they resolve.
4
12
  */
5
13
  import type { Token } from "../containerToken/containerToken.type.js";
6
14
  import { ContainerLifecycleError } from "@zudojs/errors";
7
- export interface Disposable {
8
- dispose(): void;
15
+ /**
16
+ * An object disposable via a `dispose()` method (sync or async).
17
+ * Named `DisposableLike` to avoid shadowing the ES2023 `Disposable` built-in.
18
+ */
19
+ export interface DisposableLike {
20
+ dispose(): void | Promise<void>;
21
+ }
22
+ /** An object disposable via the ES2023 `Symbol.dispose` protocol. */
23
+ export interface SymbolDisposableLike {
24
+ [Symbol.dispose](): void;
9
25
  }
10
- export interface AsyncDisposable {
11
- [Symbol.asyncDispose]?: () => Promise<void>;
26
+ /**
27
+ * An object disposable via the ES2023 `Symbol.asyncDispose` protocol.
28
+ * Named `AsyncDisposableLike` to avoid shadowing the `AsyncDisposable`
29
+ * built-in.
30
+ */
31
+ export interface AsyncDisposableLike {
32
+ [Symbol.asyncDispose](): Promise<void> | void;
12
33
  }
13
- export type DisposableInstance = Disposable | AsyncDisposable;
34
+ /** @deprecated Use {@link DisposableLike} instead. */
35
+ export type Disposable = DisposableLike;
36
+ /** @deprecated Use {@link AsyncDisposableLike} instead. */
37
+ export type AsyncDisposable = AsyncDisposableLike;
38
+ export type DisposableInstance = DisposableLike | SymbolDisposableLike | AsyncDisposableLike;
14
39
  export declare enum ContainerLifecycleOwner {
15
40
  CONTAINER = "container",
16
41
  SCOPE = "scope"
@@ -30,26 +55,51 @@ export declare class ContainerDisposalError extends ContainerLifecycleError {
30
55
  readonly tokens: readonly Token<unknown>[];
31
56
  constructor(errors: readonly unknown[], tokens: readonly Token<unknown>[]);
32
57
  }
33
- export declare function isDisposable(value: unknown): value is Disposable;
34
- export declare function isAsyncDisposable(value: unknown): value is AsyncDisposable;
58
+ export declare function isDisposable(value: unknown): value is DisposableLike;
59
+ export declare function isSymbolDisposable(value: unknown): value is SymbolDisposableLike;
60
+ export declare function isAsyncDisposable(value: unknown): value is AsyncDisposableLike;
35
61
  export declare function isDisposableInstance(value: unknown): value is DisposableInstance;
36
62
  export declare class ContainerLifecycle {
37
63
  private readonly instances;
38
64
  private readonly options;
39
65
  private disposed;
40
66
  constructor(options?: ContainerLifecycleOptions);
67
+ /**
68
+ * Tracks a disposable instance for later cleanup.
69
+ *
70
+ * Re-tracking a token removes the previous entry and re-inserts it at the
71
+ * end of the map, so reverse-creation disposal order stays sound.
72
+ * Non-disposable instances are ignored.
73
+ */
41
74
  track<T>(token: Token<T>, instance: T, owner?: ContainerLifecycleOwner): void;
42
75
  has<T>(token: Token<T>): boolean;
43
76
  get<T>(token: Token<T>): TrackedInstance<T> | undefined;
44
77
  getAll(): readonly TrackedInstance[];
45
78
  get size(): number;
46
79
  untrack<T>(token: Token<T>): boolean;
80
+ /**
81
+ * Disposes a single tracked instance and untracks it. Untracking happens
82
+ * even when disposal fails — a failed disposal is terminal for the entry.
83
+ */
47
84
  disposeInstance<T>(token: Token<T>): Promise<void>;
85
+ /**
86
+ * Disposes tracked instances in reverse creation order.
87
+ *
88
+ * Entries are untracked even when their disposal fails (terminal). When
89
+ * `owner` is omitted the whole lifecycle is marked disposed — this happens
90
+ * even on failure — and every failure is reported in the thrown
91
+ * ContainerDisposalError.
92
+ */
48
93
  dispose(owner?: ContainerLifecycleOwner): Promise<void>;
49
94
  disposeScope(): Promise<void>;
50
95
  disposeContainer(): Promise<void>;
96
+ /**
97
+ * Releases all tracked references WITHOUT disposing them and marks the
98
+ * lifecycle disposed so further `track()` calls are refused. Used when a
99
+ * container is disposed with `autoDispose: false`.
100
+ */
101
+ shutdown(): void;
51
102
  isDisposed(): boolean;
52
- reset(): void;
53
103
  getTrackedTokens(): readonly Token<unknown>[];
54
104
  }
55
105
  export declare function createContainerLifecycle(options?: ContainerLifecycleOptions): ContainerLifecycle;
@@ -1,6 +1,14 @@
1
1
  /**
2
2
  * Lifecycle management for resolved container instances.
3
- * Tracks instances that need cleanup and disposes them when a container or scope is destroyed.
3
+ *
4
+ * Tracks SINGLETON instances (container-owned) and SCOPED instances
5
+ * (scope-owned) that need cleanup and disposes them when their owner is
6
+ * destroyed, in reverse creation order.
7
+ *
8
+ * TRANSIENT instances are deliberately NOT tracked: the container creates a
9
+ * new transient per resolution, so tracking them per token would either leak
10
+ * (unbounded growth) or silently drop all but the last instance. Callers own
11
+ * the disposal of transient instances they resolve.
4
12
  */
5
13
  import { describeToken } from "../containerToken/containerToken.type.js";
6
14
  import { ContainerLifecycleError } from "@zudojs/errors";
@@ -24,6 +32,12 @@ export function isDisposable(value) {
24
32
  "dispose" in value &&
25
33
  typeof value.dispose === "function");
26
34
  }
35
+ export function isSymbolDisposable(value) {
36
+ return (typeof value === "object" &&
37
+ value !== null &&
38
+ Symbol.dispose in value &&
39
+ typeof value[Symbol.dispose] === "function");
40
+ }
27
41
  export function isAsyncDisposable(value) {
28
42
  return (typeof value === "object" &&
29
43
  value !== null &&
@@ -31,7 +45,7 @@ export function isAsyncDisposable(value) {
31
45
  typeof value[Symbol.asyncDispose] === "function");
32
46
  }
33
47
  export function isDisposableInstance(value) {
34
- return isDisposable(value) || isAsyncDisposable(value);
48
+ return (isDisposable(value) || isSymbolDisposable(value) || isAsyncDisposable(value));
35
49
  }
36
50
  export class ContainerLifecycle {
37
51
  instances = new Map();
@@ -40,11 +54,19 @@ export class ContainerLifecycle {
40
54
  constructor(options = {}) {
41
55
  this.options = { failFast: options.failFast ?? false };
42
56
  }
57
+ /**
58
+ * Tracks a disposable instance for later cleanup.
59
+ *
60
+ * Re-tracking a token removes the previous entry and re-inserts it at the
61
+ * end of the map, so reverse-creation disposal order stays sound.
62
+ * Non-disposable instances are ignored.
63
+ */
43
64
  track(token, instance, owner = ContainerLifecycleOwner.CONTAINER) {
44
65
  if (this.disposed)
45
- throw new Error("Cannot track an instance after the container lifecycle has been disposed.");
66
+ throw new ContainerLifecycleError("track", "Cannot track an instance after the container lifecycle has been disposed.");
46
67
  if (!isDisposableInstance(instance))
47
68
  return;
69
+ this.instances.delete(token);
48
70
  this.instances.set(token, {
49
71
  token,
50
72
  instance,
@@ -68,14 +90,18 @@ export class ContainerLifecycle {
68
90
  untrack(token) {
69
91
  return this.instances.delete(token);
70
92
  }
93
+ /**
94
+ * Disposes a single tracked instance and untracks it. Untracking happens
95
+ * even when disposal fails — a failed disposal is terminal for the entry.
96
+ */
71
97
  async disposeInstance(token) {
72
- const tracked = this.get(token);
98
+ const tracked = this.instances.get(token);
73
99
  if (!tracked || tracked.disposed)
74
100
  return;
101
+ tracked.disposed = true;
102
+ this.instances.delete(token);
75
103
  try {
76
104
  await disposeValue(tracked.instance);
77
- tracked.disposed = true;
78
- this.instances.delete(token);
79
105
  }
80
106
  catch (error) {
81
107
  if (this.options.failFast)
@@ -83,6 +109,14 @@ export class ContainerLifecycle {
83
109
  throw new ContainerDisposalError([error], [token]);
84
110
  }
85
111
  }
112
+ /**
113
+ * Disposes tracked instances in reverse creation order.
114
+ *
115
+ * Entries are untracked even when their disposal fails (terminal). When
116
+ * `owner` is omitted the whole lifecycle is marked disposed — this happens
117
+ * even on failure — and every failure is reported in the thrown
118
+ * ContainerDisposalError.
119
+ */
86
120
  async dispose(owner) {
87
121
  if (this.disposed)
88
122
  return;
@@ -95,10 +129,10 @@ export class ContainerLifecycle {
95
129
  for (const entry of selected) {
96
130
  if (entry.disposed)
97
131
  continue;
132
+ entry.disposed = true;
133
+ this.instances.delete(entry.token);
98
134
  try {
99
135
  await disposeValue(entry.instance);
100
- entry.disposed = true;
101
- this.instances.delete(entry.token);
102
136
  }
103
137
  catch (error) {
104
138
  errors.push(error);
@@ -107,10 +141,10 @@ export class ContainerLifecycle {
107
141
  break;
108
142
  }
109
143
  }
110
- if (errors.length > 0)
111
- throw new ContainerDisposalError(errors, failedTokens);
112
144
  if (owner === undefined)
113
145
  this.disposed = true;
146
+ if (errors.length > 0)
147
+ throw new ContainerDisposalError(errors, failedTokens);
114
148
  }
115
149
  async disposeScope() {
116
150
  await this.dispose(ContainerLifecycleOwner.SCOPE);
@@ -118,13 +152,18 @@ export class ContainerLifecycle {
118
152
  async disposeContainer() {
119
153
  await this.dispose(ContainerLifecycleOwner.CONTAINER);
120
154
  }
155
+ /**
156
+ * Releases all tracked references WITHOUT disposing them and marks the
157
+ * lifecycle disposed so further `track()` calls are refused. Used when a
158
+ * container is disposed with `autoDispose: false`.
159
+ */
160
+ shutdown() {
161
+ this.instances.clear();
162
+ this.disposed = true;
163
+ }
121
164
  isDisposed() {
122
165
  return this.disposed;
123
166
  }
124
- reset() {
125
- this.instances.clear();
126
- this.disposed = false;
127
- }
128
167
  getTrackedTokens() {
129
168
  return [...this.instances.keys()];
130
169
  }
@@ -134,8 +173,12 @@ async function disposeValue(value) {
134
173
  await value[Symbol.asyncDispose]();
135
174
  return;
136
175
  }
176
+ if (isSymbolDisposable(value)) {
177
+ value[Symbol.dispose]();
178
+ return;
179
+ }
137
180
  if (isDisposable(value)) {
138
- value.dispose();
181
+ await value.dispose();
139
182
  return;
140
183
  }
141
184
  }
@@ -4,26 +4,18 @@
4
4
  import type { ContainerLifecycleOptions } from "../containerLifecycle/containerLifecycle.core.js";
5
5
  import type { ContainerRegistryOptions } from "../containerRegistry/containerRegistry.type.js";
6
6
  import type { ResolutionOptions } from "../containerResolution/containerResolution.type.js";
7
- export declare enum ContainerLogLevel {
8
- NONE = "none",
9
- ERROR = "error",
10
- WARN = "warn",
11
- INFO = "info",
12
- DEBUG = "debug",
13
- TRACE = "trace"
14
- }
15
- export declare const DEFAULT_CONTAINER_LOG_LEVEL: ContainerLogLevel;
16
- export interface ContainerResolutionOptions extends ResolutionOptions {
17
- readonly autoRegisterClasses?: boolean;
18
- readonly detectCircularDependencies?: boolean;
19
- readonly maxResolutionDepth?: number;
20
- }
7
+ /**
8
+ * The subset of {@link ResolutionOptions} a container accepts at
9
+ * construction time. Per-call plumbing (`cache`, `path`,
10
+ * `allowRegistration`, `onInstanceCreated`) is managed by the container
11
+ * itself and deliberately not configurable here.
12
+ */
13
+ export type ContainerResolutionOptions = Pick<ResolutionOptions, "autoRegisterClasses" | "detectCircularDependencies" | "maxResolutionDepth">;
21
14
  export interface ContainerOptions {
22
15
  readonly name?: string;
23
16
  readonly registry?: ContainerRegistryOptions;
24
17
  readonly lifecycle?: ContainerLifecycleOptions;
25
18
  readonly resolution?: ContainerResolutionOptions;
26
- readonly logLevel?: ContainerLogLevel;
27
19
  readonly autoDispose?: boolean;
28
20
  readonly allowScopes?: boolean;
29
21
  readonly freezeRegistrations?: boolean;
@@ -34,7 +26,6 @@ export interface ResolvedContainerOptions {
34
26
  readonly registry: ContainerRegistryOptions;
35
27
  readonly lifecycle: ContainerLifecycleOptions;
36
28
  readonly resolution: ContainerResolutionOptions;
37
- readonly logLevel: ContainerLogLevel;
38
29
  readonly autoDispose: boolean;
39
30
  readonly allowScopes: boolean;
40
31
  readonly freezeRegistrations: boolean;
@@ -47,7 +38,6 @@ export declare const DEFAULT_FREEZE_REGISTRATIONS = false;
47
38
  export declare const DEFAULT_RESOLUTION_OPTIONS: Required<Pick<ContainerResolutionOptions, "autoRegisterClasses" | "detectCircularDependencies" | "maxResolutionDepth">>;
48
39
  export declare function resolveContainerOptions(options?: ContainerOptions): ResolvedContainerOptions;
49
40
  export declare function validateResolutionOptions(options: ContainerResolutionOptions): void;
50
- export declare function isContainerLogLevel(value: unknown): value is ContainerLogLevel;
51
41
  export declare function allowsContainerScopes(options: ResolvedContainerOptions): boolean;
52
42
  export declare function shouldAutoDisposeContainer(options: ResolvedContainerOptions): boolean;
53
43
  export declare function canModifyRegistrations(options: ResolvedContainerOptions): boolean;
@@ -1,16 +1,6 @@
1
1
  /**
2
2
  * Configuration options for the Zudojs dependency injection container.
3
3
  */
4
- export var ContainerLogLevel;
5
- (function (ContainerLogLevel) {
6
- ContainerLogLevel["NONE"] = "none";
7
- ContainerLogLevel["ERROR"] = "error";
8
- ContainerLogLevel["WARN"] = "warn";
9
- ContainerLogLevel["INFO"] = "info";
10
- ContainerLogLevel["DEBUG"] = "debug";
11
- ContainerLogLevel["TRACE"] = "trace";
12
- })(ContainerLogLevel || (ContainerLogLevel = {}));
13
- export const DEFAULT_CONTAINER_LOG_LEVEL = ContainerLogLevel.WARN;
14
4
  export const DEFAULT_CONTAINER_NAME = "zudojs-container";
15
5
  export const DEFAULT_AUTO_DISPOSE = true;
16
6
  export const DEFAULT_ALLOW_SCOPES = true;
@@ -39,7 +29,6 @@ export function resolveContainerOptions(options = {}) {
39
29
  registry: Object.freeze({ ...(options.registry ?? {}) }),
40
30
  lifecycle: Object.freeze({ ...(options.lifecycle ?? {}) }),
41
31
  resolution: Object.freeze({ ...resolution }),
42
- logLevel: options.logLevel ?? DEFAULT_CONTAINER_LOG_LEVEL,
43
32
  autoDispose: options.autoDispose ?? DEFAULT_AUTO_DISPOSE,
44
33
  allowScopes: options.allowScopes ?? DEFAULT_ALLOW_SCOPES,
45
34
  freezeRegistrations: options.freezeRegistrations ?? DEFAULT_FREEZE_REGISTRATIONS,
@@ -53,14 +42,6 @@ export function validateResolutionOptions(options) {
53
42
  throw new RangeError("Container maxResolutionDepth must be a positive integer.");
54
43
  }
55
44
  }
56
- export function isContainerLogLevel(value) {
57
- return (value === ContainerLogLevel.NONE ||
58
- value === ContainerLogLevel.ERROR ||
59
- value === ContainerLogLevel.WARN ||
60
- value === ContainerLogLevel.INFO ||
61
- value === ContainerLogLevel.DEBUG ||
62
- value === ContainerLogLevel.TRACE);
63
- }
64
45
  export function allowsContainerScopes(options) {
65
46
  return options.allowScopes;
66
47
  }
@@ -6,6 +6,11 @@ import type { Constructor, InjectionToken, Token } from "../containerToken/conta
6
6
  export type ProviderToken<T = unknown> = Token<T> | InjectionToken<T>;
7
7
  export interface ClassProvider<T> {
8
8
  readonly useClass: Constructor<T>;
9
+ /**
10
+ * Tokens resolved and passed to the constructor, in order.
11
+ * Omit (or leave empty) for zero-argument constructors.
12
+ */
13
+ readonly inject?: readonly ProviderToken[];
9
14
  }
10
15
  export interface FactoryProvider<T> {
11
16
  readonly useFactory: (...dependencies: unknown[]) => T;
@@ -25,6 +30,7 @@ export interface TokenProvider<T = unknown> {
25
30
  export interface ClassRegistration<T = unknown> {
26
31
  readonly provide: ProviderToken<T>;
27
32
  readonly useClass: Constructor<T>;
33
+ readonly inject?: readonly ProviderToken[];
28
34
  }
29
35
  export interface FactoryRegistration<T = unknown> {
30
36
  readonly provide: ProviderToken<T>;
@@ -45,12 +51,14 @@ export declare function isFactoryProvider<T = unknown>(provider: Provider<T>): p
45
51
  export declare function isValueProvider<T = unknown>(provider: Provider<T>): provider is ValueProvider<T>;
46
52
  export declare function isExistingProvider<T = unknown>(provider: Provider<T>): provider is ExistingProvider<T>;
47
53
  export declare function isTokenProvider<T = unknown>(provider: ContainerProvider<T>): provider is TokenProvider<T>;
48
- export declare function hasInjectedDependencies<T = unknown>(provider: Provider<T>): provider is FactoryProvider<T>;
49
- export declare function classProvider<T>(useClass: Constructor<T>): ClassProvider<T>;
54
+ export declare function hasInjectedDependencies<T = unknown>(provider: Provider<T>): provider is (FactoryProvider<T> | ClassProvider<T>) & {
55
+ readonly inject: readonly ProviderToken[];
56
+ };
57
+ export declare function classProvider<T>(useClass: Constructor<T>, inject?: readonly ProviderToken[]): ClassProvider<T>;
50
58
  export declare function factoryProvider<T>(useFactory: (...dependencies: unknown[]) => T, inject?: readonly ProviderToken[]): FactoryProvider<T>;
51
59
  export declare function valueProvider<T>(useValue: T): ValueProvider<T>;
52
60
  export declare function existingProvider<T>(useExisting: ProviderToken<T>): ExistingProvider<T>;
53
- export declare function provideClass<T>(provide: ProviderToken<T>, useClass: Constructor<T>): ClassRegistration<T>;
61
+ export declare function provideClass<T>(provide: ProviderToken<T>, useClass: Constructor<T>, inject?: readonly ProviderToken[]): ClassRegistration<T>;
54
62
  export declare function provideFactory<T>(provide: ProviderToken<T>, useFactory: (...dependencies: unknown[]) => T, inject?: readonly ProviderToken[]): FactoryRegistration<T>;
55
63
  export declare function provideValue<T>(provide: ProviderToken<T>, useValue: T): ValueRegistration<T>;
56
64
  export declare function provideExisting<T>(provide: ProviderToken<T>, useExisting: ProviderToken<T>): ExistingRegistration<T>;
@@ -18,10 +18,12 @@ export function isTokenProvider(provider) {
18
18
  return "provide" in provider && "provider" in provider;
19
19
  }
20
20
  export function hasInjectedDependencies(provider) {
21
- return isFactoryProvider(provider) && Array.isArray(provider.inject);
21
+ return ((isFactoryProvider(provider) || isClassProvider(provider)) &&
22
+ Array.isArray(provider.inject) &&
23
+ provider.inject.length > 0);
22
24
  }
23
- export function classProvider(useClass) {
24
- return Object.freeze({ useClass });
25
+ export function classProvider(useClass, inject = []) {
26
+ return Object.freeze({ useClass, inject: Object.freeze([...inject]) });
25
27
  }
26
28
  export function factoryProvider(useFactory, inject = []) {
27
29
  return Object.freeze({ useFactory, inject: Object.freeze([...inject]) });
@@ -32,8 +34,12 @@ export function valueProvider(useValue) {
32
34
  export function existingProvider(useExisting) {
33
35
  return Object.freeze({ useExisting });
34
36
  }
35
- export function provideClass(provide, useClass) {
36
- return Object.freeze({ provide, useClass });
37
+ export function provideClass(provide, useClass, inject = []) {
38
+ return Object.freeze({
39
+ provide,
40
+ useClass,
41
+ inject: Object.freeze([...inject]),
42
+ });
37
43
  }
38
44
  export function provideFactory(provide, useFactory, inject = []) {
39
45
  return Object.freeze({
@@ -6,6 +6,15 @@ import { ContainerScope } from "../containerScope/containerScope.type.js";
6
6
  import type { ContainerProvider, ProviderToken } from "../containerProvider/containerProvider.core.js";
7
7
  import type { InjectionToken, Token } from "../containerToken/containerToken.type.js";
8
8
  export type RegistrationToken<T = unknown> = Token<T> | InjectionToken<T>;
9
+ /** The type a registration token resolves to (`unknown` for untyped tokens). */
10
+ export type ResolvedToken<T extends RegistrationToken> = T extends RegistrationToken<infer U> ? U : never;
11
+ /**
12
+ * Maps a tuple of registration tokens to a tuple of their resolved types, so
13
+ * `resolveMany([LOGGER, DB])` is typed `[Logger, Db]`.
14
+ */
15
+ export type ResolvedTokens<Tokens extends readonly RegistrationToken[]> = {
16
+ -readonly [K in keyof Tokens]: Tokens[K] extends RegistrationToken ? ResolvedToken<Tokens[K]> : never;
17
+ };
9
18
  export interface RegistrationMetadata {
10
19
  readonly name?: string;
11
20
  readonly description?: string;
@@ -18,7 +27,6 @@ export interface ContainerRegistration<T = unknown> {
18
27
  readonly provider: ContainerProvider<T>;
19
28
  readonly scope: ContainerScope;
20
29
  readonly metadata: RegistrationMetadata;
21
- readonly initialized: boolean;
22
30
  readonly createdAt: Date;
23
31
  }
24
32
  export interface CreateRegistrationOptions extends RegistrationMetadata {
@@ -29,13 +37,11 @@ export interface MutableRegistrationState<T = unknown> {
29
37
  readonly provider: ContainerProvider<T>;
30
38
  scope: ContainerScope;
31
39
  metadata: RegistrationMetadata;
32
- initialized: boolean;
33
40
  createdAt: Date;
34
41
  }
35
42
  export declare function createRegistration<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
36
43
  export declare function createMutableRegistrationState<T>(registration: ContainerRegistration<T>): MutableRegistrationState<T>;
37
44
  export declare function freezeRegistration<T>(state: MutableRegistrationState<T>): ContainerRegistration<T>;
38
- export declare function markRegistrationInitialized<T>(registration: ContainerRegistration<T>): ContainerRegistration<T>;
39
45
  export declare function getRegistrationToken<T>(registration: ContainerRegistration<T>): Token<T>;
40
46
  export declare function getRegistrationProviderToken<T>(registration: ContainerRegistration<T>): ProviderToken<T> | undefined;
41
47
  export declare function isSingletonRegistration<T>(registration: ContainerRegistration<T>): boolean;
@@ -13,7 +13,6 @@ export function createRegistration(token, provider, options = {}) {
13
13
  provider: normalizedProvider,
14
14
  scope: resolveContainerScope(options.scope),
15
15
  metadata: createRegistrationMetadata(options, normalizedToken),
16
- initialized: false,
17
16
  createdAt: new Date(),
18
17
  };
19
18
  return Object.freeze({
@@ -43,7 +42,6 @@ export function createMutableRegistrationState(registration) {
43
42
  provider: registration.provider,
44
43
  scope: registration.scope,
45
44
  metadata: registration.metadata,
46
- initialized: registration.initialized,
47
45
  createdAt: registration.createdAt,
48
46
  };
49
47
  }
@@ -58,13 +56,9 @@ export function freezeRegistration(state) {
58
56
  ? Object.freeze({ ...state.metadata.metadata })
59
57
  : undefined,
60
58
  }),
61
- initialized: state.initialized,
62
59
  createdAt: state.createdAt,
63
60
  });
64
61
  }
65
- export function markRegistrationInitialized(registration) {
66
- return Object.freeze({ ...registration, initialized: true });
67
- }
68
62
  export function getRegistrationToken(registration) {
69
63
  return unwrapToken(registration.token);
70
64
  }
@@ -1,9 +1,12 @@
1
1
  /**
2
2
  * Container registration registry.
3
+ *
4
+ * The registry stores normalized registrations and emits change events
5
+ * (REGISTER / REPLACE / REMOVE / CLEAR / RESTORE) so collaborators — notably
6
+ * the resolver's singleton cache — can react to mutations.
3
7
  */
4
8
  import type { ContainerProvider } from "../containerProvider/containerProvider.core.js";
5
- import type { ContainerScope } from "../containerScope/containerScope.type.js";
6
- import type { ContainerRegistration, CreateRegistrationOptions, RegistrationMetadata, RegistrationToken } from "../containerRegistration/containerRegistration.core.js";
9
+ import type { ContainerRegistration, CreateRegistrationOptions, RegistrationToken } from "../containerRegistration/containerRegistration.core.js";
7
10
  import type { Token } from "../containerToken/containerToken.type.js";
8
11
  import type { ContainerRegistryOptions, RegistryListener } from "./containerRegistry.type.js";
9
12
  export declare class ContainerRegistry {
@@ -12,25 +15,36 @@ export declare class ContainerRegistry {
12
15
  private readonly allowDuplicates;
13
16
  constructor(options?: ContainerRegistryOptions);
14
17
  register<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
15
- registerRegistration<T>(registration: ContainerRegistration<T>): ContainerRegistration<T>;
16
18
  replace<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
17
19
  get<T>(token: RegistrationToken<T>): ContainerRegistration<T> | undefined;
18
- getOrThrow<T>(token: RegistrationToken<T>): ContainerRegistration<T>;
19
20
  has<T>(token: RegistrationToken<T>): boolean;
20
21
  remove<T>(token: RegistrationToken<T>): boolean;
21
- removeOrThrow<T>(token: RegistrationToken<T>): void;
22
22
  get size(): number;
23
23
  getAll(): readonly ContainerRegistration[];
24
24
  getTokens(): readonly Token<unknown>[];
25
- getByModule(module: string): readonly ContainerRegistration[];
26
- getByScope(scope: ContainerScope): readonly ContainerRegistration[];
27
- find(predicate: (r: ContainerRegistration) => boolean): readonly ContainerRegistration[];
28
- getMetadata<T>(token: RegistrationToken<T>): RegistrationMetadata | undefined;
29
25
  clear(): void;
30
26
  subscribe(listener: RegistryListener): () => void;
31
27
  clearListeners(): void;
28
+ /**
29
+ * Notifies all listeners. Listener errors are collected and rethrown as a
30
+ * single AggregateError after every listener has been notified — they are
31
+ * never silently swallowed.
32
+ */
32
33
  private emit;
34
+ /**
35
+ * Returns an immutable snapshot of the current registrations.
36
+ * Pass the result to {@link restore} to roll the registry back.
37
+ */
33
38
  snapshot(): readonly ContainerRegistration[];
39
+ /**
40
+ * Wholesale replacement of the registry's contents.
41
+ *
42
+ * Every existing registration is discarded and replaced by `regs` (entries
43
+ * are validated first; duplicate tokens in `regs` throw unless
44
+ * `allowDuplicates` is enabled, in which case the last entry wins).
45
+ * Emits a single RESTORE event so caches keyed on the old registrations
46
+ * can be evicted.
47
+ */
34
48
  restore(regs: readonly ContainerRegistration[]): void;
35
49
  }
36
50
  //# sourceMappingURL=containerRegistry.core.d.ts.map