@zudojs/container 1.2.3 → 1.3.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 (54) hide show
  1. package/README.md +25 -6
  2. package/dist/containerCore/containerCore.core.d.ts +32 -7
  3. package/dist/containerCore/containerCore.core.js +23 -1
  4. package/dist/containerCore/containerCore.scope.d.ts +0 -1
  5. package/dist/containerCore/containerCore.scope.js +0 -1
  6. package/dist/containerCore/containerCore.type.d.ts +0 -1
  7. package/dist/containerCore/containerCore.type.js +0 -1
  8. package/dist/containerCore/index.d.ts +0 -1
  9. package/dist/containerCore/index.js +0 -1
  10. package/dist/containerLifecycle/containerLifecycle.core.d.ts +0 -1
  11. package/dist/containerLifecycle/containerLifecycle.core.js +0 -1
  12. package/dist/containerLifecycle/index.d.ts +0 -1
  13. package/dist/containerLifecycle/index.js +0 -1
  14. package/dist/containerOptions/containerOptions.type.d.ts +0 -1
  15. package/dist/containerOptions/containerOptions.type.js +0 -1
  16. package/dist/containerOptions/index.d.ts +0 -1
  17. package/dist/containerOptions/index.js +0 -1
  18. package/dist/containerProvider/containerProvider.core.d.ts +29 -3
  19. package/dist/containerProvider/containerProvider.core.js +14 -3
  20. package/dist/containerProvider/index.d.ts +0 -1
  21. package/dist/containerProvider/index.js +0 -1
  22. package/dist/containerRegistration/containerRegistration.core.d.ts +0 -1
  23. package/dist/containerRegistration/containerRegistration.core.js +0 -1
  24. package/dist/containerRegistration/index.d.ts +0 -1
  25. package/dist/containerRegistration/index.js +0 -1
  26. package/dist/containerRegistry/containerRegistry.core.d.ts +0 -1
  27. package/dist/containerRegistry/containerRegistry.core.js +0 -1
  28. package/dist/containerRegistry/containerRegistry.type.d.ts +0 -1
  29. package/dist/containerRegistry/containerRegistry.type.js +0 -1
  30. package/dist/containerRegistry/index.d.ts +0 -1
  31. package/dist/containerRegistry/index.js +0 -1
  32. package/dist/containerResolution/containerResolution.autoRegister.d.ts +7 -3
  33. package/dist/containerResolution/containerResolution.autoRegister.js +7 -3
  34. package/dist/containerResolution/containerResolution.core.d.ts +0 -1
  35. package/dist/containerResolution/containerResolution.core.js +17 -3
  36. package/dist/containerResolution/containerResolution.dependents.d.ts +0 -1
  37. package/dist/containerResolution/containerResolution.dependents.js +0 -1
  38. package/dist/containerResolution/containerResolution.error.d.ts +0 -1
  39. package/dist/containerResolution/containerResolution.error.js +0 -1
  40. package/dist/containerResolution/containerResolution.type.d.ts +10 -2
  41. package/dist/containerResolution/containerResolution.type.js +0 -1
  42. package/dist/containerResolution/index.d.ts +0 -1
  43. package/dist/containerResolution/index.js +0 -1
  44. package/dist/containerScope/containerScope.type.d.ts +0 -1
  45. package/dist/containerScope/containerScope.type.js +0 -1
  46. package/dist/containerScope/index.d.ts +0 -1
  47. package/dist/containerScope/index.js +0 -1
  48. package/dist/containerToken/containerToken.type.d.ts +0 -1
  49. package/dist/containerToken/containerToken.type.js +0 -1
  50. package/dist/containerToken/index.d.ts +0 -1
  51. package/dist/containerToken/index.js +0 -1
  52. package/dist/index.d.ts +0 -1
  53. package/dist/index.js +0 -1
  54. package/package.json +2 -2
package/README.md CHANGED
@@ -47,6 +47,12 @@ container.registerFactory(API, (db) => new Api(db), [DB]); // deps via inject li
47
47
  container.registerExisting("db-alias", DB); // alias to another token
