inwire 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +32 -11
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -169,7 +169,7 @@ interface ContainerHealth {
|
|
|
169
169
|
* A warning detected by the container's runtime analysis.
|
|
170
170
|
*/
|
|
171
171
|
interface ContainerWarning {
|
|
172
|
-
type: 'scope_mismatch';
|
|
172
|
+
type: 'scope_mismatch' | 'async_init_error';
|
|
173
173
|
message: string;
|
|
174
174
|
details: Record<string, unknown>;
|
|
175
175
|
}
|
|
@@ -264,7 +264,7 @@ declare abstract class ContainerError extends Error {
|
|
|
264
264
|
*
|
|
265
265
|
* @example
|
|
266
266
|
* ```typescript
|
|
267
|
-
*
|
|
267
|
+
* container().add('apiKey', 'sk-123');
|
|
268
268
|
* // ContainerConfigError: 'apiKey' must be a factory function, got string.
|
|
269
269
|
* // hint: "Wrap it: apiKey: () => 'sk-123'"
|
|
270
270
|
* ```
|
|
@@ -282,7 +282,7 @@ declare class ContainerConfigError extends ContainerError {
|
|
|
282
282
|
*
|
|
283
283
|
* @example
|
|
284
284
|
* ```typescript
|
|
285
|
-
*
|
|
285
|
+
* container().add('inspect', () => 'foo');
|
|
286
286
|
* // ReservedKeyError: 'inspect' is a reserved container method.
|
|
287
287
|
* // hint: "Rename this dependency, e.g. 'inspectService' or 'dataInspector'."
|
|
288
288
|
* ```
|
|
@@ -391,6 +391,27 @@ declare class ScopeMismatchWarning implements ContainerWarning {
|
|
|
391
391
|
};
|
|
392
392
|
constructor(singletonKey: string, transientKey: string);
|
|
393
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
|
+
}
|
|
394
415
|
//#endregion
|
|
395
416
|
//#region src/domain/lifecycle.d.ts
|
|
396
417
|
/**
|
|
@@ -436,18 +457,18 @@ declare function detectDuplicateKeys(...modules: Record<string, unknown>[]): str
|
|
|
436
457
|
*
|
|
437
458
|
* @example
|
|
438
459
|
* ```typescript
|
|
439
|
-
* import {
|
|
460
|
+
* import { container, transient } from 'inwire';
|
|
440
461
|
*
|
|
441
|
-
* const
|
|
442
|
-
* logger
|
|
443
|
-
* requestId
|
|
444
|
-
*
|
|
462
|
+
* const app = container()
|
|
463
|
+
* .add('logger', () => new LoggerService()) // singleton (default)
|
|
464
|
+
* .addTransient('requestId', () => crypto.randomUUID()) // new instance every access
|
|
465
|
+
* .build();
|
|
445
466
|
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
467
|
+
* app.requestId; // 'abc-123'
|
|
468
|
+
* app.requestId; // 'def-456' (different!)
|
|
448
469
|
* ```
|
|
449
470
|
*/
|
|
450
471
|
declare function transient<T>(factory: Factory<T>): Factory<T>;
|
|
451
472
|
//#endregion
|
|
452
|
-
export { CircularDependencyError, type Container, ContainerBuilder, ContainerConfigError, ContainerError, type ContainerGraph, type ContainerHealth, type ContainerWarning, FactoryError, type IContainer, type OnDestroy, type OnInit, type ProviderInfo, ProviderNotFoundError, ReservedKeyError, ScopeMismatchWarning, type ScopeOptions, UndefinedReturnError, container, detectDuplicateKeys, transient };
|
|
473
|
+
export { AsyncInitErrorWarning, CircularDependencyError, type Container, ContainerBuilder, ContainerConfigError, ContainerError, type ContainerGraph, type ContainerHealth, type ContainerWarning, FactoryError, type IContainer, type OnDestroy, type OnInit, type ProviderInfo, ProviderNotFoundError, ReservedKeyError, ScopeMismatchWarning, type ScopeOptions, UndefinedReturnError, container, detectDuplicateKeys, transient };
|
|
453
474
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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}`)
|
|
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}}};const
|
|
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};
|
|
4
4
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED