katagami 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +140 -584
  2. package/dist/chunk-J2NYR3SH.js +6 -0
  3. package/dist/container/index.d.cts +108 -0
  4. package/dist/container/index.d.ts +2 -2
  5. package/dist/disposable/index.cjs +16 -25
  6. package/dist/disposable/index.d.cts +69 -0
  7. package/dist/disposable/index.d.ts +13 -5
  8. package/dist/disposable/index.js +1 -1
  9. package/dist/error/index.d.cts +11 -0
  10. package/dist/index.cjs +91 -55
  11. package/dist/index.d.cts +6 -0
  12. package/dist/index.d.ts +6 -6
  13. package/dist/index.js +76 -31
  14. package/dist/internal.d.cts +29 -0
  15. package/dist/internal.d.ts +3 -1
  16. package/dist/lazy/index.cjs +16 -25
  17. package/dist/lazy/index.d.cts +33 -0
  18. package/dist/lazy/index.d.ts +3 -3
  19. package/dist/lazy/index.js +1 -1
  20. package/dist/resolver/index.d.cts +93 -0
  21. package/dist/scope/index.d.cts +120 -0
  22. package/dist/scope/index.d.ts +4 -4
  23. package/docs/README.de.md +84 -0
  24. package/docs/README.es.md +84 -0
  25. package/docs/README.fr.md +84 -0
  26. package/docs/README.ja.md +105 -0
  27. package/docs/README.ko.md +84 -0
  28. package/docs/README.zh-CN.md +84 -0
  29. package/docs/README.zh-TW.md +84 -0
  30. package/docs/ai-coding-agents.md +78 -0
  31. package/docs/articles/ai-coding-agents.ja.md +83 -0
  32. package/docs/articles/ai-coding-agents.md +70 -0
  33. package/docs/articles/request-scope.md +48 -0
  34. package/docs/articles/without-decorators.md +54 -0
  35. package/docs/choosing-di.md +143 -0
  36. package/docs/growth/baseline-2026-09-11.json +68 -0
  37. package/docs/growth/github-metadata.json +13 -0
  38. package/docs/growth/rollout.md +77 -0
  39. package/docs/guide.md +186 -0
  40. package/docs/type-safety.md +126 -0
  41. package/examples/request-scope/README.md +37 -0
  42. package/examples/request-scope/app.ts +31 -0
  43. package/examples/request-scope/demo.ts +10 -0
  44. package/examples/request-scope/tsconfig.json +11 -0
  45. package/llms.txt +16 -0
  46. package/package.json +56 -23
  47. package/dist/index-jx8b52m0.js +0 -4
@@ -0,0 +1,78 @@
1
+ # TypeScript dependency injection with AI coding agents
2
+
3
+ Use Katagami's accumulated registration types as feedback while an agent edits dependency wiring.
4
+ This guide describes the v3 API. Check the installed package version before editing an existing app.
5
+
6
+ ## A repeatable workflow
7
+
8
+ 1. Read the composition root, nearby service constructors and tests.
9
+ 2. Define dependencies explicitly in factories. Start with `createContainer()` and preserve inferred types.
10
+ 3. Register a dependency before the factory that uses it. Resolve services through `createScope(container)`.
11
+ 4. Choose a lifetime: singleton for shared infrastructure, scoped for request state, transient for a new instance per resolution.
12
+ 5. Run the application's `npx tsc --noEmit`, then its existing tests.
13
+ 6. Correct registration, lifetime or asynchronous usage based on diagnostics. Repeat until both checks pass.
14
+
15
+ When changing Katagami itself, use `bun run verify` instead; it includes type tests,
16
+ runtime tests, examples, the packed package and documentation checks.
17
+
18
+ ## Minimal working example
19
+
20
+ ```ts
21
+ import { createContainer, createScope } from 'katagami';
22
+
23
+ const container = createContainer()
24
+ .registerSingleton('users', async () => ({ findName: (id: string) => `user-${id}` }))
25
+ .registerScoped('handler', async r => {
26
+ const users = await r.resolve('users');
27
+ return (id: string) => users.findName(id);
28
+ });
29
+
30
+ const scope = createScope(container);
31
+ const handler = await scope.resolve('handler');
32
+ handler('42');
33
+ ```
34
+
35
+ Use the [request-scope starter](../examples/request-scope/README.md) for cleanup,
36
+ concurrent calls and replacement of infrastructure with a fake.
37
+
38
+ ## Diagnose the error before changing code
39
+
40
+ | Diagnostic or symptom | Check | Typical correction |
41
+ | --- | --- | --- |
42
+ | `No overload matches this call` at `resolve`, often mentioning `never` | Is this exact token registered and visible here? | Register it earlier, correct its spelling, or compose the module first |
43
+ | The same error inside a singleton/transient factory after a scoped registration | Does the factory capture request state? | Make the consumer scoped, or pass request data into a method without storing it |
44
+ | A service method does not exist on `Promise<...>` | Is the dependency factory async? | Await the resolution; make the consuming factory async if needed |
45
+ | `resolve` does not exist on `Container` | v3 separates registration from resolution | Call `createScope(container).resolve(token)` |
46
+ | `lazy` rejects a token | Is it an async or PropertyKey token? | Use direct resolution; `lazy` accepts synchronous class tokens |
47
+ | Runtime `Token ... is not registered` despite a passing type check | Predeclared map, compatible class, widened key or assertion? | Register the actual token and review the type-safety guide |
48
+
49
+ The wording of compiler diagnostics varies with TypeScript versions. Check the failing
50
+ expression and the resolver's visible registrations; do not match an error string blindly.
51
+
52
+ ## Project instruction you can copy
53
+
54
+ ```text
55
+ Use the installed Katagami v3 API for dependency wiring. Read
56
+ node_modules/katagami/docs/ai-coding-agents.md and
57
+ node_modules/katagami/docs/type-safety.md first.
58
+ Preserve inferred registration chains and narrow literal/unique-symbol tokens.
59
+ Resolve through createScope. Keep request state scoped and await async dependencies.
60
+ Use explicit factories and inject fakes in tests.
61
+ Fix type errors at their cause; do not silence them with any, assertions,
62
+ @ts-ignore, @ts-expect-error or optional resolution for required dependencies.
63
+ Run this application's type checker and tests after changes.
64
+ ```
65
+
66
+ Add this instruction to the project instructions your agent already reads, or pass it explicitly
67
+ with the task. Installing a dependency does not ensure that an agent reads its documentation.
68
+
69
+ ## Guarantees and evidence
70
+
71
+ Accumulated literal keys and unique symbols provide a finite set of registered tokens.
72
+ Class tokens follow structural compatibility; predeclared service maps can name missing factories.
73
+ See [the complete guarantee and boundary examples](./type-safety.md).
74
+
75
+ The compiler checks and example tests are automated in CI. Agent repair success and token savings
76
+ are hypotheses, not measured product claims. Use the
77
+ [controlled evaluation protocol](https://github.com/hiroiku/katagami/tree/master/benchmarks/agent-wiring)
78
+ before making quantitative comparisons.
@@ -0,0 +1,83 @@
1
+ ---
2
+ title: "AIエージェントが書く依存関係を、TypeScriptの型で検証する"
3
+ emoji: "🧩"
4
+ type: "tech"
5
+ topics: ["typescript", "ai", "di"]
6
+ published: false
7
+ ---
8
+
9
+ # AIエージェントが書く依存関係を、TypeScriptの型で検証する
10
+
11
+ AIとコードを書くときも、変更の正しさを確認する手段が必要です。依存関係の配線なら、
12
+ コードを変更し、TypeScriptを実行し、診断に沿って修正する流れを作れます。
13
+ 私が開発しているDIコンテナのKatagamiは、依存を登録するたびに型を積み上げ、
14
+ ファクトリから参照できる依存を型として表現します。
15
+
16
+ ## 登録から型を積み上げる
17
+
18
+ ```ts
19
+ import { createContainer, createScope } from 'katagami';
20
+
21
+ const container = createContainer()
22
+ .registerSingleton('users', () => ({ find: (id: string) => `user-${id}` }))
23
+ .registerScoped('handler', r => (id: string) => r.resolve('users').find(id));
24
+
25
+ createScope(container).resolve('handler')('42');
26
+ ```
27
+
28
+ この例にサービス一覧のインターフェースはありません。usersを登録すると、次のファクトリで
29
+ usersを参照できる型になります。r.resolve('user')と書き間違えたり、usersの登録を削除したり
30
+ すると、依存を使う側で型エラーが出ます。起動せずに確認できる検査です。
31
+
32
+ ## ライフタイムの誤りを検出する
33
+
34
+ リクエスト固有の状態を、すべてのリクエストで共有するSingletonが保持すると問題になります。
35
+
36
+ ```ts
37
+ import { createContainer } from 'katagami';
38
+
39
+ createContainer()
40
+ .registerScoped('requestId', () => crypto.randomUUID())
41
+ // @ts-expect-error — SingletonのファクトリにはScopedのトークンが見えない
42
+ .registerSingleton('handler', r => r.resolve('requestId'));
43
+ ```
44
+
45
+ この場合、r.resolve('requestId')でNo overload matches this callという診断が出ます。
46
+ handlerがリクエストの状態を保持するなら、registerScopedに変えるのが修正です。
47
+ 状態を保持する必要がなければ、共有サービスのメソッドへrequestIdを引数で渡す設計もできます。
48
+
49
+ @ts-expect-errorは、この記事の失敗例をCIで検証するための注記です。
50
+ 実際のアプリでは注記でエラーを隠さず、依存関係やライフタイムを直します。
51
+
52
+ ## エージェントに渡すもの
53
+
54
+ 現行APIの説明、アプリの依存登録箇所、型チェックとテストのコマンドを渡します。
55
+ エージェントには推論された型を保ち、渡されたファクトリのリゾルバを使ってもらいます。
56
+ 変更後にnpx tsc --noEmitとアプリのテストを実行し、問題があれば修正します。
57
+
58
+ [実行可能なスターター](https://github.com/hiroiku/katagami/tree/master/examples/request-scope)には、
59
+ リクエストごとの状態、テスト用のリポジトリ差し替え、成功・失敗時のリソース破棄を含めました。
60
+ AI向けの利用ガイドもnpmパッケージに同梱します。
61
+
62
+ ## 型で保証できる範囲を分ける
63
+
64
+ デフォルトの蓄積方式では、リテラルキーやunique symbolの型を保つことで、見えている登録集合に
65
+ 含まれないトークンを拒否できます。一方、createContainer<Services>()で事前宣言する方式は、
66
+ 後から登録する依存を参照できる代わりに、全キーの実際の登録までは証明しません。
67
+
68
+ クラストークンには構造的型付けも関係します。同じ構造の別クラスは型として互換でも、
69
+ 実行時には別のトークンです。この区別が必要なら、unique symbolやリテラルキー、
70
+ 個別のprivateメンバーで区別したクラスを使います。
71
+ [保証と例外](https://github.com/hiroiku/katagami/blob/master/docs/type-safety.md)をコード付きで整理しています。
72
+
73
+ 型チェックの例と実行テストは自動検証しています。ただし、AIの修正成功率やトークン消費の改善は
74
+ まだ測定していません。同じ課題・モデル・条件で失敗も含めて記録する評価手順を用意しています。
75
+
76
+ 依存が少なければ、普通の関数やコンストラクタの引数でも十分です。
77
+ 依存の構築・共有・リクエスト単位の管理が増えた場面で、選択肢として試してもらえればと思います。
78
+
79
+ ```sh
80
+ npm install katagami
81
+ ```
82
+
83
+ [KatagamiのREADME](https://github.com/hiroiku/katagami)から、基本例と利用ガイドを読めます。
@@ -0,0 +1,70 @@
1
+ # Type-safe dependency injection for AI coding agents
2
+
3
+ AI-assisted development still needs a way to check the code it produces. For dependency wiring,
4
+ a useful loop is small: edit the composition root, run TypeScript, read the diagnostics, and repair
5
+ the missing dependency or incorrect lifetime. Katagami makes some of those wiring constraints visible
6
+ to the compiler by accumulating types as dependencies are registered.
7
+
8
+ ## Let registration define the available dependencies
9
+
10
+ ```ts
11
+ import { createContainer, createScope } from 'katagami';
12
+
13
+ const container = createContainer()
14
+ .registerSingleton('users', () => ({ find: (id: string) => `user-${id}` }))
15
+ .registerScoped('handler', r => (id: string) => r.resolve('users').find(id));
16
+
17
+ createScope(container).resolve('handler')('42');
18
+ ```
19
+
20
+ There is no manually maintained service interface in this example. The first registration adds
21
+ `users` to the type known by the next factory. The second adds `handler` to the scope's visible set.
22
+ Changing `r.resolve('users')` to `r.resolve('user')` produces a type error. Removing the first
23
+ registration also produces a type error at the consumer.
24
+
25
+ The check is useful for both people and coding agents: the factory's actual dependency is written
26
+ in the same code that TypeScript checks. The compiler can report a problem without starting the app.
27
+
28
+ ## Turn a diagnostic into a repair
29
+
30
+ ```ts
31
+ import { createContainer } from 'katagami';
32
+
33
+ createContainer()
34
+ .registerScoped('requestId', () => crypto.randomUUID())
35
+ // @ts-expect-error — a singleton factory cannot access this scoped dependency
36
+ .registerSingleton('handler', r => r.resolve('requestId'));
37
+ ```
38
+
39
+ The diagnostic includes `No overload matches this call`. Inspect the failing resolution and its
40
+ lifetime: the factory requests state belonging to one request while asking to be shared as a singleton.
41
+ Register the handler as scoped, or pass the request ID into a shared service's method without storing it.
42
+
43
+ `@ts-expect-error` is only present to test this intentionally invalid example. It is not the repair.
44
+ In application code, change the wiring, run `npx tsc --noEmit`, then run behavior tests.
45
+
46
+ ## Make the workflow usable
47
+
48
+ Give the agent the [v3 usage guide](../ai-coding-agents.md), the application's composition root and
49
+ its verification command. Have it use the supplied factory resolver, preserve inferred registration
50
+ types and run the checker after changes. A [runnable request-scope starter](../../examples/request-scope/README.md)
51
+ shows fake injection, concurrent calls and cleanup on both success and failure.
52
+
53
+ Ordinary constructor or function injection is still a useful baseline. It also gets TypeScript's
54
+ parameter checks and can be enough for small applications. Introduce a container when construction,
55
+ sharing, request scope or module composition is otherwise becoming repetitive.
56
+
57
+ ## State the guarantee accurately
58
+
59
+ Accumulated literal keys and unique symbols let the checker reject tokens outside the visible
60
+ registered set. A predeclared `createContainer<Services>()` map instead permits forward references
61
+ and does not establish runtime registration completeness. Class tokens follow TypeScript's
62
+ structural typing, so another compatible class may pass the checker while being a different runtime key.
63
+ See [working examples of these boundaries](../type-safety.md).
64
+
65
+ The compiler cases in this article are tested. We have not measured agent repair success or token
66
+ savings. Those need [controlled repeated trials](https://github.com/hiroiku/katagami/tree/master/benchmarks/agent-wiring),
67
+ including failures and the same tasks, model settings and runtime tests across variants.
68
+
69
+ Install with `npm install katagami`, then start with the
70
+ [quick start](../../README.md#quick-start) or the [request-scope example](../../examples/request-scope/README.md).
@@ -0,0 +1,48 @@
1
+ # Catch request-scope mistakes at compile time in TypeScript
2
+
3
+ A service shared by all requests should not retain state from just one request. A DI container
4
+ can make that mistake easier to express if every factory can resolve every dependency. Katagami's
5
+ typed singleton and transient factories receive a resolver that excludes scoped registrations.
6
+
7
+ ## Reproduce the problem
8
+
9
+ ```ts
10
+ import { createContainer } from 'katagami';
11
+
12
+ createContainer()
13
+ .registerScoped('request', () => ({ id: crypto.randomUUID() }))
14
+ // @ts-expect-error — the request belongs to one scope, not a shared singleton
15
+ .registerSingleton('handler', r => ({ requestId: r.resolve('request').id }));
16
+ ```
17
+
18
+ The checker rejects the resolution of `request`. The fix depends on what the handler should do.
19
+ If it holds request state, give it a scoped lifetime:
20
+
21
+ ```ts
22
+ import { createContainer, createScope } from 'katagami';
23
+
24
+ const container = createContainer()
25
+ .registerScoped('request', () => ({ id: crypto.randomUUID() }))
26
+ .registerScoped('handler', r => ({ requestId: r.resolve('request').id }));
27
+
28
+ const first = createScope(container);
29
+ const second = createScope(container);
30
+ first.resolve('handler').requestId !== second.resolve('handler').requestId; // true
31
+ ```
32
+
33
+ If the service can be stateless and shared, take request data as a method parameter instead.
34
+ Do not close over another request scope to get around the factory resolver.
35
+
36
+ ## Test what types cannot establish
37
+
38
+ Type-check the wiring, then check that concurrent requests have distinct IDs, shared infrastructure
39
+ stays shared, and resources are cleaned on rejection as well as success. The
40
+ [request-scope starter](../../examples/request-scope/README.md) and its tests cover these cases.
41
+
42
+ The compile-time example uses accumulated literal keys. A broad type annotation, predeclared map,
43
+ compatible class token, assertion or captured external resolver can change what is checked.
44
+ The runtime captive-dependency guard also has limits around work resumed after an `await`.
45
+ The [type-safety guide](../type-safety.md) explains the exact scope of the guarantee.
46
+
47
+ Katagami provides Singleton, Transient and Scoped lifetimes without decorator metadata.
48
+ The [API guide](../guide.md) shows composition, async factories and optional disposal.
@@ -0,0 +1,54 @@
1
+ # TypeScript dependency injection without decorators
2
+
3
+ Dependency injection can be ordinary TypeScript: a factory receives a resolver and explicitly
4
+ constructs a service. Katagami uses this model and has no runtime package dependencies, decorator
5
+ compiler flags or reflect-metadata requirement.
6
+
7
+ ```sh
8
+ npm install katagami
9
+ ```
10
+
11
+ ## Start with a factory
12
+
13
+ ```ts
14
+ import { createContainer, createScope } from 'katagami';
15
+
16
+ class Logger {
17
+ log(message: string) { console.log(message); }
18
+ }
19
+ class Greeting {
20
+ constructor(private logger: Logger) {}
21
+ say(name: string) { this.logger.log(`Hello, ${name}!`); }
22
+ }
23
+
24
+ const container = createContainer()
25
+ .registerSingleton(Logger, () => new Logger())
26
+ .registerTransient(Greeting, r => new Greeting(r.resolve(Logger)));
27
+
28
+ createScope(container).resolve(Greeting).say('Ada');
29
+ ```
30
+
31
+ The registration chain determines which class types the next factory can resolve. Class tokens
32
+ are convenient when the classes are structurally distinguishable. Literal keys or unique symbols
33
+ are also supported; see [token identity and type guarantees](../type-safety.md).
34
+
35
+ ## Substitute infrastructure in a test
36
+
37
+ Factories can accept infrastructure as ordinary parameters. The
38
+ [request-scope starter](../../examples/request-scope/README.md) takes a `UserRepository` argument.
39
+ Its tests pass a small fake that returns a known name, then check the greeting. No global container
40
+ or decorator setup is required.
41
+
42
+ For larger compositions, group registrations in a container and copy them with `use()`.
43
+ Apply the fake module before resolving anything. `use()` replaces matching registration entries;
44
+ it is mutable composition, not automatic file loading or a snapshot API.
45
+
46
+ ## Choose only the lifecycle features you need
47
+
48
+ Core imports come from `katagami`. Add cleanup from `katagami/disposable` or synchronous class-based
49
+ lazy resolution from `katagami/lazy` when needed. Those entry points are separate so bundlers can
50
+ omit unused implementations. Cleanup uses the host's disposal symbols; it does not provide a polyfill.
51
+
52
+ For a small application, manual constructor parameters may remain the simplest choice.
53
+ The [DI decision guide](../choosing-di.md) explains when accumulated registration types and request
54
+ scopes are useful and links to other containers' own documentation.
@@ -0,0 +1,143 @@
1
+ # Choosing a TypeScript dependency injection approach
2
+
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 all eight libraries, including their
6
+ typing, setup, lifetimes, asynchronous behavior and cleanup. This guide records the evidence and
7
+ the features that need more explanation than a table cell.
8
+
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.2 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 |
117
+ | --- | --- | --- |
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()` |
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
+ Start with the [runnable starter](../examples/request-scope/README.md) and
134
+ [composition guide](./guide.md#composition-and-test-substitution). For a project already built on
135
+ NestJS or Effect, adopting its existing DI model can be simpler than maintaining a second container.
136
+
137
+ ## Updating the comparison
138
+
139
+ Preserve a comparison and Katagami's supported advantages in the README when editing positioning.
140
+ Refresh the date, npm dist-tag versions and official sources together. Check published declarations
141
+ when a claim involves inference or registration guarantees, and distinguish built-in features from
142
+ wrappers, configuration and framework behavior. Keep localized summaries aligned with the English
143
+ comparison. Do not infer a feature's absence from its omission in a quick-start guide.
@@ -0,0 +1,68 @@
1
+ {
2
+ "collectedAt": "2026-09-11T10:53:46.834Z",
3
+ "package": "katagami",
4
+ "npm": {
5
+ "week": {
6
+ "downloads": 2,
7
+ "start": "2026-09-03",
8
+ "end": "2026-09-09",
9
+ "package": "katagami"
10
+ },
11
+ "month": {
12
+ "downloads": 109,
13
+ "start": "2026-08-11",
14
+ "end": "2026-09-09",
15
+ "package": "katagami"
16
+ },
17
+ "nonOverlappingWeeks": [
18
+ {
19
+ "start": "2026-07-16",
20
+ "end": "2026-07-22",
21
+ "downloads": 2
22
+ },
23
+ {
24
+ "start": "2026-07-23",
25
+ "end": "2026-07-29",
26
+ "downloads": 15
27
+ },
28
+ {
29
+ "start": "2026-07-30",
30
+ "end": "2026-08-05",
31
+ "downloads": 8
32
+ },
33
+ {
34
+ "start": "2026-08-06",
35
+ "end": "2026-08-12",
36
+ "downloads": 57
37
+ },
38
+ {
39
+ "start": "2026-08-13",
40
+ "end": "2026-08-19",
41
+ "downloads": 48
42
+ },
43
+ {
44
+ "start": "2026-08-20",
45
+ "end": "2026-08-26",
46
+ "downloads": 15
47
+ },
48
+ {
49
+ "start": "2026-08-27",
50
+ "end": "2026-09-02",
51
+ "downloads": 14
52
+ },
53
+ {
54
+ "start": "2026-09-03",
55
+ "end": "2026-09-09",
56
+ "downloads": 2
57
+ }
58
+ ]
59
+ },
60
+ "github": {
61
+ "stars": 4,
62
+ "forks": 0,
63
+ "topics": [],
64
+ "homepage": null,
65
+ "pushedAt": "2026-02-09T11:30:14Z"
66
+ },
67
+ "errors": []
68
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "description": "Type-safe dependency injection for TypeScript, with inferred types and scope checks for AI-assisted development. No decorators or reflect-metadata.",
3
+ "homepage": "https://github.com/hiroiku/katagami#readme",
4
+ "topics": [
5
+ "typescript",
6
+ "dependency-injection",
7
+ "di-container",
8
+ "type-safety",
9
+ "type-inference",
10
+ "ai-assisted-development",
11
+ "coding-agents"
12
+ ]
13
+ }
@@ -0,0 +1,77 @@
1
+ # Katagami discovery and adoption rollout
2
+
3
+ ## Positioning and audience
4
+
5
+ Type-safe dependency injection for TypeScript, with compiler feedback for AI-assisted development.
6
+ The first audience is developers building a new TypeScript application with coding agents who need
7
+ explicit dependency wiring, fake injection or request state. Avoid forcing a container into tiny apps.
8
+
9
+ ## Release assets
10
+
11
+ - English and seven localized README entry points.
12
+ - npm description/keywords and [GitHub metadata](./github-metadata.json).
13
+ - [AI guide](../ai-coding-agents.md), [type guarantees](../type-safety.md), [API guide](../guide.md).
14
+ - [Runnable starter](../../examples/request-scope/README.md) with checked examples.
15
+ - [AI coding article](../articles/ai-coding-agents.md), [request scopes](../articles/request-scope.md),
16
+ [decorator-free DI](../articles/without-decorators.md) and a [Japanese Zenn draft](../articles/ai-coding-agents.ja.md).
17
+ - [Evaluation protocol](../../benchmarks/agent-wiring/README.md) and results summarizer; agent benefits remain unmeasured.
18
+
19
+ ## First four weeks
20
+
21
+ | Period | Action | Evidence to retain |
22
+ | --- | --- | --- |
23
+ | Week 1 | Ship checks, README, package metadata and starter; update GitHub Topics | Released version, CI run and public metrics snapshot |
24
+ | Week 2 | Publish the worked-example article on the owner's chosen blog/Zenn account; adapt relative links to the published location | URL, date, channel and campaign label |
25
+ | Weeks 3–4 | Observe 3–5 willing developers using the starter with their usual agent | Task attempted, first-run outcome, diagnostic confusion, whether they keep using it |
26
+ | Weekly | Capture npm trends and, locally, owner-only repository traffic | Non-overlapping date ranges and unavailable data recorded as null |
27
+ | After four weeks | Compare the funnel and fix the largest observed obstacle | Evidence for discovery, first successful use, continued use; no attribution from downloads alone |
28
+
29
+ Publishing destinations and interview participants are selected by the owner. The article files
30
+ are ready for adaptation, but an external publication or a participant interview must be recorded
31
+ only after it actually happens. Do not post or message people without authorization for that destination.
32
+
33
+ ## Collect metrics
34
+
35
+ ```sh
36
+ bun run metrics --output metrics.local/public.json
37
+ bun run metrics --traffic --output metrics.local/owner-traffic.json
38
+ ```
39
+
40
+ The second command requires authenticated owner access through `gh` and contains private traffic
41
+ data. `metrics.local/` is ignored by Git. Do not commit those snapshots. Public release baselines can
42
+ be recorded separately under this directory. Re-run weekly: GitHub traffic is a short rolling window.
43
+
44
+ Track npm totals across four weeks using the non-overlapping weekly buckets, then compare with
45
+ the preceding four weeks. Downloads are not unique users or installations and can include automation.
46
+ Traffic, clones and external adoption reports provide different evidence; none alone is a conversion rate.
47
+ Where the chosen publication platform supports it, use a per-channel campaign link to a page with
48
+ analytics. GitHub alone does not provide complete visit-to-install attribution.
49
+
50
+ ## Interview script
51
+
52
+ Ask a consenting participant to add a service and a fake to the starter using their normal agent.
53
+ Observe rather than coach the first attempt. Record:
54
+
55
+ 1. What made the package seem relevant, and what almost stopped installation?
56
+ 2. Did the first run work? Which command or prerequisite was unclear?
57
+ 3. Could the agent fix a missing registration and an incorrect scope without suppressions?
58
+ 4. Were error messages actionable? Which documentation did the participant or agent actually read?
59
+ 5. Would the participant use it in a real project? Follow up on continued use with their consent.
60
+
61
+ Record observations without names or private code unless the participant agrees. A suggested
62
+ invitation, for an owner-approved channel:
63
+
64
+ > TypeScriptのDIコンテナKatagamiの導入体験を改善しています。普段使っているAIエージェントで
65
+ > 小さなサンプルにサービスとテスト用の依存を追加する、20分ほどの試用に協力いただける方を探しています。
66
+ > うまく動かない点や分かりにくい点を知りたいです。公開コードだけで参加できます。
67
+
68
+ ## Search and claim hygiene
69
+
70
+ Keep the description specific to dependency injection. Link guides from the README and use actual
71
+ examples for queries about AI coding agents, request scopes and DI without decorators. `llms.txt`
72
+ is a navigation aid, not a promised ranking boost.
73
+
74
+ Sources: [npm discovery metadata](https://docs.npmjs.com/files/package.json/),
75
+ [npm README publication](https://docs.npmjs.com/about-package-readme-files/),
76
+ [GitHub Topics](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics),
77
+ [Google AI search guidance](https://developers.google.com/search/docs/appearance/ai-features).