@teqfw/di 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +449 -263
- package/ai/AGENTS.md +42 -55
- package/ai/concepts.md +11 -54
- package/ai/container.md +57 -45
- package/ai/dependency-id.md +78 -58
- package/ai/extensions.md +68 -38
- package/ai/package-api.ts +13 -11
- package/ai/usage.md +80 -205
- package/dist/esm.js +1 -1
- package/dist/umd.js +1 -1
- package/package.json +1 -1
- package/src/Config/NamespaceRegistry.mjs +19 -15
- package/src/Container/Lifecycle/Registry.mjs +2 -12
- package/src/Container/Resolve/GraphResolver.mjs +8 -28
- package/src/Container/Runtime.mjs +244 -0
- package/src/Container.mjs +14 -387
- package/src/Internal/DependencyKey.mjs +29 -0
- package/src/Internal/DepsDecl.mjs +42 -0
- package/src/Internal/PromiseSafe.mjs +39 -0
- package/src/{Def/Parser.mjs → Parser.mjs} +82 -35
- package/src/Container/Instantiate/ExportSelector.mjs +0 -44
package/ai/extensions.md
CHANGED
|
@@ -1,73 +1,103 @@
|
|
|
1
1
|
# extensions.md
|
|
2
2
|
|
|
3
|
-
Version:
|
|
3
|
+
Version: 20260606
|
|
4
4
|
|
|
5
5
|
## Purpose
|
|
6
6
|
|
|
7
|
-
The container supports controlled extension of
|
|
7
|
+
The container supports controlled extension of dependency resolution through three distinct mechanisms:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- preprocess hooks;
|
|
10
|
+
- postprocess hooks;
|
|
11
|
+
- wrapper exports.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
These mechanisms are related but not interchangeable.
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Preprocess Hooks
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
- **Postprocess wrappers** — modify or decorate created objects after instantiation.
|
|
17
|
+
Preprocess hooks transform CDC identities before resolution.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Signature:
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
```js
|
|
22
|
+
(depId) => depId
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Properties:
|
|
26
|
+
|
|
27
|
+
- registered with `addPreprocess()`;
|
|
28
|
+
- run in declared order;
|
|
29
|
+
- receive and return DepId DTO values;
|
|
30
|
+
- affect identifier interpretation before module resolution.
|
|
31
|
+
|
|
32
|
+
Typical uses:
|
|
33
|
+
|
|
34
|
+
- CDC alias rewriting;
|
|
35
|
+
- policy-driven identifier normalization;
|
|
36
|
+
- project-specific prefix adaptation.
|
|
37
|
+
|
|
38
|
+
## Postprocess Hooks
|
|
21
39
|
|
|
22
|
-
|
|
40
|
+
Postprocess hooks transform resolved values after instantiation and before wrapper exports.
|
|
23
41
|
|
|
24
|
-
|
|
42
|
+
Signature:
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
```js
|
|
45
|
+
(value) => value
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Properties:
|
|
49
|
+
|
|
50
|
+
- registered with `addPostprocess()`;
|
|
51
|
+
- run for every resolved value;
|
|
52
|
+
- run in declared order;
|
|
53
|
+
- do not alter CDC parsing or module resolution.
|
|
29
54
|
|
|
30
|
-
|
|
55
|
+
Typical uses:
|
|
31
56
|
|
|
32
|
-
|
|
57
|
+
- global instrumentation;
|
|
58
|
+
- value normalization;
|
|
59
|
+
- cross-cutting adaptation applied uniformly to all resolved values.
|
|
33
60
|
|
|
34
|
-
|
|
61
|
+
## Wrapper Exports
|
|
35
62
|
|
|
36
|
-
|
|
63
|
+
Wrapper exports are selected directly from CDC suffixes and are resolved from the same module namespace as the dependency being composed.
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
- instrumentation
|
|
40
|
-
- capability injection
|
|
41
|
-
- runtime adaptation of object behavior
|
|
65
|
+
Signature:
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
```js
|
|
68
|
+
(value) => value
|
|
69
|
+
```
|
|
44
70
|
|
|
45
|
-
|
|
71
|
+
Properties:
|
|
46
72
|
|
|
47
|
-
|
|
73
|
+
- selected by wrapper suffixes such as `_wrapLog`;
|
|
74
|
+
- applied only when present in the CDC;
|
|
75
|
+
- executed after postprocess hooks and before freeze;
|
|
76
|
+
- not registered globally in the container.
|
|
48
77
|
|
|
49
78
|
Example:
|
|
50
79
|
|
|
51
80
|
```txt
|
|
52
|
-
|
|
81
|
+
App_Service$$_wrapLog_wrapTrace
|
|
53
82
|
```
|
|
54
83
|
|
|
55
|
-
In this example the container
|
|
56
|
-
|
|
57
|
-
Wrappers do not change the structure of `__deps__`. Dependency descriptors remain either hierarchical export-scoped descriptors, shorthand flat descriptors for limited single-export cases, or omitted entirely for empty-descriptor modules.
|
|
84
|
+
In this example the container composes the dependency, applies postprocess hooks, then applies wrapper exports `wrapLog` and `wrapTrace` in that order.
|
|
58
85
|
|
|
59
86
|
## Execution Order
|
|
60
87
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Each wrapper receives the object returned by the previous wrapper and may return a new object that becomes the input to the next wrapper.
|
|
88
|
+
The extension-related execution order is:
|
|
64
89
|
|
|
65
|
-
|
|
90
|
+
1. preprocess hooks;
|
|
91
|
+
2. instantiation or as-is resolution;
|
|
92
|
+
3. postprocess hooks;
|
|
93
|
+
4. wrapper exports;
|
|
94
|
+
5. freeze.
|
|
66
95
|
|
|
67
|
-
|
|
96
|
+
## Constraints
|
|
68
97
|
|
|
69
|
-
|
|
70
|
-
- they must be deterministic and free of side effects that alter container state
|
|
71
|
-
- they must not bypass lifecycle semantics enforced by the container
|
|
98
|
+
Extensions must satisfy these constraints:
|
|
72
99
|
|
|
73
|
-
|
|
100
|
+
- they must be registered before the first `get()` if they use container registration APIs;
|
|
101
|
+
- they should be deterministic for the same input;
|
|
102
|
+
- they must not rely on mutating frozen returned values;
|
|
103
|
+
- they must not bypass lifecycle semantics enforced by the container.
|
package/ai/package-api.ts
CHANGED
|
@@ -110,9 +110,10 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
110
110
|
name: 'addNamespaceRoot',
|
|
111
111
|
signature: 'addNamespaceRoot(prefix: string, target: string, defaultExt: string): void',
|
|
112
112
|
stage: 'builder',
|
|
113
|
-
summary: 'Registers one namespace
|
|
113
|
+
summary: 'Registers one namespace root that maps a CDC prefix to a module-specifier base.',
|
|
114
114
|
constraints: [
|
|
115
115
|
'Allowed only before the first get().',
|
|
116
|
+
'The target may be filesystem-backed or URL-backed depending on runtime environment.',
|
|
116
117
|
'Namespace rules are snapshotted and locked on the first get().',
|
|
117
118
|
],
|
|
118
119
|
},
|
|
@@ -130,10 +131,10 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
130
131
|
name: 'addPostprocess',
|
|
131
132
|
signature: 'addPostprocess(fn: (value: unknown) => unknown): void',
|
|
132
133
|
stage: 'builder',
|
|
133
|
-
summary: 'Adds an ordered
|
|
134
|
+
summary: 'Adds an ordered value transform applied to every resolved value after instantiation.',
|
|
134
135
|
constraints: [
|
|
135
136
|
'Allowed only before the first get().',
|
|
136
|
-
'Runs
|
|
137
|
+
'Runs after instantiation and before wrapper exports.',
|
|
137
138
|
],
|
|
138
139
|
},
|
|
139
140
|
{
|
|
@@ -168,7 +169,7 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
168
169
|
name: 'get',
|
|
169
170
|
signature: 'get(cdc: string): Promise<any>',
|
|
170
171
|
stage: 'runtime',
|
|
171
|
-
summary: 'Parses, resolves, instantiates, postprocesses, wraps, applies lifecycle, freezes, and returns a linked value.',
|
|
172
|
+
summary: 'Parses, preprocesses, resolves, instantiates, postprocesses, wraps, applies lifecycle, freezes, and returns a linked value.',
|
|
172
173
|
constraints: [
|
|
173
174
|
'The first get() locks configuration and creates internal infrastructure.',
|
|
174
175
|
'Any fatal pipeline error moves the container into failed state.',
|
|
@@ -220,7 +221,7 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
220
221
|
fields: {
|
|
221
222
|
moduleName: 'Logical module identifier without platform prefix.',
|
|
222
223
|
platform: '"teq" | "node" | "npm".',
|
|
223
|
-
exportName: 'Named export or "default"; null means whole-module
|
|
224
|
+
exportName: 'Named export or "default"; null means whole-module as-is resolution.',
|
|
224
225
|
composition: '"A" | "F" in the current implementation.',
|
|
225
226
|
life: '"S" | "T" | null in the current implementation.',
|
|
226
227
|
wrappers: 'Ordered wrapper export names.',
|
|
@@ -267,15 +268,16 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
267
268
|
kind: 'module-contract',
|
|
268
269
|
summary: 'Shape expected from application modules resolved by the container.',
|
|
269
270
|
fields: {
|
|
270
|
-
__deps__: 'Optional
|
|
271
|
+
__deps__: 'Optional dependency descriptor. Canonical form is hierarchical Record<exportName, Record<dependencyKey, CDC string>>. Supported shorthand form is a flat Record<dependencyKey, CDC string> for default-export-only modules. Omission means there are no declared dependencies.',
|
|
271
272
|
moduleNamespace: 'Whole ES module namespace object returned for as-is CDC without selected export.',
|
|
272
273
|
defaultExport: 'Used when the parsed DepId selects exportName="default" for factory composition.',
|
|
273
|
-
namedExports: 'May be selected via __ExportName for factory composition and may also provide wrapper
|
|
274
|
+
namedExports: 'May be selected via __ExportName for factory composition and may also provide wrapper exports.',
|
|
274
275
|
wrapperExport: 'Named export whose identifier appears in depId.wrappers; it must be synchronous and unary.',
|
|
275
276
|
},
|
|
276
277
|
notes: [
|
|
277
|
-
'The
|
|
278
|
-
'
|
|
278
|
+
'The hierarchical export-scoped descriptor is canonical.',
|
|
279
|
+
'The flat shorthand descriptor is supported only for default-export-only modules and does not replace the canonical hierarchical model.',
|
|
280
|
+
'Wrapper exports are resolved from the same module namespace and are not globally registered in the container.',
|
|
279
281
|
],
|
|
280
282
|
},
|
|
281
283
|
],
|
|
@@ -429,8 +431,8 @@ export const PACKAGE_API: PackageApiContract = {
|
|
|
429
431
|
operationalNotes: [
|
|
430
432
|
'Only two runtime entrypoints are supported by package.json exports: @teqfw/di and @teqfw/di/src/Config/NamespaceRegistry.mjs.',
|
|
431
433
|
'Resolved values are frozen before being returned.',
|
|
432
|
-
'
|
|
433
|
-
'With the default parser, CDC without lifecycle
|
|
434
|
+
'The hierarchical export-scoped descriptor is canonical. The flat shorthand descriptor is supported only for default-export-only modules.',
|
|
435
|
+
'With the default parser, CDC without lifecycle resolves the selected module export as-is.',
|
|
434
436
|
'Named wrapper exports are executed after addPostprocess() hooks and before freeze.',
|
|
435
437
|
'In the current implementation, CDC markers $$ and $$$ both end up as transient/no-cache behavior.',
|
|
436
438
|
'types.d.ts is broader than the runtime import surface. Presence of an alias there does not by itself make the underlying module a supported runtime entrypoint.',
|
package/ai/usage.md
CHANGED
|
@@ -1,59 +1,35 @@
|
|
|
1
1
|
# usage.md
|
|
2
2
|
|
|
3
|
-
Version:
|
|
3
|
+
Version: 20260606
|
|
4
4
|
|
|
5
5
|
## Purpose
|
|
6
6
|
|
|
7
|
-
This document
|
|
7
|
+
This document shows canonical usage patterns for the container. Examples are intentionally short and prioritize supported, recommended forms over convenience shorthand.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Canonical Module Descriptor
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Modules intended for container linking may expose a default export, a named export, or both. The static dependency descriptor `__deps__` is canonical when it is hierarchical and keyed by export name. It describes the dependencies of the export selected by the CDC.
|
|
14
|
-
|
|
15
|
-
Dependencies are injected into the constructor as a single structured object. In TeqFW-style modules the public API is defined inside the constructor through assignments to `this`, while internal state may be held in constructor-local variables captured by closures.
|
|
16
|
-
|
|
17
|
-
Example module:
|
|
11
|
+
The canonical form of `__deps__` is hierarchical and keyed by export name.
|
|
18
12
|
|
|
19
13
|
```js
|
|
20
14
|
// @ts-check
|
|
21
15
|
|
|
22
16
|
export const __deps__ = {
|
|
23
17
|
default: {
|
|
24
|
-
cast: "
|
|
25
|
-
},
|
|
26
|
-
Factory: {
|
|
27
|
-
cast: "Fl32_Web_Helper_Cast$",
|
|
18
|
+
cast: "App_Helper_Cast$",
|
|
28
19
|
},
|
|
29
20
|
};
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
* Runtime wrapper that can hold non-DI behavior.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
export default class RuntimeWrapper {
|
|
36
|
-
constructor() {
|
|
37
|
-
return proxy;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @typedef {Object} App_Factory$Deps
|
|
43
|
-
* @property {object} cast
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
export class Factory {
|
|
22
|
+
export default class App_Root {
|
|
47
23
|
/**
|
|
48
|
-
* @param {
|
|
24
|
+
* @param {{cast: (value: unknown) => string}} deps
|
|
49
25
|
*/
|
|
50
26
|
constructor({ cast }) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
27
|
+
return {
|
|
28
|
+
configure(params = {}) {
|
|
29
|
+
return {
|
|
30
|
+
name: cast(params.name ?? "app"),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
57
33
|
};
|
|
58
34
|
}
|
|
59
35
|
}
|
|
@@ -64,28 +40,23 @@ Dependency module:
|
|
|
64
40
|
```js
|
|
65
41
|
// @ts-check
|
|
66
42
|
|
|
67
|
-
export default
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
}
|
|
43
|
+
export default function App_Helper_Cast() {
|
|
44
|
+
return function cast(value) {
|
|
45
|
+
return String(value);
|
|
46
|
+
};
|
|
73
47
|
}
|
|
74
48
|
```
|
|
75
49
|
|
|
76
50
|
Rules:
|
|
77
51
|
|
|
78
|
-
- the
|
|
79
|
-
- each export entry maps constructor dependency names to CDC identifiers
|
|
80
|
-
- if `__deps__` is
|
|
81
|
-
-
|
|
82
|
-
- dependencies are resolved recursively before instantiation
|
|
52
|
+
- the hierarchical export-scoped form is canonical;
|
|
53
|
+
- each export entry maps constructor dependency names to CDC identifiers;
|
|
54
|
+
- if `__deps__` is omitted, the module has no declared dependencies;
|
|
55
|
+
- dependencies are resolved recursively before instantiation.
|
|
83
56
|
|
|
84
|
-
|
|
57
|
+
## Canonical Container Setup
|
|
85
58
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
The container is configured in the composition root of the application. Namespace roots define how CDC prefixes map to module locations.
|
|
59
|
+
The container is configured in the composition root before the first resolution.
|
|
89
60
|
|
|
90
61
|
```js
|
|
91
62
|
import path from "node:path";
|
|
@@ -96,224 +67,128 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
96
67
|
const __dirname = path.dirname(__filename);
|
|
97
68
|
|
|
98
69
|
const container = new Container();
|
|
99
|
-
|
|
100
70
|
container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
|
|
101
71
|
```
|
|
102
72
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
## Resolving Dependencies
|
|
106
|
-
|
|
107
|
-
Dependencies are obtained using CDC identifiers.
|
|
73
|
+
Namespace roots may also use URL-backed module-specifier bases:
|
|
108
74
|
|
|
109
75
|
```js
|
|
110
|
-
|
|
76
|
+
container.addNamespaceRoot("App_", "https://cdn.example.com/app", ".mjs");
|
|
111
77
|
```
|
|
112
78
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- parses the CDC
|
|
116
|
-
- loads the module
|
|
117
|
-
- resolves dependencies declared in `__deps__`
|
|
118
|
-
- instantiates modules
|
|
119
|
-
- links the dependency graph
|
|
120
|
-
- freezes the produced value
|
|
79
|
+
## Resolve Root Dependency
|
|
121
80
|
|
|
122
|
-
|
|
81
|
+
Applications typically resolve one root dependency and let the container build the full object graph.
|
|
123
82
|
|
|
124
83
|
```js
|
|
125
|
-
|
|
126
|
-
console.log(root.
|
|
84
|
+
const root = await container.get("App_Root$");
|
|
85
|
+
console.log(root.configure({name: 123}).name);
|
|
127
86
|
console.log(Object.isFrozen(root));
|
|
128
87
|
```
|
|
129
88
|
|
|
130
|
-
##
|
|
131
|
-
|
|
132
|
-
CDC identifiers define how the container interprets a dependency. The following patterns represent common usage scenarios.
|
|
133
|
-
|
|
134
|
-
### Module As-Is
|
|
135
|
-
|
|
136
|
-
A CDC without lifecycle marker returns the module export as-is.
|
|
137
|
-
|
|
138
|
-
```text
|
|
139
|
-
App_Service
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Typical usage:
|
|
143
|
-
|
|
144
|
-
- utility modules
|
|
145
|
-
- stateless helpers
|
|
146
|
-
- constant providers
|
|
147
|
-
|
|
148
|
-
Example:
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
const math = await container.get("App_Math");
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Singleton from Default Export
|
|
155
|
-
|
|
156
|
-
A lifecycle marker `$` creates a singleton instance.
|
|
157
|
-
|
|
158
|
-
```text
|
|
159
|
-
App_Service$
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Typical usage:
|
|
163
|
-
|
|
164
|
-
- application services
|
|
165
|
-
- repositories
|
|
166
|
-
- infrastructure adapters
|
|
167
|
-
|
|
168
|
-
### Transient Instance
|
|
169
|
-
|
|
170
|
-
Marker `$$` creates a new instance for every request.
|
|
171
|
-
|
|
172
|
-
```text
|
|
173
|
-
App_Service$$
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Typical usage:
|
|
177
|
-
|
|
178
|
-
- request objects
|
|
179
|
-
- short-lived workers
|
|
180
|
-
- task processors
|
|
181
|
-
|
|
182
|
-
### Named Export Resolution
|
|
183
|
-
|
|
184
|
-
CDC may reference a named export using the `__ExportName` segment.
|
|
185
|
-
|
|
186
|
-
```text
|
|
187
|
-
App_Module__build$
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Typical usage:
|
|
191
|
-
|
|
192
|
-
- builders
|
|
193
|
-
- factory entry points
|
|
194
|
-
- specialized constructors
|
|
89
|
+
## Named Export
|
|
195
90
|
|
|
196
|
-
|
|
91
|
+
Named exports use the `__ExportName` segment in the CDC and the same hierarchical `__deps__` structure.
|
|
197
92
|
|
|
198
93
|
```js
|
|
199
94
|
export const __deps__ = {
|
|
200
95
|
default: {
|
|
201
|
-
cast: "
|
|
96
|
+
cast: "App_Helper_Cast$",
|
|
202
97
|
},
|
|
203
98
|
Factory: {
|
|
204
|
-
cast: "
|
|
99
|
+
cast: "App_Helper_Cast$",
|
|
205
100
|
},
|
|
206
101
|
};
|
|
207
102
|
|
|
208
103
|
export default class RuntimeWrapper {
|
|
209
104
|
constructor() {
|
|
210
|
-
return
|
|
105
|
+
return {mode: "runtime"};
|
|
211
106
|
}
|
|
212
107
|
}
|
|
213
108
|
|
|
214
109
|
export class Factory {
|
|
215
110
|
constructor({ cast }) {
|
|
216
111
|
this.configure = function (params = {}) {
|
|
217
|
-
return {
|
|
112
|
+
return {
|
|
113
|
+
mode: "factory",
|
|
114
|
+
name: cast(params.name ?? "app"),
|
|
115
|
+
};
|
|
218
116
|
};
|
|
219
117
|
}
|
|
220
118
|
}
|
|
221
119
|
```
|
|
222
120
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
Wrappers modify the produced value through postprocess plugins.
|
|
121
|
+
Resolution examples:
|
|
226
122
|
|
|
227
|
-
```
|
|
228
|
-
|
|
123
|
+
```js
|
|
124
|
+
const runtime = await container.get("App_Module$");
|
|
125
|
+
const factory = await container.get("App_Module__Factory$");
|
|
229
126
|
```
|
|
230
127
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
### Shorthand Form
|
|
128
|
+
## Singleton And Transient
|
|
234
129
|
|
|
235
|
-
|
|
130
|
+
Common lifecycle-based compositions:
|
|
236
131
|
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
132
|
+
```txt
|
|
133
|
+
App_Service$
|
|
134
|
+
App_Task$$
|
|
135
|
+
App_Task$$$
|
|
241
136
|
```
|
|
242
137
|
|
|
243
|
-
|
|
138
|
+
- `$` creates and reuses a singleton instance;
|
|
139
|
+
- `$$` creates a new instance for each request;
|
|
140
|
+
- `$$$` is a transient alias in the current implementation.
|
|
244
141
|
|
|
245
|
-
|
|
142
|
+
## Wrappers
|
|
246
143
|
|
|
247
|
-
|
|
144
|
+
Wrapper exports are selected by CDC suffixes and are applied after postprocess hooks.
|
|
248
145
|
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
constructor() {
|
|
252
|
-
this.ready = function () {
|
|
253
|
-
return true;
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
}
|
|
146
|
+
```txt
|
|
147
|
+
App_Service$$_wrapLog_wrapTrace
|
|
257
148
|
```
|
|
258
149
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
- logging
|
|
262
|
-
- tracing
|
|
263
|
-
- metrics collection
|
|
264
|
-
- behavioral instrumentation
|
|
150
|
+
This pattern is useful when runtime behavior should be decorated without changing the service module contract.
|
|
265
151
|
|
|
266
|
-
|
|
152
|
+
## Platform Modules
|
|
267
153
|
|
|
268
|
-
CDC may
|
|
154
|
+
CDC may refer to platform modules directly.
|
|
269
155
|
|
|
270
|
-
```
|
|
156
|
+
```txt
|
|
271
157
|
node:fs
|
|
272
158
|
npm:@humanfs/core
|
|
273
159
|
node:worker_threads
|
|
274
|
-
npm:lodash
|
|
275
160
|
```
|
|
276
161
|
|
|
277
|
-
These
|
|
162
|
+
These forms resolve the selected platform module export as-is unless a lifecycle marker is explicitly added.
|
|
278
163
|
|
|
279
|
-
|
|
164
|
+
## Non-Canonical Shorthand
|
|
280
165
|
|
|
281
|
-
|
|
282
|
-
- `npm:@humanfs/core` for a scoped npm package dependency
|
|
283
|
-
|
|
284
|
-
### Root Graph Resolution
|
|
285
|
-
|
|
286
|
-
Applications typically resolve a single root dependency.
|
|
166
|
+
A flat `__deps__` object is a supported shorthand for default-export-only modules, but it is not the canonical model.
|
|
287
167
|
|
|
288
168
|
```js
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
The container recursively resolves all dependencies declared through `__deps__` and constructs the object graph. Empty descriptor modules omit `__deps__` entirely.
|
|
293
|
-
|
|
294
|
-
## Wrapper-Based Behavioral Composition
|
|
295
|
-
|
|
296
|
-
Wrappers enable declarative behavioral composition at the dependency level. By attaching wrapper identifiers to CDC strings the caller can modify the runtime behavior of a dependency without modifying its module implementation.
|
|
297
|
-
|
|
298
|
-
Example:
|
|
169
|
+
export const __deps__ = {
|
|
170
|
+
cast: "App_Helper_Cast$",
|
|
171
|
+
};
|
|
299
172
|
|
|
300
|
-
|
|
301
|
-
|
|
173
|
+
export default class App_Short {
|
|
174
|
+
constructor({ cast }) {
|
|
175
|
+
this.cast = cast;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
302
178
|
```
|
|
303
179
|
|
|
304
|
-
|
|
180
|
+
Prefer the hierarchical form for new integrations and for any module that exposes named exports.
|
|
305
181
|
|
|
306
|
-
|
|
182
|
+
## Empty Descriptor
|
|
307
183
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
A minimal integration scenario demonstrating container operation:
|
|
184
|
+
Modules with no declared dependencies omit `__deps__` entirely.
|
|
311
185
|
|
|
312
186
|
```js
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
187
|
+
export default class App_Empty {
|
|
188
|
+
constructor() {
|
|
189
|
+
this.ready = function () {
|
|
190
|
+
return true;
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
317
194
|
```
|
|
318
|
-
|
|
319
|
-
The container loads modules, resolves dependencies, instantiates objects, and returns a frozen result.
|