48
48
  ```
49
49
 
50
+ Every `register*` call except `registerValue` defaults to
51
+ **`ContainerScope.TRANSIENT`**: the class or factory runs again on every
52
+ `resolve()`. Pass `{ scope: ContainerScope.SINGLETON }` (the fourth argument
53
+ of `registerFactory`) for a pool, a client or anything else that must be
54
+ shared.
55
+
50
56
  A factory's parameters are typed from its `inject` list, in order: with
51
57
  `DB = createToken<Db>("Db")`, `(db) => new Api(db)` receives `db: Db`, and a
52
58
  factory whose parameters do not match the tokens is a compile error. Class
@@ -54,6 +60,14 @@ tokens type the same way; plain string and symbol tokens give `unknown`.
54
60
  `factoryProvider(factory, inject)` and `provideFactory(token, factory,
55
61
  inject)` infer the same way.
56
62
 
63
+ `registerClass(token, Class, { inject })`, `classProvider(Class, inject)` and
64
+ `provideClass(token, Class, inject)` check the constructor the same way:
65
+ `inject: [CLOCK, DB]` against `constructor(db: Db, clock: Clock)` is a compile
66
+ error, and so is omitting `inject` for a constructor with required
67
+ parameters. Untyped string/symbol tokens check nothing for classes, a
68
+ non-tuple `ProviderToken[]` built at runtime accepts any constructor, and
69
+ defaulted parameters beyond the list are fine.
70
+
57
71
  ```typescript
