katagami 3.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +84 -37
  2. package/dist/chunk-R66WOZUM.js +71 -0
  3. package/dist/container/index.d.cts +142 -35
  4. package/dist/container/index.d.ts +142 -35
  5. package/dist/container/policy.d.cts +36 -0
  6. package/dist/container/policy.d.ts +36 -0
  7. package/dist/disposable/index.cjs +27 -5
  8. package/dist/disposable/index.d.cts +17 -7
  9. package/dist/disposable/index.d.ts +17 -7
  10. package/dist/disposable/index.js +2 -41
  11. package/dist/entrypoint/index.d.cts +20 -0
  12. package/dist/entrypoint/index.d.ts +20 -0
  13. package/dist/index.cjs +551 -149
  14. package/dist/index.d.cts +8 -0
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.js +495 -150
  17. package/dist/internal.d.cts +65 -0
  18. package/dist/internal.d.ts +65 -0
  19. package/dist/metadata/index.d.cts +67 -0
  20. package/dist/metadata/index.d.ts +67 -0
  21. package/dist/resolver/index.d.cts +5 -0
  22. package/dist/resolver/index.d.ts +5 -0
  23. package/dist/scope/index.d.cts +49 -24
  24. package/dist/scope/index.d.ts +49 -24
  25. package/dist/scope/operations.d.cts +22 -0
  26. package/dist/scope/operations.d.ts +22 -0
  27. package/docs/README.de.md +3 -2
  28. package/docs/README.es.md +3 -2
  29. package/docs/README.fr.md +3 -2
  30. package/docs/README.ja.md +61 -27
  31. package/docs/README.ko.md +3 -2
  32. package/docs/README.zh-CN.md +3 -2
  33. package/docs/README.zh-TW.md +3 -2
  34. package/docs/ai-coding-agents.md +3 -3
  35. package/docs/articles/ai-coding-agents.md +1 -1
  36. package/docs/articles/request-scope.md +2 -1
  37. package/docs/choosing-di.md +36 -9
  38. package/docs/guide.md +35 -4
  39. package/docs/registration-policies.ja.md +261 -0
  40. package/docs/registration-policies.md +435 -0
  41. package/docs/type-safety.md +13 -4
  42. package/llms.txt +1 -0
  43. package/package.json +1 -1
  44. package/dist/chunk-J2NYR3SH.js +0 -6
@@ -1,4 +1,6 @@
1
+ import type { PolicyState } from './container/policy.cjs';
1
2
  import type { Registration } from './resolver/index.cjs';
3
+ import type { BeforeResolve } from './scope/index.cjs';
2
4
  /**
3
5
  * Symbol used by extension modules (scope, disposable) to access container/scope internals.
4
6
  *
@@ -7,6 +9,7 @@ import type { Registration } from './resolver/index.cjs';
7
9
  export declare const INTERNALS: unique symbol;
8
10
  /** Type-only registration state retained by disposable views. No runtime property is emitted. */
9
11
  export declare const TYPE_STATE: unique symbol;
12
+ export declare const REGISTRATION_STATE: unique symbol;
10
13
  /**
11
14
  * Internal state exposed via the INTERNALS symbol.
12
15
  *
@@ -16,6 +19,9 @@ export declare const TYPE_STATE: unique symbol;
16
19
  * @internal
17
20
  */
