inwire 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -106,7 +106,8 @@ app.db; // safe to use, fully initialized
106
106
  - **Smart errors** — 7 error types, each with `hint`, `details`, and fuzzy matching ("did you mean `userService`?"). Designed for both humans and LLMs to parse.
107
107
  - **Built-in introspection** — `inspect()` returns a serializable JSON graph. Feed it to an LLM, render it in a dashboard, or use `health()` to catch scope mismatches at runtime.
108
108
  - **Runtime agnostic** — pure ES2022. No decorators, no `reflect-metadata`, no compiler plugins. Works in Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge, and browsers.
109
- - **Tiny** — 3.2 KB gzip, zero dependencies.
109
+ - **Clean internals** — Clean Architecture, SOLID, single-responsibility files. Open any file, understand it, change it without fear.
110
+ - **Tiny** — ~4 KB gzip, zero dependencies.
110
111
 
111
112
  ## Features
112
113
 
@@ -346,23 +347,31 @@ detectDuplicateKeys(authModule, userModule);
346
347
 
347
348
  ## Architecture
348
349
 
350
+ Clean Architecture / SOLID internals. The dependency rule is enforced: `domain/` has zero imports from other layers.
351
+
349
352
  ```
350
353
  src/
351
- index.ts # barrel export
352
- domain/
353
- types.ts # interfaces, types, RESERVED_KEYS
354
- errors.ts # 7 error classes + ScopeMismatchWarning
355
- lifecycle.ts # OnInit / OnDestroy interfaces
354
+ index.ts # public barrel — only file consumers import
355
+ domain/ # pure contracts — no framework deps
356
+ types.ts # interfaces (IResolver, ICycleDetector, IDependencyTracker, IValidator)
357
+ errors.ts # 7 error classes + 2 warning types, each with hint + details
358
+ lifecycle.ts # OnInit / OnDestroy (duck-typed)
356
359
  validation.ts # Validator, detectDuplicateKeys, Levenshtein
357
- infrastructure/
358
- resolver.ts # Resolver (Proxy handler, cache, cycle detection)
359
- transient.ts # transient() marker
360
- application/
361
- container-builder.ts # ContainerBuilder class + container() function
362
- container-proxy.ts # buildContainerProxy + scope/extend inline
360
+ infrastructure/ # low-level mechanisms — depends on domain/ only
361
+ resolver.ts # lazy resolution, singleton cache, parent chain
362
+ cycle-detector.ts # circular dependency detection
363
+ dependency-tracker.ts # tracking Proxy + dependency graph builder
364
+ transient.ts # transient() marker (Symbol-based)
365
+ application/ # use cases + orchestration — depends on domain/ + infrastructure/
366
+ container-builder.ts # fluent builder + container() factory
367
+ container-proxy.ts # Proxy construction, scope/extend/reset
368
+ preloader.ts # topological sort (Kahn) + parallel onInit
369
+ disposer.ts # reverse-order onDestroy + cleanup
363
370
  introspection.ts # inspect, describe, health, toString
364
371
  ```
365
372
 
373
+ Each file has a single responsibility. The Resolver receives its collaborators (`CycleDetector`, `DependencyTracker`) via constructor injection — no internal `new`, no hidden coupling. `Preloader`, `Disposer`, and `Introspection` depend on the `IResolver` interface, not the concrete class.
374
+
366
375
  ## LLM / AI Integration
367
376
 