58
72
  container.registerFactory(
59
73
  REPORT,
@@ -164,10 +178,11 @@ container.register(API, {
164
178
 
165
179
  Classes without an `inject` list are constructed with zero arguments, so
166
180
  only a constructor that declares no parameters may omit it (parameters with
167
- a default value do not count). Registering such a class without `inject`
168
- is allowed, but resolving it throws a `ProviderResolutionError` naming the
169
- class and the `inject: [...]` fix, instead of building it with `undefined`
170
- dependencies. There is no reflection/decorator magic — dependencies are
181
+ a default value do not count). In TypeScript, registering such a class
182
+ without `inject` is a compile error; at runtime (JavaScript callers, casts)
183
+ registering is allowed but resolving throws a `ProviderResolutionError`
184
+ naming the class and the `inject: [...]` fix, instead of building it with
185
+ `undefined` dependencies. There is no reflection/decorator magic — dependencies are
171
186
  exactly the tokens you list, resolved in order.
172
187
 
173
188
  ## Duplicate registrations
@@ -212,8 +227,12 @@ const container = createContainer({
212
227
  has no inject list, so `resolve(NeedsDep)` for
213
228
  `constructor(dep: Dep)` throws `RegistrationNotFoundError` naming the
214
229
  class and telling you to register it with an `inject` list, instead of
215
- building it with `dep = undefined`. Parameters with defaults do not
216
- count.
230
+ building it with `dep = undefined`. Parameters with defaults and rest
231
+ parameters do not count: `constructor(deps: Deps = {})` has
232
+ `length === 0`, so it _is_ auto-registered and built with no arguments —
233
+ the default applies and nothing is injected. Register such a class with
234
+ an `inject` list when the container should supply those values; the
235
+ container cannot tell "optional" from "please inject" at runtime.
217
236
  - `detectCircularDependencies` — circular chains throw
218
237
  `CircularDependencyError` with the full chain. When disabled,
219
238
  `maxResolutionDepth` still stops runaway recursion.
@@ -12,20 +12,23 @@
12
12
  * - TRANSIENT instances are never cached and never tracked — callers own
13
13
  * their disposal.
14
14
  */
15
- import type { ContainerProvider, InjectedFactory, ProviderToken } from "../containerProvider/containerProvider.core.js";
15
+ import type { ContainerProvider, InjectedConstructor, InjectedFactory, ProviderToken } from "../containerProvider/containerProvider.core.js";
16
16
  import type { ContainerRegistration, CreateRegistrationOptions, RegistrationToken, ResolvedTokens } from "../containerRegistration/containerRegistration.core.js";
17
17
  import type { ResolutionCache, ResolutionResult } from "../containerResolution/containerResolution.type.js";
18
18
  import type { ContainerOptions, ResolvedContainerOptions } from "../containerOptions/containerOptions.type.js";
19
- import type { Constructor, Token } from "../containerToken/containerToken.type.js";
19
+ import type { Token } from "../containerToken/containerToken.type.js";
20
20
  import type { ContainerLike, ContainerScopeOptions } from "./containerCore.type.js";
21
21
  import { ContainerScopeContext } from "./containerCore.scope.js";
22
- /** Options accepted by {@link Container.registerClass}. */
23
- export interface RegisterClassOptions extends CreateRegistrationOptions {
22
+ /**
23
+ * Options accepted by {@link Container.registerClass}. `Deps` is inferred
24
+ * from the `inject` tuple and checked against the class's constructor.
25
+ */
26
+ export interface RegisterClassOptions<Deps extends readonly ProviderToken[] = readonly ProviderToken[]> extends CreateRegistrationOptions {
24
27
  /**
25
28
  * Tokens resolved and passed to the constructor, in order.
26
29
  * Omit for zero-argument constructors.
27
30
  */
28
- readonly inject?: readonly ProviderToken[];
31
+ readonly inject?: Deps;
29
32
  }
30
33
  export declare class Container implements ContainerLike {
31
34
  #private;
@@ -41,8 +44,26 @@ export declare class Container implements ContainerLike {
41
44
  * performed by the first `resolve()` — freezes the registration set.
42
45
  */
43
46
  start(): this;
47
+ /**
48
+ * Registers a provider under a token.
49
+ *
50
+ * The default `scope` is **`ContainerScope.TRANSIENT`**: the provider
51
+ * runs on every `resolve()`. Pass `{ scope: ContainerScope.SINGLETON }`
52
+ * for anything that must be shared (a pool, a client, a cache).
53
+ */
44
54
  register<T>(token: RegistrationToken<T>, provider: ContainerProvider<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
45
- registerClass<T>(token: RegistrationToken<T>, ctor: Constructor<T>, options?: RegisterClassOptions): ContainerRegistration<T>;
55
+ /**
56
+ * Registers a class. Its constructor parameters are checked against the
57
+ * `inject` tokens, in order: `registerClass(API, Api, { inject: [DB] })`
58
+ * requires `Api`'s constructor to accept a `Db` when `DB` is a
59
+ * `createToken<Db>()` or class token, and swapping two typed tokens is a
60
+ * compile error. String/symbol tokens are untyped and check nothing.
61
+ * Without `inject` the class must be constructible with no arguments.
62
+ *
63
+ * Defaults to **`ContainerScope.TRANSIENT`** (a new instance per
64
+ * resolution) unless `options.scope` says otherwise.
65
+ */
66
+ registerClass<T, const Deps extends readonly ProviderToken[] = readonly []>(token: RegistrationToken<T>, ctor: InjectedConstructor<T, NoInfer<Deps>>, options?: RegisterClassOptions<Deps>): ContainerRegistration<T>;
46
67
  /**
47
68
  * Registers a pre-built value.
48
69
  *
@@ -57,6 +78,11 @@ export declare class Container implements ContainerLike {
57
78
  * as `Db` when `DB` is a `createToken<Db>()` or class token, and rejects a
58
79
  * factory whose parameters do not match. String/symbol tokens give
59
80
  * `unknown`.
81
+ *
82
+ * **The default scope is `ContainerScope.TRANSIENT`: the factory runs on
83
+ * every `resolve()`.** A database pool or HTTP client registered this way
84
+ * is rebuilt for each consumer unless you pass
85
+ * `{ scope: ContainerScope.SINGLETON }` as the fourth argument.
60
86
  */
61
87
  registerFactory<T, const Deps extends readonly ProviderToken[] = readonly []>(token: RegistrationToken<T>, factory: InjectedFactory<T, Deps>, inject?: Deps, options?: CreateRegistrationOptions): ContainerRegistration<T>;
62
88
  registerExisting<T>(token: RegistrationToken<T>, existing: ProviderToken<T>, options?: CreateRegistrationOptions): ContainerRegistration<T>;
@@ -159,4 +185,3 @@ export declare class Container implements ContainerLike {
159
185
  }
160
186
  export declare function createContainer(options?: ContainerOptions): Container;
161
187
  export declare function createStartedContainer(options?: ContainerOptions): Container;
162
- //# sourceMappingURL=containerCore.core.d.ts.map
@@ -66,10 +66,28 @@ export class Container {
66
66
  this.#started = true;
67
67
  return this;
68
68
  }
69
+ /**
70
+ * Registers a provider under a token.
71
+ *
72
+ * The default `scope` is **`ContainerScope.TRANSIENT`**: the provider
73
+ * runs on every `resolve()`. Pass `{ scope: ContainerScope.SINGLETON }`
74
+ * for anything that must be shared (a pool, a client, a cache).
75
+ */
69
76
  register(token, provider, options = {}) {
70
77
  this.ensureMutable();
71
78
  return this.#registry.register(token, provider, options);
72
79
  }
80
+ /**
81
+ * Registers a class. Its constructor parameters are checked against the
82
+ * `inject` tokens, in order: `registerClass(API, Api, { inject: [DB] })`
83
+ * requires `Api`'s constructor to accept a `Db` when `DB` is a
84
+ * `createToken<Db>()` or class token, and swapping two typed tokens is a
85
+ * compile error. String/symbol tokens are untyped and check nothing.
86
+ * Without `inject` the class must be constructible with no arguments.
87
+ *
88
+ * Defaults to **`ContainerScope.TRANSIENT`** (a new instance per
89
+ * resolution) unless `options.scope` says otherwise.
90
+ */
73
91
  registerClass(token, ctor, options = {}) {
74
92
  const { inject, ...rest } = options;
75
93
  return this.register(token, classProvider(ctor, inject ?? []), rest);
@@ -93,6 +111,11 @@ export class Container {
93
111
  * as `Db` when `DB` is a `createToken<Db>()` or class token, and rejects a
94
112
  * factory whose parameters do not match. String/symbol tokens give
95
113
  * `unknown`.
114
+ *
115
+ * **The default scope is `ContainerScope.TRANSIENT`: the factory runs on
116
+ * every `resolve()`.** A database pool or HTTP client registered this way
117
+ * is rebuilt for each consumer unless you pass
118
+ * `{ scope: ContainerScope.SINGLETON }` as the fourth argument.
96
119
  */
97
120
  registerFactory(token, factory, inject = [], options = {}) {
98
121
  return this.register(token, factoryProvider(factory, inject), options);
@@ -346,4 +369,3 @@ export function createContainer(options = {}) {
346
369
  export function createStartedContainer(options = {}) {
347
370
  return new Container(options).start();
348
371
  }
349
- //# sourceMappingURL=containerCore.core.js.map
@@ -110,4 +110,3 @@ export declare class ContainerScopeContext {
110
110
  */
111
111
  private ensureActive;
112
112
  }
113
- //# sourceMappingURL=containerCore.scope.d.ts.map
@@ -200,4 +200,3 @@ export class ContainerScopeContext {
200
200
  }
201
201
  }
202
202
  }
203
- //# sourceMappingURL=containerCore.scope.js.map
@@ -43,4 +43,3 @@ export interface ContainerLike {
43
43
  /** @internal Unregisters a top-level scope from the container's live-scope set. */
44
44
  releaseScope(scope: ContainerScopeContext): void;
45
45
  }
46
- //# sourceMappingURL=containerCore.type.d.ts.map
@@ -2,4 +2,3 @@
2
2
  * Types for the core container.
3
3
  */
4
4
  export {};
5
- //# sourceMappingURL=containerCore.type.js.map
@@ -6,4 +6,3 @@
6
6
  export * from "./containerCore.type.js";
7
7
  export * from "./containerCore.scope.js";
8
8
  export * from "./containerCore.core.js";
9
- //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,3 @@
6
6
  export * from "./containerCore.type.js";
7
7
  export * from "./containerCore.scope.js";
8
8
  export * from "./containerCore.core.js";
9
- //# sourceMappingURL=index.js.map
@@ -103,4 +103,3 @@ export declare class ContainerLifecycle {
103
103
  getTrackedTokens(): readonly Token<unknown>[];
104
104
  }
105
105
  export declare function createContainerLifecycle(options?: ContainerLifecycleOptions): ContainerLifecycle;
106
- //# sourceMappingURL=containerLifecycle.core.d.ts.map
@@ -187,4 +187,3 @@ async function disposeValue(value) {
187
187
  export function createContainerLifecycle(options = {}) {
188
188
  return new ContainerLifecycle(options);
189
189
  }
190
- //# sourceMappingURL=containerLifecycle.core.js.map
@@ -4,4 +4,3 @@
4
4
  * Container lifecycle management and scoping.
5
5
  */
6
6
  export * from "./containerLifecycle.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Container lifecycle management and scoping.
5
5
  */
6
6
  export * from "./containerLifecycle.core.js";
7
- //# sourceMappingURL=index.js.map
@@ -41,4 +41,3 @@ export declare function validateResolutionOptions(options: ContainerResolutionOp
41
41
  export declare function allowsContainerScopes(options: ResolvedContainerOptions): boolean;
42
42
  export declare function shouldAutoDisposeContainer(options: ResolvedContainerOptions): boolean;
43
43
  export declare function canModifyRegistrations(options: ResolvedContainerOptions): boolean;
44
- //# sourceMappingURL=containerOptions.type.d.ts.map
@@ -51,4 +51,3 @@ export function shouldAutoDisposeContainer(options) {
51
51
  export function canModifyRegistrations(options) {
52
52
  return !options.freezeRegistrations;
53
53
  }
54
- //# sourceMappingURL=containerOptions.type.js.map
@@ -4,4 +4,3 @@
4
4
  * Container configuration options and types.
5
5
  */
6
6
  export * from "./containerOptions.type.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Container configuration options and types.
5
5
  */
6
6
  export * from "./containerOptions.type.js";
7
- //# sourceMappingURL=index.js.map
@@ -15,6 +15,24 @@ export type InjectedDependencies<Deps extends readonly ProviderToken[]> = {
15
15
  };
16
16
  /** A factory whose parameters are typed from its `inject` list. */
17
17
  export type InjectedFactory<T, Deps extends readonly ProviderToken[]> = (...dependencies: InjectedDependencies<Deps>) => T;
18
+ /**
19
+ * The constructor parameter list an `inject` list must satisfy. A typed
20
+ * token (`createToken<Db>()`, a class) contributes its type; an untyped
21
+ * string/symbol token contributes `any`, because a class declares its own
22
+ * parameter types and an untyped token carries nothing to check them
23
+ * against. A non-tuple `readonly ProviderToken[]` (a list built at runtime)
24
+ * has no positions to check and accepts any constructor.
25
+ */
26
+ export type InjectedConstructorArgs<Deps extends readonly ProviderToken[]> = number extends Deps["length"] ? any[] : {
27
+ -readonly [K in keyof Deps]: Deps[K] extends ProviderToken<infer U> ? unknown extends U ? any : U : never;
28
+ };
29
+ /**
30
+ * A class whose constructor parameters are typed from its `inject` list, in
31
+ * order: `[DB, Clock]` requires `new (db: Db, clock: Clock)`. Swapping two
32
+ * typed tokens, or omitting the list for a constructor with required
33
+ * parameters, is a compile error instead of a runtime `undefined`.
34
+ */
35
+ export type InjectedConstructor<T, Deps extends readonly ProviderToken[]> = new (...args: InjectedConstructorArgs<Deps>) => T;
18
36
  export interface ClassProvider<T> {
19
37
  readonly useClass: Constructor<T>;
20
38
  /**
@@ -65,7 +83,12 @@ export declare function isTokenProvider<T = unknown>(provider: ContainerProvider
65
83
  export declare function hasInjectedDependencies<T = unknown>(provider: Provider<T>): provider is (FactoryProvider<T> | ClassProvider<T>) & {
66
84
  readonly inject: readonly ProviderToken[];
67
85
  };
68
- export declare function classProvider<T>(useClass: Constructor<T>, inject?: readonly ProviderToken[]): ClassProvider<T>;
86
+ /**
87
+ * Builds a class provider. The constructor's parameters are checked against
88
+ * the `inject` tokens, in order (see {@link InjectedConstructor}); with no
89
+ * list the class must be constructible with no arguments.
90
+ */
91
+ export declare function classProvider<T, const Deps extends readonly ProviderToken[] = readonly []>(useClass: InjectedConstructor<T, NoInfer<Deps>>, inject?: Deps): ClassProvider<T>;
69
92
  /**
70
93
  * Builds a factory provider. The factory's parameters are inferred from the
71
94
  * `inject` tokens, in order.
@@ -73,7 +96,11 @@ export declare function classProvider<T>(useClass: Constructor<T>, inject?: read
73
96
  export declare function factoryProvider<T, const Deps extends readonly ProviderToken[] = readonly []>(useFactory: InjectedFactory<T, Deps>, inject?: Deps): FactoryProvider<T>;
74
97
  export declare function valueProvider<T>(useValue: T): ValueProvider<T>;
75
98
  export declare function existingProvider<T>(useExisting: ProviderToken<T>): ExistingProvider<T>;
76
- export declare function provideClass<T>(provide: ProviderToken<T>, useClass: Constructor<T>, inject?: readonly ProviderToken[]): ClassRegistration<T>;
99
+ /**
100
+ * Builds a class registration. The constructor's parameters are checked
101
+ * against the `inject` tokens, in order (see {@link InjectedConstructor}).
102
+ */
103
+ export declare function provideClass<T, const Deps extends readonly ProviderToken[] = readonly []>(provide: ProviderToken<T>, useClass: InjectedConstructor<T, NoInfer<Deps>>, inject?: Deps): ClassRegistration<T>;
77
104
  /**
78
105
  * Builds a factory registration. The factory's parameters are inferred from
79
106
  * the `inject` tokens, in order.
@@ -83,4 +110,3 @@ export declare function provideValue<T>(provide: ProviderToken<T>, useValue: T):
83
110
  export declare function provideExisting<T>(provide: ProviderToken<T>, useExisting: ProviderToken<T>): ExistingRegistration<T>;
84
111
  export declare function getProviderToken<T>(provider: ContainerProvider<T>): ProviderToken<T> | undefined;
85
112
  export declare function normalizeProvider<T>(provider: ContainerProvider<T>): Provider<T>;
86
- //# sourceMappingURL=containerProvider.core.d.ts.map
@@ -22,8 +22,16 @@ export function hasInjectedDependencies(provider) {
22
22
  Array.isArray(provider.inject) &&
23
23
  provider.inject.length > 0);
24
24
  }
25
+ /**
26
+ * Builds a class provider. The constructor's parameters are checked against
27
+ * the `inject` tokens, in order (see {@link InjectedConstructor}); with no
28
+ * list the class must be constructible with no arguments.
29
+ */
25
30
  export function classProvider(useClass, inject = []) {
26
- return Object.freeze({ useClass, inject: Object.freeze([...inject]) });
31
+ return Object.freeze({
32
+ useClass: useClass,
33
+ inject: Object.freeze([...inject]),
34
+ });
27
35
  }
28
36
  /**
29
37
  * Builds a factory provider. The factory's parameters are inferred from the
@@ -41,10 +49,14 @@ export function valueProvider(useValue) {
41
49
  export function existingProvider(useExisting) {
42
50
  return Object.freeze({ useExisting });
43
51
  }
52
+ /**
53
+ * Builds a class registration. The constructor's parameters are checked
54
+ * against the `inject` tokens, in order (see {@link InjectedConstructor}).
55
+ */
44
56
  export function provideClass(provide, useClass, inject = []) {
45
57
  return Object.freeze({
46
58
  provide,
47
- useClass,
59
+ useClass: useClass,
48
60
  inject: Object.freeze([...inject]),
49
61
  });
50
62
  }
@@ -75,4 +87,3 @@ export function normalizeProvider(provider) {
75
87
  return provider.provider;
76
88
  return provider;
77
89
  }
78
- //# sourceMappingURL=containerProvider.core.js.map
@@ -4,4 +4,3 @@
4
4
  * Dependency provider implementations and factories.
5
5
  */
6
6
  export * from "./containerProvider.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Dependency provider implementations and factories.
5
5
  */
6
6
  export * from "./containerProvider.core.js";
7
- //# sourceMappingURL=index.js.map
@@ -57,4 +57,3 @@ export declare function defineRegistration<T>(token: RegistrationToken<T>, provi
57
57
  export declare const DEFAULT_REGISTRATION_SCOPE: ContainerScope;
58
58
  export type RegistrationMap = ReadonlyMap<Token<unknown>, ContainerRegistration<unknown>>;
59
59
  export declare function createRegistrationMap(registrations: readonly ContainerRegistration[]): RegistrationMap;
60
- //# sourceMappingURL=containerRegistration.core.d.ts.map
@@ -126,4 +126,3 @@ export function createRegistrationMap(registrations) {
126
126
  map.set(unwrapToken(reg.token), reg);
127
127
  return map;
128
128
  }
129
- //# sourceMappingURL=containerRegistration.core.js.map
@@ -4,4 +4,3 @@
4
4
  * Service registration and token binding.
5
5
  */
6
6
  export * from "./containerRegistration.core.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Service registration and token binding.
5
5
  */
6
6
  export * from "./containerRegistration.core.js";
7
- //# sourceMappingURL=index.js.map
@@ -47,4 +47,3 @@ export declare class ContainerRegistry {
47
47
  */
48
48
  restore(regs: readonly ContainerRegistration[]): void;
49
49
  }
50
- //# sourceMappingURL=containerRegistry.core.d.ts.map
@@ -153,4 +153,3 @@ export class ContainerRegistry {
153
153
  });
154
154
  }
155
155
  }
156
- //# sourceMappingURL=containerRegistry.core.js.map
@@ -42,4 +42,3 @@ export interface ContainerRegistryOptions {
42
42
  */
43
43
  readonly allowDuplicates?: boolean;
44
44
  }
45
- //# sourceMappingURL=containerRegistry.type.d.ts.map
@@ -13,4 +13,3 @@ export var RegistryOperation;
13
13
  /** Wholesale replacement of all registrations via `restore()`. */
14
14
  RegistryOperation["RESTORE"] = "restore";
15
15
  })(RegistryOperation || (RegistryOperation = {}));
16
- //# sourceMappingURL=containerRegistry.type.js.map
@@ -5,4 +5,3 @@
5
5
  */
6
6
  export * from "./containerRegistry.type.js";
7
7
  export * from "./containerRegistry.core.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -5,4 +5,3 @@
5
5
  */
6
6
  export * from "./containerRegistry.type.js";
7
7
  export * from "./containerRegistry.core.js";
8
- //# sourceMappingURL=index.js.map
@@ -9,8 +9,13 @@
9
9
  * Whether an unregistered token may be auto-registered: a class whose
10
10
  * constructor declares no required parameters (`Class.length === 0`).
11
11
  *
12
- * Parameters with a default value do not count, so
13
- * `constructor(value = 7)` still qualifies.
12
+ * `Function.length` counts parameters before the first default or rest
13
+ * parameter, so `constructor(value = 7)`, `constructor(deps: Deps = {})`
14
+ * and `constructor(...rest)` all qualify and are built with **no
15
+ * arguments** — their defaults apply and nothing is injected. A class that
16
+ * expects the container to supply a defaulted parameter must be registered
17
+ * explicitly with an `inject` list; the container cannot tell "optional"
18
+ * from "please inject" at runtime.
14
19
  */
15
20
  export declare function isAutoRegistrable(token: unknown): boolean;
16
21
  /**
@@ -39,4 +44,3 @@ export declare function assertClassInjectable(token: string, ctor: {
39
44
  readonly length: number;
40
45
  readonly name: string;
41
46
  }, inject: readonly unknown[]): void;
42
- //# sourceMappingURL=containerResolution.autoRegister.d.ts.map
@@ -11,8 +11,13 @@ import { describeToken } from "../containerToken/containerToken.type.js";
11
11
  * Whether an unregistered token may be auto-registered: a class whose
12
12
  * constructor declares no required parameters (`Class.length === 0`).
13
13
  *
14
- * Parameters with a default value do not count, so
15
- * `constructor(value = 7)` still qualifies.
14
+ * `Function.length` counts parameters before the first default or rest
15
+ * parameter, so `constructor(value = 7)`, `constructor(deps: Deps = {})`
16
+ * and `constructor(...rest)` all qualify and are built with **no
17
+ * arguments** — their defaults apply and nothing is injected. A class that
18
+ * expects the container to supply a defaulted parameter must be registered
19
+ * explicitly with an `inject` list; the container cannot tell "optional"
20
+ * from "please inject" at runtime.
16
21
  */
17
22
  export function isAutoRegistrable(token) {
18
23
  return typeof token === "function" && token.length === 0;
@@ -59,4 +64,3 @@ export function assertClassInjectable(token, ctor, inject) {
59
64
  `dependencies. Register it with container.registerClass(${token}, ` +
60
65
  `${name}, { inject: [/* one token per parameter */] }).`);
61
66
  }
62
- //# sourceMappingURL=containerResolution.autoRegister.js.map
@@ -88,4 +88,3 @@ export declare class ContainerResolver {
88
88
  private evictAliasesOf;
89
89
  private aliasChainReaches;
90
90
  }
91
- //# sourceMappingURL=containerResolution.core.d.ts.map
@@ -135,7 +135,16 @@ export class ContainerResolver {
135
135
  }
136
136
  }
137
137
  else {
138
- throw new RegistrationNotFoundError(describeToken(token));
138
+ // Name the consumer as well as the missing token: as a dependency
139
+ // this error is wrapped by the consumer's DependencyResolutionError,
140
+ // whose chain used to end at the consumer and never say what was
141
+ // missing.
142
+ const name = describeToken(token);
143
+ const requiredBy = state.path[state.path.length - 1];
144
+ throw new RegistrationNotFoundError(name, requiredBy === undefined
145
+ ? undefined
146
+ : `No registration found for token "${name}" (required by ` +
147
+ `"${describeToken(requiredBy)}").`);
139
148
  }
140
149
  }
141
150
  const currentPath = [...state.path, token];
@@ -259,7 +268,13 @@ export class ContainerResolver {
259
268
  error instanceof MaxResolutionDepthError ||
260
269
  error instanceof AsyncProviderError)
261
270
  throw error;
262
- throw new DependencyResolutionError(describeToken(token), error, state.path.map((t) => describeToken(t)));
271
+ // A missing dependency is the one failure whose token is not on the
272
+ // path (it never started resolving), so append it: the chain must end
273
+ // at the token that was missing, not at the consumer that needed it.
274
+ const chain = state.path.map((t) => describeToken(t));
275
+ if (error instanceof RegistrationNotFoundError)
276
+ chain.push(error.requestedToken);
277
+ throw new DependencyResolutionError(describeToken(token), error, chain);
263
278
  }
264
279
  }
265
280
  /**
@@ -373,4 +388,3 @@ function isPromiseLike(value) {
373
388
  "then" in value &&
374
389
  typeof value.then === "function");
375
390
  }
376
- //# sourceMappingURL=containerResolution.core.js.map
@@ -30,4 +30,3 @@ export declare class DependentIndex {
30
30
  /** Forgets every recorded dependency. */
31
31
  clear(): void;
32
32
  }
33
- //# sourceMappingURL=containerResolution.dependents.d.ts.map
@@ -63,4 +63,3 @@ export class DependentIndex {
63
63
  this.#dependents.clear();
64
64
  }
65
65
  }
66
- //# sourceMappingURL=containerResolution.dependents.js.map
@@ -70,4 +70,3 @@ export declare class AsyncProviderError extends ContainerError {
70
70
  readonly scope: string;
71
71
  constructor(token: string, scope: string);
72
72
  }
73
- //# sourceMappingURL=containerResolution.error.d.ts.map
@@ -109,4 +109,3 @@ export class AsyncProviderError extends ContainerError {
109
109
  this.scope = scope;
110
110
  }
111
111
  }
112
- //# sourceMappingURL=containerResolution.error.js.map
@@ -36,7 +36,16 @@ export interface ResolutionOptions {
36
36
  readonly cache?: ResolutionCache;
37
37
  /** Current dependency resolution path. Normally managed internally. */
38
38
  readonly path?: ResolutionPath;
39
- /** Whether unregistered class tokens may be resolved. Defaults to true. */
39
+ /**
40
+ * Whether unregistered class tokens may be resolved. Defaults to true.
41
+ *
42
+ * Only a class whose constructor declares no *required* parameters
43
+ * (`Class.length === 0`) qualifies, and it is built with no arguments.
44
+ * Parameters with defaults and rest parameters do not count, so such a
45
+ * class is auto-registered with its defaults applied and nothing
46
+ * injected; register it with an `inject` list when the container should
47
+ * supply those values. Set to `false` to require explicit registration.
48
+ */
40
49
  readonly autoRegisterClasses?: boolean;
41
50
  /**
42
51
  * Whether auto-resolved class tokens may be added to the registry.
@@ -69,4 +78,3 @@ export interface ResolutionResult<T> {
69
78
  readonly fromCache: boolean;
70
79
  readonly path: ResolutionPath;
71
80
  }
72
- //# sourceMappingURL=containerResolution.type.d.ts.map
@@ -2,4 +2,3 @@
2
2
  * Types for dependency resolution.
3
3
  */
4
4
  export {};
5
- //# sourceMappingURL=containerResolution.type.js.map
@@ -6,4 +6,3 @@
6
6
  export * from "./containerResolution.type.js";
7
7
  export * from "./containerResolution.error.js";
8
8
  export * from "./containerResolution.core.js";
9
- //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,3 @@
6
6
  export * from "./containerResolution.type.js";
7
7
  export * from "./containerResolution.error.js";
8
8
  export * from "./containerResolution.core.js";
9
- //# sourceMappingURL=index.js.map
@@ -14,4 +14,3 @@ export declare function isScopedScope(scope: ContainerScope): boolean;
14
14
  export declare function isTransientScope(scope: ContainerScope): boolean;
15
15
  export declare function isCachedScope(scope: ContainerScope): boolean;
16
16
  export declare function describeContainerScope(scope: ContainerScope): string;
17
- //# sourceMappingURL=containerScope.type.d.ts.map
@@ -40,4 +40,3 @@ export function describeContainerScope(scope) {
40
40
  return "Unknown container scope.";
41
41
  }
42
42
  }
43
- //# sourceMappingURL=containerScope.type.js.map
@@ -4,4 +4,3 @@
4
4
  * Scope management for dependency lifetimes.
5
5
  */
6
6
  export * from "./containerScope.type.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Scope management for dependency lifetimes.
5
5
  */
6
6
  export * from "./containerScope.type.js";
7
- //# sourceMappingURL=index.js.map
@@ -53,4 +53,3 @@ export declare function isStringToken<T = unknown>(token: Token<T>): token is st
53
53
  * `Symbol(MissingService)`. A symbol without a description is `Symbol()`.
54
54
  */
55
55
  export declare function describeToken<T>(token: Token<T> | InjectionToken<T>): string;
56
- //# sourceMappingURL=containerToken.type.d.ts.map
@@ -66,4 +66,3 @@ export function describeToken(token) {
66
66
  return resolved.name || "AnonymousConstructor";
67
67
  return "UnknownToken";
68
68
  }
69
- //# sourceMappingURL=containerToken.type.js.map
@@ -4,4 +4,3 @@
4
4
  * Token types for service identification.
5
5
  */
6
6
  export * from "./containerToken.type.js";
7
- //# sourceMappingURL=index.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * Token types for service identification.
5
5
  */
6
6
  export * from "./containerToken.type.js";
7
- //# sourceMappingURL=index.js.map
package/dist/index.d.ts CHANGED
@@ -13,4 +13,3 @@ export * from "./containerResolution/index.js";
13
13
  export * from "./containerScope/index.js";
14
14
  export * from "./containerToken/index.js";
15
15
  export { CircularDependencyError, DuplicateRegistrationError, RegistrationNotFoundError, ProviderResolutionError, } from "@zudojs/errors";
16
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,4 +15,3 @@ export * from "./containerToken/index.js";
15
15
  // Error classes the container throws but that live in @zudojs/errors,
16
16
  // re-exported so `instanceof` checks need only this package.
17
17
  export { CircularDependencyError, DuplicateRegistrationError, RegistrationNotFoundError, ProviderResolutionError, } from "@zudojs/errors";
18
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/container",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "Token-based dependency injection container for managing application dependencies and service lifetimes.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "!dist/.tsbuildinfo"
19
19
  ],
20
20
  "dependencies": {
21
- "@zudojs/errors": "1.3.2"
21
+ "@zudojs/errors": "1.4.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "typescript": "7.0.2",