18
21
  export interface ContainerInternals {
22
+ readonly kind: 'container' | 'scope';
23
+ readonly policy: PolicyState | undefined;
24
+ readonly beforeResolve: readonly BeforeResolve[];
19
25
  /** All registrations (singleton / transient / scoped). Each token maps to an array of registrations. */
20
26
  readonly registrations: Map<unknown, Registration[]>;
21
27
  /** Singleton cache keyed by Registration object (Container: singletons, Scope: shared with parent). */
@@ -27,3 +33,62 @@ export interface ContainerInternals {
27
33
  /** Mark this container / scope as disposed. */
28
34
  markDisposed(): void;
29
35
  }
36
+ /**
37
+ * Outcome of an asynchronous creation.
38
+ *
39
+ * Disposal needs the created value in order to close it, but must not listen to the promise the
40
+ * scope handed to the caller: that would take over a failure the caller was meant to see. The
41
+ * scope records the outcome on a chain of its own, which never rejects.
42
+ *
43
+ * @internal
44
+ */
45
+ export type Creation = {
46
+ readonly failed: false;
47
+ readonly value: unknown;
48
+ } | {
49
+ readonly failed: true;
50
+ readonly error: unknown;
51
+ };
52
+ /**
53
+ * Settlement records for cached asynchronous creations, keyed by the promise the scope caches.
54
+ *
55
+ * @internal
56
+ */
57
+ export declare const creations: WeakMap<Promise<unknown>, Promise<Creation>>;
58
+ /**
59
+ * Record how a creation settles, on a chain that never rejects.
60
+ *
61
+ * @internal
62
+ */
63
+ export declare function settle(creation: Promise<unknown>): Promise<Creation>;
64
+ /**
65
+ * A factory running synchronously right now.
66
+ *
67
+ * @internal
68
+ */
69
+ export interface RunningFactory {
70
+ readonly scope: object;
71
+ readonly token: unknown;
72
+ readonly registration: Registration;
73
+ /** The singleton cache of the container the scope belongs to. */
74
+ readonly singletons: object;
75
+ readonly context: unknown;
76
+ }
77
+ /**
78
+ * Factories running synchronously right now, innermost last, across every scope and module copy.
79
+ *
80
+ * @internal
81
+ */
82
+ export declare const constructing: RunningFactory[];
83
+ /**
84
+ * Internal state of a Scope.
85
+ *
86
+ * `resolveInternal` resolves without the policy return check: the value stays inside the
87
+ * face that asked for it. The operations face uses it to obtain the callable it never hands out.
88
+ *
89
+ * @internal
90
+ */
91
+ export interface ScopeInternals extends ContainerInternals {
92
+ readonly kind: 'scope';
93
+ resolveInternal(token: unknown): unknown;
94
+ }
@@ -1,4 +1,6 @@
1
+ import type { PolicyState } from './container/policy.js';
1
2
  import type { Registration } from './resolver/index.js';
3
+ import type { BeforeResolve } from './scope/index.js';
2
4
  /**
3
5
  * Symbol used by extension modules (scope, disposable) to access container/scope internals.
4
6
  *
@@ -7,6 +9,7 @@ import type { Registration } from './resolver/index.js';
7
9
  export declare const INTERNALS: unique symbol;
8
10
  /** Type-only registration state retained by disposable views. No runtime property is emitted. */
9
11
  export declare const TYPE_STATE: unique symbol;
12
+ export declare const REGISTRATION_STATE: unique symbol;
10
13
  /**
11
14
  * Internal state exposed via the INTERNALS symbol.
12
15
  *
@@ -16,6 +19,9 @@ export declare const TYPE_STATE: unique symbol;
16
19
  * @internal
17
20
  */
18
21
  export interface ContainerInternals {
22
+ readonly kind: 'container' | 'scope';
23
+ readonly policy: PolicyState | undefined;
24
+ readonly beforeResolve: readonly BeforeResolve[];
19
25
  /** All registrations (singleton / transient / scoped). Each token maps to an array of registrations. */
20
26
  readonly registrations: Map<unknown, Registration[]>;
21
27
  /** Singleton cache keyed by Registration object (Container: singletons, Scope: shared with parent). */
@@ -27,3 +33,62 @@ export interface ContainerInternals {
27
33
  /** Mark this container / scope as disposed. */
28
34
  markDisposed(): void;
29
35
  }
36
+ /**
37
+ * Outcome of an asynchronous creation.
38
+ *
39
+ * Disposal needs the created value in order to close it, but must not listen to the promise the
40
+ * scope handed to the caller: that would take over a failure the caller was meant to see. The
41
+ * scope records the outcome on a chain of its own, which never rejects.
42
+ *
43
+ * @internal
44
+ */
45
+ export type Creation = {
46
+ readonly failed: false;
47
+ readonly value: unknown;
48
+ } | {
49
+ readonly failed: true;
50
+ readonly error: unknown;
51
+ };
52
+ /**
53
+ * Settlement records for cached asynchronous creations, keyed by the promise the scope caches.
54
+ *
55
+ * @internal
56
+ */
57
+ export declare const creations: WeakMap<Promise<unknown>, Promise<Creation>>;
58
+ /**
59
+ * Record how a creation settles, on a chain that never rejects.
60
+ *
61
+ * @internal
62
+ */
63
+ export declare function settle(creation: Promise<unknown>): Promise<Creation>;
64
+ /**
65
+ * A factory running synchronously right now.
66
+ *
67
+ * @internal
68
+ */
69
+ export interface RunningFactory {
70
+ readonly scope: object;
71
+ readonly token: unknown;
72
+ readonly registration: Registration;
73
+ /** The singleton cache of the container the scope belongs to. */
74
+ readonly singletons: object;
75
+ readonly context: unknown;
76
+ }
77
+ /**
78
+ * Factories running synchronously right now, innermost last, across every scope and module copy.
79
+ *
80
+ * @internal
81
+ */
82
+ export declare const constructing: RunningFactory[];
83
+ /**
84
+ * Internal state of a Scope.
85
+ *
86
+ * `resolveInternal` resolves without the policy return check: the value stays inside the
87
+ * face that asked for it. The operations face uses it to obtain the callable it never hands out.
88
+ *
89
+ * @internal
90
+ */
91
+ export interface ScopeInternals extends ContainerInternals {
92
+ readonly kind: 'scope';
93
+ resolveInternal(token: unknown): unknown;
94
+ }
@@ -0,0 +1,67 @@
1
+ declare const KEY: unique symbol;
2
+ declare const ENTRY: unique symbol;
3
+ /**
4
+ * A typed metadata key. Call it with a value to create a metadata entry for a registration.
5
+ *
6
+ * The name is used by type checking; runtime lookups use the key object's identity.
7
+ */
8
+ export interface MetadataKey<T, Name extends PropertyKey = PropertyKey> {
9
+ (value: T): MetadataEntry<T, Name>;
10
+ readonly name: Name;
11
+ readonly [KEY]: true;
12
+ }
13
+ export interface MetadataEntry<T = unknown, Name extends PropertyKey = PropertyKey> {
14
+ readonly key: MetadataKey<T, Name>;
15
+ readonly value: T;
16
+ readonly [ENTRY]: true;
17
+ }
18
+ export interface AnyMetadataKey {
19
+ readonly name: PropertyKey;
20
+ readonly [KEY]: true;
21
+ }
22
+ export interface AnyMetadataEntry {
23
+ readonly key: AnyMetadataKey;
24
+ readonly value: unknown;
25
+ readonly [ENTRY]: true;
26
+ }
27
+ export type MetadataKeyOf<E> = E extends MetadataEntry<infer T, infer N> ? MetadataKey<T, N> : never;
28
+ /**
29
+ * Define a typed metadata key.
30
+ *
31
+ * The value type is given first and the name is inferred in a second call, so keys with different
32
+ * names are never confused.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const AREA = createMetadataKey<'internal' | 'public'>()('area');
37
+ * container.registerScoped('read', factory, { metadata: [AREA('public')] });
38
+ * ```
39
+ */
40
+ export declare function createMetadataKey<T>(): <const Name extends PropertyKey>(name: Name) => MetadataKey<T, Name>;
41
+ export interface MetadataReader {
42
+ get<T>(key: MetadataKey<T>): T | undefined;
43
+ require<T>(key: MetadataKey<T>): T;
44
+ has(key: AnyMetadataKey): boolean;
45
+ }
46
+ /** Registration metadata as a key/value pair, so origins can be compared by content. */
47
+ export type MetadataPair = readonly [key: AnyMetadataKey, value: unknown];
48
+ /** A reader and the key/value pairs for the same registration metadata, built from one copy. */
49
+ export interface RegisteredMetadata {
50
+ readonly reader: MetadataReader;
51
+ readonly pairs: readonly MetadataPair[];
52
+ }
53
+ /** Copy the metadata at registration, so later changes to the array or entries do not affect checks. */
54
+ export declare function readMetadata(entries: readonly AnyMetadataEntry[], required: readonly AnyMetadataKey[]): RegisteredMetadata;
55
+ export declare function validateMetadataKeys(keys: readonly AnyMetadataKey[]): void;
56
+ export type RegistrationArguments<Required extends readonly AnyMetadataKey[], Entries extends readonly AnyMetadataEntry[]> = Required extends readonly [] ? [options?: {
57
+ readonly metadata?: Entries;
58
+ }] : [
59
+ options: {
60
+ readonly metadata: Entries;
61
+ } & ([Exclude<Required[number], MetadataKeyOf<Entries[number]>>] extends [
62
+ never
63
+ ] ? unknown : {
64
+ readonly missingRequiredMetadata: never;
65
+ })
66
+ ];
67
+ export {};
@@ -0,0 +1,67 @@
1
+ declare const KEY: unique symbol;
2
+ declare const ENTRY: unique symbol;
3
+ /**
4
+ * A typed metadata key. Call it with a value to create a metadata entry for a registration.
5
+ *
6
+ * The name is used by type checking; runtime lookups use the key object's identity.
7
+ */
8
+ export interface MetadataKey<T, Name extends PropertyKey = PropertyKey> {
9
+ (value: T): MetadataEntry<T, Name>;
10
+ readonly name: Name;
11
+ readonly [KEY]: true;
12
+ }
13
+ export interface MetadataEntry<T = unknown, Name extends PropertyKey = PropertyKey> {
14
+ readonly key: MetadataKey<T, Name>;
15
+ readonly value: T;
16
+ readonly [ENTRY]: true;
17
+ }
18
+ export interface AnyMetadataKey {
19
+ readonly name: PropertyKey;
20
+ readonly [KEY]: true;
21
+ }
22
+ export interface AnyMetadataEntry {
23
+ readonly key: AnyMetadataKey;
24
+ readonly value: unknown;
25
+ readonly [ENTRY]: true;
26
+ }
27
+ export type MetadataKeyOf<E> = E extends MetadataEntry<infer T, infer N> ? MetadataKey<T, N> : never;
28
+ /**
29
+ * Define a typed metadata key.
30
+ *
31
+ * The value type is given first and the name is inferred in a second call, so keys with different
32
+ * names are never confused.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const AREA = createMetadataKey<'internal' | 'public'>()('area');
37
+ * container.registerScoped('read', factory, { metadata: [AREA('public')] });
38
+ * ```
39
+ */
40
+ export declare function createMetadataKey<T>(): <const Name extends PropertyKey>(name: Name) => MetadataKey<T, Name>;
41
+ export interface MetadataReader {
42
+ get<T>(key: MetadataKey<T>): T | undefined;
43
+ require<T>(key: MetadataKey<T>): T;
44
+ has(key: AnyMetadataKey): boolean;
45
+ }
46
+ /** Registration metadata as a key/value pair, so origins can be compared by content. */
47
+ export type MetadataPair = readonly [key: AnyMetadataKey, value: unknown];
48
+ /** A reader and the key/value pairs for the same registration metadata, built from one copy. */
49
+ export interface RegisteredMetadata {
50
+ readonly reader: MetadataReader;
51
+ readonly pairs: readonly MetadataPair[];
52
+ }
53
+ /** Copy the metadata at registration, so later changes to the array or entries do not affect checks. */
54
+ export declare function readMetadata(entries: readonly AnyMetadataEntry[], required: readonly AnyMetadataKey[]): RegisteredMetadata;
55
+ export declare function validateMetadataKeys(keys: readonly AnyMetadataKey[]): void;
56
+ export type RegistrationArguments<Required extends readonly AnyMetadataKey[], Entries extends readonly AnyMetadataEntry[]> = Required extends readonly [] ? [options?: {
57
+ readonly metadata?: Entries;
58
+ }] : [
59
+ options: {
60
+ readonly metadata: Entries;
61
+ } & ([Exclude<Required[number], MetadataKeyOf<Entries[number]>>] extends [
62
+ never
63
+ ] ? unknown : {
64
+ readonly missingRequiredMetadata: never;
65
+ })
66
+ ];
67
+ export {};
@@ -1,3 +1,4 @@
1
+ import type { MetadataPair, MetadataReader } from '../metadata/index.cjs';
1
2
  export type AbstractConstructor<T = unknown> = abstract new (...args: never[]) => T;
2
3
  /**
3
4
  * Resolver passed to factory callbacks.
@@ -64,6 +65,10 @@ export type Lifetime = 'singleton' | 'transient' | 'scoped';
64
65
  * Factory registration entry.
65
66
  */
66
67
  export interface Registration {
68
+ readonly metadata: MetadataReader;
69
+ /** The same metadata as key/value pairs, so origins can be compared by content. */
70
+ readonly metadataPairs: readonly MetadataPair[];
71
+ readonly entrypoint: boolean;
67
72
  /**
68
73
  * Factory function.
69
74
  *
@@ -1,3 +1,4 @@
1
+ import type { MetadataPair, MetadataReader } from '../metadata/index.js';
1
2
  export type AbstractConstructor<T = unknown> = abstract new (...args: never[]) => T;
2
3
  /**
3
4
  * Resolver passed to factory callbacks.
@@ -64,6 +65,10 @@ export type Lifetime = 'singleton' | 'transient' | 'scoped';
64
65
  * Factory registration entry.
65
66
  */
66
67
  export interface Registration {
68
+ readonly metadata: MetadataReader;
69
+ /** The same metadata as key/value pairs, so origins can be compared by content. */
70
+ readonly metadataPairs: readonly MetadataPair[];
71
+ readonly entrypoint: boolean;
67
72
  /**
68
73
  * Factory function.
69
74
  *
@@ -1,7 +1,26 @@
1
1
  import type { Container } from '../container/index.cjs';
2
+ import { type PolicyState } from '../container/policy.cjs';
2
3
  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';
4
+ import type { REGISTRATION_STATE } from '../internal.cjs';
5
+ import { type ContainerInternals, INTERNALS, type ScopeInternals } from '../internal.cjs';
6
+ import type { AnyMetadataKey, MetadataReader } from '../metadata/index.cjs';
7
+ import type { AbstractConstructor, Lifetime, Registration } from '../resolver/index.cjs';
8
+ import { type OperationsScope, type OperationsScopeOptions } from './operations.cjs';
9
+ export interface RegistrationDescription {
10
+ readonly token: unknown;
11
+ readonly lifetime: Lifetime;
12
+ readonly metadata: MetadataReader;
13
+ readonly entrypoint: boolean;
14
+ }
15
+ export interface ResolutionEvent extends RegistrationDescription {
16
+ readonly requester: RegistrationDescription | undefined;
17
+ readonly path: readonly unknown[];
18
+ }
19
+ export type BeforeResolve = (event: ResolutionEvent) => void;
20
+ export interface ScopeOptions {
21
+ readonly access?: never;
22
+ readonly beforeResolve?: BeforeResolve;
23
+ }
5
24
  /**
6
25
  * Create a new scope (child container) from a Container, Scope, or their disposable variants.
7
26
  *
@@ -12,10 +31,14 @@ import type { AbstractConstructor, Registration } from '../resolver/index.cjs';
12
31
  * @returns A new Scope instance
13
32
  * @throws ContainerError if the source has been disposed
14
33
  */
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>;
34
+ export declare function createScope<C extends {
35
+ readonly [INTERNALS]: ContainerInternals;
36
+ readonly [REGISTRATION_STATE]: unknown;
37
+ }>(source: C, options: OperationsScopeOptions): OperationsScope<C[typeof REGISTRATION_STATE]>;
38
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Required extends readonly AnyMetadataKey[], Registrations>(source: Container<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Required, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
39
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Registrations>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
40
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Required extends readonly AnyMetadataKey[], Registrations>(source: DisposableContainer<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Required, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
41
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Registrations>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
19
42
  /**
20
43
  * Scoped child container.
21
44
  *
@@ -30,20 +53,21 @@ export declare function createScope<T, Sync extends AbstractConstructor, Async e
30
53
  * @template ScopedSync Union of scoped sync class constructors
31
54
  * @template ScopedAsync Union of scoped async class constructors
32
55
  */
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> {
56
+ 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, Registrations = unknown> {
34
57
  private readonly registrations;
35
58
  private readonly singletonCache;
36
59
  private readonly scopedCache;
37
- private readonly resolvingTokens;
38
- private singletonDepth;
60
+ private readonly beforeResolve;
61
+ private readonly policy;
39
62
  private disposed;
40
63
  /**
41
64
  * Internal state accessor for extension modules (scope, disposable).
42
65
  *
43
66
  * @internal
44
67
  */
45
- readonly [INTERNALS]: ContainerInternals;
46
- constructor(registrations: Map<unknown, Registration[]>, singletonCache: Map<Registration, unknown>);
68
+ readonly [REGISTRATION_STATE]: Registrations;
69
+ readonly [INTERNALS]: ScopeInternals;
70
+ constructor(registrations: Map<unknown, Registration[]>, singletonCache: Map<Registration, unknown>, beforeResolve?: readonly BeforeResolve[], policy?: PolicyState);
47
71
  /**
48
72
  * Resolve an instance for the given token.
49
73
  *
@@ -99,22 +123,23 @@ export declare class Scope<T = Record<never, never>, Sync extends AbstractConstr
99
123
  tryResolveAll<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K][] | undefined;
100
124
  tryResolveAll<V>(token: AbstractConstructor<V>): (V | Promise<V>)[] | undefined;
101
125
  tryResolveAll(token: PropertyKey): unknown;
126
+ /** The context of a call through a public method: the running factory's, or the outside of this scope. */
127
+ private entry;
128
+ private describe;
129
+ private check;
130
+ private lookup;
131
+ /** Create a value that may leave this scope; a synchronous value passes the policy's return check here. */
132
+ private create;
102
133
  /**
103
- * Internal resolution logic shared by resolve and tryResolve.
104
- * Resolves the last registered factory for the token.
134
+ * Shape a created value for the caller.
105
135
  *
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
136
+ * The return check runs on every resolution, so under a policy with a return check, an asynchronous
137
+ * creation leaving the scope is handed out as a per-call Promise that checks the resolved value. No
138
+ * listener is attached to a Promise already handed out. The per-call Promise is built only after every
139
+ * synchronous failure is ruled out, so no Promise is left without a receiver.
109
140
  */
141
+ private handOut;
110
142
  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
143
  private resolveAllTokens;
144
+ private instantiate;
120
145
  }
@@ -1,7 +1,26 @@
1
1
  import type { Container } from '../container/index.js';
2
+ import { type PolicyState } from '../container/policy.js';
2
3
  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';
4
+ import type { REGISTRATION_STATE } from '../internal.js';
5
+ import { type ContainerInternals, INTERNALS, type ScopeInternals } from '../internal.js';
6
+ import type { AnyMetadataKey, MetadataReader } from '../metadata/index.js';
7
+ import type { AbstractConstructor, Lifetime, Registration } from '../resolver/index.js';
8
+ import { type OperationsScope, type OperationsScopeOptions } from './operations.js';
9
+ export interface RegistrationDescription {
10
+ readonly token: unknown;
11
+ readonly lifetime: Lifetime;
12
+ readonly metadata: MetadataReader;
13
+ readonly entrypoint: boolean;
14
+ }
15
+ export interface ResolutionEvent extends RegistrationDescription {
16
+ readonly requester: RegistrationDescription | undefined;
17
+ readonly path: readonly unknown[];
18
+ }
19
+ export type BeforeResolve = (event: ResolutionEvent) => void;
20
+ export interface ScopeOptions {
21
+ readonly access?: never;
22
+ readonly beforeResolve?: BeforeResolve;
23
+ }
5
24
  /**
6
25
  * Create a new scope (child container) from a Container, Scope, or their disposable variants.
7
26
  *
@@ -12,10 +31,14 @@ import type { AbstractConstructor, Registration } from '../resolver/index.js';
12
31
  * @returns A new Scope instance
13
32
  * @throws ContainerError if the source has been disposed
14
33
  */
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>;
34
+ export declare function createScope<C extends {
35
+ readonly [INTERNALS]: ContainerInternals;
36
+ readonly [REGISTRATION_STATE]: unknown;
37
+ }>(source: C, options: OperationsScopeOptions): OperationsScope<C[typeof REGISTRATION_STATE]>;
38
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Required extends readonly AnyMetadataKey[], Registrations>(source: Container<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Required, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
39
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Registrations>(source: Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
40
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Required extends readonly AnyMetadataKey[], Registrations>(source: DisposableContainer<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Required, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
41
+ export declare function createScope<T, Sync extends AbstractConstructor, Async extends AbstractConstructor, ScopedT, ScopedSync extends AbstractConstructor, ScopedAsync extends AbstractConstructor, Registrations>(source: DisposableScope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>, options?: ScopeOptions): Scope<T, Sync, Async, ScopedT, ScopedSync, ScopedAsync, Registrations>;
19
42
  /**
20
43
  * Scoped child container.
21
44
  *
@@ -30,20 +53,21 @@ export declare function createScope<T, Sync extends AbstractConstructor, Async e
30
53
  * @template ScopedSync Union of scoped sync class constructors
31
54
  * @template ScopedAsync Union of scoped async class constructors
32
55
  */
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> {
56
+ 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, Registrations = unknown> {
34
57
  private readonly registrations;
35
58
  private readonly singletonCache;
36
59
  private readonly scopedCache;
37
- private readonly resolvingTokens;
38
- private singletonDepth;
60
+ private readonly beforeResolve;
61
+ private readonly policy;
39
62
  private disposed;
40
63
  /**
41
64
  * Internal state accessor for extension modules (scope, disposable).
42
65
  *
43
66
  * @internal
44
67
  */
45
- readonly [INTERNALS]: ContainerInternals;
46
- constructor(registrations: Map<unknown, Registration[]>, singletonCache: Map<Registration, unknown>);
68
+ readonly [REGISTRATION_STATE]: Registrations;
69
+ readonly [INTERNALS]: ScopeInternals;
70
+ constructor(registrations: Map<unknown, Registration[]>, singletonCache: Map<Registration, unknown>, beforeResolve?: readonly BeforeResolve[], policy?: PolicyState);
47
71
  /**
48
72
  * Resolve an instance for the given token.
49
73
  *
@@ -99,22 +123,23 @@ export declare class Scope<T = Record<never, never>, Sync extends AbstractConstr
99
123
  tryResolveAll<K extends keyof (T & ScopedT)>(token: K): (T & ScopedT)[K][] | undefined;
100
124
  tryResolveAll<V>(token: AbstractConstructor<V>): (V | Promise<V>)[] | undefined;
101
125
  tryResolveAll(token: PropertyKey): unknown;
126
+ /** The context of a call through a public method: the running factory's, or the outside of this scope. */
127
+ private entry;
128
+ private describe;
129
+ private check;
130
+ private lookup;
131
+ /** Create a value that may leave this scope; a synchronous value passes the policy's return check here. */
132
+ private create;
102
133
  /**
103
- * Internal resolution logic shared by resolve and tryResolve.
104
- * Resolves the last registered factory for the token.
134
+ * Shape a created value for the caller.
105
135
  *
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
136
+ * The return check runs on every resolution, so under a policy with a return check, an asynchronous
137
+ * creation leaving the scope is handed out as a per-call Promise that checks the resolved value. No
138
+ * listener is attached to a Promise already handed out. The per-call Promise is built only after every
139
+ * synchronous failure is ruled out, so no Promise is left without a receiver.
109
140
  */
141
+ private handOut;
110
142
  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
143
  private resolveAllTokens;
144
+ private instantiate;
120
145
  }
@@ -0,0 +1,22 @@
1
+ import type { Callable } from '../entrypoint/index.cjs';
2
+ import type { Scope, ScopeOptions } from './index.cjs';
3
+ type PublicState<S> = S extends {
4
+ readonly callable: infer F;
5
+ } ? ([F] extends [never] ? never : S) : never;
6
+ type Token<S> = PublicState<S> extends infer P ? (P extends {
7
+ readonly token: infer K;
8
+ } ? K : never) : never;
9
+ type Operation<S, K> = Extract<PublicState<S>, {
10
+ readonly token: K;
11
+ }> extends {
12
+ readonly callable: infer F extends Callable;
13
+ } ? F : never;
14
+ export interface OperationsScopeOptions extends Omit<ScopeOptions, 'access'> {
15
+ readonly access: 'operations';
16
+ }
17
+ export interface OperationsScope<Registrations> extends AsyncDisposable {
18
+ get<K extends Token<Registrations>>(token: K): (...args: Parameters<Operation<Registrations, K>>) => Promise<Awaited<ReturnType<Operation<Registrations, K>>>>;
19
+ }
20
+ /** Build an operations scope: keep the resolver inside, and stop new calls and wait for running ones in one place. */
21
+ export declare function operations<Registrations>(source: Scope): OperationsScope<Registrations>;
22
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { Callable } from '../entrypoint/index.js';
2
+ import type { Scope, ScopeOptions } from './index.js';
3
+ type PublicState<S> = S extends {
4
+ readonly callable: infer F;
5
+ } ? ([F] extends [never] ? never : S) : never;
6
+ type Token<S> = PublicState<S> extends infer P ? (P extends {
7
+ readonly token: infer K;
8
+ } ? K : never) : never;
9
+ type Operation<S, K> = Extract<PublicState<S>, {
10
+ readonly token: K;
11
+ }> extends {
12
+ readonly callable: infer F extends Callable;
13
+ } ? F : never;
14
+ export interface OperationsScopeOptions extends Omit<ScopeOptions, 'access'> {
15
+ readonly access: 'operations';
16
+ }
17
+ export interface OperationsScope<Registrations> extends AsyncDisposable {
18
+ get<K extends Token<Registrations>>(token: K): (...args: Parameters<Operation<Registrations, K>>) => Promise<Awaited<ReturnType<Operation<Registrations, K>>>>;
19
+ }
20
+ /** Build an operations scope: keep the resolver inside, and stop new calls and wait for running ones in one place. */
21
+ export declare function operations<Registrations>(source: Scope): OperationsScope<Registrations>;
22
+ export {};
package/docs/README.de.md CHANGED
@@ -29,11 +29,11 @@ console.log(greeting);
29
29
 
30
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
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).
32
+ **Geprüft am 2026-09-11**, anhand stabiler npm-Versionen und offizieller Quellen. Die Katagami-Angaben beschreiben diese Version (4.0.0). Siehe [Versionen und Quellen](./choosing-di.md#comparison-sources) sowie den [vollständigen Vergleich mit Async-Verhalten und Ressourcenfreigabe](../README.md#library-comparison).
33
33
 
34
34
  | Bibliothek / Version | Abhängigkeitstypen und Registrierungsprüfung | Scope-Verhalten |
35
35
  | --- | --- | --- |
36
- | **Katagami 3.0.2** | **Sammelt Literal-/unique-symbol-Tokens; fehlende erforderliche Tokens sind Typfehler** | **Scoped-Tokens im Resolver von Singleton-/Transient-Factories ausgeschlossen** |
36
+ | **Katagami 4.0.0** | **Sammelt Literal-/unique-symbol-Tokens; fehlende erforderliche Tokens sind Typfehler** | **Scoped-Tokens im Resolver von Singleton-/Transient-Factories ausgeschlossen** |
37
37
  | InversifyJS 8.2.3 | Typisierte Bindings; Existenzprüfung zur Laufzeit | Konfigurierte Binding-Lebensdauer |
38
38
  | tsyringe 4.10.0 | Klassen-/generische Typen; Registrierungsprüfung zur Laufzeit | Lebensdauer und Kindcontainer |
39
39
  | TypeDI 0.10.0 | Klassen und `Token<T>`; Registrierungsprüfung zur Laufzeit | Geteilte/Transient-Services, benannte Container |
@@ -74,6 +74,7 @@ Unterstützt Singleton, Transient und Scoped, Modulkomposition mit use(), asynch
74
74
  - [Anleitung für KI-Agenten (Englisch)](./ai-coding-agents.md)
75
75
  - [Typgarantien (Englisch)](./type-safety.md)
76
76
  - [API und Anwendung (Englisch)](./guide.md)
77
+ - [Registrierungsrichtlinien und Operationen (Englisch)](./registration-policies.md)
77
78
  - [Starter für Anfrage-Scopes (Englisch)](../examples/request-scope/README.md)
78
79
  - [DI auswählen (Englisch)](./choosing-di.md)
79
80