@teqfw/di 2.0.2 → 2.0.4

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.
@@ -0,0 +1,440 @@
1
+ export type ApiExposure =
2
+ | 'public-runtime'
3
+ | 'public-structural'
4
+ | 'internal';
5
+
6
+ export interface ImportBinding {
7
+ readonly specifier: string;
8
+ readonly exportName: 'default' | string;
9
+ readonly canonical: boolean;
10
+ readonly note?: string;
11
+ }
12
+
13
+ export interface MethodContract {
14
+ readonly name: string;
15
+ readonly signature: string;
16
+ readonly stage?: 'builder' | 'runtime' | 'composition';
17
+ readonly summary: string;
18
+ readonly constraints?: readonly string[];
19
+ }
20
+
21
+ export interface RuntimeComponentContract {
22
+ readonly alias: string;
23
+ readonly kind: 'class';
24
+ readonly role: string;
25
+ readonly imports: readonly ImportBinding[];
26
+ readonly methods: readonly MethodContract[];
27
+ }
28
+
29
+ export interface StructuralContract {
30
+ readonly name: string;
31
+ readonly kind: 'dto' | 'enum' | 'protocol' | 'module-contract';
32
+ readonly summary: string;
33
+ readonly aliases?: readonly string[];
34
+ readonly fields?: Readonly<Record<string, string>>;
35
+ readonly values?: Readonly<Record<string, string>>;
36
+ readonly notes?: readonly string[];
37
+ }
38
+
39
+ export interface TypeAliasClassification {
40
+ readonly alias: string;
41
+ readonly source: string;
42
+ readonly exposure: ApiExposure;
43
+ readonly reason: string;
44
+ readonly canonicalUse?: string;
45
+ readonly sameAs?: readonly string[];
46
+ }
47
+
48
+ export interface PackageApiContract {
49
+ readonly packageName: '@teqfw/di';
50
+ readonly packageRole: string;
51
+ readonly canonicalEntrypoints: readonly string[];
52
+ readonly publicRuntime: readonly RuntimeComponentContract[];
53
+ readonly structuralContracts: readonly StructuralContract[];
54
+ readonly typeMapClassification: readonly TypeAliasClassification[];
55
+ readonly operationalNotes: readonly string[];
56
+ }
57
+
58
+ /**
59
+ * Public package contract intended for agents that consume `@teqfw/di`
60
+ * as an npm dependency.
61
+ *
62
+ * This file distinguishes between:
63
+ * - importable runtime API supported by `package.json#exports`
64
+ * - structural contracts that external code may rely on indirectly
65
+ * - internal implementation aliases present in `types.d.ts`
66
+ */
67
+ export const PACKAGE_API: PackageApiContract = {
68
+ packageName: '@teqfw/di',
69
+ packageRole: 'Deterministic runtime DI container for native ES modules with explicit CDC contracts.',
70
+ canonicalEntrypoints: [
71
+ '@teqfw/di',
72
+ '@teqfw/di/src/Config/NamespaceRegistry.mjs',
73
+ ],
74
+ publicRuntime: [
75
+ {
76
+ alias: 'TeqFw_Di_Container',
77
+ kind: 'class',
78
+ role: 'Primary runtime composition root. Resolves CDC identifiers into frozen linked values.',
79
+ imports: [
80
+ {
81
+ specifier: '@teqfw/di',
82
+ exportName: 'default',
83
+ canonical: true,
84
+ },
85
+ {
86
+ specifier: '@teqfw/di/src/Container.mjs',
87
+ exportName: 'default',
88
+ canonical: false,
89
+ note: 'Explicit source subpath export. Prefer the package root import.',
90
+ },
91
+ ],
92
+ methods: [
93
+ {
94
+ name: 'constructor',
95
+ signature: 'new Container()',
96
+ stage: 'builder',
97
+ summary: 'Creates a container in builder stage. The constructor accepts no arguments.',
98
+ },
99
+ {
100
+ name: 'setParser',
101
+ signature: 'setParser(parser: { parse(cdc: string): TeqFw_Di_DepId$DTO }): void',
102
+ stage: 'builder',
103
+ summary: 'Replaces the default CDC parser before the first resolution.',
104
+ constraints: [
105
+ 'Allowed only before the first get().',
106
+ 'The parser contract is structural. The package does not export the default parser runtime class.',
107
+ ],
108
+ },
109
+ {
110
+ name: 'addNamespaceRoot',
111
+ signature: 'addNamespaceRoot(prefix: string, target: string, defaultExt: string): void',
112
+ stage: 'builder',
113
+ summary: 'Registers one namespace-to-filesystem mapping rule.',
114
+ constraints: [
115
+ 'Allowed only before the first get().',
116
+ 'Namespace rules are snapshotted and locked on the first get().',
117
+ ],
118
+ },
119
+ {
120
+ name: 'addPreprocess',
121
+ signature: 'addPreprocess(fn: (depId: TeqFw_Di_DepId$DTO) => TeqFw_Di_DepId$DTO): void',
122
+ stage: 'builder',
123
+ summary: 'Adds an ordered CDC preprocessing hook.',
124
+ constraints: [
125
+ 'Allowed only before the first get().',
126
+ 'Each hook must return another DepId DTO.',
127
+ ],
128
+ },
129
+ {
130
+ name: 'addPostprocess',
131
+ signature: 'addPostprocess(fn: (value: unknown) => unknown): void',
132
+ stage: 'builder',
133
+ summary: 'Adds an ordered post-instantiation value transform applied to every resolved value.',
134
+ constraints: [
135
+ 'Allowed only before the first get().',
136
+ 'Runs before wrapper exports and before freeze.',
137
+ ],
138
+ },
139
+ {
140
+ name: 'enableLogging',
141
+ signature: 'enableLogging(): void',
142
+ stage: 'builder',
143
+ summary: 'Turns on diagnostic console logging without changing linking semantics.',
144
+ constraints: [
145
+ 'Allowed only before the first get().',
146
+ ],
147
+ },
148
+ {
149
+ name: 'enableTestMode',
150
+ signature: 'enableTestMode(): void',
151
+ stage: 'builder',
152
+ summary: 'Enables structural mock registration for tests.',
153
+ constraints: [
154
+ 'Allowed only before the first get().',
155
+ ],
156
+ },
157
+ {
158
+ name: 'register',
159
+ signature: 'register(cdc: string, mock: unknown): void',
160
+ stage: 'builder',
161
+ summary: 'Registers a mock by canonical DepId identity after parsing the provided CDC.',
162
+ constraints: [
163
+ 'Allowed only before the first get().',
164
+ 'Requires enableTestMode() first.',
165
+ ],
166
+ },
167
+ {
168
+ name: 'get',
169
+ signature: 'get(cdc: string): Promise<any>',
170
+ stage: 'runtime',
171
+ summary: 'Parses, resolves, instantiates, postprocesses, wraps, applies lifecycle, freezes, and returns a linked value.',
172
+ constraints: [
173
+ 'The first get() locks configuration and creates internal infrastructure.',
174
+ 'Any fatal pipeline error moves the container into failed state.',
175
+ 'All subsequent get() calls reject once the container is failed.',
176
+ ],
177
+ },
178
+ ],
179
+ },
180
+ {
181
+ alias: 'TeqFw_Di_Config_NamespaceRegistry',
182
+ kind: 'class',
183
+ role: 'Composition-stage helper that discovers namespace roots from the root package and installed npm dependencies.',
184
+ imports: [
185
+ {
186
+ specifier: '@teqfw/di/src/Config/NamespaceRegistry.mjs',
187
+ exportName: 'default',
188
+ canonical: true,
189
+ },
190
+ ],
191
+ methods: [
192
+ {
193
+ name: 'constructor',
194
+ signature: 'new NamespaceRegistry({ fs, path, appRoot })',
195
+ stage: 'composition',
196
+ summary: 'Creates a registry builder over filesystem and path adapters.',
197
+ constraints: [
198
+ 'Intended for composition root code, not for DI-managed runtime modules.',
199
+ 'Consumes static package.json metadata only.',
200
+ ],
201
+ },
202
+ {
203
+ name: 'build',
204
+ signature: 'build(): Promise<ReadonlyArray<{ prefix: string; dirAbs: string; ext: string }>>',
205
+ stage: 'composition',
206
+ summary: 'Builds an immutable namespace registry sorted by descending prefix length.',
207
+ constraints: [
208
+ 'Fails fast on invalid namespace metadata or duplicate canonical prefixes.',
209
+ ],
210
+ },
211
+ ],
212
+ },
213
+ ],
214
+ structuralContracts: [
215
+ {
216
+ name: 'DepId DTO',
217
+ kind: 'dto',
218
+ aliases: ['TeqFw_Di_DepId$DTO', 'TeqFw_Di_Dto_DepId$DTO'],
219
+ summary: 'Canonical structural dependency identity passed to preprocess hooks and expected from custom parsers.',
220
+ fields: {
221
+ moduleName: 'Logical module identifier without platform prefix.',
222
+ platform: '"teq" | "node" | "npm".',
223
+ exportName: 'Named export or "default"; null means whole-module/as-is resolution.',
224
+ composition: '"A" | "F" in the current implementation.',
225
+ life: '"S" | "T" | null in the current implementation.',
226
+ wrappers: 'Ordered wrapper export names.',
227
+ origin: 'Original CDC string for diagnostics.',
228
+ },
229
+ notes: [
230
+ 'Identity excludes origin.',
231
+ 'Consumers should treat it as a structural protocol, not as a factory import surface.',
232
+ ],
233
+ },
234
+ {
235
+ name: 'Parser Protocol',
236
+ kind: 'protocol',
237
+ aliases: ['TeqFw_Di_Def_Parser'],
238
+ summary: 'Structural contract accepted by Container.setParser().',
239
+ fields: {
240
+ parse: '(cdc: string) => TeqFw_Di_DepId$DTO',
241
+ },
242
+ notes: [
243
+ 'The package does not export the default parser runtime class through package exports.',
244
+ 'External code may provide any object that satisfies the parse() contract.',
245
+ ],
246
+ },
247
+ {
248
+ name: 'DepId Enums',
249
+ kind: 'enum',
250
+ aliases: [
251
+ 'TeqFw_Di_Enum_Composition',
252
+ 'TeqFw_Di_Enum_Life',
253
+ 'TeqFw_Di_Enum_Platform',
254
+ ],
255
+ summary: 'Current implementation literals used inside DepId DTO values.',
256
+ values: {
257
+ composition: 'AS_IS -> "A", FACTORY -> "F"',
258
+ life: 'SINGLETON -> "S", TRANSIENT -> "T"',
259
+ platform: 'TEQ -> "teq", NODE -> "node", NPM -> "npm"',
260
+ },
261
+ notes: [
262
+ 'These aliases are useful for tooling and JSDoc, not for runtime imports from the package.',
263
+ ],
264
+ },
265
+ {
266
+ name: 'Module Contract',
267
+ kind: 'module-contract',
268
+ summary: 'Shape expected from application modules resolved by the container.',
269
+ fields: {
270
+ __deps__: 'Optional top-level Record<string, string> mapping constructor keys to CDC strings.',
271
+ moduleNamespace: 'Whole ES module namespace object returned for as-is CDC without selected export.',
272
+ 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 functions.',
274
+ wrapperExport: 'Named export whose identifier appears in depId.wrappers; it must be synchronous and unary.',
275
+ },
276
+ notes: [
277
+ 'The current runtime reads namespace.__deps__ directly; it does not use export-scoped dependency maps.',
278
+ 'Wrapper functions are exported by the same resolved module namespace, not registered globally in the container.',
279
+ ],
280
+ },
281
+ ],
282
+ typeMapClassification: [
283
+ {
284
+ alias: 'TeqFw_Di_Config_NamespaceRegistry',
285
+ source: './src/Config/NamespaceRegistry.mjs',
286
+ exposure: 'public-runtime',
287
+ reason: 'Exported through package.json exports as a supported subpath entrypoint.',
288
+ canonicalUse: 'Composition-stage helper imported from @teqfw/di/src/Config/NamespaceRegistry.mjs.',
289
+ },
290
+ {
291
+ alias: 'TeqFw_Di_Container',
292
+ source: './src/Container.mjs',
293
+ exposure: 'public-runtime',
294
+ reason: 'Default export of the package root and of the explicit source subpath.',
295
+ canonicalUse: 'Primary container API imported from @teqfw/di.',
296
+ },
297
+ {
298
+ alias: 'TeqFw_Di_Container_Instantiate_ExportSelector',
299
+ source: './src/Container/Instantiate/ExportSelector.mjs',
300
+ exposure: 'internal',
301
+ reason: 'Internal immutable-core helper. Not exported via package.json.',
302
+ },
303
+ {
304
+ alias: 'TeqFw_Di_Container_Instantiate_Instantiator',
305
+ source: './src/Container/Instantiate/Instantiator.mjs',
306
+ exposure: 'internal',
307
+ reason: 'Internal immutable-core helper. Not exported via package.json.',
308
+ },
309
+ {
310
+ alias: 'TeqFw_Di_Container_Lifecycle_Registry',
311
+ source: './src/Container/Lifecycle/Registry.mjs',
312
+ exposure: 'internal',
313
+ reason: 'Internal lifecycle cache component. Not exported via package.json.',
314
+ },
315
+ {
316
+ alias: 'TeqFw_Di_Container_Resolve_GraphResolver',
317
+ source: './src/Container/Resolve/GraphResolver.mjs',
318
+ exposure: 'internal',
319
+ reason: 'Internal graph builder used by Container.get(). Not exported via package.json.',
320
+ },
321
+ {
322
+ alias: 'TeqFw_Di_Container_Wrapper_Executor',
323
+ source: './src/Container/Wrapper/Executor.mjs',
324
+ exposure: 'internal',
325
+ reason: 'Internal wrapper-stage executor. Not exported via package.json.',
326
+ },
327
+ {
328
+ alias: 'TeqFw_Di_Def_Parser',
329
+ source: './src/Def/Parser.mjs',
330
+ exposure: 'public-structural',
331
+ reason: 'Container.setParser() accepts this structural contract, but the runtime class is not importable from the package.',
332
+ canonicalUse: 'Typing/protocol alias for custom parser implementations.',
333
+ },
334
+ {
335
+ alias: 'TeqFw_Di_DepId',
336
+ source: './src/Dto/DepId.mjs',
337
+ exposure: 'internal',
338
+ reason: 'Factory class behind the DepId DTO module. Not needed for the supported package runtime API.',
339
+ sameAs: ['TeqFw_Di_Dto_DepId'],
340
+ },
341
+ {
342
+ alias: 'TeqFw_Di_DepId$DTO',
343
+ source: './src/Dto/DepId.mjs#DTO',
344
+ exposure: 'public-structural',
345
+ reason: 'Public structural protocol used by preprocess hooks and parser replacement.',
346
+ canonicalUse: 'Primary type alias for canonical dependency identity.',
347
+ sameAs: ['TeqFw_Di_Dto_DepId$DTO'],
348
+ },
349
+ {
350
+ alias: 'TeqFw_Di_Dto_DepId',
351
+ source: './src/Dto/DepId.mjs',
352
+ exposure: 'internal',
353
+ reason: 'Legacy-namespaced alias of the DepId factory class; not part of the supported runtime import surface.',
354
+ sameAs: ['TeqFw_Di_DepId'],
355
+ },
356
+ {
357
+ alias: 'TeqFw_Di_Dto_DepId$DTO',
358
+ source: './src/Dto/DepId.mjs#DTO',
359
+ exposure: 'public-structural',
360
+ reason: 'Synonym of TeqFw_Di_DepId$DTO kept in the type map.',
361
+ sameAs: ['TeqFw_Di_DepId$DTO'],
362
+ },
363
+ {
364
+ alias: 'TeqFw_Di_Dto_Resolver_Config',
365
+ source: './src/Dto/Resolver/Config.mjs',
366
+ exposure: 'internal',
367
+ reason: 'Internal DTO factory used inside Container when bootstrapping Resolver.',
368
+ },
369
+ {
370
+ alias: 'TeqFw_Di_Dto_Resolver_Config$DTO',
371
+ source: './src/Dto/Resolver/Config.mjs#DTO',
372
+ exposure: 'internal',
373
+ reason: 'Internal resolver configuration DTO. External code configures the container through addNamespaceRoot() instead.',
374
+ },
375
+ {
376
+ alias: 'TeqFw_Di_Dto_Resolver_Config_Namespace',
377
+ source: './src/Dto/Resolver/Config/Namespace.mjs',
378
+ exposure: 'internal',
379
+ reason: 'Internal DTO factory for resolver namespace rules.',
380
+ },
381
+ {
382
+ alias: 'TeqFw_Di_Dto_Resolver_Config_Namespace$DTO',
383
+ source: './src/Dto/Resolver/Config/Namespace.mjs#DTO',
384
+ exposure: 'internal',
385
+ reason: 'Internal resolver namespace DTO alias retained for type-map completeness.',
386
+ sameAs: ['TeqFw_Di_Dto_Resolver_Config_Namespace$DTO$'],
387
+ },
388
+ {
389
+ alias: 'TeqFw_Di_Dto_Resolver_Config_Namespace$DTO$',
390
+ source: './src/Dto/Resolver/Config/Namespace.mjs#DTO',
391
+ exposure: 'internal',
392
+ reason: 'Duplicate DTO alias retained for compatibility inside implementation typings.',
393
+ sameAs: ['TeqFw_Di_Dto_Resolver_Config_Namespace$DTO'],
394
+ },
395
+ {
396
+ alias: 'TeqFw_Di_Enum_Composition',
397
+ source: './src/Enum/Composition.mjs',
398
+ exposure: 'public-structural',
399
+ reason: 'Useful static vocabulary for interpreting DepId.composition values.',
400
+ canonicalUse: 'Type/JSDoc vocabulary only; no package export for runtime import.',
401
+ },
402
+ {
403
+ alias: 'TeqFw_Di_Enum_Life',
404
+ source: './src/Enum/Life.mjs',
405
+ exposure: 'public-structural',
406
+ reason: 'Useful static vocabulary for interpreting DepId.life values.',
407
+ canonicalUse: 'Type/JSDoc vocabulary only; no package export for runtime import.',
408
+ },
409
+ {
410
+ alias: 'TeqFw_Di_Enum_Platform',
411
+ source: './src/Enum/Platform.mjs',
412
+ exposure: 'public-structural',
413
+ reason: 'Useful static vocabulary for interpreting DepId.platform values.',
414
+ canonicalUse: 'Type/JSDoc vocabulary only; no package export for runtime import.',
415
+ },
416
+ {
417
+ alias: 'TeqFw_Di_Internal_Logger',
418
+ source: './src/Internal/Logger.mjs',
419
+ exposure: 'internal',
420
+ reason: 'Diagnostic helper used only inside the container implementation.',
421
+ },
422
+ {
423
+ alias: 'TeqFw_Di_Resolver',
424
+ source: './src/Container/Resolver.mjs',
425
+ exposure: 'internal',
426
+ reason: 'Internal module resolver infrastructure. Consumers should configure the Container, not instantiate Resolver directly.',
427
+ },
428
+ ],
429
+ operationalNotes: [
430
+ 'Only two runtime entrypoints are supported by package.json exports: @teqfw/di and @teqfw/di/src/Config/NamespaceRegistry.mjs.',
431
+ 'Resolved values are frozen before being returned.',
432
+ 'The current runtime reads __deps__ as a flat top-level map exported by the module namespace.',
433
+ 'With the default parser, CDC without lifecycle returns the whole module namespace as-is; named export selection implies factory composition.',
434
+ 'Named wrapper exports are executed after addPostprocess() hooks and before freeze.',
435
+ 'In the current implementation, CDC markers $$ and $$$ both end up as transient/no-cache behavior.',
436
+ '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.',
437
+ ],
438
+ } as const;
439
+
440
+ export default PACKAGE_API;
package/ai/usage.md ADDED
@@ -0,0 +1,244 @@
1
+ # usage.md
2
+
3
+ Version: 20260307
4
+
5
+ ## Purpose
6
+
7
+ This document describes typical usage patterns of the container. The examples illustrate how modules declare dependencies, how the container is configured in the composition root, and how Canonical Dependency Codes (CDC) control dependency resolution, instantiation, and behavioral modification.
8
+
9
+ The container performs deterministic runtime linking of ES modules and returns frozen object graphs constructed from explicitly declared dependency contracts.
10
+
11
+ ## Module Structure
12
+
13
+ Modules intended for container linking export a default class and may export a static dependency descriptor named `__deps__`.
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:
18
+
19
+ ```js
20
+ // @ts-check
21
+
22
+ export const __deps__ = {
23
+ default: {
24
+ child: "App_Child$",
25
+ },
26
+ };
27
+
28
+ /**
29
+ * @typedef {Object} App_Root$Deps
30
+ * @property {App_Child} child
31
+ */
32
+
33
+ export default class App_Root {
34
+ /**
35
+ * @param {App_Root$Deps} deps
36
+ */
37
+ constructor({ child }) {
38
+ this.getName = function () {
39
+ return "root";
40
+ };
41
+
42
+ this.getChild = function () {
43
+ return child;
44
+ };
45
+ }
46
+ }
47
+ ```
48
+
49
+ Dependency module:
50
+
51
+ ```js
52
+ // @ts-check
53
+
54
+ export default class App_Child {
55
+ constructor() {
56
+ this.getName = function () {
57
+ return "child";
58
+ };
59
+ }
60
+ }
61
+ ```
62
+
63
+ Rules:
64
+
65
+ - if `__deps__` is absent the module has no dependencies
66
+ - `__deps__.default` describes dependencies of the default export
67
+ - keys correspond to constructor dependency names
68
+ - values are CDC identifiers
69
+ - dependencies are resolved recursively before instantiation
70
+
71
+ ## Container Configuration
72
+
73
+ The container is configured in the composition root of the application. Namespace roots define how CDC prefixes map to module locations.
74
+
75
+ ```js
76
+ import path from "node:path";
77
+ import { fileURLToPath } from "node:url";
78
+ import Container from "@teqfw/di";
79
+
80
+ const __filename = fileURLToPath(import.meta.url);
81
+ const __dirname = path.dirname(__filename);
82
+
83
+ const container = new Container();
84
+
85
+ container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
86
+ ```
87
+
88
+ Configuration must be completed before the first dependency resolution.
89
+
90
+ ## Resolving Dependencies
91
+
92
+ Dependencies are obtained using CDC identifiers.
93
+
94
+ ```js
95
+ const root = await container.get("App_Root$");
96
+ ```
97
+
98
+ The container:
99
+
100
+ - parses the CDC
101
+ - loads the module
102
+ - resolves dependencies declared in `__deps__`
103
+ - instantiates modules
104
+ - links the dependency graph
105
+ - freezes the produced value
106
+
107
+ Example usage:
108
+
109
+ ```js
110
+ console.log(root.getName());
111
+ console.log(root.getChild().getName());
112
+ console.log(Object.isFrozen(root));
113
+ ```
114
+
115
+ ## Typical CDC Usage Patterns
116
+
117
+ CDC identifiers define how the container interprets a dependency. The following patterns represent common usage scenarios.
118
+
119
+ ### Module As-Is
120
+
121
+ A CDC without lifecycle marker returns the module export as-is.
122
+
123
+ ```text
124
+ App_Service
125
+ ```
126
+
127
+ Typical usage:
128
+
129
+ - utility modules
130
+ - stateless helpers
131
+ - constant providers
132
+
133
+ Example:
134
+
135
+ ```js
136
+ const math = await container.get("App_Math");
137
+ ```
138
+
139
+ ### Singleton from Default Export
140
+
141
+ A lifecycle marker `$` creates a singleton instance.
142
+
143
+ ```text
144
+ App_Service$
145
+ ```
146
+
147
+ Typical usage:
148
+
149
+ - application services
150
+ - repositories
151
+ - infrastructure adapters
152
+
153
+ ### Transient Instance
154
+
155
+ Marker `$$` creates a new instance for every request.
156
+
157
+ ```text
158
+ App_Service$$
159
+ ```
160
+
161
+ Typical usage:
162
+
163
+ - request objects
164
+ - short-lived workers
165
+ - task processors
166
+
167
+ ### Named Export Resolution
168
+
169
+ CDC may reference a named export using the `__ExportName` segment.
170
+
171
+ ```text
172
+ App_Module__build$
173
+ ```
174
+
175
+ Typical usage:
176
+
177
+ - builders
178
+ - factory entry points
179
+ - specialized constructors
180
+
181
+ ### Wrapper Application
182
+
183
+ Wrappers modify the produced value through postprocess plugins.
184
+
185
+ ```text
186
+ App_Service$$_log_trace
187
+ ```
188
+
189
+ The container creates the dependency and applies wrappers in declared order.
190
+
191
+ Typical usage:
192
+
193
+ - logging
194
+ - tracing
195
+ - metrics collection
196
+ - behavioral instrumentation
197
+
198
+ ### Platform Dependencies
199
+
200
+ CDC may reference runtime platform modules.
201
+
202
+ ```text
203
+ node_fs
204
+ npm_lodash
205
+ ```
206
+
207
+ These identifiers provide access to Node.js built-ins and npm packages.
208
+
209
+ ### Root Graph Resolution
210
+
211
+ Applications typically resolve a single root dependency.
212
+
213
+ ```js
214
+ const root = await container.get("App_Root$");
215
+ ```
216
+
217
+ The container recursively resolves all dependencies declared through `__deps__` and constructs the object graph.
218
+
219
+ ## Wrapper-Based Behavioral Composition
220
+
221
+ 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.
222
+
223
+ Example:
224
+
225
+ ```text
226
+ App_Service$$_log
227
+ ```
228
+
229
+ The service module remains unaware of logging. The wrapper introduces cross-cutting behavior during the container postprocess stage.
230
+
231
+ This mechanism enables patterns similar to aspect-oriented programming while preserving deterministic dependency resolution.
232
+
233
+ ## Minimal Smoke Pattern
234
+
235
+ A minimal integration scenario demonstrating container operation:
236
+
237
+ ```js
238
+ const container = new Container();
239
+ container.addNamespaceRoot("Fx_", FIXTURE_DIR, ".mjs");
240
+
241
+ const value = await container.get("Fx_Root$");
242
+ ```
243
+
244
+ The container loads modules, resolves dependencies, instantiates objects, and returns a frozen result.
package/jsconfig.json CHANGED
@@ -3,11 +3,11 @@
3
3
  "baseUrl": ".",
4
4
  "checkJs": true,
5
5
  "forceConsistentCasingInFileNames": true,
6
- "module": "ESNext",
7
- "moduleResolution": "node",
6
+ "module": "nodenext",
7
+ "moduleResolution": "nodenext",
8
8
  "noEmit": true,
9
9
  "skipLibCheck": true,
10
- "target": "ES2022"
10
+ "target": "ESNext"
11
11
  },
12
- "include": ["src", "types.d.ts"]
12
+ "include": ["src", "test", "types.d.ts"]
13
13
  }