inwire 1.0.2 → 1.0.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 +1 -1
- package/dist/index.d.mts +38 -13
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* const factory: Factory<MyService> = (c) => new MyService(c.db);
|
|
8
8
|
* ```
|
|
9
9
|
*/
|
|
10
|
-
type Factory<T =
|
|
10
|
+
type Factory<T = unknown> = (container: any) => T;
|
|
11
11
|
/**
|
|
12
12
|
* An object of factory functions — the definition of a container.
|
|
13
13
|
* Each key maps to a factory that produces the dependency.
|
|
@@ -53,11 +53,11 @@ interface ScopeOptions {
|
|
|
53
53
|
* container.inspect(); // ContainerGraph
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
type Container<T extends Record<string,
|
|
56
|
+
type Container<T extends Record<string, unknown> = Record<string, unknown>> = T & IContainer<T>;
|
|
57
57
|
/**
|
|
58
58
|
* Container methods interface. Defines the API available on every container.
|
|
59
59
|
*/
|
|
60
|
-
interface IContainer<T extends Record<string,
|
|
60
|
+
interface IContainer<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
61
61
|
/**
|
|
62
62
|
* Creates a child container with additional dependencies.
|
|
63
63
|
* Child inherits all parent singletons and can add/override deps.
|
|
@@ -72,7 +72,7 @@ interface IContainer<T extends Record<string, any> = Record<string, any>> {
|
|
|
72
72
|
* request.logger; // inherited from parent
|
|
73
73
|
* ```
|
|
74
74
|
*/
|
|
75
|
-
scope<E extends DepsDefinition>(extra: E, options?: ScopeOptions): Container<T & ResolvedDeps<E>>;
|
|
75
|
+
scope<E extends DepsDefinition>(extra: E, options?: ScopeOptions): Container<Omit<T, keyof ResolvedDeps<E>> & ResolvedDeps<E>>;
|
|
76
76
|
/**
|
|
77
77
|
* Returns a new container with additional dependencies.
|
|
78
78
|
* Existing singletons are shared. The original container is not modified.
|
|
@@ -82,7 +82,7 @@ interface IContainer<T extends Record<string, any> = Record<string, any>> {
|
|
|
82
82
|
* const appWithAuth = app.extend(authDeps);
|
|
83
83
|
* ```
|
|
84
84
|
*/
|
|
85
|
-
extend<E extends DepsDefinition>(extra: E): Container<T & ResolvedDeps<E>>;
|
|
85
|
+
extend<E extends DepsDefinition>(extra: E): Container<Omit<T, keyof ResolvedDeps<E>> & ResolvedDeps<E>>;
|
|
86
86
|
/**
|
|
87
87
|
* Pre-resolves dependencies (warm-up).
|
|
88
88
|
* Call with specific keys to resolve only those, or without arguments to resolve all.
|
|
@@ -176,7 +176,7 @@ interface ContainerHealth {
|
|
|
176
176
|
* A warning detected by the container's runtime analysis.
|
|
177
177
|
*/
|
|
178
178
|
interface ContainerWarning {
|
|
179
|
-
type: 'scope_mismatch'
|
|
179
|
+
type: 'scope_mismatch';
|
|
180
180
|
message: string;
|
|
181
181
|
details: Record<string, unknown>;
|
|
182
182
|
}
|
|
@@ -215,7 +215,10 @@ declare abstract class ContainerError extends Error {
|
|
|
215
215
|
*/
|
|
216
216
|
declare class ContainerConfigError extends ContainerError {
|
|
217
217
|
readonly hint: string;
|
|
218
|
-
readonly details:
|
|
218
|
+
readonly details: {
|
|
219
|
+
key: string;
|
|
220
|
+
actualType: string;
|
|
221
|
+
};
|
|
219
222
|
constructor(key: string, actualType: string);
|
|
220
223
|
}
|
|
221
224
|
/**
|
|
@@ -230,7 +233,10 @@ declare class ContainerConfigError extends ContainerError {
|
|
|
230
233
|
*/
|
|
231
234
|
declare class ReservedKeyError extends ContainerError {
|
|
232
235
|
readonly hint: string;
|
|
233
|
-
readonly details:
|
|
236
|
+
readonly details: {
|
|
237
|
+
key: string;
|
|
238
|
+
reserved: string[];
|
|
239
|
+
};
|
|
234
240
|
constructor(key: string, reserved: readonly string[]);
|
|
235
241
|
}
|
|
236
242
|
/**
|
|
@@ -246,7 +252,12 @@ declare class ReservedKeyError extends ContainerError {
|
|
|
246
252
|
*/
|
|
247
253
|
declare class ProviderNotFoundError extends ContainerError {
|
|
248
254
|
readonly hint: string;
|
|
249
|
-
readonly details:
|
|
255
|
+
readonly details: {
|
|
256
|
+
key: string;
|
|
257
|
+
chain: string[];
|
|
258
|
+
registered: string[];
|
|
259
|
+
suggestion: string | undefined;
|
|
260
|
+
};
|
|
250
261
|
constructor(key: string, chain: string[], registered: string[], suggestion?: string);
|
|
251
262
|
}
|
|
252
263
|
/**
|
|
@@ -260,7 +271,11 @@ declare class ProviderNotFoundError extends ContainerError {
|
|
|
260
271
|
*/
|
|
261
272
|
declare class CircularDependencyError extends ContainerError {
|
|
262
273
|
readonly hint: string;
|
|
263
|
-
readonly details:
|
|
274
|
+
readonly details: {
|
|
275
|
+
key: string;
|
|
276
|
+
chain: string[];
|
|
277
|
+
cycle: string;
|
|
278
|
+
};
|
|
264
279
|
constructor(key: string, chain: string[]);
|
|
265
280
|
}
|
|
266
281
|
/**
|
|
@@ -275,7 +290,10 @@ declare class CircularDependencyError extends ContainerError {
|
|
|
275
290
|
*/
|
|
276
291
|
declare class UndefinedReturnError extends ContainerError {
|
|
277
292
|
readonly hint: string;
|
|
278
|
-
readonly details:
|
|
293
|
+
readonly details: {
|
|
294
|
+
key: string;
|
|
295
|
+
chain: string[];
|
|
296
|
+
};
|
|
279
297
|
constructor(key: string, chain: string[]);
|
|
280
298
|
}
|
|
281
299
|
/**
|
|
@@ -290,7 +308,11 @@ declare class UndefinedReturnError extends ContainerError {
|
|
|
290
308
|
*/
|
|
291
309
|
declare class FactoryError extends ContainerError {
|
|
292
310
|
readonly hint: string;
|
|
293
|
-
readonly details:
|
|
311
|
+
readonly details: {
|
|
312
|
+
key: string;
|
|
313
|
+
chain: string[];
|
|
314
|
+
originalError: string;
|
|
315
|
+
};
|
|
294
316
|
readonly originalError: unknown;
|
|
295
317
|
constructor(key: string, chain: string[], originalError: unknown);
|
|
296
318
|
}
|
|
@@ -307,7 +329,10 @@ declare class ScopeMismatchWarning implements ContainerWarning {
|
|
|
307
329
|
readonly type: "scope_mismatch";
|
|
308
330
|
readonly message: string;
|
|
309
331
|
readonly hint: string;
|
|
310
|
-
readonly details:
|
|
332
|
+
readonly details: {
|
|
333
|
+
singleton: string;
|
|
334
|
+
transient: string;
|
|
335
|
+
};
|
|
311
336
|
constructor(singletonKey: string, transientKey: string);
|
|
312
337
|
}
|
|
313
338
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function e(e){return typeof e==`object`&&!!e&&`onInit`in e&&typeof e.onInit==`function`}function t(e){return typeof e==`object`&&!!e&&`onDestroy`in e&&typeof e.onDestroy==`function`}const n=[`scope`,`extend`,`preload`,`reset`,`inspect`,`describe`,`health`,`dispose`,`toString`];var r=class extends Error{constructor(e){super(e),this.name=this.constructor.name}},i=class extends r{hint;details;constructor(e,t){super(`'${e}' must be a factory function, got ${t}.`),this.hint=`Wrap it: ${e}: () =>
|
|
1
|
+
function e(e){return typeof e==`object`&&!!e&&`onInit`in e&&typeof e.onInit==`function`}function t(e){return typeof e==`object`&&!!e&&`onDestroy`in e&&typeof e.onDestroy==`function`}const n=[`scope`,`extend`,`preload`,`reset`,`inspect`,`describe`,`health`,`dispose`,`toString`];var r=class extends Error{constructor(e){super(e),this.name=this.constructor.name}},i=class extends r{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}}},a=class extends r{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]}}},o=class extends r{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}`),this.hint=r?`Did you mean '${r}'? Or add '${e}' to your container:\n createContainer({\n ...existing,\n ${e}: (c) => new Your${e[0].toUpperCase()}${e.slice(1)}(/* deps */),\n });`:`Add '${e}' to your container:\n createContainer({\n ...existing,\n ${e}: (c) => new Your${e[0].toUpperCase()}${e.slice(1)}(/* deps */),\n });`,this.details={key:e,chain:t,registered:n,suggestion:r}}},s=class extends r{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}}},c=class extends r{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}}},l=class extends r{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}},u=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
3
|
`),this.details={singleton:e,transient:t}}},d=class{validateConfig(e){for(let[t,r]of Object.entries(e)){if(n.includes(t))throw new a(t,n);if(typeof r!=`function`)throw new i(t,typeof r)}}suggestKey(e,t){let n,r=1/0;for(let i of t){let t=p(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 f(...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 p(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 m=Symbol.for(`inwire:transient`);function h(e){let t=(t=>e(t));return t[m]=!0,t}function g(e){return typeof e==`function`&&m in e&&e[m]===!0}var _=class{factories;cache;resolving=new Set;depGraph=new Map;warnings=[];validator=new d;parent;name;constructor(e,t,n,r){this.factories=e,this.cache=t??new Map,this.parent=n,this.name=r}getName(){return this.name}resolve(t,n=[]){let r=this.factories.get(t);if(r&&!g(r)&&this.cache.has(t))return this.cache.get(t);if(!r){if(this.parent)return this.parent.resolve(t,n);let e=this.getAllRegisteredKeys();throw new o(t,n,e,this.validator.suggestKey(t,e))}if(this.resolving.has(t))throw new s(t,[...n]);this.resolving.add(t);let i=[...n,t];try{let n=[],a=r(this.createTrackingProxy(t,n,i));if(a===void 0)throw new c(t,i);if(this.depGraph.set(t,n),!g(r))for(let e of n){let n=this.getFactory(e);n&&g(n)&&this.warnings.push(new u(t,e))}if(g(r)||this.cache.set(t,a),e(a)){let e=a.onInit();e instanceof Promise&&e.catch(()=>{})}return a}catch(e){throw e instanceof s||e instanceof o||e instanceof c||e instanceof l?e:new l(t,i,e)}finally{this.resolving.delete(t)}}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]}createTrackingProxy(e,t,n){return new Proxy({},{get:(e,r)=>{if(typeof r==`symbol`)return;let i=r;return t.push(i),this.resolve(i,n)}})}getFactory(e){return this.factories.get(e)??this.parent?.getFactory(e)}},v=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:g(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:g(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 y(e,t,n){let r=new Map;for(let[e,n]of Object.entries(t))r.set(e,n);return S(new _(r,new Map,e,n?.name))}const b=new d;function x(e){b.validateConfig(e);let t=new Map;for(let[n,r]of Object.entries(e))t.set(n,r);return S(new _(t))}function S(e){let n=new v(e),r={scope:(t,n)=>y(e,t,n),extend:t=>{b.validateConfig(t);let n=new Map(e.getFactories());for(let[e,r]of Object.entries(t))n.set(e,r);return S(new _(n,new Map(e.getCache())))},preload:async(...t)=>{let n=t.length>0?t:[...e.getFactories().keys()];for(let t of n)e.resolve(t)},reset:(...t)=>{let n=e.getCache();for(let e of t)n.delete(e)},inspect:()=>n.inspect(),describe:e=>n.describe(e),health:()=>n.health(),toString:()=>n.toString(),dispose:async()=>{let n=e.getCache(),r=[...n.entries()].reverse();for(let[,e]of r)t(e)&&await e.onDestroy();n.clear()}};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}}})}export{s as CircularDependencyError,i as ContainerConfigError,r as ContainerError,l as FactoryError,o as ProviderNotFoundError,a as ReservedKeyError,u as ScopeMismatchWarning,c as UndefinedReturnError,x as createContainer,f as detectDuplicateKeys,h as transient};
|
|
4
4
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED