katagami 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,21 +12,21 @@ Lightweight TypeScript DI container with full type inference.
12
12
 
13
13
  ## Features
14
14
 
15
- | Feature | Description |
16
- | ----------------------------- | ---------------------------------------------------------------------------------------------------------- |
17
- | Zero dependencies | No decorators, no reflect-metadata, no polyfills — works with any bundler out of the box |
18
- | Full type inference | Types accumulate through method chaining; unregistered tokens are compile-time errors |
19
- | Tree-shakeable | Subpath exports (`katagami/scope`, `katagami/disposable`) and `sideEffects: false` for minimal bundle size |
20
- | Captive dependency prevention | Singleton/Transient factories cannot access scoped tokens; caught at compile time and runtime in scopes |
21
- | Hybrid token strategy | Class tokens for strict type safety, PropertyKey tokens for flexibility |
22
- | Interface type map | Pass an interface to `createContainer<T>()` for order-independent registration |
23
- | Three lifetimes | Singleton, Transient, and Scoped with child containers |
24
- | Disposable support | TC39 Explicit Resource Management (`Symbol.dispose` / `Symbol.asyncDispose` / `await using`) |
25
- | Module composition | Containers can be composed via `use()` to group and reuse registrations |
26
- | Async factories | Promise-returning factories are automatically tracked by the type system |
27
- | Circular dependency detection | Clear error messages with the full cycle path |
28
- | Optional resolution | `tryResolve` returns `undefined` for unregistered tokens instead of throwing |
29
- | Lazy resolution | Proxy-based deferred instantiation via `lazy()` from `katagami/lazy`; instance created on first access |
15
+ | Feature | Description |
16
+ | ----------------------------- | --------------------------------------------------------------------------------------------------------- |
17
+ | Zero dependencies | No decorators, no reflect-metadata, no polyfills — works with any bundler out of the box |
18
+ | Full type inference | Types accumulate through method chaining; unregistered tokens are compile-time errors |
19
+ | Tree-shakeable | Subpath exports (`katagami/disposable`, `katagami/lazy`) and `sideEffects: false` for minimal bundle size |
20
+ | Captive dependency prevention | Singleton/Transient factories cannot access scoped tokens; caught at compile time and runtime in scopes |
21
+ | Hybrid token strategy | Class tokens for strict type safety, PropertyKey tokens for flexibility |
22
+ | Interface type map | Pass an interface to `createContainer<T>()` for order-independent registration |
23
+ | Three lifetimes | Singleton, Transient, and Scoped with child containers |
24
+ | Disposable support | TC39 Explicit Resource Management (`Symbol.dispose` / `Symbol.asyncDispose` / `await using`) |
25
+ | Module composition | Containers can be composed via `use()` to group and reuse registrations |
26
+ | Async factories | Promise-returning factories are automatically tracked by the type system |
27
+ | Circular dependency detection | Clear error messages with the full cycle path |
28
+ | Optional resolution | `tryResolve` returns `undefined` for unregistered tokens instead of throwing |
29
+ | Lazy resolution | Proxy-based deferred instantiation via `lazy()` from `katagami/lazy`; instance created on first access |
30
30
 
31
31
  ## Install
32
32
 
@@ -37,7 +37,7 @@ npm install katagami
37
37
  ## Quick Start
38
38
 
39
39
  ```ts
40
- import { createContainer } from 'katagami';
40
+ import { createContainer, createScope } from 'katagami';
41
41
 
42
42
  class Logger {
43
43
  log(msg: string) {
@@ -56,7 +56,7 @@ const container = createContainer()
56
56
  .registerSingleton(Logger, () => new Logger())
57
57
  .registerSingleton(UserService, r => new UserService(r.resolve(Logger)));
58
58
 
59
- const userService = container.resolve(UserService);
59
+ const userService = createScope(container).resolve(UserService);
60
60
  // ^? UserService (fully inferred)
61
61
  userService.greet('world');
62
62
  ```
@@ -94,14 +94,13 @@ Decorator-based DI requires `experimentalDecorators` and `emitDecoratorMetadata`
94
94
 
95
95
  ### Tree-shakeable
96
96
 
97
- Katagami is split into subpath exports. Import only what you use — `katagami/scope`, `katagami/disposable`, and `katagami/lazy` are completely eliminated from the bundle if not imported. Combined with `sideEffects: false`, bundlers can remove every unused byte.
97
+ Katagami is split into subpath exports. Import only what you use — `katagami/disposable` and `katagami/lazy` are completely eliminated from the bundle if not imported. Combined with `sideEffects: false`, bundlers can remove every unused byte.
98
98
 
99
99
  ```ts
100
- // Core only — scope, disposable, and lazy are not included in the bundle
101
- import { createContainer } from 'katagami';
100
+ // Core only — disposable and lazy are not included in the bundle
101
+ import { createContainer, createScope } from 'katagami';
102
102
 
103
103
  // Import only what you need
104
- import { createScope } from 'katagami/scope';
105
104
  import { disposable } from 'katagami/disposable';
106
105
  import { lazy } from 'katagami/lazy';
107
106
  ```
@@ -129,7 +128,7 @@ No runtime dependencies, no polyfills. No need to add reflect-metadata (~50 KB u
129
128
  Singleton creates the instance on the first `resolve` and caches it. Transient creates a new instance every time.
130
129
 
131
130
  ```ts
132
- import { createContainer } from 'katagami';
131
+ import { createContainer, createScope } from 'katagami';
133
132
 
134
133
  class Database {
135
134
  constructor(public id = Math.random()) {}
@@ -143,20 +142,21 @@ const container = createContainer()
143
142
  .registerSingleton(Database, () => new Database())
144
143
  .registerTransient(RequestHandler, () => new RequestHandler());
145
144
 
145
+ const scope = createScope(container);
146
+
146
147
  // Singleton — same instance every time
147
- container.resolve(Database) === container.resolve(Database); // true
148
+ scope.resolve(Database) === scope.resolve(Database); // true
148
149
 
149
150
  // Transient — new instance every time
150
- container.resolve(RequestHandler) === container.resolve(RequestHandler); // false
151
+ scope.resolve(RequestHandler) === scope.resolve(RequestHandler); // false
151
152
  ```
152
153
 
153
154
  ### Scoped Lifetime & Child Containers
154
155
 
155
- Scoped registrations behave like singletons within a scope but produce a fresh instance in each new scope. Import `createScope` from `katagami/scope` to create a child container. Scoped tokens cannot be resolved from the root container.
156
+ Scoped registrations behave like singletons within a scope but produce a fresh instance in each new scope. Use `createScope` to create a child container. Scoped tokens cannot be resolved from the root container.
156
157
 
157
158
  ```ts
158
- import { createContainer } from 'katagami';
159
- import { createScope } from 'katagami/scope';
159
+ import { createContainer, createScope } from 'katagami';
160
160
 
161
161
  class DbPool {
162
162
  constructor(public name = 'main') {}
@@ -247,7 +247,7 @@ const container = createContainer().use(appModule);
247
247
  Factories that return a `Promise` are automatically tracked by the type system. When you `resolve` an async token, the return type is `Promise<V>` instead of `V`:
248
248
 
249
249
  ```ts
250
- import { createContainer } from 'katagami';
250
+ import { createContainer, createScope } from 'katagami';
251
251
 
252
252
  class Database {
253
253
  constructor(public connected: boolean) {}
@@ -266,10 +266,12 @@ const container = createContainer()
266
266
  return new Database(true);
267
267
  });
268
268
 
269
- const logger = container.resolve(Logger);
269
+ const scope = createScope(container);
270
+
271
+ const logger = scope.resolve(Logger);
270
272
  // ^? Logger
271
273
 
272
- const db = await container.resolve(Database);
274
+ const db = await scope.resolve(Database);
273
275
  // ^? Promise<Database> (awaited → Database)
274
276
  db.connected; // true
275
277
  ```
@@ -291,7 +293,7 @@ const container = createContainer()
291
293
  Katagami tracks which tokens are currently being resolved. If a circular dependency is found, a `ContainerError` is thrown with a clear message showing the full cycle path:
292
294
 
293
295
  ```ts
294
- import { createContainer } from 'katagami';
296
+ import { createContainer, createScope } from 'katagami';
295
297
 
