@teqfw/di 2.5.1 → 2.6.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/CHANGELOG.md +14 -0
- package/README.md +430 -119
- package/ai/AGENTS.md +42 -74
- package/ai/concepts.md +11 -54
- package/ai/container.md +56 -47
- package/ai/dependency-id.md +77 -59
- package/ai/extensions.md +68 -38
- package/ai/package-api.ts +13 -11
- package/ai/usage.md +67 -207
- 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 -40
- package/src/Container/Runtime.mjs +244 -0
- package/src/Container.mjs +14 -402
- 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/types.d.ts +1 -2
- package/src/Container/Instantiate/ExportSelector.mjs +0 -44
package/README.md
CHANGED
|
@@ -3,65 +3,348 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**Enterprise-scale dependency architecture for pure JavaScript.**
|
|
7
7
|
|
|
8
|
-
`@teqfw/di`
|
|
8
|
+
`@teqfw/di` replaces fragile file-path-based wiring with namespace-based component contracts and deterministic runtime linking, so large JavaScript codebases remain understandable to humans and reconstructible by coding agents.
|
|
9
9
|
|
|
10
|
-
It is
|
|
10
|
+
It is built for pure JavaScript ES modules.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
No TypeScript metadata.
|
|
13
|
+
No decorators.
|
|
14
|
+
No reflection.
|
|
15
|
+
No framework-managed injection.
|
|
16
|
+
No transpilation requirement.
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
The package uses dependency injection techniques, but its main purpose is architectural governance, not constructor convenience.
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
## Why JavaScript Dependency Wiring Breaks at Scale
|
|
21
|
+
|
|
22
|
+
JavaScript applications usually express dependencies through static imports:
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import Repository from "../repository/UserRepository.js";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This looks simple.
|
|
29
|
+
|
|
30
|
+
But this line says two different things at once:
|
|
31
|
+
|
|
32
|
+
1. what the module needs;
|
|
33
|
+
2. where that dependency is physically located.
|
|
34
|
+
|
|
35
|
+
That coupling is acceptable in small codebases.
|
|
36
|
+
|
|
37
|
+
It becomes a structural problem when the application grows.
|
|
38
|
+
|
|
39
|
+
As modules multiply, dependency intent becomes scattered across:
|
|
40
|
+
|
|
41
|
+
- file paths;
|
|
42
|
+
- package specifiers;
|
|
43
|
+
- framework conventions;
|
|
44
|
+
- bundler configuration;
|
|
45
|
+
- generated code;
|
|
46
|
+
- decorators;
|
|
47
|
+
- local composition logic.
|
|
48
|
+
|
|
49
|
+
The architecture becomes harder to supervise because the real dependency graph is embedded inside implementation details.
|
|
50
|
+
|
|
51
|
+
A developer no longer sees a component dependency model.
|
|
52
|
+
|
|
53
|
+
The developer sees a filesystem.
|
|
54
|
+
|
|
55
|
+
## Why AI-Assisted Development Makes This More Important
|
|
56
|
+
|
|
57
|
+
Coding agents change the practical scale of JavaScript development.
|
|
58
|
+
|
|
59
|
+
One developer working with agents can now create and maintain systems whose size was previously more typical for enterprise teams.
|
|
60
|
+
|
|
61
|
+
The bottleneck is no longer only code generation.
|
|
62
|
+
|
|
63
|
+
The bottleneck is architectural control.
|
|
64
|
+
|
|
65
|
+
Agents can generate files quickly. They can modify many modules in one iteration. They can refactor local code. But if the dependency structure is hidden inside file paths and framework conventions, both the agent and the human supervisor must reconstruct architectural intent indirectly.
|
|
66
|
+
|
|
67
|
+
That does not scale well.
|
|
68
|
+
|
|
69
|
+
Large AI-assisted JavaScript systems need dependency structure that is:
|
|
70
|
+
|
|
71
|
+
- explicit;
|
|
72
|
+
- stable;
|
|
73
|
+
- reviewable;
|
|
74
|
+
- machine-readable;
|
|
75
|
+
- independent from local file layout;
|
|
76
|
+
- deterministic at runtime.
|
|
77
|
+
|
|
78
|
+
This is the problem `@teqfw/di` addresses.
|
|
79
|
+
|
|
80
|
+
## The Enterprise Shift: From Files to Components
|
|
81
|
+
|
|
82
|
+
Enterprise ecosystems such as Java and C# have long used namespaces, dependency inversion, IoC containers, component identifiers, explicit contracts, and runtime composition to keep large systems manageable.
|
|
83
|
+
|
|
84
|
+
`@teqfw/di` brings that model of thinking to pure JavaScript.
|
|
85
|
+
|
|
86
|
+
Instead of making a module depend on a file path:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
import Repository from "../repository/UserRepository.js";
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
the module declares a dependency on a component:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
export const __deps__ = {
|
|
96
|
+
repository: "App_User_Repository$",
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This declaration says:
|
|
101
|
+
|
|
102
|
+
> This module needs the `App_User_Repository` component.
|
|
103
|
+
|
|
104
|
+
It does not say where the source file is located.
|
|
105
|
+
|
|
106
|
+
The physical module location is resolved later by the container through configured namespace roots.
|
|
107
|
+
|
|
108
|
+
This is the central shift:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
from file paths
|
|
112
|
+
to component addresses
|
|
113
|
+
|
|
114
|
+
from local imports
|
|
115
|
+
to explicit dependency contracts
|
|
116
|
+
|
|
117
|
+
from scattered wiring
|
|
118
|
+
to deterministic runtime composition
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## What @teqfw/di Is
|
|
122
|
+
|
|
123
|
+
`@teqfw/di` is a runtime composition layer for pure JavaScript ES modules.
|
|
124
|
+
|
|
125
|
+
It provides:
|
|
126
|
+
|
|
127
|
+
- namespace-based component addressing;
|
|
128
|
+
- Canonical Dependency Codes;
|
|
129
|
+
- source-attached dependency declarations through `__deps__`;
|
|
130
|
+
- deterministic runtime linking;
|
|
131
|
+
- namespace root mapping for Node.js and browser environments;
|
|
132
|
+
- lifecycle control for singleton and new-instance dependencies;
|
|
133
|
+
- explicit replacement in test mode;
|
|
134
|
+
- wrapper-based extension points;
|
|
135
|
+
- immutable linked objects.
|
|
136
|
+
|
|
137
|
+
The ES module system remains the underlying loading mechanism.
|
|
138
|
+
|
|
139
|
+
The package does not replace ESM.
|
|
140
|
+
|
|
141
|
+
It replaces application-level dependency wiring through static imports.
|
|
142
|
+
|
|
143
|
+
## Product Goal
|
|
144
|
+
|
|
145
|
+
The goal of `@teqfw/di` is to make enterprise-scale dependency architecture practical in pure JavaScript.
|
|
146
|
+
|
|
147
|
+
The package gives JavaScript applications a dependency model that is:
|
|
148
|
+
|
|
149
|
+
- based on stable namespace-based component addresses;
|
|
150
|
+
- explicit in source artifacts;
|
|
151
|
+
- deterministic under finalized runtime configuration;
|
|
152
|
+
- usable across browser and Node.js environments;
|
|
153
|
+
- readable by humans;
|
|
154
|
+
- reconstructible by coding agents;
|
|
155
|
+
- independent from TypeScript metadata, decorators, reflection, and framework-managed injection.
|
|
156
|
+
|
|
157
|
+
The intended result is architectural supervision.
|
|
158
|
+
|
|
159
|
+
A developer should be able to see what a component needs without tracing import paths across the filesystem.
|
|
160
|
+
|
|
161
|
+
An agent should be able to modify code without silently destroying the dependency structure.
|
|
162
|
+
|
|
163
|
+
A runtime should be able to link components through explicit contracts rather than inference.
|
|
164
|
+
|
|
165
|
+
## Core Model
|
|
166
|
+
|
|
167
|
+
The model follows this chain:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
Namespace
|
|
171
|
+
-> Component Address
|
|
172
|
+
-> CDC
|
|
173
|
+
-> __deps__
|
|
174
|
+
-> Namespace Root
|
|
175
|
+
-> Runtime Linker
|
|
176
|
+
-> Linked Object
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
A **namespace** defines a stable application-level addressing space.
|
|
180
|
+
|
|
181
|
+
A **component address** identifies a component inside that namespace.
|
|
182
|
+
|
|
183
|
+
A **CDC** — Canonical Dependency Code — encodes the component address and linking semantics.
|
|
184
|
+
|
|
185
|
+
A module declares its dependencies through `__deps__`.
|
|
186
|
+
|
|
187
|
+
A **namespace root** maps a namespace prefix to a concrete runtime module location.
|
|
188
|
+
|
|
189
|
+
The container resolves CDC values under finalized configuration, imports the required ES modules, links declared dependencies, and returns linked objects.
|
|
190
|
+
|
|
191
|
+
The linking happens at runtime, but it is not heuristic. The container does not infer dependencies from behavior, constructor signatures, decorators, reflection, or naming guesses.
|
|
192
|
+
|
|
193
|
+
For identical dependency declarations, CDC values, namespace roots, module exports, lifecycle rules, and finalized container configuration, the container must produce the same linked result or the same failure.
|
|
194
|
+
|
|
195
|
+
## Example: File-Oriented vs Component-Oriented Wiring
|
|
196
|
+
|
|
197
|
+
Traditional JavaScript wiring:
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
import Repository from "../repository/UserRepository.js";
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
This is file-oriented.
|
|
204
|
+
|
|
205
|
+
The module depends on a concrete module specifier.
|
|
206
|
+
|
|
207
|
+
With `@teqfw/di`:
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
export const __deps__ = {
|
|
211
|
+
repository: "App_User_Repository$",
|
|
212
|
+
};
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
This is component-oriented.
|
|
216
|
+
|
|
217
|
+
The module depends on a logical component address.
|
|
218
|
+
|
|
219
|
+
The difference is not just technical.
|
|
220
|
+
|
|
221
|
+
It changes the source of architectural truth.
|
|
222
|
+
|
|
223
|
+
## Why It Matters for Coding Agents
|
|
224
|
+
|
|
225
|
+
In agent-assisted development, dependency declarations become part of the shared cognitive field between the human developer, the coding agent, and the runtime system.
|
|
226
|
+
|
|
227
|
+
A module can expose its dependency intent as data:
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
export const __deps__ = {
|
|
231
|
+
repository: "App_User_Repository$",
|
|
232
|
+
logger: "App_Logger$",
|
|
233
|
+
config: "App_Config$",
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
This structure is easy for agents to generate.
|
|
238
|
+
|
|
239
|
+
It is easy for humans to review.
|
|
240
|
+
|
|
241
|
+
It is deterministic for the container to execute.
|
|
242
|
+
|
|
243
|
+
Agent readability is not a separate feature. It is a consequence of explicit namespace-based dependency structure.
|
|
244
|
+
|
|
245
|
+
## Why It Matters for Browser and Node.js
|
|
246
|
+
|
|
247
|
+
Browser and Node.js environments both support ES modules, but they do not provide one shared application-level dependency wiring model.
|
|
248
|
+
|
|
249
|
+
Static imports usually depend on:
|
|
250
|
+
|
|
251
|
+
- file layout;
|
|
252
|
+
- package layout;
|
|
253
|
+
- URL layout;
|
|
254
|
+
- bundler behavior;
|
|
255
|
+
- runtime-specific module resolution.
|
|
256
|
+
|
|
257
|
+
`@teqfw/di` moves dependency intent away from those concrete specifiers.
|
|
258
|
+
|
|
259
|
+
The same source module can declare:
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
export const __deps__ = {
|
|
263
|
+
repository: "App_User_Repository$",
|
|
264
|
+
};
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
In Node.js, `App_` may point to a filesystem directory.
|
|
268
|
+
|
|
269
|
+
In a browser, `App_` may point to a URL base.
|
|
270
|
+
|
|
271
|
+
The dependency declaration remains stable.
|
|
272
|
+
|
|
273
|
+
Only the namespace root changes.
|
|
274
|
+
|
|
275
|
+
## Who It Is For
|
|
276
|
+
|
|
277
|
+
`@teqfw/di` is designed primarily for:
|
|
278
|
+
|
|
279
|
+
- solo developers and small teams building long-lived web applications;
|
|
280
|
+
- developers using coding agents as active implementation and maintenance participants;
|
|
281
|
+
- modular monolith applications;
|
|
17
282
|
- isomorphic JavaScript systems that share code between browser and server;
|
|
18
283
|
- pure JavaScript + JSDoc codebases;
|
|
19
|
-
- projects
|
|
284
|
+
- projects where explicit dependency structure is more important than minimal local ceremony;
|
|
285
|
+
- applications expected to grow beyond prototype size.
|
|
20
286
|
|
|
21
|
-
|
|
287
|
+
It is especially relevant when one human remains responsible for architectural supervision while agents participate in code generation, maintenance, and refactoring.
|
|
22
288
|
|
|
23
|
-
|
|
289
|
+
## When It Is Not the Best Fit
|
|
24
290
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
291
|
+
`@teqfw/di` is usually not the best fit when:
|
|
292
|
+
|
|
293
|
+
- the project is a short-lived prototype;
|
|
294
|
+
- the application is small enough for direct imports to remain clear;
|
|
295
|
+
- the team is fully committed to a decorator-driven TypeScript framework;
|
|
296
|
+
- framework conventions are more important than explicit dependency contracts;
|
|
297
|
+
- minimal local ceremony is more valuable than architectural traceability;
|
|
298
|
+
- runtime linking is not acceptable for the project’s deployment model.
|
|
31
299
|
|
|
32
|
-
|
|
300
|
+
This package is a deliberate architectural tradeoff.
|
|
301
|
+
|
|
302
|
+
It favors explicit structure over local simplicity.
|
|
33
303
|
|
|
34
304
|
## How It Fits in JavaScript
|
|
35
305
|
|
|
36
306
|
This approach is unusual in mainstream JavaScript.
|
|
37
307
|
|
|
38
|
-
Most JavaScript and TypeScript projects express dependency structure through some mix of:
|
|
308
|
+
Most JavaScript and TypeScript projects express application dependency structure through some mix of:
|
|
39
309
|
|
|
40
310
|
- static imports;
|
|
311
|
+
- file paths;
|
|
312
|
+
- package specifiers;
|
|
41
313
|
- framework conventions;
|
|
42
314
|
- TypeScript-first source architecture;
|
|
43
315
|
- decorators or metadata-driven injection;
|
|
44
|
-
- framework-managed DI
|
|
316
|
+
- framework-managed DI;
|
|
317
|
+
- bundler-controlled module graphs.
|
|
318
|
+
|
|
319
|
+
`@teqfw/di` makes a different tradeoff.
|
|
45
320
|
|
|
46
|
-
|
|
321
|
+
It favors namespace-based component addresses and explicit runtime contracts over hidden or inferred wiring.
|
|
47
322
|
|
|
48
|
-
|
|
323
|
+
TypeScript has had a major influence on the JavaScript ecosystem, and that influence has been broadly positive. At the same time, TeqFW targets a different design space:
|
|
49
324
|
|
|
50
|
-
|
|
325
|
+
- pure JavaScript + JSDoc;
|
|
326
|
+
- no transpilation requirement;
|
|
327
|
+
- isomorphic runtime behavior;
|
|
328
|
+
- namespace-based addressing;
|
|
329
|
+
- explicit dependency declarations;
|
|
330
|
+
- source artifacts readable by humans and agents.
|
|
51
331
|
|
|
52
|
-
|
|
332
|
+
This is not presented as the only correct way to structure JavaScript.
|
|
53
333
|
|
|
54
|
-
|
|
334
|
+
It is a focused alternative for projects that need stronger runtime explicitness and machine-reconstructible structure.
|
|
55
335
|
|
|
56
336
|
## Comparison
|
|
57
337
|
|
|
58
|
-
| Concern
|
|
59
|
-
|
|
|
60
|
-
| Dependency
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
338
|
+
| Concern | Common JS/TS Approach | `@teqfw/di` |
|
|
339
|
+
| -------------------------- | ----------------------------------------------------- | --------------------------------------- |
|
|
340
|
+
| Dependency expression | Static imports, decorators, framework wiring | `__deps__` declarations with CDC values |
|
|
341
|
+
| Addressing model | File-based, package-based, or framework-defined | Namespace-based component addressing |
|
|
342
|
+
| Resolution model | Static, implicit, framework-driven, or bundler-driven | Deterministic runtime linking |
|
|
343
|
+
| Structural source of truth | Spread across code, metadata, config, and conventions | Source-attached dependency contracts |
|
|
344
|
+
| Cross-environment wiring | Bundlers, adapters, duplicated specifiers | Namespace roots |
|
|
345
|
+
| Best fit | Framework-led or TypeScript-first applications | Pure JavaScript + JSDoc modular systems |
|
|
346
|
+
| Agent readability | Mixed and often indirect | Explicit and reconstructible |
|
|
347
|
+
| Architectural mindset | Local module graph | Enterprise-scale component composition |
|
|
65
348
|
|
|
66
349
|
## Installation
|
|
67
350
|
|
|
@@ -71,36 +354,35 @@ npm install @teqfw/di
|
|
|
71
354
|
|
|
72
355
|
## Quick Start
|
|
73
356
|
|
|
74
|
-
Define one
|
|
357
|
+
Define one repository module and one service module that declares the repository as an explicit dependency.
|
|
75
358
|
|
|
76
|
-
`src/App/
|
|
359
|
+
`src/App/User/Repository.mjs`
|
|
77
360
|
|
|
78
361
|
```javascript
|
|
79
|
-
export default function
|
|
80
|
-
return
|
|
81
|
-
|
|
362
|
+
export default function Repository() {
|
|
363
|
+
return {
|
|
364
|
+
async findNameById(id) {
|
|
365
|
+
return `User ${id}`;
|
|
366
|
+
},
|
|
82
367
|
};
|
|
83
368
|
}
|
|
84
369
|
```
|
|
85
370
|
|
|
86
|
-
`src/App/
|
|
371
|
+
`src/App/User/Service.mjs`
|
|
87
372
|
|
|
88
373
|
```javascript
|
|
374
|
+
export default function Service({ repository }) {
|
|
375
|
+
return {
|
|
376
|
+
async getProfile(id) {
|
|
377
|
+
const name = await repository.findNameById(id);
|
|
378
|
+
return { id, name };
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
89
383
|
export const __deps__ = {
|
|
90
|
-
|
|
384
|
+
repository: "App_User_Repository$",
|
|
91
385
|
};
|
|
92
|
-
|
|
93
|
-
export default class App_Root {
|
|
94
|
-
constructor({ cast }) {
|
|
95
|
-
return {
|
|
96
|
-
configure(params = {}) {
|
|
97
|
-
return {
|
|
98
|
-
name: cast(params.name ?? "app"),
|
|
99
|
-
};
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
386
|
```
|
|
105
387
|
|
|
106
388
|
Configure the container and request the dependency:
|
|
@@ -116,87 +398,129 @@ const __dirname = path.dirname(__filename);
|
|
|
116
398
|
const container = new Container();
|
|
117
399
|
container.addNamespaceRoot("App_", path.resolve(__dirname, "./src/App"), ".mjs");
|
|
118
400
|
|
|
119
|
-
const
|
|
401
|
+
const service = await container.get("App_User_Service$");
|
|
402
|
+
|
|
403
|
+
const profile = await service.getProfile(42);
|
|
120
404
|
|
|
121
|
-
console.log(
|
|
122
|
-
|
|
405
|
+
console.log(profile);
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Output:
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
{ id: 42, name: "User 42" }
|
|
123
412
|
```
|
|
124
413
|
|
|
125
414
|
In this flow the container:
|
|
126
415
|
|
|
127
416
|
- parses the dependency request;
|
|
128
|
-
- resolves
|
|
417
|
+
- resolves `App_` through the registered namespace root;
|
|
418
|
+
- translates `App_User_Repository$` into a concrete ES module location;
|
|
419
|
+
- imports the module;
|
|
129
420
|
- reads `__deps__` for the selected export;
|
|
130
421
|
- recursively links dependencies;
|
|
131
422
|
- returns a frozen linked object.
|
|
132
423
|
|
|
133
424
|
## Core Concepts
|
|
134
425
|
|
|
135
|
-
###
|
|
426
|
+
### Namespace
|
|
136
427
|
|
|
137
|
-
|
|
428
|
+
A namespace defines a stable addressing space for application components.
|
|
138
429
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
430
|
+
In TeqFW, a dependency address such as:
|
|
431
|
+
|
|
432
|
+
```text
|
|
433
|
+
App_User_Repository$
|
|
143
434
|
```
|
|
144
435
|
|
|
145
|
-
|
|
436
|
+
uses `App_` as a namespace prefix.
|
|
146
437
|
|
|
147
|
-
|
|
148
|
-
- each export entry maps constructor argument names to CDC strings;
|
|
149
|
-
- if `__deps__` is absent, the export has no declared dependencies;
|
|
150
|
-
- a flat `__deps__` object is shorthand for limited single-export cases.
|
|
438
|
+
The namespace makes the dependency address independent from local file paths and runtime-specific module specifiers.
|
|
151
439
|
|
|
152
|
-
|
|
440
|
+
### Component Address
|
|
153
441
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
localName: "Dependency_CDC",
|
|
161
|
-
},
|
|
162
|
-
};
|
|
442
|
+
A component address identifies an application component inside a namespace.
|
|
443
|
+
|
|
444
|
+
For example:
|
|
445
|
+
|
|
446
|
+
```text
|
|
447
|
+
App_User_Repository
|
|
163
448
|
```
|
|
164
449
|
|
|
450
|
+
identifies the `Repository` component inside the `App_` namespace.
|
|
451
|
+
|
|
452
|
+
The component address is logical.
|
|
453
|
+
|
|
454
|
+
It is not itself a file path or URL.
|
|
455
|
+
|
|
165
456
|
### CDC
|
|
166
457
|
|
|
167
458
|
A **Canonical Dependency Code** is the string contract used to request a dependency.
|
|
168
459
|
|
|
169
460
|
General form:
|
|
170
461
|
|
|
171
|
-
```
|
|
462
|
+
```text
|
|
172
463
|
[PlatformPrefix]ModuleName[__ExportName][LifecycleAndWrappers]
|
|
173
464
|
```
|
|
174
465
|
|
|
175
466
|
Examples:
|
|
176
467
|
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
468
|
+
```text
|
|
469
|
+
App_User_Repository$
|
|
470
|
+
App_User_Repository__Factory$$
|
|
180
471
|
node:fs
|
|
181
472
|
npm:lodash
|
|
182
473
|
```
|
|
183
474
|
|
|
184
475
|
Where:
|
|
185
476
|
|
|
477
|
+
- `App_User_Repository` is the namespace-based component address;
|
|
186
478
|
- `__Factory` selects a named export;
|
|
187
479
|
- `$` means singleton lifecycle;
|
|
188
480
|
- `$$` means new instance lifecycle;
|
|
189
481
|
- `node:` and `npm:` address platform-specific modules.
|
|
190
482
|
|
|
483
|
+
### `__deps__`
|
|
484
|
+
|
|
485
|
+
`__deps__` is a source-attached dependency declaration.
|
|
486
|
+
|
|
487
|
+
For a single-export module, dependencies can be declared in shorthand form:
|
|
488
|
+
|
|
489
|
+
```javascript
|
|
490
|
+
export const __deps__ = {
|
|
491
|
+
localName: "Dependency_CDC",
|
|
492
|
+
};
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Rules:
|
|
496
|
+
|
|
497
|
+
- the canonical form is hierarchical and keyed by export name;
|
|
498
|
+
- each export entry maps constructor argument names to CDC strings;
|
|
499
|
+
- if `__deps__` is absent, the export has no declared dependencies;
|
|
500
|
+
- a flat `__deps__` object is shorthand for limited single-export cases.
|
|
501
|
+
|
|
502
|
+
Canonical export-scoped form:
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
export const __deps__ = {
|
|
506
|
+
default: {
|
|
507
|
+
localName: "Dependency_CDC",
|
|
508
|
+
},
|
|
509
|
+
Factory: {
|
|
510
|
+
localName: "Dependency_CDC",
|
|
511
|
+
},
|
|
512
|
+
};
|
|
513
|
+
```
|
|
514
|
+
|
|
191
515
|
### Namespace Root
|
|
192
516
|
|
|
193
|
-
A namespace root maps a
|
|
517
|
+
A namespace root maps a namespace prefix to a module-specifier base:
|
|
194
518
|
|
|
195
519
|
```javascript
|
|
196
520
|
container.addNamespaceRoot("App_", "/abs/path/to/src/App", ".mjs");
|
|
197
521
|
```
|
|
198
522
|
|
|
199
|
-
This lets the container translate logical module names such as `
|
|
523
|
+
This lets the container translate logical module names such as `App_User_Repository$` into concrete ES module files or URL-based module specifiers.
|
|
200
524
|
|
|
201
525
|
In Node.js, that often means filesystem-backed module roots:
|
|
202
526
|
|
|
@@ -204,7 +528,7 @@ In Node.js, that often means filesystem-backed module roots:
|
|
|
204
528
|
container.addNamespaceRoot("App_", "/project/src/App", ".mjs");
|
|
205
529
|
```
|
|
206
530
|
|
|
207
|
-
In a
|
|
531
|
+
In a browser-oriented or isomorphic application, it can also mean URL-backed roots:
|
|
208
532
|
|
|
209
533
|
```javascript
|
|
210
534
|
container.addNamespaceRoot("App_", "https://cdn.example.com/app", ".mjs");
|
|
@@ -213,6 +537,14 @@ container.addNamespaceRoot("Web_", "//cdn.example.com/web", ".mjs");
|
|
|
213
537
|
|
|
214
538
|
This keeps dependency addressing stable while allowing the same logical naming model to work across shared application code, browser-facing modules, and different runtime environments.
|
|
215
539
|
|
|
540
|
+
### Runtime Linking
|
|
541
|
+
|
|
542
|
+
Runtime linking is the process of resolving CDC values under finalized container configuration, importing the corresponding ES modules, injecting declared dependencies, and returning linked objects.
|
|
543
|
+
|
|
544
|
+
The mechanism is dynamic because it runs at runtime.
|
|
545
|
+
|
|
546
|
+
The mechanism is deterministic because dependencies are declared explicitly and resolved through fixed namespace roots and configuration.
|
|
547
|
+
|
|
216
548
|
## Public API
|
|
217
549
|
|
|
218
550
|
Create a container:
|
|
@@ -237,7 +569,9 @@ Resolve dependencies:
|
|
|
237
569
|
await container.get(cdc);
|
|
238
570
|
```
|
|
239
571
|
|
|
240
|
-
The container is builder-configurable until the first `get(...)`.
|
|
572
|
+
The container is builder-configurable until the first `get(...)`.
|
|
573
|
+
|
|
574
|
+
After that point configuration is locked.
|
|
241
575
|
|
|
242
576
|
## Test Mode
|
|
243
577
|
|
|
@@ -260,34 +594,6 @@ This keeps replacement explicit and local to container configuration.
|
|
|
260
594
|
</script>
|
|
261
595
|
```
|
|
262
596
|
|
|
263
|
-
## LLM-Oriented Development
|
|
264
|
-
|
|
265
|
-
This package is designed for codebases where LLM agents participate in implementation and maintenance.
|
|
266
|
-
|
|
267
|
-
That affects the architecture directly. In many human-oriented JavaScript codebases, local explicitness is treated as extra ceremony. Here it is a deliberate tradeoff: dependency structure stays visible where it is needed, instead of being inferred from decorators, reflection, framework conventions, or scattered configuration.
|
|
268
|
-
|
|
269
|
-
This increases local structural surface area, but it reduces ambiguity. For LLM-driven maintenance, that makes dependency structure easier to reconstruct, edit, and verify from source code alone.
|
|
270
|
-
|
|
271
|
-
## When This Fits
|
|
272
|
-
|
|
273
|
-
This approach is a good fit when you want:
|
|
274
|
-
|
|
275
|
-
- a modular monolith with explicit component boundaries;
|
|
276
|
-
- shared JavaScript code across browser and Node.js;
|
|
277
|
-
- runtime late binding instead of static application wiring;
|
|
278
|
-
- explicit, machine-readable dependency structure;
|
|
279
|
-
- a pure JavaScript + JSDoc stack instead of TypeScript-first architecture.
|
|
280
|
-
|
|
281
|
-
## When It Probably Does Not
|
|
282
|
-
|
|
283
|
-
This approach is probably a poor fit when:
|
|
284
|
-
|
|
285
|
-
- your project is deeply committed to TypeScript-first conventions;
|
|
286
|
-
- you prefer decorator-based or framework-managed injection;
|
|
287
|
-
- your team values minimal local ceremony over explicit structural contracts;
|
|
288
|
-
- you do not need isomorphic runtime structure or late binding;
|
|
289
|
-
- the codebase is optimized only for human authorship and not for machine-assisted maintenance.
|
|
290
|
-
|
|
291
597
|
## Documentation for Agents
|
|
292
598
|
|
|
293
599
|
This package includes a machine-oriented package interface under `./ai/`.
|
|
@@ -299,20 +605,25 @@ Those files are intended for system prompts, examples, and agent consumption. Th
|
|
|
299
605
|
- CDC behavior;
|
|
300
606
|
- integration patterns.
|
|
301
607
|
|
|
302
|
-
|
|
608
|
+
The package ships both a human-facing README and a machine-oriented interface for agents that need to use it as a dependency.
|
|
303
609
|
|
|
304
610
|
## Further Reading
|
|
305
611
|
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
-
|
|
309
|
-
-
|
|
310
|
-
-
|
|
311
|
-
- Container implementation contract: `ctx/docs/code/components/container.md`
|
|
612
|
+
- Usage guide: `ai/usage.md`
|
|
613
|
+
- Container API notes: `ai/container.md`
|
|
614
|
+
- Dependency descriptor concepts: `ai/concepts.md`
|
|
615
|
+
- Dependency ID format: `ai/dependency-id.md`
|
|
616
|
+
- Extension points: `ai/extensions.md`
|
|
312
617
|
- Project philosophy and intended application domain: `PHILOSOPHY.md`
|
|
313
618
|
|
|
314
619
|
## TeqFW Context
|
|
315
620
|
|
|
316
|
-
`@teqfw/di` is the core building block of the Tequila Framework
|
|
621
|
+
`@teqfw/di` is the core dependency-linking building block of the Tequila Framework.
|
|
622
|
+
|
|
623
|
+
TeqFW is aimed at building modular monolith web applications with a unified JavaScript codebase across browser and server runtimes. The method favors namespace-based component addressing, late binding, explicit contracts, pure JavaScript, and source artifacts that remain legible to both humans and LLM agents.
|
|
624
|
+
|
|
625
|
+
The broader TeqFW position is that AI-assisted development changes not only how code is written, but also what kind of structure a solo developer needs in order to supervise a growing application.
|
|
626
|
+
|
|
627
|
+
When JavaScript applications reach enterprise scale under human-agent development, file-path-based dependency wiring becomes too local and too implicit.
|
|
317
628
|
|
|
318
|
-
|
|
629
|
+
`@teqfw/di` is one concrete answer to that change: enterprise-scale dependency architecture for pure JavaScript.
|