katagami 2.3.0 → 3.0.1
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 +82 -592
- package/dist/chunk-J2NYR3SH.js +6 -0
- package/dist/container/index.d.cts +108 -0
- package/dist/container/index.d.ts +5 -82
- package/dist/disposable/index.cjs +16 -25
- package/dist/disposable/index.d.cts +69 -0
- package/dist/disposable/index.d.ts +16 -8
- package/dist/disposable/index.js +1 -1
- package/dist/error/index.d.cts +11 -0
- package/dist/index.cjs +181 -86
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +177 -45
- package/dist/internal.d.cts +29 -0
- package/dist/internal.d.ts +3 -1
- package/dist/lazy/index.cjs +16 -25
- package/dist/lazy/index.d.cts +33 -0
- package/dist/lazy/index.d.ts +7 -9
- package/dist/lazy/index.js +1 -1
- package/dist/resolver/index.d.cts +93 -0
- package/dist/scope/index.d.cts +120 -0
- package/dist/scope/index.d.ts +4 -4
- package/docs/README.de.md +65 -0
- package/docs/README.es.md +65 -0
- package/docs/README.fr.md +65 -0
- package/docs/README.ja.md +66 -0
- package/docs/README.ko.md +65 -0
- package/docs/README.zh-CN.md +65 -0
- package/docs/README.zh-TW.md +65 -0
- package/docs/ai-coding-agents.md +78 -0
- package/docs/articles/ai-coding-agents.ja.md +83 -0
- package/docs/articles/ai-coding-agents.md +70 -0
- package/docs/articles/request-scope.md +48 -0
- package/docs/articles/without-decorators.md +54 -0
- package/docs/choosing-di.md +30 -0
- package/docs/growth/baseline-2026-09-11.json +68 -0
- package/docs/growth/github-metadata.json +13 -0
- package/docs/growth/rollout.md +77 -0
- package/docs/guide.md +186 -0
- package/docs/type-safety.md +126 -0
- package/examples/request-scope/README.md +37 -0
- package/examples/request-scope/app.ts +31 -0
- package/examples/request-scope/demo.ts +10 -0
- package/examples/request-scope/tsconfig.json +11 -0
- package/llms.txt +16 -0
- package/package.json +56 -28
- package/dist/index-g50fxds1.js +0 -34
- package/dist/index-jx8b52m0.js +0 -4
- package/dist/scope/index.cjs +0 -212
- package/dist/scope/index.js +0 -153
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Registration } from './resolver/index.cjs';
|
|
2
|
+
/**
|
|
3
|
+
* Symbol used by extension modules (scope, disposable) to access container/scope internals.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare const INTERNALS: unique symbol;
|
|
8
|
+
/** Type-only registration state retained by disposable views. No runtime property is emitted. */
|
|
9
|
+
export declare const TYPE_STATE: unique symbol;
|
|
10
|
+
/**
|
|
11
|
+
* Internal state exposed via the INTERNALS symbol.
|
|
12
|
+
*
|
|
13
|
+
* Both Container and Scope implement this interface so that extension modules
|
|
14
|
+
* (scope, disposable) can operate on either without importing the concrete class.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export interface ContainerInternals {
|
|
19
|
+
/** All registrations (singleton / transient / scoped). Each token maps to an array of registrations. */
|
|
20
|
+
readonly registrations: Map<unknown, Registration[]>;
|
|
21
|
+
/** Singleton cache keyed by Registration object (Container: singletons, Scope: shared with parent). */
|
|
22
|
+
readonly singletonCache: Map<Registration, unknown>;
|
|
23
|
+
/** Instances owned by this container / scope (disposal target), keyed by Registration object. */
|
|
24
|
+
readonly ownCache: Map<Registration, unknown>;
|
|
25
|
+
/** Whether this container / scope has been disposed. */
|
|
26
|
+
isDisposed(): boolean;
|
|
27
|
+
/** Mark this container / scope as disposed. */
|
|
28
|
+
markDisposed(): void;
|
|
29
|
+
}
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { Registration } from './resolver';
|
|
1
|
+
import type { Registration } from './resolver/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Symbol used by extension modules (scope, disposable) to access container/scope internals.
|
|
4
4
|
*
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
7
|
export declare const INTERNALS: unique symbol;
|
|
8
|
+
/** Type-only registration state retained by disposable views. No runtime property is emitted. */
|
|
9
|
+
export declare const TYPE_STATE: unique symbol;
|
|
8
10
|
/**
|
|
9
11
|
* Internal state exposed via the INTERNALS symbol.
|
|
10
12
|
*
|
package/dist/lazy/index.cjs
CHANGED
|
@@ -1,37 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
-
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
8
|
-
if (entry)
|
|
9
|
-
return entry;
|
|
10
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
-
get: () => from[key],
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
}));
|
|
16
|
-
__moduleCache.set(from, entry);
|
|
17
|
-
return entry;
|
|
18
|
-
};
|
|
19
6
|
var __export = (target, all) => {
|
|
20
7
|
for (var name in all)
|
|
21
|
-
__defProp(target, name, {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
27
17
|
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
19
|
|
|
29
20
|
// src/lazy/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
21
|
+
var lazy_exports = {};
|
|
22
|
+
__export(lazy_exports, {
|
|
32
23
|
lazy: () => lazy
|
|
33
24
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(lazy_exports);
|
|
35
26
|
function lazy(source, token) {
|
|
36
27
|
let instance;
|
|
37
28
|
let resolved = false;
|
|
@@ -42,7 +33,7 @@ function lazy(source, token) {
|
|
|
42
33
|
}
|
|
43
34
|
return instance;
|
|
44
35
|
};
|
|
45
|
-
const proxyTarget = Object.create(null);
|
|
36
|
+
const proxyTarget = /* @__PURE__ */ Object.create(null);
|
|
46
37
|
return new Proxy(proxyTarget, {
|
|
47
38
|
defineProperty(_, prop, desc) {
|
|
48
39
|
return Reflect.defineProperty(ensureResolved(), prop, desc);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DisposableScope } from '../disposable/index.cjs';
|
|
2
|
+
import type { AbstractConstructor } from '../resolver/index.cjs';
|
|
3
|
+
import type { Scope } from '../scope/index.cjs';
|
|
4
|
+
/**
|
|
5
|
+
* Create a lazy proxy that defers resolution until the first property access.
|
|
6
|
+
*
|
|
7
|
+
* The returned object looks and behaves like `V`, but the underlying instance
|
|
8
|
+
* is not created until a property is read, written, or otherwise accessed.
|
|
9
|
+
* Once resolved the instance is cached — subsequent accesses hit the cache.
|
|
10
|
+
*
|
|
11
|
+
* Only **sync class tokens** are supported. Async tokens and PropertyKey tokens
|
|
12
|
+
* are rejected at the type level.
|
|
13
|
+
*
|
|
14
|
+
* @param source A Scope or DisposableScope
|
|
15
|
+
* @param token A sync class constructor token
|
|
16
|
+
* @returns A proxy that transparently forwards to the lazily-resolved instance
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { createContainer, createScope } from 'katagami';
|
|
21
|
+
* import { lazy } from 'katagami/lazy';
|
|
22
|
+
*
|
|
23
|
+
* const container = createContainer()
|
|
24
|
+
* .registerSingleton(HeavyService, () => new HeavyService());
|
|
25
|
+
*
|
|
26
|
+
* const scope = createScope(container);
|
|
27
|
+
* const service = lazy(scope, HeavyService);
|
|
28
|
+
* // Instance is NOT created yet
|
|
29
|
+
* service.doSomething(); // resolved here, then cached
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
|
33
|
+
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
package/dist/lazy/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { Scope } from '../scope';
|
|
1
|
+
import type { DisposableScope } from '../disposable/index.js';
|
|
2
|
+
import type { AbstractConstructor } from '../resolver/index.js';
|
|
3
|
+
import type { Scope } from '../scope/index.js';
|
|
5
4
|
/**
|
|
6
5
|
* Create a lazy proxy that defers resolution until the first property access.
|
|
7
6
|
*
|
|
@@ -12,24 +11,23 @@ import type { Scope } from '../scope';
|
|
|
12
11
|
* Only **sync class tokens** are supported. Async tokens and PropertyKey tokens
|
|
13
12
|
* are rejected at the type level.
|
|
14
13
|
*
|
|
15
|
-
* @param source A
|
|
14
|
+
* @param source A Scope or DisposableScope
|
|
16
15
|
* @param token A sync class constructor token
|
|
17
16
|
* @returns A proxy that transparently forwards to the lazily-resolved instance
|
|
18
17
|
*
|
|
19
18
|
* @example
|
|
20
19
|
* ```ts
|
|
21
|
-
* import { createContainer } from 'katagami';
|
|
20
|
+
* import { createContainer, createScope } from 'katagami';
|
|
22
21
|
* import { lazy } from 'katagami/lazy';
|
|
23
22
|
*
|
|
24
23
|
* const container = createContainer()
|
|
25
24
|
* .registerSingleton(HeavyService, () => new HeavyService());
|
|
26
25
|
*
|
|
27
|
-
* const
|
|
26
|
+
* const scope = createScope(container);
|
|
27
|
+
* const service = lazy(scope, HeavyService);
|
|
28
28
|
* // Instance is NOT created yet
|
|
29
29
|
* service.doSomething(); // resolved here, then cached
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: Container<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & Sync): V;
|
|
33
32
|
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
|
34
|
-
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: DisposableContainer<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & Sync): V;
|
|
35
33
|
export declare function lazy<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, V>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>, token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
package/dist/lazy/index.js
CHANGED
|
@@ -9,7 +9,7 @@ function lazy(source, token) {
|
|
|
9
9
|
}
|
|
10
10
|
return instance;
|
|
11
11
|
};
|
|
12
|
-
const proxyTarget = Object.create(null);
|
|
12
|
+
const proxyTarget = /* @__PURE__ */ Object.create(null);
|
|
13
13
|
return new Proxy(proxyTarget, {
|
|
14
14
|
defineProperty(_, prop, desc) {
|
|
15
15
|
return Reflect.defineProperty(ensureResolved(), prop, desc);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export type AbstractConstructor<T = unknown> = abstract new (...args: never[]) => T;
|
|
2
|
+
/**
|
|
3
|
+
* Resolver passed to factory callbacks.
|
|
4
|
+
*
|
|
5
|
+
* @template T PropertyKey-based type map (defined via interface, order-independent)
|
|
6
|
+
* @template Sync Union of registered sync class constructors (order-dependent)
|
|
7
|
+
* @template Async Union of registered async class constructors (order-dependent)
|
|
8
|
+
*/
|
|
9
|
+
export interface Resolver<T, Sync extends AbstractConstructor = AbstractConstructor, Async extends AbstractConstructor = never> {
|
|
10
|
+
/**
|
|
11
|
+
* Resolve an instance for the given token.
|
|
12
|
+
*
|
|
13
|
+
* @param token A registered token
|
|
14
|
+
* @returns The instance associated with the token
|
|
15
|
+
*/
|
|
16
|
+
resolve<V>(token: AbstractConstructor<V> & Async): Promise<V>;
|
|
17
|
+
resolve<V>(token: AbstractConstructor<V> & Sync): V;
|
|
18
|
+
resolve<K extends keyof T>(token: K): T[K];
|
|
19
|
+
/**
|
|
20
|
+
* Try to resolve an instance for the given token.
|
|
21
|
+
*
|
|
22
|
+
* Returns `undefined` instead of throwing when the token is not registered.
|
|
23
|
+
* Other errors (circular dependency, disposed container) are still thrown.
|
|
24
|
+
*
|
|
25
|
+
* @param token A token to resolve
|
|
26
|
+
* @returns The instance associated with the token, or `undefined` if not registered
|
|
27
|
+
*/
|
|
28
|
+
tryResolve<V>(token: AbstractConstructor<V> & Async): Promise<V> | undefined;
|
|
29
|
+
tryResolve<V>(token: AbstractConstructor<V> & Sync): V | undefined;
|
|
30
|
+
tryResolve<K extends keyof T>(token: K): T[K] | undefined;
|
|
31
|
+
tryResolve<V>(token: AbstractConstructor<V>): V | Promise<V> | undefined;
|
|
32
|
+
tryResolve(token: PropertyKey): unknown;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve all instances for the given token.
|
|
35
|
+
*
|
|
36
|
+
* Returns an array of instances from all registrations for the token.
|
|
37
|
+
*
|
|
38
|
+
* @param token A registered token
|
|
39
|
+
* @returns An array of instances associated with the token
|
|
40
|
+
*/
|
|
41
|
+
resolveAll<V>(token: AbstractConstructor<V> & Async): Promise<V>[];
|
|
42
|
+
resolveAll<V>(token: AbstractConstructor<V> & Sync): V[];
|
|
43
|
+
resolveAll<K extends keyof T>(token: K): T[K][];
|
|
44
|
+
/**
|
|
45
|
+
* Try to resolve all instances for the given token.
|
|
46
|
+
*
|
|
47
|
+
* Returns `undefined` instead of throwing when the token is not registered.
|
|
48
|
+
* Other errors (circular dependency, disposed container) are still thrown.
|
|
49
|
+
*
|
|
50
|
+
* @param token A token to resolve
|
|
51
|
+
* @returns An array of instances associated with the token, or `undefined` if not registered
|
|
52
|
+
*/
|
|
53
|
+
tryResolveAll<V>(token: AbstractConstructor<V> & Async): Promise<V>[] | undefined;
|
|
54
|
+
tryResolveAll<V>(token: AbstractConstructor<V> & Sync): V[] | undefined;
|
|
55
|
+
tryResolveAll<K extends keyof T>(token: K): T[K][] | undefined;
|
|
56
|
+
tryResolveAll<V>(token: AbstractConstructor<V>): (V | Promise<V>)[] | undefined;
|
|
57
|
+
tryResolveAll(token: PropertyKey): unknown;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Lifetime of a registration.
|
|
61
|
+
*/
|
|
62
|
+
export type Lifetime = 'singleton' | 'transient' | 'scoped';
|
|
63
|
+
/**
|
|
64
|
+
* Factory registration entry.
|
|
65
|
+
*/
|
|
66
|
+
export interface Registration {
|
|
67
|
+
/**
|
|
68
|
+
* Factory function.
|
|
69
|
+
*
|
|
70
|
+
* @param resolver Resolver
|
|
71
|
+
* @returns Instance
|
|
72
|
+
*/
|
|
73
|
+
readonly factory: (resolver: Resolver<never, never>) => unknown;
|
|
74
|
+
/**
|
|
75
|
+
* Lifetime of the registration.
|
|
76
|
+
*/
|
|
77
|
+
readonly lifetime: Lifetime;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert a token to a human-readable string.
|
|
81
|
+
*/
|
|
82
|
+
export declare function tokenToString(token: unknown): string;
|
|
83
|
+
/**
|
|
84
|
+
* Build a human-readable circular dependency path from the resolving tokens.
|
|
85
|
+
*
|
|
86
|
+
* Uses the insertion order of Set to extract only the cycle portion.
|
|
87
|
+
* e.g. if resolvingTokens is [X, A, B, C] and token is A, returns "A -> B -> C -> A"
|
|
88
|
+
*
|
|
89
|
+
* @param resolvingTokens The set of tokens currently being resolved
|
|
90
|
+
* @param token The token that caused the circular dependency
|
|
91
|
+
* @returns Formatted cycle path string
|
|
92
|
+
*/
|
|
93
|
+
export declare function buildCircularPath(resolvingTokens: Set<unknown>, token: unknown): string;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Container } from '../container/index.cjs';
|
|
2
|
+
import type { DisposableContainer, DisposableScope } from '../disposable/index.cjs';
|
|
3
|
+
import { type ContainerInternals, INTERNALS } from '../internal.cjs';
|
|
4
|
+
import type { AbstractConstructor, Registration } from '../resolver/index.cjs';
|
|
5
|
+
/**
|
|
6
|
+
* Create a new scope (child container) from a Container, Scope, or their disposable variants.
|
|
7
|
+
*
|
|
8
|
+
* The scope inherits all registrations from the source.
|
|
9
|
+
* Singleton instances are shared with the parent, while scoped instances are local to the scope.
|
|
10
|
+
*
|
|
11
|
+
* @param source A Container, Scope, DisposableContainer, or DisposableScope to create a child scope from
|
|
12
|
+
* @returns A new Scope instance
|
|
13
|
+
* @throws ContainerError if the source has been disposed
|
|
14
|
+
*/
|
|
15
|
+
export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor>(source: Container<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>;
|
|
16
|
+
export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>;
|
|
17
|
+
export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor>(source: DisposableContainer<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>;
|
|
18
|
+
export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync>;
|
|
19
|
+
/**
|
|
20
|
+
* Scoped child container.
|
|
21
|
+
*
|
|
22
|
+
* Inherits all registrations from the parent container.
|
|
23
|
+
* Singleton instances are shared with the parent, while scoped instances are local to this scope.
|
|
24
|
+
* Transient instances are always newly created.
|
|
25
|
+
*
|
|
26
|
+
* @template T PropertyKey-based token type map
|
|
27
|
+
* @template Sync Union of registered sync class constructors
|
|
28
|
+
* @template Async Union of registered async class constructors
|
|
29
|
+
* @template ScopedT PropertyKey-based token type map for scoped registrations
|
|
30
|
+
* @template ScopedSync Union of scoped sync class constructors
|
|
31
|
+
* @template ScopedAsync Union of scoped async class constructors
|
|
32
|
+
*/
|
|
33
|
+
export declare class Scope<T = Record<never, never>, Sync extends AbstractConstructor = never, Async extends AbstractConstructor = never, ScopedT = Record<never, never>, ScopedSync extends AbstractConstructor = never, ScopedAsync extends AbstractConstructor = never> {
|
|
34
|
+
private readonly registrations;
|
|
35
|
+
private readonly singletonCache;
|
|
36
|
+
private readonly scopedCache;
|
|
37
|
+
private readonly resolvingTokens;
|
|
38
|
+
private singletonDepth;
|
|
39
|
+
private disposed;
|
|
40
|
+
/**
|
|
41
|
+
* Internal state accessor for extension modules (scope, disposable).
|
|
42
|
+
*
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
readonly [INTERNALS]: ContainerInternals;
|
|
46
|
+
constructor(registrations: Map<unknown, Registration[]>, singletonCache: Map<Registration, unknown>);
|
|
47
|
+
/**
|
|
48
|
+
* Resolve an instance for the given token.
|
|
49
|
+
*
|
|
50
|
+
* - Singleton: Returns the shared instance from the parent container (creates and caches on first access).
|
|
51
|
+
* - Scoped: Returns an instance local to this scope (creates and caches on first access within the scope).
|
|
52
|
+
* - Transient: Creates a new instance on every call.
|
|
53
|
+
*
|
|
54
|
+
* @param token A registered token
|
|
55
|
+
* @returns The instance associated with the token
|
|
56
|
+
* @throws ContainerError if the token is not registered
|
|
57
|
+
*/
|
|
58
|
+
resolve<V>(token: AbstractConstructor<V> & (Async | ScopedAsync)): Promise<V>;
|
|
59
|
+
resolve<V>(token: AbstractConstructor<V> & (Sync | ScopedSync)): V;
|
|
60
|
+
resolve<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K];
|
|
61
|
+
/**
|
|
62
|
+
* Try to resolve an instance for the given token.
|
|
63
|
+
*
|
|
64
|
+
* Returns `undefined` instead of throwing when the token is not registered.
|
|
65
|
+
* Other errors (circular dependency, disposed scope) are still thrown.
|
|
66
|
+
*
|
|
67
|
+
* @param token A token to resolve
|
|
68
|
+
* @returns The instance associated with the token, or `undefined` if not registered
|
|
69
|
+
*/
|
|
70
|
+
tryResolve<V>(token: AbstractConstructor<V> & (Async | ScopedAsync)): Promise<V> | undefined;
|
|
71
|
+
tryResolve<V>(token: AbstractConstructor<V> & (Sync | ScopedSync)): V | undefined;
|
|
72
|
+
tryResolve<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K] | undefined;
|
|
73
|
+
tryResolve<V>(token: AbstractConstructor<V>): V | Promise<V> | undefined;
|
|
74
|
+
tryResolve(token: PropertyKey): unknown;
|
|
75
|
+
/**
|
|
76
|
+
* Resolve all instances for the given token.
|
|
77
|
+
*
|
|
78
|
+
* Returns an array of instances from all registered factories for the token,
|
|
79
|
+
* in registration order.
|
|
80
|
+
*
|
|
81
|
+
* @param token A registered token
|
|
82
|
+
* @returns An array of instances associated with the token
|
|
83
|
+
* @throws ContainerError if the token is not registered
|
|
84
|
+
*/
|
|
85
|
+
resolveAll<V>(token: AbstractConstructor<V> & (Async | ScopedAsync)): Promise<V>[];
|
|
86
|
+
resolveAll<V>(token: AbstractConstructor<V> & (Sync | ScopedSync)): V[];
|
|
87
|
+
resolveAll<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K][];
|
|
88
|
+
/**
|
|
89
|
+
* Try to resolve all instances for the given token.
|
|
90
|
+
*
|
|
91
|
+
* Returns `undefined` instead of throwing when the token is not registered.
|
|
92
|
+
* Other errors (circular dependency, disposed scope) are still thrown.
|
|
93
|
+
*
|
|
94
|
+
* @param token A token to resolve
|
|
95
|
+
* @returns An array of instances associated with the token, or `undefined` if not registered
|
|
96
|
+
*/
|
|
97
|
+
tryResolveAll<V>(token: AbstractConstructor<V> & (Async | ScopedAsync)): Promise<V>[] | undefined;
|
|
98
|
+
tryResolveAll<V>(token: AbstractConstructor<V> & (Sync | ScopedSync)): V[] | undefined;
|
|
99
|
+
tryResolveAll<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K][] | undefined;
|
|
100
|
+
tryResolveAll<V>(token: AbstractConstructor<V>): (V | Promise<V>)[] | undefined;
|
|
101
|
+
tryResolveAll(token: PropertyKey): unknown;
|
|
102
|
+
/**
|
|
103
|
+
* Internal resolution logic shared by resolve and tryResolve.
|
|
104
|
+
* Resolves the last registered factory for the token.
|
|
105
|
+
*
|
|
106
|
+
* @param token Token to resolve
|
|
107
|
+
* @param required If true, throws when the token is not registered. If false, returns undefined.
|
|
108
|
+
* @returns The resolved instance, or undefined if not registered and required is false
|
|
109
|
+
*/
|
|
110
|
+
private resolveToken;
|
|
111
|
+
/**
|
|
112
|
+
* Internal resolution logic shared by resolveAll and tryResolveAll.
|
|
113
|
+
* Resolves all registered factories for the token.
|
|
114
|
+
*
|
|
115
|
+
* @param token Token to resolve
|
|
116
|
+
* @param required If true, throws when the token is not registered. If false, returns undefined.
|
|
117
|
+
* @returns An array of resolved instances, or undefined if not registered and required is false
|
|
118
|
+
*/
|
|
119
|
+
private resolveAllTokens;
|
|
120
|
+
}
|
package/dist/scope/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Container } from '../container';
|
|
2
|
-
import type { DisposableContainer, DisposableScope } from '../disposable';
|
|
3
|
-
import { type ContainerInternals, INTERNALS } from '../internal';
|
|
4
|
-
import type { AbstractConstructor, Registration } from '../resolver';
|
|
1
|
+
import type { Container } from '../container/index.js';
|
|
2
|
+
import type { DisposableContainer, DisposableScope } from '../disposable/index.js';
|
|
3
|
+
import { type ContainerInternals, INTERNALS } from '../internal.js';
|
|
4
|
+
import type { AbstractConstructor, Registration } from '../resolver/index.js';
|
|
5
5
|
/**
|
|
6
6
|
* Create a new scope (child container) from a Container, Scope, or their disposable variants.
|
|
7
7
|
*
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[English](../README.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [繁體中文](./README.zh-TW.md) | [简体中文](./README.zh-CN.md) | [Español](./README.es.md) | [Deutsch](./README.de.md) | [Français](./README.fr.md)
|
|
2
|
+
|
|
3
|
+
# Katagami
|
|
4
|
+
|
|
5
|
+
**Typsichere Dependency Injection für TypeScript.**
|
|
6
|
+
|
|
7
|
+
Mache Abhängigkeiten explizit und prüfbar, auch wenn KI-Coding-Agenten den Code schreiben. Katagami sammelt Typen mit jeder Registrierung, prüft die in einer Factory verfügbaren Tokens und verfolgt asynchrone Rückgaben. Ohne Decorators, reflect-metadata oder Laufzeitabhängigkeiten.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/katagami)
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install katagami
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Schnellstart
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createContainer, createScope } from 'katagami';
|
|
19
|
+
|
|
20
|
+
const container = createContainer()
|
|
21
|
+
.registerSingleton('name', () => 'Ada')
|
|
22
|
+
.registerScoped('greeting', r => `Hello, ${r.resolve('name')}!`);
|
|
23
|
+
|
|
24
|
+
const greeting: string = createScope(container).resolve('greeting');
|
|
25
|
+
console.log(greeting);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Mit KI-Coding-Agenten arbeiten
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
Wenn eine Singleton-Factory auf Scoped-Zustand einer Anfrage zugreift, entsteht beispielsweise ein Typfehler.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createContainer } from 'katagami';
|
|
36
|
+
|
|
37
|
+
createContainer()
|
|
38
|
+
.registerScoped('request', () => ({ id: crypto.randomUUID() }))
|
|
39
|
+
// @ts-expect-error — singleton factories cannot access scoped tokens
|
|
40
|
+
.registerSingleton('handler', r => r.resolve('request'));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Registriere handler in diesem Beispiel mit registerScoped. @ts-expect-error prüft das fehlerhafte Beispiel in CI. Korrigiere im Anwendungscode die Lebensdauer und führe npx tsc --noEmit aus, statt den Fehler zu unterdrücken.
|
|
44
|
+
|
|
45
|
+
## Gesammelte Typen und Garantien
|
|
46
|
+
|
|
47
|
+
createContainer() sammelt Typen aus Registrierungen. Solange Literalschlüssel und unique-symbol-Typen erhalten bleiben, werden Tokens außerhalb der sichtbaren Registrierungen abgelehnt. Eine manuelle Service-Typzuordnung ist nicht nötig.
|
|
48
|
+
|
|
49
|
+
Klassentokens folgen struktureller Typisierung: Eine andere kompatible Klasse kann akzeptiert werden. Ein in createContainer<Services>() deklarierter Schlüssel ist ebenfalls im Typ sichtbar, auch ohne tatsächliche Registrierung.
|
|
50
|
+
|
|
51
|
+
Unterstützt Singleton, Transient und Scoped, Modulkomposition mit use(), asynchrone Factories, optionale und mehrfache Auflösung, Ressourcenfreigabe und verzögerte Auflösung. Bei wenigen Abhängigkeiten reichen oft normale Parameter.
|
|
52
|
+
|
|
53
|
+
## Anleitungen und ausführbares Beispiel
|
|
54
|
+
|
|
55
|
+
- [Anleitung für KI-Agenten (Englisch)](./ai-coding-agents.md)
|
|
56
|
+
- [Typgarantien (Englisch)](./type-safety.md)
|
|
57
|
+
- [API und Anwendung (Englisch)](./guide.md)
|
|
58
|
+
- [Starter für Anfrage-Scopes (Englisch)](../examples/request-scope/README.md)
|
|
59
|
+
- [DI auswählen (Englisch)](./choosing-di.md)
|
|
60
|
+
|
|
61
|
+
CI prüft Typbeispiele und Laufzeittests. Verbesserungen der Reparaturquote von Agenten oder Token-Einsparungen wurden noch nicht gemessen.
|
|
62
|
+
|
|
63
|
+
Der Name stammt von 型紙, den Papierschablonen der traditionellen japanischen Färberei. Typen sammeln sich wie übereinandergelegte Schablonen.
|
|
64
|
+
|
|
65
|
+
MIT
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[English](../README.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [繁體中文](./README.zh-TW.md) | [简体中文](./README.zh-CN.md) | [Español](./README.es.md) | [Deutsch](./README.de.md) | [Français](./README.fr.md)
|
|
2
|
+
|
|
3
|
+
# Katagami
|
|
4
|
+
|
|
5
|
+
**Inyección de dependencias con seguridad de tipos para TypeScript.**
|
|
6
|
+
|
|
7
|
+
Haz explícitas y verificables las dependencias, incluso cuando el código lo escriben agentes de IA. Katagami acumula tipos con cada registro, comprueba los tokens accesibles en cada fábrica y conserva los resultados asíncronos. Sin decoradores, reflect-metadata ni dependencias en tiempo de ejecución.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/katagami)
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install katagami
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Inicio rápido
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createContainer, createScope } from 'katagami';
|
|
19
|
+
|
|
20
|
+
const container = createContainer()
|
|
21
|
+
.registerSingleton('name', () => 'Ada')
|
|
22
|
+
.registerScoped('greeting', r => `Hello, ${r.resolve('name')}!`);
|
|
23
|
+
|
|
24
|
+
const greeting: string = createScope(container).resolve('greeting');
|
|
25
|
+
console.log(greeting);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Uso con agentes de programación de IA
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
Por ejemplo, acceder a un estado Scoped desde una fábrica Singleton produce un error de tipos.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createContainer } from 'katagami';
|
|
36
|
+
|
|
37
|
+
createContainer()
|
|
38
|
+
.registerScoped('request', () => ({ id: crypto.randomUUID() }))
|
|
39
|
+
// @ts-expect-error — singleton factories cannot access scoped tokens
|
|
40
|
+
.registerSingleton('handler', r => r.resolve('request'));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
En este ejemplo, registra handler con registerScoped. @ts-expect-error verifica el ejemplo incorrecto en CI; en la aplicación, corrige el ciclo de vida y ejecuta npx tsc --noEmit sin suprimir el error.
|
|
44
|
+
|
|
45
|
+
## Tipos acumulados y garantías
|
|
46
|
+
|
|
47
|
+
createContainer() acumula los tipos de los registros. Si se conservan las claves literales y los tipos unique symbol, se rechazan los tokens fuera del conjunto visible de registros. No hace falta un mapa manual de servicios.
|
|
48
|
+
|
|
49
|
+
Los tokens de clase siguen el tipado estructural: otra clase compatible puede ser aceptada. Una clave declarada en createContainer<Services>() también puede estar disponible en los tipos sin tener un registro real.
|
|
50
|
+
|
|
51
|
+
Incluye ciclos de vida Singleton, Transient y Scoped, composición con use(), fábricas asíncronas, resolución opcional y múltiple, limpieza de recursos y resolución diferida. Para pocas dependencias, los parámetros normales pueden ser suficientes.
|
|
52
|
+
|
|
53
|
+
## Guías y ejemplo ejecutable
|
|
54
|
+
|
|
55
|
+
- [Guía para agentes de IA (inglés)](./ai-coding-agents.md)
|
|
56
|
+
- [Garantías de tipos (inglés)](./type-safety.md)
|
|
57
|
+
- [Guía de uso y API (inglés)](./guide.md)
|
|
58
|
+
- [Ejemplo de ámbitos por petición (inglés)](../examples/request-scope/README.md)
|
|
59
|
+
- [Cómo elegir DI (inglés)](./choosing-di.md)
|
|
60
|
+
|
|
61
|
+
CI comprueba los ejemplos de tipos y las pruebas de ejecución. No se han medido mejoras en la tasa de reparación de agentes ni ahorro de tokens.
|
|
62
|
+
|
|
63
|
+
El nombre viene de 型紙, las plantillas de papel de la tintura tradicional japonesa. Los tipos se acumulan como capas de plantillas.
|
|
64
|
+
|
|
65
|
+
MIT
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[English](../README.md) | [日本語](./README.ja.md) | [한국어](./README.ko.md) | [繁體中文](./README.zh-TW.md) | [简体中文](./README.zh-CN.md) | [Español](./README.es.md) | [Deutsch](./README.de.md) | [Français](./README.fr.md)
|
|
2
|
+
|
|
3
|
+
# Katagami
|
|
4
|
+
|
|
5
|
+
**Injection de dépendances avec sûreté des types pour TypeScript.**
|
|
6
|
+
|
|
7
|
+
Rendez les dépendances explicites et vérifiables, même quand des agents de programmation IA écrivent le code. Katagami accumule les types à chaque enregistrement, vérifie les jetons accessibles aux fabriques et suit les retours asynchrones. Sans décorateurs, reflect-metadata ni dépendances à l’exécution.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/katagami)
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install katagami
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Démarrage rapide
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createContainer, createScope } from 'katagami';
|
|
19
|
+
|
|
20
|
+
const container = createContainer()
|
|
21
|
+
.registerSingleton('name', () => 'Ada')
|
|
22
|
+
.registerScoped('greeting', r => `Hello, ${r.resolve('name')}!`);
|
|
23
|
+
|
|
24
|
+
const greeting: string = createScope(container).resolve('greeting');
|
|
25
|
+
console.log(greeting);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Travailler avec des agents de programmation IA
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
Par exemple, accéder à un état Scoped depuis une fabrique Singleton produit une erreur de type.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createContainer } from 'katagami';
|
|
36
|
+
|
|
37
|
+
createContainer()
|
|
38
|
+
.registerScoped('request', () => ({ id: crypto.randomUUID() }))
|
|
39
|
+
// @ts-expect-error — singleton factories cannot access scoped tokens
|
|
40
|
+
.registerSingleton('handler', r => r.resolve('request'));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Dans cet exemple, enregistrez handler avec registerScoped. @ts-expect-error sert à vérifier l’exemple incorrect en CI. Dans l’application, corrigez la durée de vie et lancez npx tsc --noEmit sans masquer l’erreur.
|
|
44
|
+
|
|
45
|
+
## Types accumulés et garanties
|
|
46
|
+
|
|
47
|
+
createContainer() accumule les types des enregistrements. En conservant les clés littérales et les types unique symbol, les jetons absents de l’ensemble visible sont rejetés. Aucune table manuelle des types de services n’est nécessaire.
|
|
48
|
+
|
|
49
|
+
Les jetons de classe suivent le typage structurel : une autre classe compatible peut être acceptée. Une clé déclarée dans createContainer<Services>() peut aussi être visible dans les types sans enregistrement réel.
|
|
50
|
+
|
|
51
|
+
Prend en charge Singleton, Transient et Scoped, la composition avec use(), les fabriques asynchrones, la résolution optionnelle et multiple, la libération des ressources et la résolution différée. Pour peu de dépendances, des paramètres ordinaires peuvent suffire.
|
|
52
|
+
|
|
53
|
+
## Guides et exemple exécutable
|
|
54
|
+
|
|
55
|
+
- [Guide pour agents IA (anglais)](./ai-coding-agents.md)
|
|
56
|
+
- [Garanties de types (anglais)](./type-safety.md)
|
|
57
|
+
- [Guide et API (anglais)](./guide.md)
|
|
58
|
+
- [Exemple de portée par requête (anglais)](../examples/request-scope/README.md)
|
|
59
|
+
- [Choisir une approche DI (anglais)](./choosing-di.md)
|
|
60
|
+
|
|
61
|
+
Les exemples de types et les tests d’exécution sont vérifiés en CI. Les gains de réussite des agents ou de consommation de tokens n’ont pas encore été mesurés.
|
|
62
|
+
|
|
63
|
+
Le nom vient de 型紙, les pochoirs de papier de la teinture traditionnelle japonaise. Les types s’accumulent comme des couches de pochoirs.
|
|
64
|
+
|
|
65
|
+
MIT
|