296
298
  class ServiceA {
297
299
  constructor(public b: ServiceB) {}
@@ -305,7 +307,7 @@ const container = createContainer()
305
307
  .registerSingleton(ServiceA, r => new ServiceA(r.resolve(ServiceB)))
306
308
  .registerSingleton(ServiceB, r => new ServiceB(r.resolve(ServiceA)));
307
309
 
308
- container.resolve(ServiceA);
310
+ createScope(container).resolve(ServiceA);
309
311
  // ContainerError: Circular dependency detected: ServiceA -> ServiceB -> ServiceA
310
312
  ```
311
313
 
@@ -320,7 +322,7 @@ ContainerError: Circular dependency detected: ServiceX -> ServiceY -> ServiceZ -
320
322
  Disposal is provided by the `disposable()` wrapper from `katagami/disposable`. Wrapping a container or scope attaches `[Symbol.asyncDispose]`, enabling `await using` syntax. When disposed, owned instances are iterated in reverse creation order (LIFO) and their `[Symbol.asyncDispose]()` or `[Symbol.dispose]()` methods are called automatically.
321
323
 
322
324
  ```ts
323
- import { createContainer } from 'katagami';
325
+ import { createContainer, createScope } from 'katagami';
324
326
  import { disposable } from 'katagami/disposable';
325
327
 
326
328
  class Connection {
@@ -330,17 +332,18 @@ class Connection {
330
332
  }
331
333
 
332
334
  // Manual disposal
333
- const container = disposable(createContainer().registerSingleton(Connection, () => new Connection()));
335
+ const container = createContainer().registerSingleton(Connection, () => new Connection());
336
+ const dc = disposable(container);
334
337
 
335
- container.resolve(Connection);
336
- await container[Symbol.asyncDispose]();
338
+ createScope(container).resolve(Connection);
339
+ await dc[Symbol.asyncDispose]();
337
340
  // => "Connection closed"
338
341
  ```
339
342
 
340
343
  With `await using`, scopes are automatically disposed at the end of the block:
341
344
 
342
345
  ```ts
343
- import { createScope } from 'katagami/scope';
346
+ import { createContainer, createScope } from 'katagami';
344
347
  import { disposable } from 'katagami/disposable';
345
348
 
346
349
  const root = createContainer()
@@ -359,10 +362,9 @@ Scope disposal only affects scoped instances. Singleton instances are owned by t
359
362
  The `disposable()` wrapper also narrows the returned type so that registration methods (`registerSingleton`, `registerTransient`, `registerScoped`, `use`) are removed at the type level. This prevents accidental registration on a potentially-disposed container:
360
363
 
361
364
  ```ts
362
- const container = disposable(createContainer().registerSingleton(Connection, () => new Connection()));
365
+ const dc = disposable(createContainer().registerSingleton(Connection, () => new Connection()));
363
366
 
364
- container.resolve(Connection); // OK
365
- container.registerSingleton(/* ... */); // Compile-time error
367
+ dc.registerSingleton(/* ... */); // Compile-time error — registration methods are hidden
366
368
  ```
367
369
 
368
370
  ### Lazy Resolution
@@ -370,7 +372,7 @@ container.registerSingleton(/* ... */); // Compile-time error
370
372
  The `lazy()` function from `katagami/lazy` creates a proxy that defers instance creation until the first property access. This is useful for optimizing startup time or breaking circular dependencies.
371
373
 
372
374
  ```ts
373
- import { createContainer } from 'katagami';
375
+ import { createContainer, createScope } from 'katagami';
374
376
  import { lazy } from 'katagami/lazy';
375
377
 
376
378
  class HeavyService {
@@ -383,8 +385,9 @@ class HeavyService {
383
385
  }
384
386
 
385
387
  const container = createContainer().registerSingleton(HeavyService, () => new HeavyService());
388
+ const scope = createScope(container);
386
389
 
387
- const service = lazy(container, HeavyService);
390
+ const service = lazy(scope, HeavyService);
388
391
  // HeavyService is NOT instantiated yet
389
392
 
390
393
  service.process(); // instance created here, then cached
@@ -395,11 +398,9 @@ The proxy transparently forwards all property access, method calls, `in` checks,
395
398
 
396
399
  Only **sync class tokens** are supported. Async tokens and PropertyKey tokens are rejected at the type level because Proxy traps are synchronous.
397
400
 
398
- `lazy()` works with Container, Scope, DisposableContainer, and DisposableScope:
401
+ `lazy()` works with Scope and DisposableScope:
399
402
 
400
403
  ```ts
401
- import { createScope } from 'katagami/scope';
402
-
403
404
  const root = createContainer().registerScoped(RequestContext, () => new RequestContext());
404
405
  const scope = createScope(root);
405
406
 
@@ -408,14 +409,13 @@ const ctx = lazy(scope, RequestContext); // deferred scoped resolution
408
409
 
409
410
  ### Tree Shaking
410
411
 
411
- Katagami uses subpath exports to split functionality into independent entry points. If you only need the core container, `katagami/scope`, `katagami/disposable`, and `katagami/lazy` are completely excluded from the bundle. The package declares `sideEffects: false`, so bundlers can safely eliminate any unused code.
412
+ Katagami uses subpath exports to split functionality into independent entry points. If you only need the core container, `katagami/disposable` and `katagami/lazy` are completely excluded from the bundle. The package declares `sideEffects: false`, so bundlers can safely eliminate any unused code.
412
413
 
413
414
  ```ts
414
- // Core only — scope, disposable, and lazy are not included in the bundle
415
- import { createContainer } from 'katagami';
415
+ // Core only — disposable and lazy are not included in the bundle
416
+ import { createContainer, createScope } from 'katagami';
416
417
 
417
418
  // Import only what you need
418
- import { createScope } from 'katagami/scope';
419
419
  import { disposable } from 'katagami/disposable';
420
420
  import { lazy } from 'katagami/lazy';
421
421
  ```
@@ -425,7 +425,7 @@ import { lazy } from 'katagami/lazy';
425
425
  When you pass an interface to `createContainer<T>()`, PropertyKey tokens are typed from the interface rather than accumulated through chaining. This means you can register and resolve tokens in any order:
426
426
 
427
427
  ```ts
428
- import { createContainer } from 'katagami';
428
+ import { createContainer, createScope } from 'katagami';
429
429
 
430
430
  class Logger {
431
431
  log(msg: string) {
@@ -446,7 +446,7 @@ const container = createContainer<Services>()
446
446
  })
447
447
  .registerSingleton('logger', () => new Logger());
448
448
 
449
- const greeting = container.resolve('greeting');
449
+ const greeting = createScope(container).resolve('greeting');
450
450
  // ^? string
451
451
  ```
452
452
 
@@ -494,8 +494,7 @@ const container = createContainer()
494
494
  Katagami also enforces this rule at runtime within scopes. If a singleton factory attempts to resolve a scoped token — directly or through intermediaries — a `ContainerError` is thrown:
495
495
 
496
496
  ```ts
497
- import { createContainer } from 'katagami';
498
- import { createScope } from 'katagami/scope';
497
+ import { createContainer, createScope } from 'katagami';
499
498
 
500
499
  class DbPool {}
501
500
  class RequestContext {}
@@ -514,7 +513,7 @@ scope.resolve(DbPool);
514
513
  When you need to handle optional dependencies or want to check if a token is registered without throwing an error, use `tryResolve`. Unlike `resolve`, it returns `undefined` for unregistered tokens instead of throwing `ContainerError`:
515
514
 
516
515
  ```ts
517
- import { createContainer } from 'katagami';
516
+ import { createContainer, createScope } from 'katagami';
518
517
 
519
518
  class Logger {
520
519
  log(msg: string) {
@@ -529,12 +528,13 @@ class Analytics {
529
528
  }
530
529
 
531
530
  const container = createContainer().registerSingleton(Logger, () => new Logger());
531
+ const scope = createScope(container);
532
532
 
533
533
  // resolve throws for unregistered tokens
534
- container.resolve(Analytics); // ContainerError: Token "Analytics" is not registered.
534
+ scope.resolve(Analytics); // ContainerError: Token "Analytics" is not registered.
535
535
 
536
536
  // tryResolve returns undefined for unregistered tokens
537
- const analytics = container.tryResolve(Analytics);
537
+ const analytics = scope.tryResolve(Analytics);
538
538
  // ^? Analytics | undefined
539
539
  if (analytics) {
540
540
  analytics.track('event');
@@ -583,15 +583,7 @@ Registers a factory as scoped. Within a scope, the instance is created on the fi
583
583
 
584
584
  Copies all registrations from `source` (another `Container`) into this container. Only factory and lifetime entries are copied — singleton instance caches are not shared. Returns the container for method chaining.
585
585
 
586
- ### `Container.prototype.resolve(token)`
587
-
588
- Resolves and returns the instance for the given token. Throws `ContainerError` if the token is not registered or if a circular dependency is detected.
589
-
590
- ### `Container.prototype.tryResolve(token)`
591
-
592
- Attempts to resolve the instance for the given token. Returns `undefined` if the token is not registered, instead of throwing. Still throws `ContainerError` for circular dependencies or operations on disposed containers/scopes.
593
-
594
- ### `createScope(source)` — `katagami/scope`
586
+ ### `createScope(source)`
595
587
 
596
588
  Creates a new `Scope` (child container) from a `Container` or an existing `Scope`. The scope inherits all registrations from the source. Singleton instances are shared with the parent, while scoped instances are local to the scope.
597
589
 
@@ -601,7 +593,7 @@ A scoped child container created by `createScope()`.
601
593
 
602
594
  ### `Scope.prototype.resolve(token)`
603
595
 
604
- Resolves and returns the instance for the given token. Behaves the same as `Container.prototype.resolve`, but can also resolve scoped tokens.
596
+ Resolves and returns the instance for the given token. Throws `ContainerError` if the token is not registered or if a circular dependency is detected. Can resolve both non-scoped and scoped tokens.
605
597
 
606
598
  ### `Scope.prototype.tryResolve(token)`
607
599
 
@@ -609,11 +601,11 @@ Attempts to resolve the instance for the given token. Returns `undefined` if the
609
601
 
610
602
  ### `lazy(source, token)` — `katagami/lazy`
611
603
 
612
- Creates a Proxy that defers `resolve()` until the first property access. The resolved instance is cached — subsequent accesses use the cache. Only sync class tokens are supported; async tokens and PropertyKey tokens are rejected at the type level. Works with `Container`, `Scope`, `DisposableContainer`, and `DisposableScope`.
604
+ Creates a Proxy that defers `resolve()` until the first property access. The resolved instance is cached — subsequent accesses use the cache. Only sync class tokens are supported; async tokens and PropertyKey tokens are rejected at the type level. Works with `Scope` and `DisposableScope`.
613
605
 
614
606
  ### `disposable(container)` — `katagami/disposable`
615
607
 
616
- Attaches `[Symbol.asyncDispose]` to a `Container` or `Scope`, enabling `await using` syntax. Disposes all owned instances in reverse creation order (LIFO). Calls `[Symbol.asyncDispose]()` or `[Symbol.dispose]()` on each instance that implements them. Idempotent — subsequent calls are no-ops. After disposal, `resolve()` and `createScope()` will throw `ContainerError`. The returned type is narrowed to `DisposableContainer` or `DisposableScope`, which only expose `resolve` and `tryResolve` — registration methods are excluded at the type level.
608
+ Attaches `[Symbol.asyncDispose]` to a `Container` or `Scope`, enabling `await using` syntax. Disposes all owned instances in reverse creation order (LIFO). Calls `[Symbol.asyncDispose]()` or `[Symbol.dispose]()` on each instance that implements them. Idempotent — subsequent calls are no-ops. After disposal, `resolve()` and `createScope()` will throw `ContainerError`. The returned type is narrowed to `DisposableContainer` or `DisposableScope`. `DisposableContainer` exposes only disposal capability — registration and resolution methods are excluded. `DisposableScope` retains `resolve`, `tryResolve`, `resolveAll`, and `tryResolveAll` for resolution.
617
609
 
618
610
  ### `class ContainerError`
619
611
 
@@ -16,15 +16,12 @@ import type { AbstractConstructor, Resolver } from '../resolver';
16
16
  */
17
17
  export declare function createContainer<T = Record<never, never>, ScopedT = Record<never, never>>(): Container<T, never, never, ScopedT>;
18
18
  /**
19
- * Lightweight DI container.
19
+ * Lightweight DI container — registration only.
20
20
  *
21
- * Provides type inference through method chaining with registerSingleton/registerTransient/resolve.
22
- *
23
- * - Singleton: Creates the instance on the first resolve and returns the cached value thereafter.
24
- * - Transient: Creates a new instance via the factory function on every resolve.
21
+ * Provides type inference through method chaining with registerSingleton/registerTransient/registerScoped.
22
+ * Resolution is performed through a Scope created via `createScope(container)`.
25
23
  *
26
24
  * Registering the same token multiple times accumulates all factories.
27
- * `resolve()` returns the last registered instance, while `resolveAll()` returns all.
28
25
  *
29
26
  * @template T PropertyKey-based token type map (defined via interface, order-independent)
30
27
  * @template Sync Union of registered sync class constructors (accumulated via chaining, order-dependent)
@@ -36,7 +33,6 @@ export declare function createContainer<T = Record<never, never>, ScopedT = Reco
36
33
  export declare class Container<T = Record<never, never>, Sync extends AbstractConstructor = never, Async extends AbstractConstructor = never, ScopedT = Record<never, never>, ScopedSync extends AbstractConstructor = never, ScopedAsync extends AbstractConstructor = never> {
37
34
  private readonly registrations;
38
35
  private readonly singletonCache;
39
- private readonly resolvingTokens;
40
36
  private disposed;
41
37
  /**
42
38
  * Internal state accessor for extension modules (scope, disposable).
@@ -100,79 +96,6 @@ export declare class Container<T = Record<never, never>, Sync extends AbstractCo
100
96
  * @returns The container for method chaining
101
97
  */
102
98
  use<MT, MSync extends AbstractConstructor, MAsync extends AbstractConstructor, MScopedT, MScopedSync extends AbstractConstructor, MScopedAsync extends AbstractConstructor>(source: Container<MT, MSync, MAsync, MScopedT, MScopedSync, MScopedAsync>): Container<T & MT, Sync | MSync, Async | MAsync, ScopedT & MScopedT, ScopedSync | MScopedSync, ScopedAsync | MScopedAsync>;
103
- /**
104
- * Resolve an instance for the given token.
105
- *
106
- * Returns the instance from the last registered factory for the token.
107
- * For singleton registrations, creates the instance on the first call and caches it.
108
- * For transient registrations, creates a new instance on every call.
109
- *
110
- * @param token A registered token
111
- * @returns The instance associated with the token
112
- * @throws ContainerError if the token is not registered
113
- */
114
- resolve<V>(token: AbstractConstructor<V> & Async): Promise<V>;
115
- resolve<V>(token: AbstractConstructor<V> & Sync): V;
116
- resolve<K extends keyof T>(token: K): T[K];
117
- /**
118
- * Try to resolve an instance for the given token.
119
- *
120
- * Returns `undefined` instead of throwing when the token is not registered.
121
- * Other errors (circular dependency, disposed container) are still thrown.
122
- *
123
- * @param token A token to resolve
124
- * @returns The instance associated with the token, or `undefined` if not registered
125
- */
126
- tryResolve<V>(token: AbstractConstructor<V> & Async): Promise<V> | undefined;
127
- tryResolve<V>(token: AbstractConstructor<V> & Sync): V | undefined;
128
- tryResolve<K extends keyof T>(token: K): T[K] | undefined;
129
- tryResolve<V>(token: AbstractConstructor<V>): V | Promise<V> | undefined;
130
- tryResolve(token: PropertyKey): unknown;
131
- /**
132
- * Resolve all instances for the given token.
133
- *
134
- * Returns an array of instances from all registered factories for the token,
135
- * in registration order.
136
- *
137
- * @param token A registered token
138
- * @returns An array of instances associated with the token
139
- * @throws ContainerError if the token is not registered
140
- */
141
- resolveAll<V>(token: AbstractConstructor<V> & Async): Promise<V>[];
142
- resolveAll<V>(token: AbstractConstructor<V> & Sync): V[];
143
- resolveAll<K extends keyof T>(token: K): T[K][];
144
- /**
145
- * Try to resolve all instances for the given token.
146
- *
147
- * Returns `undefined` instead of throwing when the token is not registered.
148
- * Other errors (circular dependency, disposed container) are still thrown.
149
- *
150
- * @param token A token to resolve
151
- * @returns An array of instances associated with the token, or `undefined` if not registered
152
- */
153
- tryResolveAll<V>(token: AbstractConstructor<V> & Async): Promise<V>[] | undefined;
154
- tryResolveAll<V>(token: AbstractConstructor<V> & Sync): V[] | undefined;
155
- tryResolveAll<K extends keyof T>(token: K): T[K][] | undefined;
156
- tryResolveAll<V>(token: AbstractConstructor<V>): (V | Promise<V>)[] | undefined;
157
- tryResolveAll(token: PropertyKey): unknown;
158
- /**
159
- * Internal resolution logic shared by resolve and tryResolve.
160
- * Resolves the last registered factory for the token.
161
- *
162
- * @param token Token to resolve
163
- * @param required If true, throws when the token is not registered. If false, returns undefined.
164
- * @returns The resolved instance, or undefined if not registered and required is false
165
- */
166
- private resolveToken;
167
- /**
168
- * Internal resolution logic shared by resolveAll and tryResolveAll.
169
- * Resolves all registered factories for the token.
170
- *
171
- * @param token Token to resolve
172
- * @param required If true, throws when the token is not registered. If false, returns undefined.
173
- * @returns An array of resolved instances, or undefined if not registered and required is false
174
- */
175
- private resolveAllTokens;
176
99
  /**
177
100
  * Add a registration entry. Accumulates registrations for the same token.
178
101
  *
@@ -5,9 +5,9 @@ import type { Scope } from '../scope';
5
5
  /**
6
6
  * A container wrapped with `disposable()`.
7
7
  *
8
- * Only `resolve`, `tryResolve`, `resolveAll`, and `tryResolveAll` are available at the type level.
9
8
  * Registration methods (`registerSingleton`, `registerTransient`, `registerScoped`, `use`)
10
9
  * are excluded, preventing accidental registration on a potentially-disposed container.
10
+ * Use `createScope()` to create a scope for resolution.
11
11
  *
12
12
  * @template T PropertyKey-based token type map
13
13
  * @template Sync Union of registered sync class constructors
@@ -16,7 +16,7 @@ import type { Scope } from '../scope';
16
16
  * @template ScopedSync Union of scoped sync class constructors
17
17
  * @template ScopedAsync Union of scoped async class constructors
18
18
  */
19
- export interface DisposableContainer<T = Record<never, never>, Sync extends AbstractConstructor = never, Async extends AbstractConstructor = never, _ScopedT = Record<never, never>, _ScopedSync extends AbstractConstructor = never, _ScopedAsync extends AbstractConstructor = never> extends Resolver<T, Sync, Async>, AsyncDisposable {
19
+ export interface DisposableContainer<_T = Record<never, never>, _Sync extends AbstractConstructor = never, _Async extends AbstractConstructor = never, _ScopedT = Record<never, never>, _ScopedSync extends AbstractConstructor = never, _ScopedAsync extends AbstractConstructor = never> extends AsyncDisposable {
20
20
  readonly [INTERNALS]: ContainerInternals;
21
21
  }
22
22
  /**
@@ -41,8 +41,8 @@ export interface DisposableScope<T = Record<never, never>, Sync extends Abstract
41
41
  * Disposes owned instances in reverse creation order (LIFO), calling
42
42
  * `[Symbol.asyncDispose]()` or `[Symbol.dispose]()` on each instance that implements them.
43
43
  *
44
- * The returned type is narrowed to only expose `resolve`, `tryResolve`, `resolveAll`, and `tryResolveAll`,
45
- * preventing registration methods from being called on a potentially-disposed container.
44
+ * The returned type prevents registration methods from being called on a potentially-disposed container.
45
+ * For scopes, `resolve`, `tryResolve`, `resolveAll`, and `tryResolveAll` remain available.
46
46
  *
47
47
  * @param container A Container or Scope to make disposable
48
48
  * @returns The same object with `AsyncDisposable` capability added and registration methods removed from the type