368
377
  This package ships with [llms.txt](https://llmstxt.org/) files for AI-assisted development:
package/dist/index.d.mts CHANGED
@@ -1,3 +1,179 @@
1
+ //#region src/domain/errors.d.ts
2
+ /**
3
+ * Base class for all container errors.
4
+ * Every error includes a human-readable `hint` and structured `details`
5
+ * so that AI tools and developers can auto-correct issues.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * try { container.userService; }
10
+ * catch (e) {
11
+ * if (e instanceof ContainerError) {
12
+ * console.log(e.hint); // actionable fix
13
+ * console.log(e.details); // structured context
14
+ * }
15
+ * }
16
+ * ```
17
+ */
18
+ declare abstract class ContainerError extends Error {
19
+ abstract readonly hint: string;
20
+ abstract readonly details: Record<string, unknown>;
21
+ constructor(message: string);
22
+ }
23
+ /**
24
+ * Thrown when a non-function value is passed in the deps definition.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * container().add('apiKey', 'sk-123');
29
+ * // ContainerConfigError: 'apiKey' must be a factory function, got string.
30
+ * // hint: "Wrap it: apiKey: () => 'sk-123'"
31
+ * ```
32
+ */
33
+ declare class ContainerConfigError extends ContainerError {
34
+ readonly hint: string;
35
+ readonly details: {
36
+ key: string;
37
+ actualType: string;
38
+ };
39
+ constructor(key: string, actualType: string);
40
+ }
41
+ /**
42
+ * Thrown when a reserved container method name is used as a dependency key.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * container().add('inspect', () => 'foo');
47
+ * // ReservedKeyError: 'inspect' is a reserved container method.
48
+ * // hint: "Rename this dependency, e.g. 'inspectService' or 'dataInspector'."
49
+ * ```
50
+ */
51
+ declare class ReservedKeyError extends ContainerError {
52
+ readonly hint: string;
53
+ readonly details: {
54
+ key: string;
55
+ reserved: string[];
56
+ };
57
+ constructor(key: string, reserved: readonly string[]);
58
+ }
59
+ /**
60
+ * Thrown when a dependency cannot be found during resolution.
61
+ * Includes fuzzy suggestion if a similar key exists.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * container.userService;
66
+ * // ProviderNotFoundError: Cannot resolve 'userService': dependency 'userRepo' not found.
67
+ * // hint: "Did you mean 'userRepository'?"
68
+ * ```
69
+ */
70
+ declare class ProviderNotFoundError extends ContainerError {
71
+ readonly hint: string;
72
+ readonly details: {
73
+ key: string;
74
+ chain: string[];
75
+ registered: string[];
76
+ suggestion: string | undefined;
77
+ };
78
+ constructor(key: string, chain: string[], registered: string[], suggestion?: string);
79
+ }
80
+ /**
81
+ * Thrown when a circular dependency is detected.
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // CircularDependencyError: Circular dependency detected while resolving 'authService'.
86
+ * // Cycle: authService -> userService -> authService
87
+ * ```
88
+ */
89
+ declare class CircularDependencyError extends ContainerError {
90
+ readonly hint: string;
91
+ readonly details: {
92
+ key: string;
93
+ chain: string[];
94
+ cycle: string;
95
+ };
96
+ constructor(key: string, chain: string[]);
97
+ }
98
+ /**
99
+ * Thrown when a factory function returns `undefined`.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * container.db;
104
+ * // UndefinedReturnError: Factory 'db' returned undefined.
105
+ * // hint: "Did you forget a return statement?"
106
+ * ```
107
+ */
108
+ declare class UndefinedReturnError extends ContainerError {
109
+ readonly hint: string;
110
+ readonly details: {
111
+ key: string;
112
+ chain: string[];
113
+ };
114
+ constructor(key: string, chain: string[]);
115
+ }
116
+ /**
117
+ * Thrown when a factory function throws an error during resolution.
118
+ * Wraps the original error with resolution context.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * container.db;
123
+ * // FactoryError: Factory 'db' threw an error: "Connection refused"
124
+ * ```
125
+ */
126
+ declare class FactoryError extends ContainerError {
127
+ readonly hint: string;
128
+ readonly details: {
129
+ key: string;
130
+ chain: string[];
131
+ originalError: string;
132
+ };
133
+ readonly originalError: unknown;
134
+ constructor(key: string, chain: string[], originalError: unknown);
135
+ }
136
+ /**
137
+ * Warning emitted when a singleton depends on a transient dependency.
138
+ * The transient value gets frozen inside the singleton — almost always a bug.
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * // ScopeMismatchWarning: Singleton 'userService' depends on transient 'requestId'.
143
+ * ```
144
+ */
145
+ declare class ScopeMismatchWarning implements ContainerWarning {
146
+ readonly type: "scope_mismatch";
147
+ readonly message: string;
148
+ readonly hint: string;
149
+ readonly details: {
150
+ singleton: string;
151
+ transient: string;
152
+ };
153
+ constructor(singletonKey: string, transientKey: string);
154
+ }
155
+ /**
156
+ * Warning emitted when an async `onInit()` rejects during lazy resolution.
157
+ * The error is collected (not thrown) because lazy access is fire-and-forget.
158
+ * Use `preload()` to await and surface async init errors.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * // health().warnings may include:
163
+ * // { type: 'async_init_error', message: "onInit() for 'db' rejected: connection refused" }
164
+ * ```
165
+ */
166
+ declare class AsyncInitErrorWarning implements ContainerWarning {
167
+ readonly type: "async_init_error";
168
+ readonly message: string;
169
+ readonly hint: string;
170
+ readonly details: {
171
+ key: string;
172
+ error: string;
173
+ };
174
+ constructor(key: string, error: unknown);
175
+ }
176
+ //#endregion
1
177
  //#region src/domain/types.d.ts
2
178
  /**
3
179
  * A factory function that receives the container and returns an instance.
@@ -32,11 +208,11 @@ interface ScopeOptions {
32
208
  * c.inspect(); // ContainerGraph
33
209
  * ```
34
210
  */
35
- type Container<T extends Record<string, unknown> = Record<string, unknown>> = T & IContainer<T>;
211
+ type Container<T extends Record<string, any> = Record<string, unknown>> = T & IContainer<T>;
36
212
  /**
37
213
  * Container methods interface. Defines the API available on every container.
38
214
  */
39
- interface IContainer<T extends Record<string, unknown> = Record<string, unknown>> {
215
+ interface IContainer<T extends Record<string, any> = Record<string, unknown>> {
40
216
  /**
41
217
  * Creates a child container with additional dependencies.
42
218
  * Child inherits all parent singletons and can add/override deps.
@@ -75,7 +251,7 @@ interface IContainer<T extends Record<string, unknown> = Record<string, unknown>
75
251
  * );
76
252
  * ```
77
253
  */
78
- module<TNew extends Record<string, unknown>>(fn: (builder: ContainerBuilder<Record<string, unknown>, T>) => ContainerBuilder<Record<string, unknown>, TNew>): Container<TNew>;
254
+ module<TNew extends Record<string, any>>(fn: (builder: ContainerBuilder<Record<string, unknown>, T>) => ContainerBuilder<Record<string, unknown>, TNew>): Container<TNew>;
79
255
  /**
80
256
  * Pre-resolves dependencies (warm-up).
81
257
  * Call with specific keys to resolve only those, or without arguments to resolve all.
@@ -185,7 +361,7 @@ interface ContainerWarning {
185
361
  * Each `.add()` call accumulates the type so that subsequent factories
186
362
  * receive a fully-typed `c` parameter with all previously registered deps.
187
363
  */
188
- declare class ContainerBuilder<TContract extends Record<string, unknown> = Record<string, unknown>, TBuilt extends Record<string, unknown> = {}> {
364
+ declare class ContainerBuilder<TContract extends Record<string, any> = Record<string, unknown>, TBuilt extends Record<string, any> = {}> {
189
365
  private readonly factories;
190
366
  /**
191
367
  * Registers a dependency — factory (lazy) or instance (eager).
@@ -202,7 +378,7 @@ declare class ContainerBuilder<TContract extends Record<string, unknown> = Recor
202
378
  * Applies a module — a function that chains `.add()` calls on this builder.
203
379
  * `c` in the module's factories is fully typed with all previously registered deps.
204
380
  */
205
- addModule<TNew extends Record<string, unknown>>(module: (builder: ContainerBuilder<TContract, TBuilt>) => ContainerBuilder<TContract, TNew>): ContainerBuilder<TContract, TNew>;
381
+ addModule<TNew extends Record<string, any>>(module: (builder: ContainerBuilder<TContract, TBuilt>) => ContainerBuilder<TContract, TNew>): ContainerBuilder<TContract, TNew>;
206
382
  /**
207
383
  * Returns the accumulated factories as a plain record.
208
384
  * @internal Used by `module()` on the container.
@@ -235,183 +411,7 @@ declare class ContainerBuilder<TContract extends Record<string, unknown> = Recor
235
411
  * .build()
236
412
  * ```
237
413
  */
238
- declare function container<T extends Record<string, unknown> = Record<string, unknown>>(): ContainerBuilder<T>;
239
- //#endregion
240
- //#region src/domain/errors.d.ts
241
- /**
242
- * Base class for all container errors.
243
- * Every error includes a human-readable `hint` and structured `details`
244
- * so that AI tools and developers can auto-correct issues.
245
- *
246
- * @example
247
- * ```typescript
248
- * try { container.userService; }
249
- * catch (e) {
250
- * if (e instanceof ContainerError) {
251
- * console.log(e.hint); // actionable fix
252
- * console.log(e.details); // structured context
253
- * }
254
- * }
255
- * ```
256
- */
257
- declare abstract class ContainerError extends Error {
258
- abstract readonly hint: string;
259
- abstract readonly details: Record<string, unknown>;
260
- constructor(message: string);
261
- }
262
- /**
263
- * Thrown when a non-function value is passed in the deps definition.
264
- *
265
- * @example
266
- * ```typescript
267
- * container().add('apiKey', 'sk-123');
268
- * // ContainerConfigError: 'apiKey' must be a factory function, got string.
269
- * // hint: "Wrap it: apiKey: () => 'sk-123'"
270
- * ```
271
- */
272
- declare class ContainerConfigError extends ContainerError {
273
- readonly hint: string;
274
- readonly details: {
275
- key: string;
276
- actualType: string;
277
- };
278
- constructor(key: string, actualType: string);
279
- }
280
- /**
281
- * Thrown when a reserved container method name is used as a dependency key.
282
- *
283
- * @example
284
- * ```typescript
285
- * container().add('inspect', () => 'foo');
286
- * // ReservedKeyError: 'inspect' is a reserved container method.
287
- * // hint: "Rename this dependency, e.g. 'inspectService' or 'dataInspector'."
288
- * ```
289
- */
290
- declare class ReservedKeyError extends ContainerError {
291
- readonly hint: string;
292
- readonly details: {
293
- key: string;
294
- reserved: string[];
295
- };
296
- constructor(key: string, reserved: readonly string[]);
297
- }
298
- /**
299
- * Thrown when a dependency cannot be found during resolution.
300
- * Includes fuzzy suggestion if a similar key exists.
301
- *
302
- * @example
303
- * ```typescript
304
- * container.userService;
305
- * // ProviderNotFoundError: Cannot resolve 'userService': dependency 'userRepo' not found.
306
- * // hint: "Did you mean 'userRepository'?"
307
- * ```
308
- */
309
- declare class ProviderNotFoundError extends ContainerError {
310
- readonly hint: string;
311
- readonly details: {
312
- key: string;
313
- chain: string[];
314
- registered: string[];
315
- suggestion: string | undefined;
316
- };
317
- constructor(key: string, chain: string[], registered: string[], suggestion?: string);
318
- }
319
- /**
320
- * Thrown when a circular dependency is detected.
321
- *
322
- * @example
323
- * ```typescript
324
- * // CircularDependencyError: Circular dependency detected while resolving 'authService'.
325
- * // Cycle: authService -> userService -> authService
326
- * ```
327
- */
328
- declare class CircularDependencyError extends ContainerError {
329
- readonly hint: string;
330
- readonly details: {
331
- key: string;
332
- chain: string[];
333
- cycle: string;
334
- };
335
- constructor(key: string, chain: string[]);
336
- }
337
- /**
338
- * Thrown when a factory function returns `undefined`.
339
- *
340
- * @example
341
- * ```typescript
342
- * container.db;
343
- * // UndefinedReturnError: Factory 'db' returned undefined.
344
- * // hint: "Did you forget a return statement?"
345
- * ```
346
- */
347
- declare class UndefinedReturnError extends ContainerError {
348
- readonly hint: string;
349
- readonly details: {
350
- key: string;
351
- chain: string[];
352
- };
353
- constructor(key: string, chain: string[]);
354
- }
355
- /**
356
- * Thrown when a factory function throws an error during resolution.
357
- * Wraps the original error with resolution context.
358
- *
359
- * @example
360
- * ```typescript
361
- * container.db;
362
- * // FactoryError: Factory 'db' threw an error: "Connection refused"
363
- * ```
364
- */
365
- declare class FactoryError extends ContainerError {
366
- readonly hint: string;
367
- readonly details: {
368
- key: string;
369
- chain: string[];
370
- originalError: string;
371
- };
372
- readonly originalError: unknown;
373
- constructor(key: string, chain: string[], originalError: unknown);
374
- }
375
- /**
376
- * Warning emitted when a singleton depends on a transient dependency.
377
- * The transient value gets frozen inside the singleton — almost always a bug.
378
- *
379
- * @example
380
- * ```typescript
381
- * // ScopeMismatchWarning: Singleton 'userService' depends on transient 'requestId'.
382
- * ```
383
- */
384
- declare class ScopeMismatchWarning implements ContainerWarning {
385
- readonly type: "scope_mismatch";
386
- readonly message: string;
387
- readonly hint: string;
388
- readonly details: {
389
- singleton: string;
390
- transient: string;
391
- };
392
- constructor(singletonKey: string, transientKey: string);
393
- }
394
- /**
395
- * Warning emitted when an async `onInit()` rejects during lazy resolution.
396
- * The error is collected (not thrown) because lazy access is fire-and-forget.
397
- * Use `preload()` to await and surface async init errors.
398
- *
399
- * @example
400
- * ```typescript
401
- * // health().warnings may include:
402
- * // { type: 'async_init_error', message: "onInit() for 'db' rejected: connection refused" }
403
- * ```
404
- */
405
- declare class AsyncInitErrorWarning implements ContainerWarning {
406
- readonly type: "async_init_error";
407
- readonly message: string;
408
- readonly hint: string;
409
- readonly details: {
410
- key: string;
411
- error: string;
412
- };
413
- constructor(key: string, error: unknown);
414
- }
414
+ declare function container<T extends Record<string, any> = Record<string, unknown>>(): ContainerBuilder<T>;
415
415
  //#endregion
416
416
  //#region src/domain/lifecycle.d.ts
417
417
  /**
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  var e=class extends Error{constructor(e){super(e),this.name=this.constructor.name}},t=class extends e{hint;details;constructor(e,t){super(`'${e}' must be a factory function, got ${t}.`),this.hint=`Wrap it: ${e}: () => <your ${t} value>`,this.details={key:e,actualType:t}}},n=class extends e{hint;details;constructor(e,t){super(`'${e}' is a reserved container method.`),this.hint=`Rename this dependency, e.g. '${e}Service' or 'my${e[0].toUpperCase()}${e.slice(1)}'.`,this.details={key:e,reserved:[...t]}}},r=class extends e{hint;details;constructor(e,t,n,r){let i=t.length>0?`\n\nResolution chain: ${[...t,`${e} (not found)`].join(` -> `)}`:``,a=`\nRegistered keys: [${n.join(`, `)}]`,o=r?`\n\nDid you mean '${r}'?`:``;super(`Cannot resolve '${t[0]??e}': dependency '${e}' not found.${i}${a}${o}`);let s=`.add('${e}', (c) => new ${e[0].toUpperCase()}${e.slice(1)}(/* deps */))`;this.hint=r?`Did you mean '${r}'? Or add '${e}' to your container:\n container()${s}`:`Add '${e}' to your container:\n container()${s}`,this.details={key:e,chain:t,registered:n,suggestion:r}}},i=class extends e{hint;details;constructor(e,t){let n=[...t,e].join(` -> `);super(`Circular dependency detected while resolving '${t[0]}'.\n\nCycle: ${n}`),this.hint=[`To fix:`,` 1. Extract shared logic into a new dependency both can use`,` 2. Restructure so one doesn't depend on the other`,` 3. Use a mediator/event pattern to decouple them`].join(`
2
2
  `),this.details={key:e,chain:t,cycle:n}}},a=class extends e{hint;details;constructor(e,t){let n=t.length>1?`\n\nResolution chain: ${t.join(` -> `)}`:``;super(`Factory '${e}' returned undefined.${n}`),this.hint=`Your factory function returned undefined. Did you forget a return statement?`,this.details={key:e,chain:t}}},o=class extends e{hint;details;originalError;constructor(e,t,n){let r=n instanceof Error?n.message:String(n),i=t.length>1?`\n\nResolution chain: ${[...t.slice(0,-1),`${e} (factory threw)`].join(` -> `)}`:``;super(`Factory '${e}' threw an error: "${r}"${i}`),this.hint=`Check the factory function for '${e}'. The error occurred during instantiation.`,this.details={key:e,chain:t,originalError:r},this.originalError=n}},s=class{type=`scope_mismatch`;message;hint;details;constructor(e,t){this.message=`Singleton '${e}' depends on transient '${t}'.`,this.hint=[`The transient value was resolved once and is now frozen inside the singleton.`,`This is almost always a bug.`,``,`To fix:`,` 1. Make '${e}' transient too: transient((c) => new ${e[0].toUpperCase()}${e.slice(1)}(c.${t}))`,` 2. Make '${t}' singleton if it doesn't need to change`,` 3. Inject a factory instead: ${t}Factory: () => () => <your value>`].join(`
3
- `),this.details={singleton:e,transient:t}}},c=class{type=`async_init_error`;message;hint;details;constructor(e,t){let n=t instanceof Error?t.message:String(t);this.message=`onInit() for '${e}' rejected: ${n}`,this.hint=`Use preload('${e}') to await and handle async init errors.`,this.details={key:e,error:n}}};const l=[`scope`,`extend`,`module`,`preload`,`reset`,`inspect`,`describe`,`health`,`dispose`,`toString`];function u(e){return typeof e==`object`&&!!e&&`onInit`in e&&typeof e.onInit==`function`}function d(e){return typeof e==`object`&&!!e&&`onDestroy`in e&&typeof e.onDestroy==`function`}var f=class{validateConfig(e){for(let[r,i]of Object.entries(e)){if(l.includes(r))throw new n(r,l);if(typeof i!=`function`)throw new t(r,typeof i)}}suggestKey(e,t){let n,r=1/0;for(let i of t){let t=m(e,i);t<r&&(r=t,n=i)}if(!n)return;let i=Math.max(e.length,n.length);return 1-r/i>=.5?n:void 0}};function p(...e){let t=new Map,n=[];for(let r of e)for(let e of Object.keys(r)){let r=(t.get(e)??0)+1;t.set(e,r),r===2&&n.push(e)}return n}function m(e,t){let n=e.length,r=t.length;if(n===0)return r;if(r===0)return n;let i=Array(r+1),a=Array(r+1);for(let e=0;e<=r;e++)i[e]=e;for(let o=1;o<=n;o++){a[0]=o;for(let n=1;n<=r;n++){let r=e[o-1]===t[n-1]?0:1;a[n]=Math.min(i[n]+1,a[n-1]+1,i[n-1]+r)}[i,a]=[a,i]}return i[r]}const h=Symbol.for(`inwire:transient`);function g(e){let t=(t=>e(t));return t[h]=!0,t}function _(e){return typeof e==`function`&&h in e&&e[h]===!0}var v=class{factories;cache;resolving=new Set;depGraph=new Map;warnings=[];validator=new f;initCalled=new Set;deferOnInit=!1;parent;name;constructor(e,t,n,r,i){this.factories=e,this.cache=t??new Map,this.parent=n,this.name=r,i&&(this.initCalled=new Set(i))}getName(){return this.name}resolve(e,t=[]){let n=this.factories.get(e);if(n&&!_(n)&&this.cache.has(e))return this.cache.get(e);if(!n){if(this.parent)return this.parent.resolve(e,t);let n=this.getAllRegisteredKeys();throw new r(e,t,n,this.validator.suggestKey(e,n))}if(this.resolving.has(e))throw new i(e,[...t]);this.resolving.add(e);let l=[...t,e];try{let t=[],r=n(this.createTrackingProxy(t,l));if(r===void 0)throw new a(e,l);if(this.depGraph.set(e,t),!_(n))for(let n of t){let t=this.getFactory(n);t&&_(t)&&this.warnings.push(new s(e,n))}if(_(n)||this.cache.set(e,r),!this.deferOnInit&&!this.initCalled.has(e)&&u(r)){this.initCalled.add(e);let t=r.onInit();t instanceof Promise&&t.catch(t=>{this.warnings.push(new c(e,t))})}return r}catch(t){throw t instanceof i||t instanceof r||t instanceof a||t instanceof o?t:new o(e,l,t)}finally{this.resolving.delete(e)}}isResolved(e){return this.cache.has(e)}getDepGraph(){return new Map(this.depGraph)}getResolvedKeys(){return[...this.cache.keys()]}getFactories(){return this.factories}getCache(){return this.cache}getWarnings(){return[...this.warnings]}getAllRegisteredKeys(){let e=new Set(this.factories.keys());if(this.parent)for(let t of this.parent.getAllRegisteredKeys())e.add(t);return[...e]}setDeferOnInit(e){this.deferOnInit=e}async callOnInit(e){if(this.initCalled.has(e)||!this.cache.has(e))return;let t=this.cache.get(e);u(t)&&await t.onInit(),this.initCalled.add(e)}clearInitState(...e){for(let t of e)this.initCalled.delete(t)}clearAllInitState(){this.initCalled.clear()}clearDepGraph(...e){for(let t of e)this.depGraph.delete(t)}clearAllDepGraph(){this.depGraph.clear()}clearWarnings(){this.warnings.length=0}clearWarningsForKeys(...e){let t=new Set(e),n=this.warnings.filter(e=>e.type===`async_init_error`?!t.has(e.details.key):e.type===`scope_mismatch`?!t.has(e.details.singleton)&&!t.has(e.details.transient):!0);this.warnings.length=0,this.warnings.push(...n)}getInitCalled(){return this.initCalled}createTrackingProxy(e,t){return new Proxy({},{get:(n,r)=>{if(typeof r==`symbol`)return;let i=r;return e.push(i),this.resolve(i,t)}})}getFactory(e){return this.factories.get(e)??this.parent?.getFactory(e)}},y=class{constructor(e){this.resolver=e}inspect(){let e={};for(let[t,n]of this.resolver.getFactories())e[t]={key:t,resolved:this.resolver.isResolved(t),deps:this.resolver.getDepGraph().get(t)??[],scope:_(n)?`transient`:`singleton`};let t=this.resolver.getName();return t?{name:t,providers:e}:{providers:e}}describe(e){let t=this.resolver.getFactories().get(e);return t?{key:e,resolved:this.resolver.isResolved(e),deps:this.resolver.getDepGraph().get(e)??[],scope:_(t)?`transient`:`singleton`}:{key:e,resolved:!1,deps:[],scope:`singleton`}}health(){let e=[...this.resolver.getFactories().keys()],t=this.resolver.getResolvedKeys(),n=new Set(t),r=this.resolver.getWarnings().map(e=>({type:e.type,message:e.message,details:e.details}));return{totalProviders:e.length,resolved:t,unresolved:e.filter(e=>!n.has(e)),warnings:r}}toString(){let e=[];for(let[t]of this.resolver.getFactories()){let n=this.resolver.isResolved(t),r=this.resolver.getDepGraph().get(t),i=r&&r.length>0?` -> [${r.join(`, `)}]`:``,a=n?`(resolved)`:`(pending)`;e.push(`${t}${i} ${a}`)}let t=this.resolver.getName();return`${t?`Scope(${t})`:`Container`} { ${e.join(`, `)} }`}};const b=new f;function x(e,t){let n=new Map,r=new Map;for(let e of t)n.set(e,0);for(let i of t){let a=e.get(i)??[];for(let e of a)if(t.has(e)){n.set(i,(n.get(i)??0)+1);let t=r.get(e)??[];t.push(i),r.set(e,t)}}let i=[],a=[...t].filter(e=>n.get(e)===0);for(;a.length>0;){i.push(a);let e=[];for(let t of a)for(let i of r.get(t)??[]){let t=(n.get(i)??1)-1;n.set(i,t),t===0&&e.push(i)}a=e}if(i.reduce((e,t)=>e+t.length,0)<t.size){let e=new Set(i.flat()),n=[...t].filter(t=>!e.has(t));throw Error(`Incomplete topological sort: [${n.join(`, `)}] could not be ordered. This may indicate a cycle in the dependency graph.`)}return i}function S(e,t){let n=new y(e),r={scope:(n,r)=>{b.validateConfig(n);let i=new Map;for(let[e,t]of Object.entries(n))i.set(e,t);return S(new v(i,new Map,e,r?.name),t)},extend:n=>{b.validateConfig(n);let r=new Map(e.getFactories());for(let[e,t]of Object.entries(n))r.set(e,t);return S(new v(r,new Map(e.getCache()),void 0,void 0,e.getInitCalled()),t)},module:e=>{if(!t)throw Error(`module() is not available`);let n=e(t());return r.extend(n._toRecord())},preload:async(...t)=>{let n=t.length>0?t:[...e.getFactories().keys()],r=new Set(e.getCache().keys());e.setDeferOnInit(!0);try{for(let t of n)e.resolve(t)}catch(t){let n=e.getCache();for(let e of n.keys())r.has(e)||n.delete(e);throw t}finally{e.setDeferOnInit(!1)}let i=e.getDepGraph(),a=new Set,o=e=>{if(!a.has(e)){a.add(e);for(let t of i.get(e)??[])o(t)}};for(let e of n)o(e);let s=x(i,a),c=[];for(let t of s){let n=await Promise.allSettled(t.map(t=>e.callOnInit(t)));for(let e of n)e.status===`rejected`&&c.push(e.reason)}if(c.length===1)throw c[0];if(c.length>1)throw AggregateError(c,`preload() encountered ${c.length} onInit errors`)},reset:(...t)=>{let n=e.getCache();if(t.length===0)n.clear(),e.clearAllInitState(),e.clearAllDepGraph(),e.clearWarnings();else{for(let e of t)n.delete(e);e.clearInitState(...t),e.clearDepGraph(...t),e.clearWarningsForKeys(...t)}},inspect:()=>n.inspect(),describe:e=>n.describe(e),health:()=>n.health(),toString:()=>n.toString(),dispose:async()=>{let t=e.getCache(),n=[...t.entries()].reverse(),r=[];for(let[,e]of n)if(d(e))try{await e.onDestroy()}catch(e){r.push(e)}if(t.clear(),e.clearAllInitState(),e.clearAllDepGraph(),e.clearWarnings(),r.length===1)throw r[0];if(r.length>1)throw AggregateError(r,`dispose() encountered ${r.length} errors`)}};return new Proxy({},{get(t,i){if(typeof i==`symbol`)return i===Symbol.toPrimitive||i===Symbol.toStringTag?()=>n.toString():void 0;let a=i;return a in r?r[a]:e.resolve(a)},has(t,n){if(typeof n==`symbol`)return!1;let i=n;return i in r||e.getFactories().has(i)||e.getAllRegisteredKeys().includes(i)},ownKeys(){return[...e.getAllRegisteredKeys(),...Object.keys(r)]},getOwnPropertyDescriptor(t,n){if(typeof n==`symbol`)return;let i=n;if(i in r||e.getFactories().has(i)||e.getAllRegisteredKeys().includes(i))return{configurable:!0,enumerable:!(i in r),writable:!1}}})}var C=class e{factories=new Map;add(e,t){return this.validateKey(e),typeof t==`function`?this.factories.set(e,t):this.factories.set(e,()=>t),this}addTransient(e,t){return this.validateKey(e),this.factories.set(e,g(t)),this}addModule(e){return e(this)}_toRecord(){return Object.fromEntries(this.factories)}build(){return S(new v(new Map(this.factories)),()=>new e)}validateKey(e){if(l.includes(e))throw new n(e,l)}};function w(){return new C}export{c as AsyncInitErrorWarning,i as CircularDependencyError,C as ContainerBuilder,t as ContainerConfigError,e as ContainerError,o as FactoryError,r as ProviderNotFoundError,n as ReservedKeyError,s as ScopeMismatchWarning,a as UndefinedReturnError,w as container,p as detectDuplicateKeys,g as transient};
3
+ `),this.details={singleton:e,transient:t}}},c=class{type=`async_init_error`;message;hint;details;constructor(e,t){let n=t instanceof Error?t.message:String(t);this.message=`onInit() for '${e}' rejected: ${n}`,this.hint=`Use preload('${e}') to await and handle async init errors.`,this.details={key:e,error:n}}};const l=[`scope`,`extend`,`module`,`preload`,`reset`,`inspect`,`describe`,`health`,`dispose`,`toString`];var u=class{resolving=new Set;enter(e){this.resolving.add(e)}leave(e){this.resolving.delete(e)}isResolving(e){return this.resolving.has(e)}},d=class{depGraph=new Map;createTrackingProxy(e,t,n){return new Proxy({},{get:(r,i)=>{if(typeof i==`symbol`)return;let a=i;return e.push(a),n(a,t)}})}getDepGraph(){return new Map(this.depGraph)}recordDeps(e,t){this.depGraph.set(e,t)}clearDepGraph(...e){for(let t of e)this.depGraph.delete(t)}clearAllDepGraph(){this.depGraph.clear()}};function f(e){return typeof e==`object`&&!!e&&`onInit`in e&&typeof e.onInit==`function`}function p(e){return typeof e==`object`&&!!e&&`onDestroy`in e&&typeof e.onDestroy==`function`}var m=class{validateConfig(e){for(let[r,i]of Object.entries(e)){if(l.includes(r))throw new n(r,l);if(typeof i!=`function`)throw new t(r,typeof i)}}suggestKey(e,t){let n,r=1/0;for(let i of t){let t=g(e,i);t<r&&(r=t,n=i)}if(!n)return;let i=Math.max(e.length,n.length);return 1-r/i>=.5?n:void 0}};function h(...e){let t=new Map,n=[];for(let r of e)for(let e of Object.keys(r)){let r=(t.get(e)??0)+1;t.set(e,r),r===2&&n.push(e)}return n}function g(e,t){let n=e.length,r=t.length;if(n===0)return r;if(r===0)return n;let i=Array(r+1),a=Array(r+1);for(let e=0;e<=r;e++)i[e]=e;for(let o=1;o<=n;o++){a[0]=o;for(let n=1;n<=r;n++){let r=e[o-1]===t[n-1]?0:1;a[n]=Math.min(i[n]+1,a[n-1]+1,i[n-1]+r)}[i,a]=[a,i]}return i[r]}const _=Symbol.for(`inwire:transient`);function v(e){let t=(t=>e(t));return t[_]=!0,t}function y(e){return typeof e==`function`&&_ in e&&e[_]===!0}var b=class{factories;cache;warnings=[];validator=new m;initCalled;deferOnInit=!1;parent;name;cycleDetector;dependencyTracker;constructor(e){this.factories=e.factories,this.cache=e.cache??new Map,this.parent=e.parent,this.name=e.name,this.initCalled=e.initCalled?new Set(e.initCalled):new Set,this.cycleDetector=e.cycleDetector,this.dependencyTracker=e.dependencyTracker}getName(){return this.name}resolve(e,t=[]){let n=this.factories.get(e);if(n&&!y(n)&&this.cache.has(e))return this.cache.get(e);if(!n){if(this.parent)return this.parent.resolve(e,t);let n=this.getAllRegisteredKeys();throw new r(e,t,n,this.validator.suggestKey(e,n))}if(this.cycleDetector.isResolving(e))throw new i(e,[...t]);this.cycleDetector.enter(e);let l=[...t,e];try{let t=[],r=n(this.dependencyTracker.createTrackingProxy(t,l,(e,t)=>this.resolve(e,t)));if(r===void 0)throw new a(e,l);if(this.dependencyTracker.recordDeps(e,t),!y(n))for(let n of t){let t=this.getFactory(n);t&&y(t)&&this.warnings.push(new s(e,n))}if(y(n)||this.cache.set(e,r),!this.deferOnInit&&!this.initCalled.has(e)&&f(r)){this.initCalled.add(e);let t=r.onInit();t instanceof Promise&&t.catch(t=>{this.warnings.push(new c(e,t))})}return r}catch(t){throw t instanceof i||t instanceof r||t instanceof a||t instanceof o?t:new o(e,l,t)}finally{this.cycleDetector.leave(e)}}isResolved(e){return this.cache.has(e)}getDepGraph(){return this.dependencyTracker.getDepGraph()}getResolvedKeys(){return[...this.cache.keys()]}getFactories(){return this.factories}getCache(){return this.cache}getWarnings(){return[...this.warnings]}getAllRegisteredKeys(){let e=new Set(this.factories.keys());if(this.parent)for(let t of this.parent.getAllRegisteredKeys())e.add(t);return[...e]}setDeferOnInit(e){this.deferOnInit=e}async callOnInit(e){if(this.initCalled.has(e)||!this.cache.has(e))return;let t=this.cache.get(e);f(t)&&await t.onInit(),this.initCalled.add(e)}clearInitState(...e){for(let t of e)this.initCalled.delete(t)}clearAllInitState(){this.initCalled.clear()}clearDepGraph(...e){this.dependencyTracker.clearDepGraph(...e)}clearAllDepGraph(){this.dependencyTracker.clearAllDepGraph()}clearWarnings(){this.warnings.length=0}clearWarningsForKeys(...e){let t=new Set(e),n=this.warnings.filter(e=>e.type===`async_init_error`?!t.has(e.details.key):e.type===`scope_mismatch`?!t.has(e.details.singleton)&&!t.has(e.details.transient):!0);this.warnings.length=0,this.warnings.push(...n)}getInitCalled(){return this.initCalled}getFactory(e){return this.factories.get(e)??this.parent?.getFactory(e)}},x=class{constructor(e){this.resolver=e}async dispose(){let e=this.resolver.getCache(),t=[...e.entries()].reverse(),n=[];for(let[,e]of t)if(p(e))try{await e.onDestroy()}catch(e){n.push(e)}if(e.clear(),this.resolver.clearAllInitState(),this.resolver.clearAllDepGraph(),this.resolver.clearWarnings(),n.length===1)throw n[0];if(n.length>1)throw AggregateError(n,`dispose() encountered ${n.length} errors`)}},S=class{constructor(e){this.resolver=e}inspect(){let e={};for(let[t,n]of this.resolver.getFactories())e[t]={key:t,resolved:this.resolver.isResolved(t),deps:this.resolver.getDepGraph().get(t)??[],scope:y(n)?`transient`:`singleton`};let t=this.resolver.getName();return t?{name:t,providers:e}:{providers:e}}describe(e){let t=this.resolver.getFactories().get(e);return t?{key:e,resolved:this.resolver.isResolved(e),deps:this.resolver.getDepGraph().get(e)??[],scope:y(t)?`transient`:`singleton`}:{key:e,resolved:!1,deps:[],scope:`singleton`}}health(){let e=[...this.resolver.getFactories().keys()],t=this.resolver.getResolvedKeys(),n=new Set(t),r=this.resolver.getWarnings().map(e=>({type:e.type,message:e.message,details:e.details}));return{totalProviders:e.length,resolved:t,unresolved:e.filter(e=>!n.has(e)),warnings:r}}toString(){let e=[];for(let[t]of this.resolver.getFactories()){let n=this.resolver.isResolved(t),r=this.resolver.getDepGraph().get(t),i=r&&r.length>0?` -> [${r.join(`, `)}]`:``,a=n?`(resolved)`:`(pending)`;e.push(`${t}${i} ${a}`)}let t=this.resolver.getName();return`${t?`Scope(${t})`:`Container`} { ${e.join(`, `)} }`}};function C(e,t){let n=new Map,r=new Map;for(let e of t)n.set(e,0);for(let i of t){let a=e.get(i)??[];for(let e of a)if(t.has(e)){n.set(i,(n.get(i)??0)+1);let t=r.get(e)??[];t.push(i),r.set(e,t)}}let i=[],a=[...t].filter(e=>n.get(e)===0);for(;a.length>0;){i.push(a);let e=[];for(let t of a)for(let i of r.get(t)??[]){let t=(n.get(i)??1)-1;n.set(i,t),t===0&&e.push(i)}a=e}if(i.reduce((e,t)=>e+t.length,0)<t.size){let e=new Set(i.flat()),n=[...t].filter(t=>!e.has(t));throw Error(`Incomplete topological sort: [${n.join(`, `)}] could not be ordered. This may indicate a cycle in the dependency graph.`)}return i}var w=class{constructor(e){this.resolver=e}async preload(...e){let t=e.length>0?e:[...this.resolver.getFactories().keys()],n=new Set(this.resolver.getCache().keys());this.resolver.setDeferOnInit(!0);try{for(let e of t)this.resolver.resolve(e)}catch(e){let t=this.resolver.getCache();for(let e of t.keys())n.has(e)||t.delete(e);throw e}finally{this.resolver.setDeferOnInit(!1)}let r=this.resolver.getDepGraph(),i=new Set,a=e=>{if(!i.has(e)){i.add(e);for(let t of r.get(e)??[])a(t)}};for(let e of t)a(e);let o=C(r,i),s=[];for(let e of o){let t=await Promise.allSettled(e.map(e=>this.resolver.callOnInit(e)));for(let e of t)e.status===`rejected`&&s.push(e.reason)}if(s.length===1)throw s[0];if(s.length>1)throw AggregateError(s,`preload() encountered ${s.length} onInit errors`)}};const T=new m;function E(e,t){let n=new S(e),r=new w(e),i=new x(e),a={scope:(n,r)=>{T.validateConfig(n);let i=new Map;for(let[e,t]of Object.entries(n))i.set(e,t);return E(new b({factories:i,parent:e,name:r?.name,cycleDetector:new u,dependencyTracker:new d}),t)},extend:n=>{T.validateConfig(n);let r=new Map(e.getFactories());for(let[e,t]of Object.entries(n))r.set(e,t);return E(new b({factories:r,cache:new Map(e.getCache()),initCalled:e.getInitCalled(),cycleDetector:new u,dependencyTracker:new d}),t)},module:e=>{if(!t)throw Error(`module() is not available`);let n=e(t());return a.extend(n._toRecord())},preload:(...e)=>r.preload(...e),reset:(...t)=>{let n=e.getCache();if(t.length===0)n.clear(),e.clearAllInitState(),e.clearAllDepGraph(),e.clearWarnings();else{for(let e of t)n.delete(e);e.clearInitState(...t),e.clearDepGraph(...t),e.clearWarningsForKeys(...t)}},inspect:()=>n.inspect(),describe:e=>n.describe(e),health:()=>n.health(),toString:()=>n.toString(),dispose:()=>i.dispose()};return new Proxy({},{get(t,r){if(typeof r==`symbol`)return r===Symbol.toPrimitive||r===Symbol.toStringTag?()=>n.toString():void 0;let i=r;return i in a?a[i]:e.resolve(i)},has(t,n){if(typeof n==`symbol`)return!1;let r=n;return r in a||e.getFactories().has(r)||e.getAllRegisteredKeys().includes(r)},ownKeys(){return[...e.getAllRegisteredKeys(),...Object.keys(a)]},getOwnPropertyDescriptor(t,n){if(typeof n==`symbol`)return;let r=n;if(r in a||e.getFactories().has(r)||e.getAllRegisteredKeys().includes(r))return{configurable:!0,enumerable:!(r in a),writable:!1}}})}var D=class e{factories=new Map;add(e,t){return this.validateKey(e),typeof t==`function`?this.factories.set(e,t):this.factories.set(e,()=>t),this}addTransient(e,t){return this.validateKey(e),this.factories.set(e,v(t)),this}addModule(e){return e(this)}_toRecord(){return Object.fromEntries(this.factories)}build(){return E(new b({factories:new Map(this.factories),cycleDetector:new u,dependencyTracker:new d}),()=>new e)}validateKey(e){if(l.includes(e))throw new n(e,l)}};function O(){return new D}export{c as AsyncInitErrorWarning,i as CircularDependencyError,D as ContainerBuilder,t as ContainerConfigError,e as ContainerError,o as FactoryError,r as ProviderNotFoundError,n as ReservedKeyError,s as ScopeMismatchWarning,a as UndefinedReturnError,O as container,h as detectDuplicateKeys,v as transient};
4
4
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inwire",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Zero-ceremony dependency injection for TypeScript. Full inference, no decorators, no tokens. Built-in introspection for AI tooling.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",