katagami 3.0.1 → 3.0.3

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
@@ -37,6 +37,109 @@ No service interface or explicit generic argument is needed here. Literal string
37
37
  unique symbols and class tokens can all be used. See [type guarantees](./docs/type-safety.md)
38
38
  for the difference between accumulated registrations and a predeclared type map.
39
39
 
40
+ ## Why Katagami
41
+
42
+ Katagami combines **registration-derived types, compile-time scope restrictions and zero runtime
43
+ dependencies** in an ordinary TypeScript factory API.
44
+
45
+ - **Types grow with your registrations.** Literal keys and unique symbols carry their inferred
46
+ service types into subsequent factories; required tokens outside that set are compile-time errors.
47
+ - **Request state stays explicit.** Singleton and transient factories cannot resolve scoped tokens
48
+ through their supplied typed resolver. You can find this mistake before starting the application.
49
+ - **No decorator setup.** No `experimentalDecorators`, `emitDecoratorMetadata` or Reflect polyfill
50
+ is needed for DI. Constructors and factories stay ordinary TypeScript.
51
+ - **Import the capabilities you use.** Core DI, `katagami/disposable` and `katagami/lazy` are separate
52
+ entry points. ESM exports and `sideEffects: false` support tree shaking; optional cleanup integrates
53
+ with `await using` and the host's disposal symbols.
54
+
55
+ These checks assume narrow tokens and preserved registration types; see the
56
+ [class-token, mutation and predeclared-map boundaries](./docs/type-safety.md).
57
+
58
+ ### Library comparison
59
+
60
+ **27 features across eight libraries.** Reviewed **2026-09-11**, against the npm `latest`
61
+ versions shown below and official documentation. [Versions, sources and detailed notes](./docs/choosing-di.md#comparison-sources).
62
+
63
+ **✅ Built-in support · ⚠️ Conditions, a different model or application composition · ➖ No built-in support for this specific capability.**
64
+ Short labels identify the actual API or limitation.
65
+
66
+ #### Type safety and setup
67
+
68
+ | Feature | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
69
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
70
+ | **Runtime requirements** | **✅ Standard TypeScript** | ⚠️ Reflect metadata for class DI | ⚠️ Reflect metadata for class DI | ⚠️ Reflect metadata setup | ✅ No DI metadata | ⚠️ Nest modules / metadata | ✅ Effect / Layer APIs | ✅ Standard TypeScript |
71
+ | **Injection style** | **Explicit factories / constructors** | Constructor / property / factory | Constructor / factory | Constructor / property / factory | Proxy / classic / factory | Constructor / property / factory | Functional services / layers | Constructor / factory + `inject` |
72
+ | **Token types** | **Class / string / number / symbol** | Class / string / symbol | Class / string / symbol | Class / string / `Token<T>` | String / symbol | Class / string / symbol | `Context.Tag` | String literals |
73
+ | **Type safety** | **✅ Inferred services + scope checks** | ✅ Typed identifiers / bindings | ✅ Class / generic types | ✅ Class / `Token<T>` | ✅ Inferred cradle | ✅ Typed providers | ✅ Typed service requirements | ✅ Tokens + `inject` tuples |
74
+ | **Registration-derived types** | **✅ Accumulated tokens** | ➖ | ➖ | ➖ | ✅ `register` → cradle | ➖ | ⚠️ Layer requirements | ✅ Accumulated tokens |
75
+ | **Missing required tokens: compile-time check¹** | **✅ Literal / unique-symbol keys** | ➖ Runtime check | ➖ Runtime check | ➖ Runtime check | ⚠️ Cradle only | ➖ Runtime graph | ✅ Unsatisfied requirements | ✅ Literal keys |
76
+ | **Scoped access from singleton/transient factories: compile-time check¹** | **✅ Scoped tokens excluded** | ➖ | ➖ | ➖ | ⚠️ Runtime strict mode | ⚠️ Request-scope propagation | ⚠️ Different `Scope` model | ➖ No scoped lifetime |
77
+ | **Zero runtime dependency packages²** | **✅** | ➖ | ➖ | ⚠️ Reflect polyfill installed separately | ⚠️ Browser entry differs | ➖ | ➖ | ✅ |
78
+ | **Tree-shaking support²** | **✅ ESM / subpaths / `sideEffects: false`** | ⚠️ ESM; `sideEffects: true` | ⚠️ ESM build | ✅ ESM / `sideEffects: false` | ⚠️ ESM / browser builds | ⚠️ ESM / framework setup | ✅ ESM / subpaths / side-effect declaration | ⚠️ ESM build |
79
+
80
+ #### Lifetimes, async services and cleanup
81
+
82
+ | Feature | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
83
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
84
+ | **Lifetimes** | **✅ Singleton / Transient / Scoped** | ✅ Singleton / Transient / Request | ✅ Singleton / Transient / Resolution / Container | ✅ Shared / Transient | ✅ Singleton / Transient / Scoped | ✅ Singleton / Transient / Request | ⚠️ Memoized / fresh layers + scopes | ✅ Singleton / Transient |
85
+ | **Request / scoped lifetime³** | **✅ Explicit per-request scope** | ⚠️ One resolution graph | ✅ Container / resolution scoped | ⚠️ Named containers | ✅ Explicit per-request scope | ✅ HTTP request scope | ⚠️ Resource scopes | ⚠️ Child injectors; no Scoped provider |
86
+ | **Child containers / nested scopes³** | **✅ Nested scopes** | ✅ Container hierarchy | ✅ Child containers | ⚠️ Named containers | ✅ Child scopes | ⚠️ Module / request contexts | ⚠️ Nested resource scopes | ✅ Child injectors |
87
+ | **Async factories** | **✅ Promise-valued factories** | ✅ Async bindings | ✅ Promise-valued factories | ✅ Promise-valued services | ✅ Promise-valued factories | ✅ Async providers | ✅ Effectful acquisition | ✅ Promise-valued factories |
88
+ | **Async result type tracking** | **✅ Inferred `Promise<T>`** | ✅ `getAsync<T>` | ⚠️ Promise-valued service type | ⚠️ Promise-valued service type | ✅ Inferred `Promise<T>` | ⚠️ Provider / consumer types | ✅ Effect result / error / requirements | ✅ Inferred `Promise<T>` |
89
+ | **Automatically await async dependencies⁴** | **➖ Explicit `await`** | ✅ `getAsync` / `getAllAsync` | ➖ Consumer awaits | ➖ Consumer awaits | ➖ Consumer awaits | ✅ Before consumer construction | ✅ Effect composition | ➖ Consumer awaits |
90
+ | **Resource cleanup⁵** | **✅ Disposal symbols / `await using`** | ⚠️ Singleton deactivation | ✅ Constructed disposables | ⚠️ `destroy()` on reset / removal | ⚠️ Cached values + disposer | ⚠️ App lifecycle hooks | ✅ Scope finalizers | ✅ Owned disposable instances |
91
+ | **Await asynchronous cleanup⁵** | **✅ `Symbol.asyncDispose`** | ✅ Async deactivation | ✅ `container.dispose()` | ➖ `destroy()` is not awaited | ✅ `container.dispose()` | ⚠️ App hooks; not request-scoped classes | ✅ Effect finalizers | ✅ `injector.dispose()` |
92
+
93
+ #### Composition and advanced features
94
+
95
+ | Feature | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
96
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
97
+ | **Optional resolution** | **✅ `tryResolve` / `tryResolveAll`** | ✅ Optional get / inject | ✅ Optional injection | ⚠️ `has` then `get` | ✅ `allowUnregistered` | ✅ Optional injection | ✅ `serviceOption` | ⚠️ Compose optional values |
98
+ | **Multi-binding** | **✅ `resolveAll`** | ✅ `getAll` / `getAllAsync` | ✅ `injectAll` / `resolveAll` | ✅ `getMany` | ⚠️ Collection-valued service | ⚠️ Array provider | ⚠️ Collection-valued service | ⚠️ Collection-valued service |
99
+ | **Lazy resolution⁶** | **✅ `lazy()`; sync class tokens** | ⚠️ Deferred identifiers / factories | ✅ `delay()` proxy | ⚠️ Deferred type reference | ⚠️ Cradle property access | ⚠️ `LazyModuleLoader` | ⚠️ Lazy effect execution | ⚠️ Inject a factory |
100
+ | **Conditional bindings** | **⚠️ Tokens / factory logic** | ✅ Contextual constraints | ✅ Predicate-aware factory | ⚠️ Factory logic | ⚠️ Local injection / factory logic | ⚠️ Dynamic modules / factories | ⚠️ Select / compose layers | ⚠️ Factory logic |
101
+ | **Auto-loading / discovery⁶** | **➖ Explicit `use()`** | ⚠️ Class autobinding | ➖ Explicit registrations | ➖ Explicit imports | ✅ `loadModules` (Node) | ⚠️ `DiscoveryService` | ➖ Explicit layers | ➖ Explicit providers |
102
+ | **Module system / composition** | **✅ `use()`** | ✅ Container modules | ✅ `@registry` | ⚠️ Group registrations | ✅ `loadModules` / `register` | ✅ Modules / dynamic modules | ✅ Layer composition | ⚠️ Compose provider chains |
103
+ | **Circular dependency detection⁷** | **✅ Runtime cycle path** | ✅ Runtime detection | ⚠️ Constructor error / `delay` | ⚠️ Deferred type references | ✅ Runtime cycle path | ⚠️ Cycle errors / `forwardRef` | ⚠️ Typed Layer requirements | ⚠️ Registration order constrains dependencies |
104
+ | **Middleware / interceptors⁶** | **⚠️ Higher-order factories** | ✅ Activation / deactivation hooks | ✅ Before / after resolution | ⚠️ Factory wrappers | ⚠️ Factory wrappers | ⚠️ Request interceptors, not DI hooks | ⚠️ Effect composition | ⚠️ Provider decoration |
105
+ | **Snapshot / restore⁶** | **➖** | ✅ `snapshot` / `restore` | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ |
106
+ | **Test substitution / isolation** | **✅ Fresh scopes / containers + `use()`** | ✅ Rebind / snapshots | ✅ Child container overrides | ✅ Named containers / reset | ✅ Child scopes / overrides | ✅ `overrideProvider` | ✅ Substitute test layers | ✅ Child injector overrides |
107
+
108
+ **What stands out:** Katagami combines **accumulated registration types, scope-filtered factory
109
+ resolvers, three lifetimes and zero runtime dependencies** with direct `r.resolve(token)` calls.
110
+ Optional/multiple resolution, module composition, lazy class resolution and standards-based cleanup
111
+ stay available without decorator setup. Awilix, Effect and typed-inject also provide meaningful
112
+ compile-time checks, as shown above.
113
+
114
+ <details>
115
+ <summary>Comparison notes: type guarantees, scopes, async behavior and feature boundaries</summary>
116
+
117
+ 1. **Type guarantees:** Katagami's missing-token guarantee applies to accumulated literal keys and
118
+ unique symbols with their types preserved. Class tokens, predeclared maps and mutable aliases
119
+ have [documented boundaries](./docs/type-safety.md). Awilix rejects unknown cradle properties,
120
+ but its broad `resolve` overload accepts unknown names. Effect checks service requirements in
121
+ its own model. Scope checks here mean excluding scoped tokens from singleton/transient resolvers.
122
+ 2. **Setup and bundles:** Metadata notes describe the documented class-injection path; explicit
123
+ value/factory bindings can avoid decorating individual services. Core Katagami needs no polyfills;
124
+ disposal has [host/compiler requirements](./docs/guide.md#compatibility). ESM and side-effect
125
+ declarations help tree shaking, but these are packaging comparisons, not measured bundle sizes.
126
+ 3. **Scopes:** InversifyJS Request means one resolution graph, not an HTTP request. Named containers,
127
+ module contexts, child injectors and Effect resource scopes are not identical lifetime policies.
128
+ 4. **Async:** Returning a Promise is distinct from awaiting dependencies before injection.
129
+ Katagami keeps the Promise in the inferred type and leaves `await` explicit.
130
+ 5. **Cleanup:** Katagami's opt-in `disposable()` integrates `Symbol.dispose`, `Symbol.asyncDispose`
131
+ and `await using`. Ownership varies by library; InversifyJS deactivation is for singletons,
132
+ Awilix disposers are for cached values, and Nest hooks exclude request-scoped classes.
133
+ 6. **Composition versus dedicated APIs:** A service proxy, deferred token and lazy module are
134
+ different features. Autobinding/discovery is not filesystem loading. Katagami's `use()` copies
135
+ registrations; containers are mutable. Factory wrappers are not interceptor APIs, and fresh
136
+ containers are not snapshots. [Composition details](./docs/choosing-di.md#composition-and-tooling).
137
+ 7. **Cycles:** Runtime cycle detection, deferred references and static dependency requirements are
138
+ different mechanisms. A ⚠️ entry does not promise a general cycle detector; runtime checks do
139
+ not imply detection of every asynchronous deadlock.
140
+
141
+ </details>
142
+
40
143
  ## Why Katagami for AI-assisted development?
41
144
 
42
145
  Give coding agents a concrete feedback loop: edit dependency wiring, run the TypeScript checker,
package/docs/README.de.md CHANGED
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## Warum Katagami? Bibliotheksvergleich
29
+
30
+ Katagami verbindet **aus Registrierungen abgeleitete Typen, Scope-Prüfungen zur Compile-Zeit und keine Laufzeitabhängigkeiten** mit gewöhnlichen TypeScript-Factories. Decorators und Metadaten sind nicht nötig. Ressourcenfreigabe und Lazy Resolution haben eigene Einstiegspunkte.
31
+
32
+ **Geprüft am 2026-09-11**, anhand stabiler npm-Versionen und offizieller Quellen. Siehe [Versionen und Quellen](./choosing-di.md#comparison-sources) sowie den [vollständigen Vergleich mit Async-Verhalten und Ressourcenfreigabe](../README.md#library-comparison).
33
+
34
+ | Bibliothek / Version | Abhängigkeitstypen und Registrierungsprüfung | Scope-Verhalten |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **Sammelt Literal-/unique-symbol-Tokens; fehlende erforderliche Tokens sind Typfehler** | **Scoped-Tokens im Resolver von Singleton-/Transient-Factories ausgeschlossen** |
37
+ | InversifyJS 8.2.3 | Typisierte Bindings; Existenzprüfung zur Laufzeit | Konfigurierte Binding-Lebensdauer |
38
+ | tsyringe 4.10.0 | Klassen-/generische Typen; Registrierungsprüfung zur Laufzeit | Lebensdauer und Kindcontainer |
39
+ | TypeDI 0.10.0 | Klassen und `Token<T>`; Registrierungsprüfung zur Laufzeit | Geteilte/Transient-Services, benannte Container |
40
+ | Awilix 13.0.5 | Abgeleitete Cradle-Typen; breites `resolve` akzeptiert unbekannte Namen | Laufzeitprüfung von Lebensdauern mit `strict: true` |
41
+ | NestJS 12.0.1 | Typisierte Provider; Abhängigkeitsgraph zur Laufzeit | Request-Scope überträgt sich auf abhängige Provider |
42
+ | Effect 3.22.2 | Service-Anforderungen in `Effect`-/`Layer`-Typen | Typisierter `Scope` und Finalizer |
43
+ | typed-inject 5.0.0 | Gesammelte String-Tokens, geprüfte `inject`-Tupel | Singleton, Transient, Kindinjectoren |
44
+
45
+ Auch Awilix, Effect und typed-inject bieten Typprüfungen. Katagami kombiniert Registrierungs- und Scope-Prüfungen mit direkten `r.resolve(token)`-Aufrufen. Die [Grenzen für Tokentypen, Klassen und veränderliche Referenzen](./type-safety.md) gelten weiterhin.
46
+
28
47
  ## Mit KI-Coding-Agenten arbeiten
29
48
 
30
49
  Der Agent ändert die Abhängigkeiten, führt den TypeScript-Checker aus und korrigiert den Code anhand der Diagnosen. Explizite Factories zeigen Abhängigkeiten als gewöhnlichen TypeScript-Code.
package/docs/README.es.md CHANGED
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## Por qué elegir Katagami: comparación
29
+
30
+ Katagami combina **tipos derivados del registro, restricciones de ámbito en compilación y cero dependencias de ejecución** en factorías de TypeScript normales. No requiere decoradores ni metadatos. La liberación de recursos y la resolución diferida tienen puntos de entrada separados.
31
+
32
+ **Revisado el 2026-09-11**, con versiones estables de npm y fuentes oficiales. Consulta las [versiones y fuentes](./choosing-di.md#comparison-sources) y la [comparación completa de asincronía y liberación de recursos](../README.md#library-comparison).
33
+
34
+ | Biblioteca / versión | Tipos y comprobación de registros | Política de ámbitos |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **Acumula tokens literales/unique symbol; rechaza tokens requeridos sin registrar** | **Excluye tokens Scoped del resolver de factorías Singleton/Transient** |
37
+ | InversifyJS 8.2.3 | Bindings tipados; existencia comprobada en ejecución | Ciclo de vida configurado por binding |
38
+ | tsyringe 4.10.0 | Tipos de clase/genéricos; registros comprobados en ejecución | Ciclos de vida y contenedores hijos |
39
+ | TypeDI 0.10.0 | Clases y `Token<T>`; registros comprobados en ejecución | Servicios compartidos/Transient y contenedores con nombre |
40
+ | Awilix 13.0.5 | Infiere el cradle del registro; el `resolve` amplio acepta nombres desconocidos | `strict: true` comprueba fugas de ciclo de vida en ejecución |
41
+ | NestJS 12.0.1 | Providers tipados; grafo resuelto en ejecución | Request se propaga a los providers dependientes |
42
+ | Effect 3.22.2 | Requisitos de servicios en los tipos `Effect`/`Layer` | `Scope` tipado y finalizadores |
43
+ | typed-inject 5.0.0 | Acumula tokens de cadena y comprueba tuplas `inject` | Singleton, Transient e injectores hijos |
44
+
45
+ Awilix, Effect y typed-inject también ofrecen comprobaciones de tipos. Katagami combina las de registro y ámbito con llamadas directas a `r.resolve(token)`. Se aplican los [límites de tokens, clases y referencias mutables](./type-safety.md).
46
+
28
47
  ## Uso con agentes de programación de IA
29
48
 
30
49
  El agente modifica las dependencias, ejecuta el comprobador de TypeScript y corrige el código a partir de los diagnósticos. Las fábricas explícitas muestran las dependencias en código TypeScript normal.
package/docs/README.fr.md CHANGED
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## Pourquoi choisir Katagami ? Comparaison
29
+
30
+ Katagami associe **types déduits des enregistrements, restrictions de portée à la compilation et aucune dépendance d'exécution** dans des fabriques TypeScript ordinaires. Aucun décorateur ni métadonnée n'est nécessaire. La libération des ressources et la résolution différée ont des points d'entrée distincts.
31
+
32
+ **Vérifié le 2026-09-11**, à partir des versions stables npm et des sources officielles. Consultez les [versions et sources](./choosing-di.md#comparison-sources) et le [comparatif complet sur l'asynchronisme et la libération des ressources](../README.md#library-comparison).
33
+
34
+ | Bibliothèque / version | Types et vérification des enregistrements | Politique de portée |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **Accumule les tokens littéraux/unique symbol ; rejette les tokens requis non enregistrés** | **Exclut les tokens Scoped du résolveur des fabriques Singleton/Transient** |
37
+ | InversifyJS 8.2.3 | Bindings typés ; existence vérifiée à l'exécution | Durée de vie configurée par binding |
38
+ | tsyringe 4.10.0 | Types de classe/génériques ; enregistrements vérifiés à l'exécution | Durées de vie et conteneurs enfants |
39
+ | TypeDI 0.10.0 | Classes et `Token<T>` ; enregistrements vérifiés à l'exécution | Services partagés/Transient, conteneurs nommés |
40
+ | Awilix 13.0.5 | Cradle déduit des enregistrements ; `resolve` accepte aussi des noms inconnus | `strict: true` vérifie les fuites de durée de vie à l'exécution |
41
+ | NestJS 12.0.1 | Providers typés ; graphe résolu à l'exécution | La portée Request se propage aux providers dépendants |
42
+ | Effect 3.22.2 | Services requis suivis dans les types `Effect`/`Layer` | `Scope` typé et finaliseurs |
43
+ | typed-inject 5.0.0 | Tokens chaînes accumulés et tuples `inject` vérifiés | Singleton, Transient, injecteurs enfants |
44
+
45
+ Awilix, Effect et typed-inject proposent aussi des vérifications de types. Katagami associe celles des enregistrements et des portées avec des appels directs à `r.resolve(token)`. Les [limites des tokens, classes et références mutables](./type-safety.md) s'appliquent.
46
+
28
47
  ## Travailler avec des agents de programmation IA
29
48
 
30
49
  L’agent modifie les dépendances, exécute le vérificateur TypeScript, puis corrige le code à partir des diagnostics. Les fabriques explicites rendent les dépendances visibles dans du code TypeScript ordinaire.
package/docs/README.ja.md CHANGED
@@ -25,6 +25,78 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## Katagamiを選ぶ理由
29
+
30
+ Katagamiの強みは、**登録からの型推論・コンパイル時のスコープ制約・ランタイム依存ゼロ**を、通常のTypeScriptファクトリで組み合わせられることです。
31
+
32
+ - **登録した型がそのまま使える。** リテラルキーやunique symbolの型を保てば、登録集合にない必須トークンは型エラーになります。
33
+ - **リクエストの状態を型で分離できる。** Singleton・Transientのファクトリに渡されるresolverからは、Scopedのトークンを解決できません。
34
+ - **デコレータ設定が不要。** DIのための`experimentalDecorators`・`emitDecoratorMetadata`・Reflectポリフィルを追加する必要がありません。
35
+ - **必要な機能だけ取り込める。** コア・`katagami/disposable`・`katagami/lazy`を別々にインポートできます。ESMと`sideEffects: false`でツリーシェイキングに対応し、破棄はホストのdisposalシンボルと`await using`に連携します。
36
+
37
+ ### 他ライブラリとの比較
38
+
39
+ **8ライブラリ・27項目の比較。2026-09-11確認。** 表中のnpm `latest`安定版と公式資料をもとにしています。[対象バージョン・出典・詳細な注記](./choosing-di.md#comparison-sources)。
40
+
41
+ **✅ 標準で対応 · ⚠️ 条件付き・異なるモデル・利用側での合成 · ➖ その機能の標準対応なし。** 各セルに具体的なAPIや条件を添えています。
42
+
43
+ #### 型安全性・導入設定
44
+
45
+ | 比較項目 | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
46
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
47
+ | **ランタイム要件** | **✅ 通常のTypeScript** | ⚠️ クラスDIにReflectメタデータ | ⚠️ クラスDIにReflectメタデータ | ⚠️ Reflectメタデータ設定 | ✅ DIメタデータ不要 | ⚠️ Nestモジュール・メタデータ | ✅ Effect・Layer API | ✅ 通常のTypeScript |
48
+ | **注入方式** | **明示的なファクトリ・コンストラクタ** | コンストラクタ・プロパティ・ファクトリ | コンストラクタ・ファクトリ | コンストラクタ・プロパティ・ファクトリ | Proxy・Classic・ファクトリ | コンストラクタ・プロパティ・ファクトリ | 関数型サービス・Layer | コンストラクタ・ファクトリ+`inject` |
49
+ | **トークンの種類** | **クラス・文字列・数値・symbol** | クラス・文字列・symbol | クラス・文字列・symbol | クラス・文字列・`Token<T>` | 文字列・symbol | クラス・文字列・symbol | `Context.Tag` | 文字列リテラル |
50
+ | **型安全性** | **✅ サービス推論+スコープ検査** | ✅ 型付き識別子・binding | ✅ クラス・ジェネリック | ✅ クラス・`Token<T>` | ✅ cradleの推論 | ✅ 型付きprovider | ✅ サービス要求の型検査 | ✅ トークン+`inject`タプル |
51
+ | **登録からの型の蓄積** | **✅ トークンの型を蓄積** | ➖ | ➖ | ➖ | ✅ `register` → cradle | ➖ | ⚠️ Layerの要求型 | ✅ トークンの型を蓄積 |
52
+ | **未登録の必須トークンをコンパイル時に検出¹** | **✅ リテラル・unique symbol** | ➖ 実行時に検査 | ➖ 実行時に検査 | ➖ 実行時に検査 | ⚠️ cradleでの参照のみ | ➖ 実行時の依存グラフ | ✅ 未充足のサービス要求 | ✅ リテラルキー |
53
+ | **Singleton・TransientからのScoped参照を型で制限¹** | **✅ Scopedトークンを除外** | ➖ | ➖ | ➖ | ⚠️ strictモードで実行時検査 | ⚠️ Requestスコープが伝播 | ⚠️ 異なる`Scope`モデル | ➖ Scopedライフタイムなし |
54
+ | **ランタイム依存パッケージゼロ²** | **✅** | ➖ | ➖ | ⚠️ Reflectポリフィルを別途導入 | ⚠️ ブラウザ版は構成が異なる | ➖ | ➖ | ✅ |
55
+ | **ツリーシェイキング対応²** | **✅ ESM・サブパス・`sideEffects: false`** | ⚠️ ESM・`sideEffects: true` | ⚠️ ESMビルド | ✅ ESM・`sideEffects: false` | ⚠️ ESM・ブラウザビルド | ⚠️ ESM・フレームワーク設定 | ✅ ESM・サブパス・副作用宣言 | ⚠️ ESMビルド |
56
+
57
+ #### ライフタイム・非同期・リソース破棄
58
+
59
+ | 比較項目 | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
60
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
61
+ | **ライフタイム** | **✅ Singleton・Transient・Scoped** | ✅ Singleton・Transient・Request | ✅ Singleton・Transient・Resolution・Container | ✅ 共有・Transient | ✅ Singleton・Transient・Scoped | ✅ Singleton・Transient・Request | ⚠️ メモ化/fresh Layer+Scope | ✅ Singleton・Transient |
62
+ | **リクエスト/Scopedライフタイム³** | **✅ リクエストごとに明示的なScope** | ⚠️ 1回の解決グラフ | ✅ Container/Resolution単位 | ⚠️ 名前付きコンテナ | ✅ リクエストごとに明示的なScope | ✅ HTTPリクエスト単位 | ⚠️ リソースScope | ⚠️ 子injector。Scoped登録なし |
63
+ | **子コンテナ/ネストしたスコープ³** | **✅ ネストしたScope** | ✅ コンテナ階層 | ✅ 子コンテナ | ⚠️ 名前付きコンテナ | ✅ 子Scope | ⚠️ モジュール/Requestのコンテキスト | ⚠️ ネストしたリソースScope | ✅ 子injector |
64
+ | **非同期ファクトリ** | **✅ Promiseを返すファクトリ** | ✅ 非同期binding | ✅ Promiseを返すファクトリ | ✅ Promise値のサービス | ✅ Promiseを返すファクトリ | ✅ 非同期provider | ✅ Effectによる取得 | ✅ Promiseを返すファクトリ |
65
+ | **非同期の戻り値の型追跡** | **✅ `Promise<T>`を推論** | ✅ `getAsync<T>` | ⚠️ Promise値として型付け | ⚠️ Promise値として型付け | ✅ `Promise<T>`を推論 | ⚠️ provider・利用側の型指定 | ✅ 結果・エラー・要求の型 | ✅ `Promise<T>`を推論 |
66
+ | **非同期の依存を自動的にawait⁴** | **➖ 明示的に`await`** | ✅ `getAsync`・`getAllAsync` | ➖ 利用側でawait | ➖ 利用側でawait | ➖ 利用側でawait | ✅ 依存元の構築前に待機 | ✅ Effectの合成 | ➖ 利用側でawait |
67
+ | **リソース破棄⁵** | **✅ disposalシンボル・`await using`** | ⚠️ Singletonのdeactivation | ✅ 構築したDisposable | ⚠️ reset・削除時の`destroy()` | ⚠️ キャッシュした値+disposer | ⚠️ アプリのライフサイクルフック | ✅ Scopeのfinalizer | ✅ 所有するDisposable |
68
+ | **非同期の破棄完了を待機⁵** | **✅ `Symbol.asyncDispose`** | ✅ 非同期deactivation | ✅ `container.dispose()` | ➖ `destroy()`を待機しない | ✅ `container.dispose()` | ⚠️ アプリのフック。Requestは対象外 | ✅ Effectのfinalizer | ✅ `injector.dispose()` |
69
+
70
+ #### 合成・拡張機能
71
+
72
+ | 比較項目 | **Katagami**<br>**3.0.3** | InversifyJS<br>8.2.3 | tsyringe<br>4.10.0 | TypeDI<br>0.10.0 | Awilix<br>13.0.5 | NestJS<br>12.0.1 | Effect<br>3.22.2 | typed-inject<br>5.0.0 |
73
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- |
74
+ | **オプショナル解決** | **✅ `tryResolve`・`tryResolveAll`** | ✅ オプショナルget・inject | ✅ オプショナル注入 | ⚠️ `has`で確認して`get` | ✅ `allowUnregistered` | ✅ オプショナル注入 | ✅ `serviceOption` | ⚠️ オプショナル値を合成 |
75
+ | **複数登録・一括解決** | **✅ `resolveAll`** | ✅ `getAll`・`getAllAsync` | ✅ `injectAll`・`resolveAll` | ✅ `getMany` | ⚠️ コレクション値を登録 | ⚠️ 配列provider | ⚠️ コレクション値を登録 | ⚠️ コレクション値を登録 |
76
+ | **遅延解決⁶** | **✅ `lazy()`・同期クラストークン** | ⚠️ 識別子の遅延・ファクトリ | ✅ `delay()`のProxy | ⚠️ 型の遅延参照 | ⚠️ cradleのプロパティ参照 | ⚠️ `LazyModuleLoader` | ⚠️ Effectの遅延実行 | ⚠️ ファクトリを注入 |
77
+ | **条件付きbinding** | **⚠️ トークン分離・ファクトリ内の分岐** | ✅ コンテキスト制約 | ✅ 条件付きファクトリ | ⚠️ ファクトリ内の分岐 | ⚠️ ローカル注入・分岐 | ⚠️ 動的モジュール・ファクトリ | ⚠️ Layerの選択・合成 | ⚠️ ファクトリ内の分岐 |
78
+ | **自動ロード/検出⁶** | **➖ 明示的な`use()`** | ⚠️ クラスの自動binding | ➖ 明示的な登録 | ➖ 明示的なimport | ✅ `loadModules`(Node) | ⚠️ `DiscoveryService` | ➖ 明示的なLayer | ➖ 明示的なprovider |
79
+ | **モジュールシステム・合成** | **✅ `use()`** | ✅ コンテナモジュール | ✅ `@registry` | ⚠️ 登録をまとめる | ✅ `loadModules`・`register` | ✅ モジュール・動的モジュール | ✅ Layerの合成 | ⚠️ providerチェーンの合成 |
80
+ | **循環依存の検出⁷** | **✅ 実行時に循環経路を表示** | ✅ 実行時に検出 | ⚠️ コンストラクタのエラー・`delay` | ⚠️ 型の遅延参照 | ✅ 実行時に循環経路を表示 | ⚠️ 循環エラー・`forwardRef` | ⚠️ Layerの要求型 | ⚠️ 登録順で依存を制限 |
81
+ | **ミドルウェア/インターセプタ⁶** | **⚠️ 高階ファクトリで合成** | ✅ activation・deactivationフック | ✅ 解決前後のフック | ⚠️ ファクトリをラップ | ⚠️ ファクトリをラップ | ⚠️ Request用。DIフックとは異なる | ⚠️ Effectを合成 | ⚠️ providerの装飾 |
82
+ | **スナップショット/復元⁶** | **➖** | ✅ `snapshot`・`restore` | ➖ | ➖ | ➖ | ➖ | ➖ | ➖ |
83
+ | **テスト用の差し替え・分離** | **✅ 新しいScope・コンテナ+`use()`** | ✅ 再binding・スナップショット | ✅ 子コンテナで上書き | ✅ 名前付きコンテナ・reset | ✅ 子Scopeで上書き | ✅ `overrideProvider` | ✅ テスト用Layerに差し替え | ✅ 子injectorで上書き |
84
+
85
+ **Katagamiの強み:登録型の蓄積・ファクトリのスコープ制約・3つのライフタイム・ランタイム依存ゼロ**を、直接`r.resolve(token)`を呼べるAPIで組み合わせられます。オプショナル/複数解決、モジュール合成、クラスの遅延解決、標準のdisposalシンボルによる破棄も、デコレータ設定なしで利用できます。Awilix・Effect・typed-injectにも、表に示したコンパイル時の検査機能があります。
86
+
87
+ <details>
88
+ <summary>比較の注記:型の保証・スコープ・非同期・各機能の対応範囲</summary>
89
+
90
+ 1. **型の保証:** Katagamiは、型が保たれたリテラルキー・unique symbolを蓄積する方式で未登録トークンを検出します。クラストークン・事前宣言・変更可能な参照には[保証範囲の条件](./type-safety.md)があります。Awilixは未登録のcradleプロパティを拒否しますが、広い`resolve`オーバーロードは未登録名も許可します。Effectは独自のサービス要求を検査します。スコープ制約の行は、Singleton・TransientのresolverからScopedを型で除外する機能の比較です。
91
+ 2. **導入とバンドル:** メタデータの記述は公式のクラス注入手順が対象です。明示的な値・ファクトリの登録では、各サービスへのデコレータを省ける場合があります。Katagamiのコアにポリフィルは不要ですが、破棄機能には[ホスト・コンパイラの要件](./guide.md#compatibility)があります。ESM・副作用宣言はツリーシェイキングを助ける構成であり、バンドルサイズの実測比較ではありません。
92
+ 3. **スコープ:** InversifyJSのRequestは1回の解決グラフで、HTTPリクエストとは異なります。名前付きコンテナ・モジュールのコンテキスト・子injector・EffectのリソースScopeも、それぞれ異なる管理方式です。
93
+ 4. **非同期:** Promiseを返せることと、注入前に依存の完了を自動的に待つことは別です。KatagamiはPromiseを型に残し、`await`を明示します。
94
+ 5. **破棄:** Katagamiは追加の`disposable()`で`Symbol.dispose`・`Symbol.asyncDispose`・`await using`に連携します。所有権と破棄対象はライブラリごとに異なり、InversifyJSのdeactivationはSingleton、Awilixのdisposerはキャッシュした値が対象です。NestのフックはRequestスコープのクラスには適用されません。
95
+ 6. **合成と専用API:** サービスの遅延Proxy・型参照の遅延・モジュールの遅延ロードは別の機能です。自動binding・検出も、ファイルの自動ロードとは異なります。Katagamiの`use()`は登録をコピーし、コンテナ自体は変更可能です。ファクトリのラップは専用インターセプタではなく、新しいコンテナでの分離はスナップショットではありません。[合成機能の詳細](./choosing-di.md#composition-and-tooling)。
96
+ 7. **循環依存:** 実行時の循環検出・参照の遅延・依存の型検査は異なる仕組みです。⚠️は汎用的な循環検出器の存在を意味しません。また、実行時の検出が、あらゆる非同期デッドロックの検出を保証するわけではありません。
97
+
98
+ </details>
99
+
28
100
  ## AIエージェントによるコーディングで役立つ理由
29
101
 
30
102
  エージェントが依存関係を変更し、TypeScriptの型チェックを実行し、診断をもとに修正する。この手順に、登録漏れやライフタイムの誤用を検出する具体的なチェックを組み込めます。依存関係は通常のTypeScriptのファクトリとして記述します。
package/docs/README.ko.md CHANGED
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## Katagami를 선택하는 이유와 라이브러리 비교
29
+
30
+ **등록에서 추론한 타입, 컴파일 시점의 스코프 제한, 런타임 의존성 없음**을 일반 TypeScript 팩터리에서 함께 사용할 수 있습니다. 데코레이터나 메타데이터 설정이 필요 없으며, 리소스 정리와 지연 해석은 별도 진입점으로 가져옵니다.
31
+
32
+ **2026-09-11 확인.** npm의 안정 버전과 공식 자료를 비교했습니다. [버전과 출처](./choosing-di.md#comparison-sources), [비동기·정리 기능까지 포함한 전체 비교](../README.md#library-comparison)를 참고하세요.
33
+
34
+ | 라이브러리 / 버전 | 의존성 타입과 등록 확인 | 스코프 정책 |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **리터럴·unique symbol 등록을 누적하고 미등록 필수 토큰 거부** | **Singleton·Transient 팩터리에서 Scoped 토큰을 타입으로 제외** |
37
+ | InversifyJS 8.2.3 | 타입이 있는 binding, 등록 여부는 런타임 확인 | binding의 라이프타임 설정 |
38
+ | tsyringe 4.10.0 | 클래스·제네릭 타입, 등록 여부는 런타임 확인 | 라이프타임 설정과 자식 컨테이너 |
39
+ | TypeDI 0.10.0 | 클래스·`Token<T>`, 등록 여부는 런타임 확인 | 공유·Transient 서비스와 이름 있는 컨테이너 |
40
+ | Awilix 13.0.5 | 등록에서 cradle 추론. 넓은 `resolve`는 미등록 이름도 허용 | `strict: true`로 런타임 라이프타임 검사 |
41
+ | NestJS 12.0.1 | 타입이 있는 provider, 런타임 의존성 그래프 | Request 스코프가 의존하는 쪽으로 전파 |
42
+ | Effect 3.22.2 | `Effect`·`Layer` 타입으로 필요한 서비스 추적 | 타입이 있는 `Scope`와 finalizer |
43
+ | typed-inject 5.0.0 | 문자열 토큰 누적과 `inject` 튜플 검사 | Singleton·Transient, 자식 injector |
44
+
45
+ Awilix, Effect, typed-inject에도 컴파일 시점 기능이 있습니다. Katagami는 등록 확인과 스코프 제한을 직접 `r.resolve(token)`을 호출하는 API로 결합합니다. [토큰 타입·클래스·변경 가능한 참조의 조건](./type-safety.md)이 적용됩니다.
46
+
28
47
  ## AI 코딩 에이전트와 함께 사용하기
29
48
 
30
49
  에이전트가 의존 관계를 수정하고 TypeScript 검사기를 실행한 뒤 진단에 따라 수정하는 흐름을 만듭니다. 팩터리에 의존 관계가 일반 TypeScript 코드로 드러납니다.
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## 为什么选择 Katagami:库对比
29
+
30
+ Katagami 在普通 TypeScript 工厂中结合了**从注册推导类型、编译时作用域限制、零运行时依赖**。无需装饰器或元数据配置,资源清理和延迟解析可通过独立入口按需导入。
31
+
32
+ **核查日期:2026-09-11。** 对照 npm 稳定版和官方资料;参见[版本与来源](./choosing-di.md#comparison-sources)及[包含异步和清理功能的完整对比](../README.md#library-comparison)。
33
+
34
+ | 库/版本 | 依赖类型与注册检查 | 作用域策略 |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **累积字面量、unique symbol 的注册类型,拒绝未注册的必需 token** | **从 Singleton、Transient 工厂的 resolver 类型中排除 Scoped token** |
37
+ | InversifyJS 8.2.3 | 有类型的 binding;运行时检查是否已绑定 | binding 的生命周期设置 |
38
+ | tsyringe 4.10.0 | 类与泛型类型;运行时检查注册 | 生命周期设置与子容器 |
39
+ | TypeDI 0.10.0 | 类与 `Token<T>`;运行时检查注册 | 共享、Transient 服务与命名容器 |
40
+ | Awilix 13.0.5 | 从注册推导 cradle;宽泛的 `resolve` 仍接受未知名称 | `strict: true` 在运行时检查生命周期泄漏 |
41
+ | NestJS 12.0.1 | 有类型的 provider;运行时解析依赖图 | Request 作用域向依赖方传播 |
42
+ | Effect 3.22.2 | 通过 `Effect`、`Layer` 类型追踪所需服务 | 有类型的 `Scope` 与 finalizer |
43
+ | typed-inject 5.0.0 | 累积字符串 token,检查 `inject` 元组 | Singleton、Transient 与子 injector |
44
+
45
+ Awilix、Effect、typed-inject 也有编译时检查能力。Katagami 的特点是通过直接调用 `r.resolve(token)` 的 API 结合注册检查与作用域限制。[窄 token 类型、类和可变引用的边界](./type-safety.md)仍然适用。
46
+
28
47
  ## 配合 AI 编程智能体使用
29
48
 
30
49
  让智能体修改依赖关系,运行 TypeScript 检查,再根据诊断修复。显式工厂让依赖关系直接体现在普通 TypeScript 代码中。
@@ -25,6 +25,25 @@ const greeting: string = createScope(container).resolve('greeting');
25
25
  console.log(greeting);
26
26
  ```
27
27
 
28
+ ## 為什麼選擇 Katagami:函式庫比較
29
+
30
+ Katagami 在一般 TypeScript 工廠中結合了**從註冊推導型別、編譯時作用域限制、零執行期依賴**。不需要裝飾器或中繼資料設定,資源清理與延遲解析可透過獨立入口按需匯入。
31
+
32
+ **查核日期:2026-09-11。** 對照 npm 穩定版與官方資料;請參閱[版本與來源](./choosing-di.md#comparison-sources)及[包含非同步與清理功能的完整比較](../README.md#library-comparison)。
33
+
34
+ | 函式庫/版本 | 依賴型別與註冊檢查 | 作用域策略 |
35
+ | --- | --- | --- |
36
+ | **Katagami 3.0.3** | **累積字面值、unique symbol 的註冊型別,拒絕未註冊的必要 token** | **從 Singleton、Transient 工廠的 resolver 型別中排除 Scoped token** |
37
+ | InversifyJS 8.2.3 | 具型別的 binding;執行時檢查是否已綁定 | binding 的生命週期設定 |
38
+ | tsyringe 4.10.0 | 類別與泛型型別;執行時檢查註冊 | 生命週期設定與子容器 |
39
+ | TypeDI 0.10.0 | 類別與 `Token<T>`;執行時檢查註冊 | 共用、Transient 服務與具名容器 |
40
+ | Awilix 13.0.5 | 從註冊推導 cradle;寬泛的 `resolve` 仍接受未知名稱 | `strict: true` 在執行時檢查生命週期洩漏 |
41
+ | NestJS 12.0.1 | 具型別的 provider;執行時解析依賴圖 | Request 作用域向依賴方傳播 |
42
+ | Effect 3.22.2 | 透過 `Effect`、`Layer` 型別追蹤所需服務 | 具型別的 `Scope` 與 finalizer |
43
+ | typed-inject 5.0.0 | 累積字串 token,檢查 `inject` 元組 | Singleton、Transient 與子 injector |
44
+
45
+ Awilix、Effect、typed-inject 也有編譯時檢查能力。Katagami 的特色是透過直接呼叫 `r.resolve(token)` 的 API 結合註冊檢查與作用域限制。[窄 token 型別、類別與可變參照的邊界](./type-safety.md)仍然適用。
46
+
28
47
  ## 與 AI 程式設計代理搭配使用
29
48
 
30
49
  讓代理修改依賴關係,執行 TypeScript 檢查,再根據診斷修正。明確的工廠讓依賴關係直接呈現在一般 TypeScript 程式碼中。
@@ -1,30 +1,169 @@
1
1
  # Choosing a TypeScript dependency injection approach
2
2
 
3
- Choose based on the application's wiring and lifecycle needs. There is no measured claim here
4
- that Katagami is faster, safer in every scenario, or more effective for every coding agent.
3
+ Katagami is a strong fit when you want **registration-derived types, explicit request scopes and
4
+ ordinary TypeScript factories without decorators or runtime dependencies**. The
5
+ [README comparison](../README.md#library-comparison) covers 27 features across eight libraries,
6
+ including typing, setup, lifetimes, asynchronous behavior, cleanup and composition. This guide records the evidence and
7
+ the features that need more explanation than a table cell.
5
8
 
6
- | Approach | Consider it when | What to account for |
9
+ ## What distinguishes Katagami
10
+
11
+ The default registration chain accumulates the tokens visible to each factory. With literal keys
12
+ or unique symbols preserved, a missing required token is rejected before execution. Singleton and
13
+ transient factories receive a resolver that excludes scoped tokens. Async results stay visible as
14
+ Promises. This combination gives a coding agent actionable TypeScript errors while keeping the
15
+ wiring in ordinary factory functions.
16
+
17
+ Accumulation alone is not unique to Katagami: typed-inject checks accumulated tokens and injection
18
+ tuples, and Awilix 13 infers cradle types from registrations. Effect tracks required services in its
19
+ effect and layer types. Katagami adds a specific scope restriction to its factory resolver API.
20
+ See [the guarantee examples](./type-safety.md) for narrow-token requirements, structural class
21
+ typing, mutable aliases and predeclared-map boundaries.
22
+
23
+ | Approach | A reason to choose it |
24
+ | --- | --- |
25
+ | Ordinary constructor/function parameters | Few dependencies; direct wiring remains easy to maintain |
26
+ | Katagami | Registration checks and explicit scoped DI in standard TypeScript factories |
27
+ | InversifyJS | Class-oriented binding, contextual constraints, container modules and snapshots |
28
+ | tsyringe | Constructor injection with decorators, child containers and resolution interceptors |
29
+ | TypeDI | An existing application built around its decorators, typed tokens and named containers |
30
+ | Awilix | Proxy/classic injection, inferred cradles, module loading and runtime lifetime checks |
31
+ | NestJS | The app already benefits from Nest modules, request handling and framework integrations |
32
+ | Effect | Service composition belongs with typed errors, effectful execution and scoped resources |
33
+ | typed-inject | Accumulated string-token checks with explicit injection tuples and child injectors |
34
+
35
+ ## Comparison sources
36
+
37
+ Reviewed **2026-09-11**. Competitor versions are the npm `latest` dist-tag versions observed on that date,
38
+ not prerelease versions or unreleased features from repository default branches. TypeDI refers to
39
+ the `typedi` package maintained under TypeStack, not similarly named forks. NestJS's version is
40
+ the version of `@nestjs/core`. The comparison uses Effect **3** documentation explicitly. Katagami 3.0.3 is this documentation
41
+ release; its runtime and public APIs are unchanged from the reviewed 3.0.1 package.
42
+
43
+ | Package | Reviewed version and registry metadata | Primary documentation / shipped API |
44
+ | --- | --- | --- |
45
+ | Katagami | [3.0.1](https://registry.npmjs.org/katagami/3.0.1) | [Type guarantees](./type-safety.md), [API guide](./guide.md) |
46
+ | InversifyJS | [8.2.3](https://registry.npmjs.org/inversify/8.2.3) | [8.x setup](https://inversify.io/docs/introduction/getting-started/), [bindings](https://inversify.io/docs/fundamentals/binding/), [container API](https://inversify.io/docs/api/container/) |
47
+ | tsyringe | [4.10.0](https://registry.npmjs.org/tsyringe/4.10.0) | [Release README](https://github.com/microsoft/tsyringe/blob/e033769d97cfb6cc4a8569e2b50eb32015453302/README.md), [container types](https://github.com/microsoft/tsyringe/blob/e033769d97cfb6cc4a8569e2b50eb32015453302/src/types/dependency-container.ts) |
48
+ | TypeDI | [0.10.0](https://registry.npmjs.org/typedi/0.10.0) | [Release source](https://github.com/typestack/typedi/tree/v0.10.0), [container implementation](https://github.com/typestack/typedi/blob/v0.10.0/src/container-instance.class.ts) |
49
+ | Awilix | [13.0.5](https://registry.npmjs.org/awilix/13.0.5) | [Release README](https://github.com/jeffijoe/awilix/blob/f72d175ddb950c3f13ef41e8be98b24471d59900/README.md), [container types/implementation](https://github.com/jeffijoe/awilix/blob/f72d175ddb950c3f13ef41e8be98b24471d59900/src/container.ts) |
50
+ | NestJS | [12.0.1](https://registry.npmjs.org/@nestjs%2fcore/12.0.1) | [Providers](https://docs.nestjs.com/fundamentals/custom-providers), [scopes](https://docs.nestjs.com/fundamentals/injection-scopes), [async providers](https://docs.nestjs.com/fundamentals/async-providers), [lifecycle](https://docs.nestjs.com/fundamentals/lifecycle-events) |
51
+ | Effect | [3.22.2](https://registry.npmjs.org/effect/3.22.2) | [v3 layers](https://effect.website/docs/v3/requirements-management/layers), [v3 scope](https://effect.website/docs/v3/resource-management/scope) |
52
+ | typed-inject | [5.0.0](https://registry.npmjs.org/typed-inject/5.0.0) | [Release README](https://github.com/nicojs/typed-inject/blob/5d3c0276e65ade1d683239346488708b7a11e443/README.md), [injector types](https://github.com/nicojs/typed-inject/blob/5d3c0276e65ade1d683239346488708b7a11e443/src/api/Injector.ts) |
53
+
54
+ Versioned npm tarballs were also inspected. A focused TypeScript 5.9.3 check confirmed that
55
+ Awilix 13.0.5 infers registered cradle properties and rejects an unknown cradle property, while
56
+ `resolve('missing')` still compiles through its broad overload. The same check confirmed that
57
+ typed-inject 5.0.0 and Katagami 3.0.1 reject an unknown literal token, and that Awilix and
58
+ typed-inject infer a Promise returned by a factory. This is a type check, not a performance benchmark
59
+ or an exhaustive runtime compatibility test.
60
+
61
+ ## Reading the comparison
62
+
63
+ ### Registration types and scope restrictions
64
+
65
+ A typed return value is different from proving that the container has a registration. InversifyJS,
66
+ tsyringe and TypeDI expose class/generic-token APIs without accumulating the set of registered keys
67
+ into the container's type. Awilix has both inferred cradle access and a broad string/symbol `resolve`
68
+ overload. Its opt-in strict mode checks lifetime leaks at runtime. These observations come from the
69
+ published APIs linked above, not from treating all of these libraries as “untyped.”
70
+
71
+ NestJS handles request-scoped dependencies by propagating request scope up the dependency chain.
72
+ That is a different policy from Katagami rejecting scoped access in a singleton factory. Effect's
73
+ `Scope` requirement ensures resource acquisition has a scope; it does not use Katagami's
74
+ singleton/transient/scoped categories. typed-inject has disposable child injectors, but its provider
75
+ scope enum offers singleton and transient, not a separate scoped registration policy.
76
+
77
+ ### Setup and bundles
78
+
79
+ Katagami, Awilix, Effect and typed-inject do not require decorator metadata for their DI APIs.
80
+ The documented TypeScript class-injection paths for InversifyJS, tsyringe and TypeDI use metadata;
81
+ explicit factory/value bindings should not be described as requiring decorators on every service.
82
+ NestJS provides framework modules and metadata-based injection as well as custom providers.
83
+
84
+ Katagami and typed-inject have no runtime dependency packages. TypeDI's manifest also has no
85
+ `dependencies`, but its TypeScript setup asks the application to install `reflect-metadata`.
86
+ Awilix's Node package lists `fast-glob`; its browser build excludes filesystem-based module loading.
87
+ “No decorators” therefore does not mean “no dependency packages.”
88
+
89
+ Katagami publishes ESM, CommonJS, subpath exports and `sideEffects: false`. Effect also exposes
90
+ ESM/subpath exports and a side-effect declaration, and TypeDI declares `sideEffects: false`.
91
+ The other libraries should not receive an automatic “no tree shaking” mark. Actual output size
92
+ depends on the entry point, imports, bundler and application; no comparative bundle-size benchmark
93
+ was run for this table.
94
+
95
+ ### Async and cleanup
96
+
97
+ Katagami exposes `Promise<T>` for async factories: dependent factories explicitly await that value.
98
+ Awilix, typed-inject and the generic factory/value APIs in tsyringe and TypeDI can also carry a
99
+ Promise-valued service. This is different from InversifyJS's async resolution or NestJS's async
100
+ providers, which await dependencies before constructing their consumers. Effect models acquisition
101
+ as an effect. A binary “async factories: no” would conceal these distinctions.
102
+
103
+ Katagami's `disposable()` owns container singletons or scope instances and calls disposal-symbol
104
+ methods. Its [compatibility requirements](./guide.md#compatibility) still apply. InversifyJS has
105
+ [singleton deactivation handlers](https://inversify.io/docs/fundamentals/lifecycle/deactivation/); tsyringe and typed-inject support disposable constructed instances;
106
+ Awilix disposes cached scoped/singleton values through registered disposers. TypeDI can call
107
+ `destroy()` during reset/removal but does not await its return. NestJS's application lifecycle hooks
108
+ are not invoked for request-scoped classes. Effect scopes run registered finalizers. These are
109
+ different ownership and shutdown models, not interchangeable cleanup guarantees.
110
+
111
+ ## Composition and tooling
112
+
113
+ This table restores the broader feature comparison using concrete APIs. “Compose” means ordinary
114
+ application code can implement the pattern; it does not claim a dedicated container feature.
115
+
116
+ | Library | Optional / multiple resolution | Composition, discovery and extension |
7
117
  | --- | --- | --- |
8
- | Ordinary constructor/function parameters | A small number of dependencies is easy to wire by hand | Your code owns construction, sharing and cleanup; TypeScript still checks parameter types |
9
- | Katagami | You want explicit factories, accumulated registration types and request scopes | Preserve narrow token types; understand structural class identity and predeclared-map limits |
10
- | Your framework's existing DI | The application already uses a framework container | Its conventions and lifecycle integrations may avoid maintaining a second container |
11
- | Awilix | Its registration, injection and loading conventions fit your app | Read its own TypeScript and strict-mode documentation for guarantees and configuration |
12
- | InversifyJS | Its class-oriented binding model and ecosystem fit your app | Follow its current setup instructions, including metadata requirements where applicable |
118
+ | Katagami | `tryResolve`, `resolveAll`, `tryResolveAll` | `use()` copies registrations; opt-in `lazy()`; ordinary higher-order factories |
119
+ | InversifyJS | Optional get/inject, `getAll`, `getAllAsync` | Container modules/hierarchy, autobinding, contextual constraints, activation/deactivation, snapshot/restore |
120
+ | tsyringe | Optional inject, `injectAll`, `resolveAll` | `@registry`, child containers, before/after resolution interceptors, `delay()`, `predicateAwareClassFactory` |
121
+ | TypeDI | `has` before `get`; `getMany` with multiple registrations | Named containers, factory configuration and service decorators |
122
+ | Awilix | `allowUnregistered`; compose collections as values/factories | `loadModules`, child scopes, local injections and proxy/classic injection |
123
+ | NestJS | Optional injection/provider dependencies; compose array providers | Modules/dynamic modules, provider overrides, discovery service and lazy modules |
124
+ | Effect | [`serviceOption`](https://effect.website/docs/v3/requirements-management/services#optional-services); compose collection-valued services | Layer composition, service substitution and scoped acquisition |
125
+ | typed-inject | Required tokens checked statically; compose optional values/collections | Child injectors, provider replacement/decoration and explicit injection tuples |
126
+
127
+ Katagami does not implement filesystem auto-discovery or snapshot/restore, and its runtime
128
+ containers are mutable. `use()` and fresh test containers provide explicit composition and test
129
+ substitution. Factory wrappers are an application pattern, not a middleware/interceptor API.
130
+ Similarly, a lazy module loader is not the same feature as a proxy that constructs one service on
131
+ first property access, and a resolution graph scope is not an HTTP request scope.
132
+
133
+ The README retains all 18 original comparison aspects and adds nine more specific checks:
134
+ registration-derived types, missing-token checking, compile-time scope restrictions, dependency
135
+ packages, scoped lifetime behavior, async result typing, automatic awaiting, async cleanup and
136
+ test substitution. Its three feature-by-library matrices use the same columns. ✅ means built-in
137
+ support, ⚠️ marks a condition, different model or application composition, and ➖ means that the
138
+ specific capability has no built-in support. The icons are not a total score.
13
139
 
14
- Katagami's concrete distinction is that the default registration chain accumulates a resolver's
15
- visible token set. For literal keys or unique symbols, a missing token is rejected before execution.
16
- That is a useful check for both human-written and AI-generated wiring. It does not establish that
17
- other libraries lack type safety, and it does not eliminate runtime tests.
140
+ Additional API notes for the expanded rows:
18
141
 
19
- Start with the [runnable starter](../examples/request-scope/README.md),
20
- [guarantee examples](./type-safety.md) and [composition guide](./guide.md#composition-and-test-substitution).
142
+ - tsyringe's release README documents `predicateAwareClassFactory` for conditional construction
143
+ and `delay()` for a proxy that constructs an instance on first use. Its circular-dependency
144
+ example reports an undefined constructor; that is narrower than a general graph cycle detector.
145
+ - InversifyJS has a dedicated [snapshot API](https://inversify.io/docs/fundamentals/snapshot/).
146
+ Its activation/deactivation hooks are the extension mechanism shown here; the table does not
147
+ claim that the old `applyMiddleware` API exists in version 8. A deferred service identifier
148
+ delays reading a token, which is different from a proxy that delays constructing its service.
149
+ - Effect 3's [layer memoization guide](https://effect.website/docs/v3/requirements-management/layer-memoization)
150
+ documents both shared layer construction and `Layer.fresh`. These are not container
151
+ Singleton/Transient registration flags. Typed requirements are not a claim of a general
152
+ runtime cycle detector.
153
+ - Nest's `forwardRef` and TypeDI's deferred type references address reference timing. Neither
154
+ should be marked as equivalent to Katagami's lazy service proxy. A runtime cycle guard also
155
+ does not establish detection of every asynchronous deadlock.
21
156
 
22
- Primary references, reviewed 2026-09-11:
157
+ Start with the [runnable starter](../examples/request-scope/README.md) and
158
+ [composition guide](./guide.md#composition-and-test-substitution). For a project already built on
159
+ NestJS or Effect, adopting its existing DI model can be simpler than maintaining a second container.
23
160
 
24
- - [Awilix's maintained README](https://github.com/jeffijoe/awilix#readme), including TypeScript and strict mode.
25
- - [InversifyJS getting started](https://inversify.io/docs/introduction/getting-started/).
26
- - [TypeScript type compatibility](https://www.typescriptlang.org/docs/handbook/type-compatibility).
161
+ ## Updating the comparison
27
162
 
28
- The previous broad feature matrix was replaced with this decision guide. Replacing registrations
29
- with `use()` is explicit composition; Katagami does not implement automatic module discovery,
30
- immutable containers or a dedicated snapshot/restore API.
163
+ Preserve a comparison and Katagami's supported advantages in the README when editing positioning.
164
+ Keep the feature-by-library layout, status icons and all existing comparison aspects when refreshing
165
+ it; add detail rather than replacing the matrix with a smaller library-by-library summary.
166
+ Refresh the date, npm dist-tag versions and official sources together. Check published declarations
167
+ when a claim involves inference or registration guarantees, and distinguish built-in features from
168
+ wrappers, configuration and framework behavior. Keep localized summaries aligned with the English
169
+ comparison. Do not infer a feature's absence from its omission in a quick-start guide.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katagami",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Type-safe dependency injection for TypeScript, with inferred types and scope checks for AI-assisted development. No decorators or reflect-metadata.",
5
5
  "license": "MIT",
6
6
  "type": "module",