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 +60 -68
- package/dist/container/index.d.ts +3 -80
- package/dist/disposable/index.d.ts +4 -4
- package/dist/index.cjs +110 -51
- package/dist/index.d.ts +1 -1
- package/dist/index.js +118 -31
- package/dist/lazy/index.d.ts +5 -7
- package/package.json +3 -8
- package/dist/index-g50fxds1.js +0 -34
- package/dist/scope/index.cjs +0 -212
- package/dist/scope/index.js +0 -153
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/
|
|
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/
|
|
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 —
|
|
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
|
-
|
|
148
|
+
scope.resolve(Database) === scope.resolve(Database); // true
|
|
148
149
|
|
|
149
150
|
// Transient — new instance every time
|
|
150
|
-
|
|
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.
|
|
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
|
|
269
|
+
const scope = createScope(container);
|
|
270
|
+
|
|
271
|
+
const logger = scope.resolve(Logger);
|
|
270
272
|
// ^? Logger
|
|
271
273
|
|
|
272
|
-
const db = await
|
|
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 =
|
|
335
|
+
const container = createContainer().registerSingleton(Connection, () => new Connection());
|
|
336
|
+
const dc = disposable(container);
|
|
334
337
|
|
|
335
|
-
container.resolve(Connection);
|
|
336
|
-
await
|
|
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
|
|
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
|
|
365
|
+
const dc = disposable(createContainer().registerSingleton(Connection, () => new Connection()));
|
|
363
366
|
|
|
364
|
-
|
|
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(
|
|
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
|
|
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/
|
|
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 —
|
|
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
|
-
|
|
534
|
+
scope.resolve(Analytics); // ContainerError: Token "Analytics" is not registered.
|
|
535
535
|
|
|
536
536
|
// tryResolve returns undefined for unregistered tokens
|
|
537
|
-
const 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
|
-
### `
|
|
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.
|
|
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 `
|
|
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
|
|
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/
|
|
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<
|
|
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
|
|
45
|
-
*
|
|
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
|