@vielzeug/conduit 1.0.2
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 +95 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/conduit.cjs +2 -0
- package/dist/conduit.cjs.map +1 -0
- package/dist/conduit.d.ts +5 -0
- package/dist/conduit.d.ts.map +1 -0
- package/dist/conduit.iife.js +2 -0
- package/dist/conduit.iife.js.map +1 -0
- package/dist/conduit.js +2 -0
- package/dist/conduit.js.map +1 -0
- package/dist/container.cjs +2 -0
- package/dist/container.cjs.map +1 -0
- package/dist/container.d.ts +5 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +262 -0
- package/dist/container.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +49 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.cjs +2 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.ts +41 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +62 -0
- package/dist/utils.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @vielzeug/conduit
|
|
2
|
+
|
|
3
|
+
> Typed dependency injection for TypeScript.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@vielzeug/conduit) [](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
<details>
|
|
8
|
+
<summary>Quick Reference</summary>
|
|
9
|
+
|
|
10
|
+
**Package:** `@vielzeug/conduit` · **Category:** Di
|
|
11
|
+
|
|
12
|
+
**Key exports:** `createContainer`, `token`, `scope`, `loadModules`
|
|
13
|
+
|
|
14
|
+
**When to use:** Type-safe DI container with async-first resolution, singleton/transient/named-scope lifetimes, scope containers, disposal hooks, and cycle detection.
|
|
15
|
+
|
|
16
|
+
**Related:** [@vielzeug/rune](https://vielzeug.dev/rune/) · [@vielzeug/herald](https://vielzeug.dev/herald/) · [@vielzeug/ward](https://vielzeug.dev/ward/)
|
|
17
|
+
|
|
18
|
+
</details>
|
|
19
|
+
|
|
20
|
+
`@vielzeug/conduit` is part of Vielzeug and ships as a zero-dependency TypeScript package with ESM+CJS output.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pnpm add @vielzeug/conduit
|
|
26
|
+
npm install @vielzeug/conduit
|
|
27
|
+
yarn add @vielzeug/conduit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createContainer, token, loadModules, type ContainerModule } from '@vielzeug/conduit';
|
|
34
|
+
|
|
35
|
+
const Logger = token<{ log(message: string): void }>('Logger');
|
|
36
|
+
const Service = token<{ run(): Promise<void> }>('Service');
|
|
37
|
+
|
|
38
|
+
const appModule: ContainerModule = (c) => {
|
|
39
|
+
c.value(Logger, console);
|
|
40
|
+
c.factory(Service, async (r) => {
|
|
41
|
+
const logger = await r.resolve(Logger);
|
|
42
|
+
return { run: async () => logger.log('running') };
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const container = createContainer();
|
|
47
|
+
await loadModules(container, appModule);
|
|
48
|
+
|
|
49
|
+
const service = await container.resolve(Service);
|
|
50
|
+
await service.run();
|
|
51
|
+
|
|
52
|
+
await container.dispose();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- Typed symbol tokens via `token()` with phantom type inference
|
|
58
|
+
- Named scope tokens via `scope()` and `createScope()` for explicit lifecycle control
|
|
59
|
+
- `value()` and `factory()` registration with optional dispose hooks
|
|
60
|
+
- `singleton`, `transient`, and named-scope lifetimes
|
|
61
|
+
- Async-first `resolve()` with concurrent-caller deduplication
|
|
62
|
+
- Sync `resolveSync()` for cached values and post-warm-up hot paths
|
|
63
|
+
- `resolveMany()` to resolve multiple tokens in parallel with typed tuples
|
|
64
|
+
- `resolveAll()` to eagerly warm all singletons at startup
|
|
65
|
+
- `has()` to check registration without executing the factory
|
|
66
|
+
- `ContainerModule` for grouping and async provider setup via `loadModules()`
|
|
67
|
+
- `freeze()` to lock the container after startup (runs cycle detection)
|
|
68
|
+
- `inspect()` to get a serializable dependency graph
|
|
69
|
+
- `on()` to subscribe to container lifecycle events with `source` metadata
|
|
70
|
+
- Named scope containers for request, job, or test scopes
|
|
71
|
+
- `Symbol.asyncDispose` support for `await using`
|
|
72
|
+
- Free-function helpers: `resolveOptional`, `resolveOrDefault`, `tryResolve`, `resolveSyncOptional`, `resolveSyncOrDefault`
|
|
73
|
+
|
|
74
|
+
## Errors
|
|
75
|
+
|
|
76
|
+
| Error | When thrown |
|
|
77
|
+
| ----------------------------------- | --------------------------------------------------------------------------------- |
|
|
78
|
+
| `ConduitProviderNotFoundError` | `resolve()` called for an unregistered token; message includes container name |
|
|
79
|
+
| `ConduitDuplicateRegistrationError` | `value()` or `factory()` called for an already-registered token |
|
|
80
|
+
| `ConduitSyncResolutionError` | `resolveSync()` called for a transient or not-yet-resolved factory |
|
|
81
|
+
| `ConduitScopedResolutionError` | `resolve()` called outside a matching named-scope container |
|
|
82
|
+
| `ConduitCircularDependencyError` | `freeze()` detected a cycle; message includes the full path |
|
|
83
|
+
| `ConduitDisposedError` | Any operation called after `dispose()`; message includes container name |
|
|
84
|
+
| `ConduitFrozenError` | `value()` or `factory()` called after `freeze()`; message includes container name |
|
|
85
|
+
|
|
86
|
+
## Documentation
|
|
87
|
+
|
|
88
|
+
- [Overview](https://vielzeug.dev/conduit/)
|
|
89
|
+
- [Usage Guide](https://vielzeug.dev/conduit/usage)
|
|
90
|
+
- [API Reference](https://vielzeug.dev/conduit/api)
|
|
91
|
+
- [Examples](https://vielzeug.dev/conduit/examples)
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
package/dist/_dev.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __CONDUIT_PROD__?: boolean }).__CONDUIT_PROD__;\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/conduit] ${msg}`, ...args);\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAA8C,iBAG9D,SAAgB,EAAM,EAAa,GAAG,EAAuB,CACvD,GAAO,QAAQ,MAAM,uBAAuB,IAAO,GAAG,CAAI,CAChE"}
|
package/dist/_dev.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
|
package/dist/_dev.js
ADDED
package/dist/_dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __CONDUIT_PROD__?: boolean }).__CONDUIT_PROD__;\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/conduit] ${msg}`, ...args);\n}\n"],"mappings":";AAAA,IAAM,IAAQ,CAAE,WAA8C;AAG9D,SAAgB,EAAM,GAAa,GAAG,GAAuB;CAC3D,AAAI,KAAO,QAAQ,MAAM,uBAAuB,KAAO,GAAG,CAAI;AAChE"}
|
package/dist/conduit.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=!globalThis.__CONDUIT_PROD__;function t(t,...n){e&&console.error(`[@vielzeug/conduit] ${t}`,...n)}var n=e=>e.description??`anonymous`,r=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},i=class extends r{cycle;constructor(e){super(`Circular dependency detected: ${e.map(n).join(` -> `)}`),this.cycle=e}},a=class extends r{token;containerName;constructor(e,t=`unknown`){super(`No provider registered for token: ${n(e)} (in container '${t}')`),this.token=e,this.containerName=t}},o=class extends r{token;constructor(e){super(`Token "${n(e)}" is already registered.`),this.token=e}},s=class extends r{token;lifetime;constructor(e,t){let r=t===`transient`?`transient factories are never cached`:typeof t==`symbol`?`named-scope "${t.description??`anonymous`}" instance has not been resolved yet in this scope`:`the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first`;super(`Token "${n(e)}" cannot be resolved synchronously: ${r}.`),this.token=e,this.lifetime=t}},c=class extends r{token;requiredScope;constructor(e,t){let r=t?.description??`anonymous`;super(t?`Token "${n(e)}" requires scope "${r}" but no matching scope container was found in the hierarchy.`:`Token "${n(e)}" requires a scope container but was resolved from the root.`),this.token=e,this.requiredScope=t}},l=class extends r{containerName;constructor(e=`unknown`){super(`Cannot use a disposed container (container '${e}').`),this.containerName=e}},u=class extends r{containerName;constructor(e){super(`Container '${e}' is frozen and cannot accept new registrations.`),this.containerName=e}},d=class e{#e=new Map;#t=new Map;#n;#r;#i=new Set;#a=new Set;#o=new AbortController;#s=!1;#c=!1;name;constructor(e,t={}){this.#n=e,this.#r=t.scopeTag,this.name=t.name??(e?t.scopeTag?`${e.name}:${t.scopeTag.description??`scope`}`:`${e.name}:child`:`root`)}#l(){if(this.#s)throw new l(this.name)}#u(){if(this.#c)throw new u(this.name)}#d(e){for(let t of this.#i)try{t(e)}catch{}this.#n&&this.#n.#d(e)}get disposalSignal(){return this.#o.signal}get disposed(){return this.#s}value(e,t,r){if(this.#l(),this.#u(),this.#e.has(e))throw new o(e);let i={dispose:r?.dispose,kind:`value`,value:t};return this.#e.set(e,i),this.#d({description:n(e),kind:`value`,source:this.name,type:`register`}),this}factory(e,t,r){if(this.#l(),this.#u(),this.#e.has(e))throw new o(e);let i={deps:r?.deps,dispose:r?.dispose,factory:t,kind:`factory`,lifetime:r?.lifetime??`singleton`};return this.#e.set(e,i),this.#d({description:n(e),kind:`factory`,source:this.name,type:`register`}),this}has(e){return this.#l(),this.#p(e)!==void 0}async resolve(e){this.#l();let t=await this.#b(e,new Set,[]);return this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,t),t}resolveSync(e){this.#l();let t=this.#p(e);if(!t)throw new a(e,this.name);let r=this.#S(e,t);return this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,r),r}async resolveMany(e){return Promise.all(e.map(e=>this.resolve(e)))}async resolveAll(e){this.#l();let t=new Set,r=[],i=async e=>{let t=await this.#b(e,new Set,[]);this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,t)};for(let n of this.#h())for(let[a,o]of n.#e)t.has(a)||o.kind!==`factory`||(t.add(a),(o.lifetime===`singleton`||e?.includeScoped&&typeof o.lifetime==`symbol`&&this.#g(o.lifetime))&&r.push(i(a)));await Promise.all(r)}inspect(e){this.#l();let t=e?.deep??!0,r=[],i=new Set;for(let e of this.#h()){for(let[t,a]of e.#e)if(!i.has(t))if(i.add(t),a.kind===`value`)r.push({description:n(t),kind:`value`});else{let e=typeof a.lifetime==`symbol`?`scope:${a.lifetime.description??`anonymous`}`:a.lifetime;r.push({deps:a.deps?.map(e=>n(e)),description:n(t),kind:`factory`,lifetime:e})}if(!t)break}return{nodes:r}}validate(){this.#l();let e=new Set,t=new Map;for(let n of this.#h())for(let[r,i]of n.#e)if(!e.has(r)&&(e.add(r),i.kind===`factory`&&i.deps&&i.deps.length>0)){t.set(r,i.deps);for(let e of i.deps)if(this.#p(e)===void 0)throw new a(e,this.name)}if(t.size>0){let e=new Set,n=new Set,r=(a,o)=>{if(e.has(a))throw new i([...o,a]);if(!n.has(a)){e.add(a);for(let e of t.get(a)??[])r(e,[...o,a]);e.delete(a),n.add(a)}};for(let e of t.keys())n.has(e)||r(e,[])}return this}freeze(){return this.#l(),this.#c?this:(this.validate(),this.#c=!0,this)}createScope(t,n){return this.#l(),new e(this,{name:n?.name,scopeTag:t})}on(e){return this.#l(),this.#i.add(e),()=>this.#i.delete(e)}onResolve(e){return this.#l(),this.#a.add(e),()=>this.#a.delete(e)}async dispose(){if(this.#s)return;this.#s=!0,this.#o.abort(),this.#d({source:this.name,type:`dispose`});let e=[],n=new Set;for(let t of this.#e.values())if(t.kind===`value`)t.dispose&&e.push(Promise.resolve().then(()=>t.dispose(t.value)));else if(n.add(t),t.dispose){let n=this.#t.get(t);n?.resolved&&e.push(Promise.resolve().then(()=>t.dispose(n.instance)))}for(let[t,r]of this.#t)!n.has(t)&&t.dispose&&r.resolved&&e.push(Promise.resolve().then(()=>t.dispose(r.instance)));let r=await Promise.allSettled(e);this.#t.clear(),this.#e.clear(),this.#i.clear(),this.#a.clear();for(let e of r)e.status===`rejected`&&t(`dispose hook failed in container '${this.name}':`,e.reason)}[Symbol.asyncDispose](){return this.dispose()}#f(e,t){for(let n of this.#a)try{n(e,t)}catch{}this.#n&&this.#n.#f(e,t)}#p(e){let t=this.#e.get(e);if(t)return t;if(this.#n)return this.#n.#l(),this.#n.#p(e)}#m(e){for(let t of this.#h())if(t.#e.has(e))return t;return this}*#h(){yield this;let e=this.#n;for(;e;)yield e,e=e.#n}#g(e){if(this.#r===e)return this;if(this.#n)return this.#n.#g(e)}#_(e){let t=this.#t.get(e);return t||(t={resolved:!1},this.#t.set(e,t)),t}#v(e,t){return{resolve:n=>this.#b(n,new Set(e),t),resolveSync:e=>this.resolveSync(e)}}#y(e,t,n,r){return e.resolved?Promise.resolve(e.instance):(e.promise||=Promise.resolve(t.factory(this.#v(n,r))).then(t=>(e.instance=t,e.resolved=!0,t)).catch(t=>{throw e.rejection=t,t}),e.promise)}async#b(e,t,n){if(t.has(e))throw new i([...n,e]);let r=this.#p(e);if(!r)throw new a(e,this.name);t.add(e);let o=await this.#x(e,r,t,[...n,e]);return t.delete(e),o}async#x(e,t,n,r){if(t.kind===`value`)return t.value;let{lifetime:i}=t;if(typeof i==`symbol`){let a=this.#g(i);if(!a)throw new c(e,i);return this.#y(a.#_(t),t,n,r)}if(i===`transient`)return t.factory(this.#v(n,r));let a=this.#m(e);return this.#y(a.#_(t),t,n,r)}#S(e,t){if(t.kind===`value`)return t.value;let{lifetime:n}=t;if(typeof n==`symbol`){let r=this.#g(n);if(!r)throw new c(e,n);let i=r.#t.get(t);if(i?.resolved)return i.instance;throw i?.rejection===void 0?new s(e,n):i.rejection}if(n===`transient`)throw new s(e,n);let r=this.#m(e).#t.get(t);if(r?.resolved)return r.instance;throw r?.rejection===void 0?new s(e,n):r.rejection}};function f(e){return new d(void 0,{name:e?.name??`root`})}function p(e){return Symbol(e)}function m(e){return Symbol(e)}async function h(e,t){try{return await e.resolve(t)}catch(e){if(e instanceof a)return;throw e}}async function g(e,t,n){let r=await h(e,t);return r===void 0?n:r}async function _(e,t){try{return{ok:!0,value:await e.resolve(t)}}catch(e){if(e instanceof a)return{error:e,ok:!1};throw e}}function v(e,t){try{return e.resolveSync(t)}catch(e){if(e instanceof a)return;throw e}}function y(e,t,n){let r=v(e,t);return r===void 0?n:r}function b(e,t){try{return{ok:!0,value:e.resolveSync(t)}}catch(e){if(e instanceof a)return{error:e,ok:!1};throw e}}async function x(e,...t){for(let n of t)await n(e);return e}exports.ConduitCircularDependencyError=i,exports.ConduitDisposedError=l,exports.ConduitDuplicateRegistrationError=o,exports.ConduitError=r,exports.ConduitFrozenError=u,exports.ConduitProviderNotFoundError=a,exports.ConduitScopedResolutionError=c,exports.ConduitSyncResolutionError=s,exports.createContainer=f,exports.loadModules=x,exports.resolveOptional=h,exports.resolveOrDefault=g,exports.resolveSyncOptional=v,exports.resolveSyncOrDefault=y,exports.scope=m,exports.token=p,exports.tryResolve=_,exports.trySyncResolve=b;
|
|
2
|
+
//# sourceMappingURL=conduit.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.cjs","names":["#parent","#scopeTag","#disposed","#frozen","#listeners","#emit","#disposeController","#assertNotDisposed","#assertNotFrozen","#registry","#getRegistration","#resolveToken","#fireInterceptors","#resolveSyncReg","#ancestors","#findScope","#resolveInterceptors","#cache","#makeResolver","#resolveReg","#populate","#getCache","#findOwnerContainer"],"sources":["../src/_dev.ts","../src/errors.ts","../src/container.ts","../src/types.ts","../src/utils.ts"],"sourcesContent":["const isDev = !(globalThis as { __CONDUIT_PROD__?: boolean }).__CONDUIT_PROD__;\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/conduit] ${msg}`, ...args);\n}\n","import type { Lifetime, ScopeToken, Token } from './types.js';\n\nexport const tokenName = (t: Token<any>): string => t.description ?? 'anonymous';\n\n/** Base class for all conduit errors. Use `instanceof ConduitError` to catch any conduit-originated error. */\nexport class ConduitError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ConduitError {\n return err instanceof ConduitError;\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n /** The token path that forms the cycle. */\n readonly cycle: Token<any>[];\n\n constructor(path: Token<any>[]) {\n super(`Circular dependency detected: ${path.map(tokenName).join(' -> ')}`);\n this.cycle = path;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n /** The token that could not be found. */\n readonly token: Token<any>;\n /** The container name at the time of the lookup. */\n readonly containerName: string;\n\n constructor(tok: Token<any>, containerName = 'unknown') {\n super(`No provider registered for token: ${tokenName(tok)} (in container '${containerName}')`);\n this.token = tok;\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n /** The token that was registered twice. */\n readonly token: Token<any>;\n\n constructor(tok: Token<any>) {\n super(`Token \"${tokenName(tok)}\" is already registered.`);\n this.token = tok;\n }\n}\n\nexport class ConduitSyncResolutionError extends ConduitError {\n /** The token that could not be resolved synchronously. */\n readonly token: Token<any>;\n /** The lifetime that prevented synchronous resolution. */\n readonly lifetime: Lifetime;\n\n constructor(tok: Token<any>, lifetime: Lifetime) {\n const reason =\n lifetime === 'transient'\n ? 'transient factories are never cached'\n : typeof lifetime === 'symbol'\n ? `named-scope \"${(lifetime as symbol).description ?? 'anonymous'}\" instance has not been resolved yet in this scope`\n : 'the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first';\n\n super(`Token \"${tokenName(tok)}\" cannot be resolved synchronously: ${reason}.`);\n this.token = tok;\n this.lifetime = lifetime;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n /** The token that required a scope container. */\n readonly token: Token<any>;\n /** The required scope token, if any. */\n readonly requiredScope: ScopeToken | undefined;\n\n constructor(tok: Token<any>, requiredScope?: ScopeToken) {\n const scopeName = requiredScope?.description ?? 'anonymous';\n\n super(\n requiredScope\n ? `Token \"${tokenName(tok)}\" requires scope \"${scopeName}\" but no matching scope container was found in the hierarchy.`\n : `Token \"${tokenName(tok)}\" requires a scope container but was resolved from the root.`,\n );\n this.token = tok;\n this.requiredScope = requiredScope;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n /** The name of the container that was already disposed. */\n readonly containerName: string;\n\n constructor(containerName = 'unknown') {\n super(`Cannot use a disposed container (container '${containerName}').`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitFrozenError extends ConduitError {\n /** The name of the container that is frozen. */\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Container '${containerName}' is frozen and cannot accept new registrations.`);\n this.containerName = containerName;\n }\n}\n","import type {\n Container,\n ContainerEvent,\n ContainerEventListener,\n ContainerGraph,\n ContainerNode,\n FactoryOptions,\n FactoryResolver,\n Lifetime,\n ResolveInterceptor,\n ScopeToken,\n Token,\n ValueOptions,\n} from './types.js';\n\nimport { error } from './_dev';\nimport {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitFrozenError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n ConduitSyncResolutionError,\n tokenName,\n} from './errors.js';\n\n// ---------------------------------------------------------------------------\n// Internal registration types\n// ---------------------------------------------------------------------------\n\ntype ValueRegistration<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n kind: 'value';\n value: T;\n};\n\ntype FactoryDescriptor<T> = {\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n factory: (resolver: FactoryResolver) => Promise<T> | T;\n kind: 'factory';\n lifetime: Lifetime;\n};\n\ntype Registration<T = unknown> = FactoryDescriptor<T> | ValueRegistration<T>;\n\n// Cache state is separate from the immutable factory descriptor.\ntype CacheEntry<T = unknown> = {\n instance?: T;\n // Retained on failure — subsequent calls rethrow the same rejection (no silent retry).\n promise?: Promise<T>;\n // Stored on rejection so resolveSync() can rethrow the original error synchronously.\n rejection?: unknown;\n resolved: boolean;\n};\n\n// ---------------------------------------------------------------------------\n// ContainerImpl\n// ---------------------------------------------------------------------------\n\nclass ContainerImpl implements Container {\n #registry = new Map<Token<any>, Registration<any>>();\n #cache = new Map<FactoryDescriptor<any>, CacheEntry<any>>();\n #parent?: ContainerImpl;\n #scopeTag?: ScopeToken;\n #listeners = new Set<ContainerEventListener>();\n #resolveInterceptors = new Set<ResolveInterceptor>();\n #disposeController = new AbortController();\n #disposed = false;\n #frozen = false;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, opts: { name?: string; scopeTag?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scopeTag = opts.scopeTag;\n this.name =\n opts.name ??\n (parent\n ? opts.scopeTag\n ? `${parent.name}:${opts.scopeTag.description ?? 'scope'}`\n : `${parent.name}:child`\n : 'root');\n }\n\n #assertNotDisposed(): void {\n if (this.#disposed) throw new ConduitDisposedError(this.name);\n }\n\n #assertNotFrozen(): void {\n if (this.#frozen) throw new ConduitFrozenError(this.name);\n }\n\n // Emit to local listeners then propagate up to parent.\n #emit(event: ContainerEvent): void {\n for (const listener of this.#listeners) {\n try {\n listener(event);\n } catch {\n // swallowed — listener errors must not disrupt container operation\n }\n }\n\n if (this.#parent) this.#parent.#emit(event);\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposeController.signal;\n }\n\n get disposed(): boolean {\n return this.#disposed;\n }\n\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: ValueRegistration<T> = { dispose: opts?.dispose, kind: 'value', value: val };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'value', source: this.name, type: 'register' });\n\n return this;\n }\n\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: FactoryDescriptor<T> = {\n deps: opts?.deps,\n dispose: opts?.dispose,\n factory: fn,\n kind: 'factory',\n lifetime: opts?.lifetime ?? 'singleton',\n };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'factory', source: this.name, type: 'register' });\n\n return this;\n }\n\n has<T>(tok: Token<T>): boolean {\n this.#assertNotDisposed();\n\n return this.#getRegistration(tok) !== undefined;\n }\n\n async resolve<T>(tok: Token<T>): Promise<T> {\n this.#assertNotDisposed();\n\n const result = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n resolveSync<T>(tok: Token<T>): T {\n this.#assertNotDisposed();\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n const result = this.#resolveSyncReg(tok, reg);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n async resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }> {\n return Promise.all(toks.map((t) => this.resolve(t))) as Promise<{\n [K in keyof D]: D[K] extends Token<infer U> ? U : never;\n }>;\n }\n\n async resolveAll(opts?: { includeScoped?: boolean }): Promise<void> {\n this.#assertNotDisposed();\n\n const seen = new Set<Token<any>>();\n const work: Promise<unknown>[] = [];\n\n const resolveAndNotify = async (tok: Token<unknown>): Promise<void> => {\n const value = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, value);\n };\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (seen.has(tok as Token<any>) || reg.kind !== 'factory') continue;\n\n seen.add(tok as Token<any>);\n\n if (reg.lifetime === 'singleton') {\n work.push(resolveAndNotify(tok as Token<unknown>));\n } else if (opts?.includeScoped && typeof reg.lifetime === 'symbol') {\n const scopeContainer = this.#findScope(reg.lifetime);\n\n if (scopeContainer) work.push(resolveAndNotify(tok as Token<unknown>));\n }\n }\n }\n\n await Promise.all(work);\n }\n\n inspect(opts?: { deep?: boolean }): ContainerGraph {\n this.#assertNotDisposed();\n\n const deep = opts?.deep ?? true;\n const nodes: ContainerNode[] = [];\n const seen = new Set<Token<any>>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (!seen.has(tok as Token<any>)) {\n seen.add(tok as Token<any>);\n\n if (reg.kind === 'value') {\n nodes.push({ description: tokenName(tok as Token<any>), kind: 'value' });\n } else {\n const lifetime: ContainerNode['lifetime'] =\n typeof reg.lifetime === 'symbol'\n ? `scope:${(reg.lifetime as symbol).description ?? 'anonymous'}`\n : (reg.lifetime as 'singleton' | 'transient');\n\n nodes.push({\n deps: reg.deps?.map((d) => tokenName(d)),\n description: tokenName(tok as Token<any>),\n kind: 'factory',\n lifetime,\n });\n }\n }\n }\n\n if (!deep) break;\n }\n\n return { nodes };\n }\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this {\n this.#assertNotDisposed();\n\n const visited = new Set<Token<any>>();\n\n // Build token→deps map for static cycle detection.\n const staticDeps = new Map<Token<any>, readonly Token<any>[]>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (visited.has(tok as Token<any>)) continue;\n\n visited.add(tok as Token<any>);\n\n if (reg.kind === 'factory' && reg.deps && reg.deps.length > 0) {\n staticDeps.set(tok as Token<any>, reg.deps);\n\n for (const dep of reg.deps) {\n if (this.#getRegistration(dep) === undefined) {\n throw new ConduitProviderNotFoundError(dep, this.name);\n }\n }\n }\n }\n }\n\n // Static cycle detection over declared deps.\n if (staticDeps.size > 0) {\n const visiting = new Set<Token<any>>();\n const done = new Set<Token<any>>();\n\n const dfs = (tok: Token<any>, path: Token<any>[]): void => {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n if (done.has(tok)) return;\n\n visiting.add(tok);\n\n for (const dep of staticDeps.get(tok) ?? []) {\n dfs(dep, [...path, tok]);\n }\n\n visiting.delete(tok);\n done.add(tok);\n };\n\n for (const tok of staticDeps.keys()) {\n if (!done.has(tok)) dfs(tok, []);\n }\n }\n\n return this;\n }\n\n freeze(): this {\n this.#assertNotDisposed();\n\n if (this.#frozen) return this;\n\n this.validate();\n this.#frozen = true;\n\n return this;\n }\n\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container {\n this.#assertNotDisposed();\n\n return new ContainerImpl(this, { name: opts?.name, scopeTag: scopeToken });\n }\n\n on(listener: ContainerEventListener): () => void {\n this.#assertNotDisposed();\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n onResolve(interceptor: ResolveInterceptor): () => void {\n this.#assertNotDisposed();\n this.#resolveInterceptors.add(interceptor);\n\n return () => this.#resolveInterceptors.delete(interceptor);\n }\n\n async dispose(): Promise<void> {\n if (this.#disposed) return;\n\n this.#disposed = true;\n this.#disposeController.abort();\n this.#emit({ source: this.name, type: 'dispose' });\n\n const hooks: Promise<void>[] = [];\n const ownDescriptors = new Set<FactoryDescriptor<any>>();\n\n for (const reg of this.#registry.values()) {\n if (reg.kind === 'value') {\n if (reg.dispose) hooks.push(Promise.resolve().then(() => reg.dispose!(reg.value)));\n } else {\n ownDescriptors.add(reg);\n\n if (reg.dispose) {\n const entry = this.#cache.get(reg);\n\n if (entry?.resolved) hooks.push(Promise.resolve().then(() => reg.dispose!(entry.instance as any)));\n }\n }\n }\n\n // Inherited scope instances cached locally (not in #registry)\n for (const [descriptor, entry] of this.#cache) {\n if (!ownDescriptors.has(descriptor) && descriptor.dispose && entry.resolved) {\n hooks.push(Promise.resolve().then(() => descriptor.dispose!(entry.instance as any)));\n }\n }\n\n const outcomes = await Promise.allSettled(hooks);\n\n this.#cache.clear();\n this.#registry.clear();\n this.#listeners.clear();\n this.#resolveInterceptors.clear();\n\n for (const outcome of outcomes) {\n if (outcome.status === 'rejected') {\n error(`dispose hook failed in container '${this.name}':`, outcome.reason);\n }\n }\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n #fireInterceptors<T>(tok: Token<T>, value: T): void {\n for (const interceptor of this.#resolveInterceptors) {\n try {\n interceptor(tok, value);\n } catch {\n // swallowed — interceptor errors must not disrupt resolution\n }\n }\n\n if (this.#parent) this.#parent.#fireInterceptors(tok, value);\n }\n\n #getRegistration<T>(tok: Token<T>): Registration<T> | undefined {\n const local = this.#registry.get(tok) as Registration<T> | undefined;\n\n if (local) return local;\n\n if (!this.#parent) return undefined;\n\n this.#parent.#assertNotDisposed();\n\n return this.#parent.#getRegistration(tok);\n }\n\n #findOwnerContainer<T>(tok: Token<T>): ContainerImpl {\n for (const c of this.#ancestors()) {\n if (c.#registry.has(tok)) return c;\n }\n\n return this;\n }\n\n *#ancestors(): Generator<ContainerImpl> {\n yield this;\n\n let parent = this.#parent;\n\n while (parent) {\n yield parent;\n parent = parent.#parent;\n }\n }\n\n #findScope(scopeToken: ScopeToken): ContainerImpl | undefined {\n if (this.#scopeTag === scopeToken) return this;\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#findScope(scopeToken);\n }\n\n #getCache<T>(descriptor: FactoryDescriptor<T>): CacheEntry<T> {\n let entry = this.#cache.get(descriptor) as CacheEntry<T> | undefined;\n\n if (!entry) {\n entry = { resolved: false };\n this.#cache.set(descriptor, entry);\n }\n\n return entry;\n }\n\n /** Build a FactoryResolver scoped to the current resolution context. */\n #makeResolver(visiting: Set<Token<any>>, path: Token<any>[]): FactoryResolver {\n return {\n resolve: <T>(tok: Token<T>): Promise<T> => this.#resolveToken(tok, new Set(visiting), path),\n resolveSync: <T>(tok: Token<T>): T => this.resolveSync(tok),\n };\n }\n\n /** Populate a cache entry for a factory, deduplicating concurrent calls. */\n #populate<T>(\n entry: CacheEntry<T>,\n reg: FactoryDescriptor<T>,\n visiting: Set<Token<any>>,\n path: Token<any>[],\n ): Promise<T> {\n if (entry.resolved) return Promise.resolve(entry.instance as T);\n\n if (entry.promise) return entry.promise;\n\n entry.promise = Promise.resolve(reg.factory(this.#makeResolver(visiting, path)))\n .then((instance) => {\n entry.instance = instance;\n entry.resolved = true;\n\n return instance;\n })\n .catch((err) => {\n entry.rejection = err;\n throw err;\n });\n\n return entry.promise;\n }\n\n async #resolveToken<T>(tok: Token<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n visiting.add(tok);\n\n const result = await this.#resolveReg(tok, reg, visiting, [...path, tok]);\n\n visiting.delete(tok);\n\n return result;\n }\n\n async #resolveReg<T>(tok: Token<T>, reg: Registration<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n // Named scope token\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n return this.#populate(scopeContainer.#getCache(reg), reg, visiting, path);\n }\n\n if (lifetime === 'transient') {\n return reg.factory(this.#makeResolver(visiting, path));\n }\n\n // singleton — cache in owner container\n const cacheContainer = this.#findOwnerContainer(tok);\n\n return this.#populate(cacheContainer.#getCache(reg), reg, visiting, path);\n }\n\n #resolveSyncReg<T>(tok: Token<T>, reg: Registration<T>): T {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n const entry = scopeContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n\n if (lifetime === 'transient') throw new ConduitSyncResolutionError(tok, lifetime);\n\n const cacheContainer = this.#findOwnerContainer(tok);\n const entry = cacheContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public factory\n// ---------------------------------------------------------------------------\n\nexport function createContainer(opts?: { name?: string }): Container {\n return new ContainerImpl(undefined, { name: opts?.name ?? 'root' });\n}\n","// ---------------------------------------------------------------------------\n// Token\n// ---------------------------------------------------------------------------\n\nexport type Token<T = unknown> = symbol & { __type?: T };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\n// ---------------------------------------------------------------------------\n// ScopeToken — named lifecycle scopes\n// ---------------------------------------------------------------------------\n\nexport type ScopeToken = symbol & { __scopeToken?: never };\n\n/**\n * Creates a named scope token. Factories registered with a ScopeToken lifetime\n * are only resolvable from a container created with createScope(scopeToken).\n */\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\n// ---------------------------------------------------------------------------\n// Lifetime & options\n// ---------------------------------------------------------------------------\n\n/** Caching strategy for factory registrations. Named scopes use a ScopeToken. */\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n};\n\nexport type FactoryOptions<T> = {\n /** Optional statically-declared dependencies. Used for early validation in `freeze()`. */\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n lifetime?: Lifetime;\n};\n\n// ---------------------------------------------------------------------------\n// Resolver — injected into factories\n// ---------------------------------------------------------------------------\n\n/** Minimal resolver passed to every factory function. */\nexport interface FactoryResolver {\n resolve<T>(tok: Token<T>): Promise<T>;\n /**\n * Resolve synchronously. Works for value providers and already-resolved\n * singleton/scoped instances. Throws `ConduitSyncResolutionError` if the instance\n * has not been resolved yet.\n */\n resolveSync<T>(tok: Token<T>): T;\n}\n\n// ---------------------------------------------------------------------------\n// ContainerModule — grouping and async setup\n// ---------------------------------------------------------------------------\n\nexport type ContainerModule = (container: Container) => Promise<void> | void;\n\n// ---------------------------------------------------------------------------\n// Events — observable container state\n// ---------------------------------------------------------------------------\n\nexport type ContainerEvent =\n | { description: string; kind: 'factory' | 'value'; source: string; type: 'register' }\n | { description: string; source: string; type: 'resolve' }\n | { source: string; type: 'dispose' };\n\nexport type ContainerEventListener = (event: ContainerEvent) => void;\n\n// ---------------------------------------------------------------------------\n// Result type\n// ---------------------------------------------------------------------------\n\nexport type ResolveResult<T> = { ok: true; value: T } | { error: unknown; ok: false };\n\n/**\n * Infer the resolved-value tuple type from a `readonly` array of tokens.\n * Mirrors the return type of `resolveMany`.\n *\n * @example\n * const TOKENS = [AuthToken, LoggerToken] as const;\n * type Services = InferTokenTypes<typeof TOKENS>;\n * // → [AuthService, Logger]\n */\nexport type InferTokenTypes<T extends readonly Token<any>[]> = {\n [K in keyof T]: T[K] extends Token<infer U> ? U : never;\n};\n\n/** Interceptor called after every successful resolution. Receives the token and resolved value. */\nexport type ResolveInterceptor = <T>(tok: Token<T>, value: T) => void;\n\n// ---------------------------------------------------------------------------\n// ContainerGraph — inspect() output\n// ---------------------------------------------------------------------------\n\nexport type ContainerNode = {\n /** Statically-declared dependency token descriptions (from `deps:` option). */\n deps?: string[];\n description: string;\n kind: 'factory' | 'value';\n /** 'singleton', 'transient', or 'scope:<name>' for named scopes. */\n lifetime?: 'singleton' | 'transient' | `scope:${string}`;\n};\n\nexport type ContainerGraph = {\n nodes: ContainerNode[];\n};\n\n// ---------------------------------------------------------------------------\n// Container public interface\n// ---------------------------------------------------------------------------\n\nexport interface Container {\n /** Delegates to `dispose()`. Enables `await using` declarations. */\n [Symbol.asyncDispose](): Promise<void>;\n /** Human-readable identifier for this container. Set via createContainer({ name }). */\n readonly name: string;\n\n /** `AbortSignal` aborted when the container is disposed. Use to tie external lifecycles to this container. */\n readonly disposalSignal: AbortSignal;\n\n /** Whether the container has been disposed. */\n readonly disposed: boolean;\n\n /** Register a static value. */\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this;\n\n /**\n * Register a factory. The factory receives a `FactoryResolver` to resolve\n * its own dependencies lazily via `resolver.resolve(Token)`.\n */\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this;\n\n /** Check whether a token is registered (walks parent chain). */\n has<T>(tok: Token<T>): boolean;\n\n /** Resolve a single registered provider. */\n resolve<T>(tok: Token<T>): Promise<T>;\n\n /**\n * Resolve a token synchronously.\n * Works for value registrations and already-resolved singleton/scope instances.\n * Throws `ConduitSyncResolutionError` for transient factories or unresolved singletons.\n * Rethrows the cached rejection if the factory previously failed.\n */\n resolveSync<T>(tok: Token<T>): T;\n\n /**\n * Resolve multiple tokens in parallel, returning a typed tuple.\n */\n resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }>;\n\n /**\n * Eagerly resolve all registered singleton factories across the entire\n * container hierarchy. Useful for startup validation and pre-warming\n * `resolveSync()` hot paths.\n *\n * Pass `{ includeScoped: true }` to also pre-warm named-scope factories\n * registered on the current scope container.\n */\n resolveAll(opts?: { includeScoped?: boolean }): Promise<void>;\n\n /**\n * Return a serializable graph of every registered token.\n * By default traverses the full parent chain (deep: true).\n */\n inspect(opts?: { deep?: boolean }): ContainerGraph;\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this;\n\n /**\n * Freeze the container, locking it against further registrations.\n * After `freeze()`, `value()` and `factory()` throw `ConduitFrozenError`.\n * Validates statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Idempotent — calling `freeze()` again on an already-frozen container is a no-op.\n * Note: cycle detection for lazy (undeclared) deps happens at resolve time.\n */\n freeze(): this;\n\n /**\n * Create a child scope container. If `scopeToken` is provided, factories\n * registered with that token as their lifetime are resolved and cached here.\n * Omit `scopeToken` for a plain child container with no named scope.\n */\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container;\n\n /**\n * Subscribe to container events (register, resolve, dispose).\n * Events propagate up to parent containers. Returns an unsubscribe function.\n */\n on(listener: ContainerEventListener): () => void;\n\n /**\n * Register an interceptor called after every successful resolution.\n * Returns an unsubscribe function. Interceptor errors are swallowed.\n */\n onResolve(interceptor: ResolveInterceptor): () => void;\n\n /** Dispose the container, running all registered cleanup hooks in parallel. */\n dispose(): Promise<void>;\n}\n","import type { Container, ContainerModule, ResolveResult, Token } from './types.js';\n\nimport { ConduitProviderNotFoundError } from './errors.js';\n\n/**\n * Resolve a token, returning `undefined` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOptional<T>(container: Container, tok: Token<T>): Promise<T | undefined> {\n try {\n return await container.resolve(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token, returning `defaultValue` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): Promise<T> {\n const result = await resolveOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitDisposedError` and `ConduitCircularDependencyError`.\n */\nexport async function tryResolve<T>(container: Container, tok: Token<T>): Promise<ResolveResult<T>> {\n try {\n const value = await container.resolve(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `undefined` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOptional<T>(container: Container, tok: Token<T>): T | undefined {\n try {\n return container.resolveSync(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `defaultValue` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): T {\n const result = resolveSyncOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token synchronously, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitSyncResolutionError`, `ConduitDisposedError`, and `ConduitScopedResolutionError`.\n */\nexport function trySyncResolve<T>(container: Container, tok: Token<T>): ResolveResult<T> {\n try {\n const value = container.resolveSync(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Apply container modules sequentially (each module may be async).\n * Returns the container for chaining.\n */\nexport async function loadModules(container: Container, ...modules: ContainerModule[]): Promise<Container> {\n for (const mod of modules) await mod(container);\n\n return container;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.d.ts","sourceRoot":"","sources":["../src/conduit.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Conduit=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=!globalThis.__CONDUIT_PROD__;function n(e,...n){t&&console.error(`[@vielzeug/conduit] ${e}`,...n)}var r=e=>e.description??`anonymous`,i=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},a=class extends i{cycle;constructor(e){super(`Circular dependency detected: ${e.map(r).join(` -> `)}`),this.cycle=e}},o=class extends i{token;containerName;constructor(e,t=`unknown`){super(`No provider registered for token: ${r(e)} (in container '${t}')`),this.token=e,this.containerName=t}},s=class extends i{token;constructor(e){super(`Token "${r(e)}" is already registered.`),this.token=e}},c=class extends i{token;lifetime;constructor(e,t){let n=t===`transient`?`transient factories are never cached`:typeof t==`symbol`?`named-scope "${t.description??`anonymous`}" instance has not been resolved yet in this scope`:`the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first`;super(`Token "${r(e)}" cannot be resolved synchronously: ${n}.`),this.token=e,this.lifetime=t}},l=class extends i{token;requiredScope;constructor(e,t){let n=t?.description??`anonymous`;super(t?`Token "${r(e)}" requires scope "${n}" but no matching scope container was found in the hierarchy.`:`Token "${r(e)}" requires a scope container but was resolved from the root.`),this.token=e,this.requiredScope=t}},u=class extends i{containerName;constructor(e=`unknown`){super(`Cannot use a disposed container (container '${e}').`),this.containerName=e}},d=class extends i{containerName;constructor(e){super(`Container '${e}' is frozen and cannot accept new registrations.`),this.containerName=e}},f=class e{#e=new Map;#t=new Map;#n;#r;#i=new Set;#a=new Set;#o=new AbortController;#s=!1;#c=!1;name;constructor(e,t={}){this.#n=e,this.#r=t.scopeTag,this.name=t.name??(e?t.scopeTag?`${e.name}:${t.scopeTag.description??`scope`}`:`${e.name}:child`:`root`)}#l(){if(this.#s)throw new u(this.name)}#u(){if(this.#c)throw new d(this.name)}#d(e){for(let t of this.#i)try{t(e)}catch{}this.#n&&this.#n.#d(e)}get disposalSignal(){return this.#o.signal}get disposed(){return this.#s}value(e,t,n){if(this.#l(),this.#u(),this.#e.has(e))throw new s(e);let i={dispose:n?.dispose,kind:`value`,value:t};return this.#e.set(e,i),this.#d({description:r(e),kind:`value`,source:this.name,type:`register`}),this}factory(e,t,n){if(this.#l(),this.#u(),this.#e.has(e))throw new s(e);let i={deps:n?.deps,dispose:n?.dispose,factory:t,kind:`factory`,lifetime:n?.lifetime??`singleton`};return this.#e.set(e,i),this.#d({description:r(e),kind:`factory`,source:this.name,type:`register`}),this}has(e){return this.#l(),this.#p(e)!==void 0}async resolve(e){this.#l();let t=await this.#b(e,new Set,[]);return this.#d({description:r(e),source:this.name,type:`resolve`}),this.#f(e,t),t}resolveSync(e){this.#l();let t=this.#p(e);if(!t)throw new o(e,this.name);let n=this.#S(e,t);return this.#d({description:r(e),source:this.name,type:`resolve`}),this.#f(e,n),n}async resolveMany(e){return Promise.all(e.map(e=>this.resolve(e)))}async resolveAll(e){this.#l();let t=new Set,n=[],i=async e=>{let t=await this.#b(e,new Set,[]);this.#d({description:r(e),source:this.name,type:`resolve`}),this.#f(e,t)};for(let r of this.#h())for(let[a,o]of r.#e)t.has(a)||o.kind!==`factory`||(t.add(a),(o.lifetime===`singleton`||e?.includeScoped&&typeof o.lifetime==`symbol`&&this.#g(o.lifetime))&&n.push(i(a)));await Promise.all(n)}inspect(e){this.#l();let t=e?.deep??!0,n=[],i=new Set;for(let e of this.#h()){for(let[t,a]of e.#e)if(!i.has(t))if(i.add(t),a.kind===`value`)n.push({description:r(t),kind:`value`});else{let e=typeof a.lifetime==`symbol`?`scope:${a.lifetime.description??`anonymous`}`:a.lifetime;n.push({deps:a.deps?.map(e=>r(e)),description:r(t),kind:`factory`,lifetime:e})}if(!t)break}return{nodes:n}}validate(){this.#l();let e=new Set,t=new Map;for(let n of this.#h())for(let[r,i]of n.#e)if(!e.has(r)&&(e.add(r),i.kind===`factory`&&i.deps&&i.deps.length>0)){t.set(r,i.deps);for(let e of i.deps)if(this.#p(e)===void 0)throw new o(e,this.name)}if(t.size>0){let e=new Set,n=new Set,r=(i,o)=>{if(e.has(i))throw new a([...o,i]);if(!n.has(i)){e.add(i);for(let e of t.get(i)??[])r(e,[...o,i]);e.delete(i),n.add(i)}};for(let e of t.keys())n.has(e)||r(e,[])}return this}freeze(){return this.#l(),this.#c?this:(this.validate(),this.#c=!0,this)}createScope(t,n){return this.#l(),new e(this,{name:n?.name,scopeTag:t})}on(e){return this.#l(),this.#i.add(e),()=>this.#i.delete(e)}onResolve(e){return this.#l(),this.#a.add(e),()=>this.#a.delete(e)}async dispose(){if(this.#s)return;this.#s=!0,this.#o.abort(),this.#d({source:this.name,type:`dispose`});let e=[],t=new Set;for(let n of this.#e.values())if(n.kind===`value`)n.dispose&&e.push(Promise.resolve().then(()=>n.dispose(n.value)));else if(t.add(n),n.dispose){let t=this.#t.get(n);t?.resolved&&e.push(Promise.resolve().then(()=>n.dispose(t.instance)))}for(let[n,r]of this.#t)!t.has(n)&&n.dispose&&r.resolved&&e.push(Promise.resolve().then(()=>n.dispose(r.instance)));let r=await Promise.allSettled(e);this.#t.clear(),this.#e.clear(),this.#i.clear(),this.#a.clear();for(let e of r)e.status===`rejected`&&n(`dispose hook failed in container '${this.name}':`,e.reason)}[Symbol.asyncDispose](){return this.dispose()}#f(e,t){for(let n of this.#a)try{n(e,t)}catch{}this.#n&&this.#n.#f(e,t)}#p(e){let t=this.#e.get(e);if(t)return t;if(this.#n)return this.#n.#l(),this.#n.#p(e)}#m(e){for(let t of this.#h())if(t.#e.has(e))return t;return this}*#h(){yield this;let e=this.#n;for(;e;)yield e,e=e.#n}#g(e){if(this.#r===e)return this;if(this.#n)return this.#n.#g(e)}#_(e){let t=this.#t.get(e);return t||(t={resolved:!1},this.#t.set(e,t)),t}#v(e,t){return{resolve:n=>this.#b(n,new Set(e),t),resolveSync:e=>this.resolveSync(e)}}#y(e,t,n,r){return e.resolved?Promise.resolve(e.instance):(e.promise||=Promise.resolve(t.factory(this.#v(n,r))).then(t=>(e.instance=t,e.resolved=!0,t)).catch(t=>{throw e.rejection=t,t}),e.promise)}async#b(e,t,n){if(t.has(e))throw new a([...n,e]);let r=this.#p(e);if(!r)throw new o(e,this.name);t.add(e);let i=await this.#x(e,r,t,[...n,e]);return t.delete(e),i}async#x(e,t,n,r){if(t.kind===`value`)return t.value;let{lifetime:i}=t;if(typeof i==`symbol`){let a=this.#g(i);if(!a)throw new l(e,i);return this.#y(a.#_(t),t,n,r)}if(i===`transient`)return t.factory(this.#v(n,r));let a=this.#m(e);return this.#y(a.#_(t),t,n,r)}#S(e,t){if(t.kind===`value`)return t.value;let{lifetime:n}=t;if(typeof n==`symbol`){let r=this.#g(n);if(!r)throw new l(e,n);let i=r.#t.get(t);if(i?.resolved)return i.instance;throw i?.rejection===void 0?new c(e,n):i.rejection}if(n===`transient`)throw new c(e,n);let r=this.#m(e).#t.get(t);if(r?.resolved)return r.instance;throw r?.rejection===void 0?new c(e,n):r.rejection}};function p(e){return new f(void 0,{name:e?.name??`root`})}function m(e){return Symbol(e)}function h(e){return Symbol(e)}async function g(e,t){try{return await e.resolve(t)}catch(e){if(e instanceof o)return;throw e}}async function _(e,t,n){let r=await g(e,t);return r===void 0?n:r}async function v(e,t){try{return{ok:!0,value:await e.resolve(t)}}catch(e){if(e instanceof o)return{error:e,ok:!1};throw e}}function y(e,t){try{return e.resolveSync(t)}catch(e){if(e instanceof o)return;throw e}}function b(e,t,n){let r=y(e,t);return r===void 0?n:r}function x(e,t){try{return{ok:!0,value:e.resolveSync(t)}}catch(e){if(e instanceof o)return{error:e,ok:!1};throw e}}async function S(e,...t){for(let n of t)await n(e);return e}return e.ConduitCircularDependencyError=a,e.ConduitDisposedError=u,e.ConduitDuplicateRegistrationError=s,e.ConduitError=i,e.ConduitFrozenError=d,e.ConduitProviderNotFoundError=o,e.ConduitScopedResolutionError=l,e.ConduitSyncResolutionError=c,e.createContainer=p,e.loadModules=S,e.resolveOptional=g,e.resolveOrDefault=_,e.resolveSyncOptional=y,e.resolveSyncOrDefault=b,e.scope=h,e.token=m,e.tryResolve=v,e.trySyncResolve=x,e})({});
|
|
2
|
+
//# sourceMappingURL=conduit.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.iife.js","names":["#parent","#scopeTag","#disposed","#frozen","#listeners","#emit","#disposeController","#assertNotDisposed","#assertNotFrozen","#registry","#getRegistration","#resolveToken","#fireInterceptors","#resolveSyncReg","#ancestors","#findScope","#resolveInterceptors","#cache","#makeResolver","#resolveReg","#populate","#getCache","#findOwnerContainer"],"sources":["../src/_dev.ts","../src/errors.ts","../src/container.ts","../src/types.ts","../src/utils.ts"],"sourcesContent":["const isDev = !(globalThis as { __CONDUIT_PROD__?: boolean }).__CONDUIT_PROD__;\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/conduit] ${msg}`, ...args);\n}\n","import type { Lifetime, ScopeToken, Token } from './types.js';\n\nexport const tokenName = (t: Token<any>): string => t.description ?? 'anonymous';\n\n/** Base class for all conduit errors. Use `instanceof ConduitError` to catch any conduit-originated error. */\nexport class ConduitError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ConduitError {\n return err instanceof ConduitError;\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n /** The token path that forms the cycle. */\n readonly cycle: Token<any>[];\n\n constructor(path: Token<any>[]) {\n super(`Circular dependency detected: ${path.map(tokenName).join(' -> ')}`);\n this.cycle = path;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n /** The token that could not be found. */\n readonly token: Token<any>;\n /** The container name at the time of the lookup. */\n readonly containerName: string;\n\n constructor(tok: Token<any>, containerName = 'unknown') {\n super(`No provider registered for token: ${tokenName(tok)} (in container '${containerName}')`);\n this.token = tok;\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n /** The token that was registered twice. */\n readonly token: Token<any>;\n\n constructor(tok: Token<any>) {\n super(`Token \"${tokenName(tok)}\" is already registered.`);\n this.token = tok;\n }\n}\n\nexport class ConduitSyncResolutionError extends ConduitError {\n /** The token that could not be resolved synchronously. */\n readonly token: Token<any>;\n /** The lifetime that prevented synchronous resolution. */\n readonly lifetime: Lifetime;\n\n constructor(tok: Token<any>, lifetime: Lifetime) {\n const reason =\n lifetime === 'transient'\n ? 'transient factories are never cached'\n : typeof lifetime === 'symbol'\n ? `named-scope \"${(lifetime as symbol).description ?? 'anonymous'}\" instance has not been resolved yet in this scope`\n : 'the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first';\n\n super(`Token \"${tokenName(tok)}\" cannot be resolved synchronously: ${reason}.`);\n this.token = tok;\n this.lifetime = lifetime;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n /** The token that required a scope container. */\n readonly token: Token<any>;\n /** The required scope token, if any. */\n readonly requiredScope: ScopeToken | undefined;\n\n constructor(tok: Token<any>, requiredScope?: ScopeToken) {\n const scopeName = requiredScope?.description ?? 'anonymous';\n\n super(\n requiredScope\n ? `Token \"${tokenName(tok)}\" requires scope \"${scopeName}\" but no matching scope container was found in the hierarchy.`\n : `Token \"${tokenName(tok)}\" requires a scope container but was resolved from the root.`,\n );\n this.token = tok;\n this.requiredScope = requiredScope;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n /** The name of the container that was already disposed. */\n readonly containerName: string;\n\n constructor(containerName = 'unknown') {\n super(`Cannot use a disposed container (container '${containerName}').`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitFrozenError extends ConduitError {\n /** The name of the container that is frozen. */\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Container '${containerName}' is frozen and cannot accept new registrations.`);\n this.containerName = containerName;\n }\n}\n","import type {\n Container,\n ContainerEvent,\n ContainerEventListener,\n ContainerGraph,\n ContainerNode,\n FactoryOptions,\n FactoryResolver,\n Lifetime,\n ResolveInterceptor,\n ScopeToken,\n Token,\n ValueOptions,\n} from './types.js';\n\nimport { error } from './_dev';\nimport {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitFrozenError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n ConduitSyncResolutionError,\n tokenName,\n} from './errors.js';\n\n// ---------------------------------------------------------------------------\n// Internal registration types\n// ---------------------------------------------------------------------------\n\ntype ValueRegistration<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n kind: 'value';\n value: T;\n};\n\ntype FactoryDescriptor<T> = {\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n factory: (resolver: FactoryResolver) => Promise<T> | T;\n kind: 'factory';\n lifetime: Lifetime;\n};\n\ntype Registration<T = unknown> = FactoryDescriptor<T> | ValueRegistration<T>;\n\n// Cache state is separate from the immutable factory descriptor.\ntype CacheEntry<T = unknown> = {\n instance?: T;\n // Retained on failure — subsequent calls rethrow the same rejection (no silent retry).\n promise?: Promise<T>;\n // Stored on rejection so resolveSync() can rethrow the original error synchronously.\n rejection?: unknown;\n resolved: boolean;\n};\n\n// ---------------------------------------------------------------------------\n// ContainerImpl\n// ---------------------------------------------------------------------------\n\nclass ContainerImpl implements Container {\n #registry = new Map<Token<any>, Registration<any>>();\n #cache = new Map<FactoryDescriptor<any>, CacheEntry<any>>();\n #parent?: ContainerImpl;\n #scopeTag?: ScopeToken;\n #listeners = new Set<ContainerEventListener>();\n #resolveInterceptors = new Set<ResolveInterceptor>();\n #disposeController = new AbortController();\n #disposed = false;\n #frozen = false;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, opts: { name?: string; scopeTag?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scopeTag = opts.scopeTag;\n this.name =\n opts.name ??\n (parent\n ? opts.scopeTag\n ? `${parent.name}:${opts.scopeTag.description ?? 'scope'}`\n : `${parent.name}:child`\n : 'root');\n }\n\n #assertNotDisposed(): void {\n if (this.#disposed) throw new ConduitDisposedError(this.name);\n }\n\n #assertNotFrozen(): void {\n if (this.#frozen) throw new ConduitFrozenError(this.name);\n }\n\n // Emit to local listeners then propagate up to parent.\n #emit(event: ContainerEvent): void {\n for (const listener of this.#listeners) {\n try {\n listener(event);\n } catch {\n // swallowed — listener errors must not disrupt container operation\n }\n }\n\n if (this.#parent) this.#parent.#emit(event);\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposeController.signal;\n }\n\n get disposed(): boolean {\n return this.#disposed;\n }\n\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: ValueRegistration<T> = { dispose: opts?.dispose, kind: 'value', value: val };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'value', source: this.name, type: 'register' });\n\n return this;\n }\n\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: FactoryDescriptor<T> = {\n deps: opts?.deps,\n dispose: opts?.dispose,\n factory: fn,\n kind: 'factory',\n lifetime: opts?.lifetime ?? 'singleton',\n };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'factory', source: this.name, type: 'register' });\n\n return this;\n }\n\n has<T>(tok: Token<T>): boolean {\n this.#assertNotDisposed();\n\n return this.#getRegistration(tok) !== undefined;\n }\n\n async resolve<T>(tok: Token<T>): Promise<T> {\n this.#assertNotDisposed();\n\n const result = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n resolveSync<T>(tok: Token<T>): T {\n this.#assertNotDisposed();\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n const result = this.#resolveSyncReg(tok, reg);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n async resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }> {\n return Promise.all(toks.map((t) => this.resolve(t))) as Promise<{\n [K in keyof D]: D[K] extends Token<infer U> ? U : never;\n }>;\n }\n\n async resolveAll(opts?: { includeScoped?: boolean }): Promise<void> {\n this.#assertNotDisposed();\n\n const seen = new Set<Token<any>>();\n const work: Promise<unknown>[] = [];\n\n const resolveAndNotify = async (tok: Token<unknown>): Promise<void> => {\n const value = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, value);\n };\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (seen.has(tok as Token<any>) || reg.kind !== 'factory') continue;\n\n seen.add(tok as Token<any>);\n\n if (reg.lifetime === 'singleton') {\n work.push(resolveAndNotify(tok as Token<unknown>));\n } else if (opts?.includeScoped && typeof reg.lifetime === 'symbol') {\n const scopeContainer = this.#findScope(reg.lifetime);\n\n if (scopeContainer) work.push(resolveAndNotify(tok as Token<unknown>));\n }\n }\n }\n\n await Promise.all(work);\n }\n\n inspect(opts?: { deep?: boolean }): ContainerGraph {\n this.#assertNotDisposed();\n\n const deep = opts?.deep ?? true;\n const nodes: ContainerNode[] = [];\n const seen = new Set<Token<any>>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (!seen.has(tok as Token<any>)) {\n seen.add(tok as Token<any>);\n\n if (reg.kind === 'value') {\n nodes.push({ description: tokenName(tok as Token<any>), kind: 'value' });\n } else {\n const lifetime: ContainerNode['lifetime'] =\n typeof reg.lifetime === 'symbol'\n ? `scope:${(reg.lifetime as symbol).description ?? 'anonymous'}`\n : (reg.lifetime as 'singleton' | 'transient');\n\n nodes.push({\n deps: reg.deps?.map((d) => tokenName(d)),\n description: tokenName(tok as Token<any>),\n kind: 'factory',\n lifetime,\n });\n }\n }\n }\n\n if (!deep) break;\n }\n\n return { nodes };\n }\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this {\n this.#assertNotDisposed();\n\n const visited = new Set<Token<any>>();\n\n // Build token→deps map for static cycle detection.\n const staticDeps = new Map<Token<any>, readonly Token<any>[]>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (visited.has(tok as Token<any>)) continue;\n\n visited.add(tok as Token<any>);\n\n if (reg.kind === 'factory' && reg.deps && reg.deps.length > 0) {\n staticDeps.set(tok as Token<any>, reg.deps);\n\n for (const dep of reg.deps) {\n if (this.#getRegistration(dep) === undefined) {\n throw new ConduitProviderNotFoundError(dep, this.name);\n }\n }\n }\n }\n }\n\n // Static cycle detection over declared deps.\n if (staticDeps.size > 0) {\n const visiting = new Set<Token<any>>();\n const done = new Set<Token<any>>();\n\n const dfs = (tok: Token<any>, path: Token<any>[]): void => {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n if (done.has(tok)) return;\n\n visiting.add(tok);\n\n for (const dep of staticDeps.get(tok) ?? []) {\n dfs(dep, [...path, tok]);\n }\n\n visiting.delete(tok);\n done.add(tok);\n };\n\n for (const tok of staticDeps.keys()) {\n if (!done.has(tok)) dfs(tok, []);\n }\n }\n\n return this;\n }\n\n freeze(): this {\n this.#assertNotDisposed();\n\n if (this.#frozen) return this;\n\n this.validate();\n this.#frozen = true;\n\n return this;\n }\n\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container {\n this.#assertNotDisposed();\n\n return new ContainerImpl(this, { name: opts?.name, scopeTag: scopeToken });\n }\n\n on(listener: ContainerEventListener): () => void {\n this.#assertNotDisposed();\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n onResolve(interceptor: ResolveInterceptor): () => void {\n this.#assertNotDisposed();\n this.#resolveInterceptors.add(interceptor);\n\n return () => this.#resolveInterceptors.delete(interceptor);\n }\n\n async dispose(): Promise<void> {\n if (this.#disposed) return;\n\n this.#disposed = true;\n this.#disposeController.abort();\n this.#emit({ source: this.name, type: 'dispose' });\n\n const hooks: Promise<void>[] = [];\n const ownDescriptors = new Set<FactoryDescriptor<any>>();\n\n for (const reg of this.#registry.values()) {\n if (reg.kind === 'value') {\n if (reg.dispose) hooks.push(Promise.resolve().then(() => reg.dispose!(reg.value)));\n } else {\n ownDescriptors.add(reg);\n\n if (reg.dispose) {\n const entry = this.#cache.get(reg);\n\n if (entry?.resolved) hooks.push(Promise.resolve().then(() => reg.dispose!(entry.instance as any)));\n }\n }\n }\n\n // Inherited scope instances cached locally (not in #registry)\n for (const [descriptor, entry] of this.#cache) {\n if (!ownDescriptors.has(descriptor) && descriptor.dispose && entry.resolved) {\n hooks.push(Promise.resolve().then(() => descriptor.dispose!(entry.instance as any)));\n }\n }\n\n const outcomes = await Promise.allSettled(hooks);\n\n this.#cache.clear();\n this.#registry.clear();\n this.#listeners.clear();\n this.#resolveInterceptors.clear();\n\n for (const outcome of outcomes) {\n if (outcome.status === 'rejected') {\n error(`dispose hook failed in container '${this.name}':`, outcome.reason);\n }\n }\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n #fireInterceptors<T>(tok: Token<T>, value: T): void {\n for (const interceptor of this.#resolveInterceptors) {\n try {\n interceptor(tok, value);\n } catch {\n // swallowed — interceptor errors must not disrupt resolution\n }\n }\n\n if (this.#parent) this.#parent.#fireInterceptors(tok, value);\n }\n\n #getRegistration<T>(tok: Token<T>): Registration<T> | undefined {\n const local = this.#registry.get(tok) as Registration<T> | undefined;\n\n if (local) return local;\n\n if (!this.#parent) return undefined;\n\n this.#parent.#assertNotDisposed();\n\n return this.#parent.#getRegistration(tok);\n }\n\n #findOwnerContainer<T>(tok: Token<T>): ContainerImpl {\n for (const c of this.#ancestors()) {\n if (c.#registry.has(tok)) return c;\n }\n\n return this;\n }\n\n *#ancestors(): Generator<ContainerImpl> {\n yield this;\n\n let parent = this.#parent;\n\n while (parent) {\n yield parent;\n parent = parent.#parent;\n }\n }\n\n #findScope(scopeToken: ScopeToken): ContainerImpl | undefined {\n if (this.#scopeTag === scopeToken) return this;\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#findScope(scopeToken);\n }\n\n #getCache<T>(descriptor: FactoryDescriptor<T>): CacheEntry<T> {\n let entry = this.#cache.get(descriptor) as CacheEntry<T> | undefined;\n\n if (!entry) {\n entry = { resolved: false };\n this.#cache.set(descriptor, entry);\n }\n\n return entry;\n }\n\n /** Build a FactoryResolver scoped to the current resolution context. */\n #makeResolver(visiting: Set<Token<any>>, path: Token<any>[]): FactoryResolver {\n return {\n resolve: <T>(tok: Token<T>): Promise<T> => this.#resolveToken(tok, new Set(visiting), path),\n resolveSync: <T>(tok: Token<T>): T => this.resolveSync(tok),\n };\n }\n\n /** Populate a cache entry for a factory, deduplicating concurrent calls. */\n #populate<T>(\n entry: CacheEntry<T>,\n reg: FactoryDescriptor<T>,\n visiting: Set<Token<any>>,\n path: Token<any>[],\n ): Promise<T> {\n if (entry.resolved) return Promise.resolve(entry.instance as T);\n\n if (entry.promise) return entry.promise;\n\n entry.promise = Promise.resolve(reg.factory(this.#makeResolver(visiting, path)))\n .then((instance) => {\n entry.instance = instance;\n entry.resolved = true;\n\n return instance;\n })\n .catch((err) => {\n entry.rejection = err;\n throw err;\n });\n\n return entry.promise;\n }\n\n async #resolveToken<T>(tok: Token<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n visiting.add(tok);\n\n const result = await this.#resolveReg(tok, reg, visiting, [...path, tok]);\n\n visiting.delete(tok);\n\n return result;\n }\n\n async #resolveReg<T>(tok: Token<T>, reg: Registration<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n // Named scope token\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n return this.#populate(scopeContainer.#getCache(reg), reg, visiting, path);\n }\n\n if (lifetime === 'transient') {\n return reg.factory(this.#makeResolver(visiting, path));\n }\n\n // singleton — cache in owner container\n const cacheContainer = this.#findOwnerContainer(tok);\n\n return this.#populate(cacheContainer.#getCache(reg), reg, visiting, path);\n }\n\n #resolveSyncReg<T>(tok: Token<T>, reg: Registration<T>): T {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n const entry = scopeContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n\n if (lifetime === 'transient') throw new ConduitSyncResolutionError(tok, lifetime);\n\n const cacheContainer = this.#findOwnerContainer(tok);\n const entry = cacheContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public factory\n// ---------------------------------------------------------------------------\n\nexport function createContainer(opts?: { name?: string }): Container {\n return new ContainerImpl(undefined, { name: opts?.name ?? 'root' });\n}\n","// ---------------------------------------------------------------------------\n// Token\n// ---------------------------------------------------------------------------\n\nexport type Token<T = unknown> = symbol & { __type?: T };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\n// ---------------------------------------------------------------------------\n// ScopeToken — named lifecycle scopes\n// ---------------------------------------------------------------------------\n\nexport type ScopeToken = symbol & { __scopeToken?: never };\n\n/**\n * Creates a named scope token. Factories registered with a ScopeToken lifetime\n * are only resolvable from a container created with createScope(scopeToken).\n */\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\n// ---------------------------------------------------------------------------\n// Lifetime & options\n// ---------------------------------------------------------------------------\n\n/** Caching strategy for factory registrations. Named scopes use a ScopeToken. */\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n};\n\nexport type FactoryOptions<T> = {\n /** Optional statically-declared dependencies. Used for early validation in `freeze()`. */\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n lifetime?: Lifetime;\n};\n\n// ---------------------------------------------------------------------------\n// Resolver — injected into factories\n// ---------------------------------------------------------------------------\n\n/** Minimal resolver passed to every factory function. */\nexport interface FactoryResolver {\n resolve<T>(tok: Token<T>): Promise<T>;\n /**\n * Resolve synchronously. Works for value providers and already-resolved\n * singleton/scoped instances. Throws `ConduitSyncResolutionError` if the instance\n * has not been resolved yet.\n */\n resolveSync<T>(tok: Token<T>): T;\n}\n\n// ---------------------------------------------------------------------------\n// ContainerModule — grouping and async setup\n// ---------------------------------------------------------------------------\n\nexport type ContainerModule = (container: Container) => Promise<void> | void;\n\n// ---------------------------------------------------------------------------\n// Events — observable container state\n// ---------------------------------------------------------------------------\n\nexport type ContainerEvent =\n | { description: string; kind: 'factory' | 'value'; source: string; type: 'register' }\n | { description: string; source: string; type: 'resolve' }\n | { source: string; type: 'dispose' };\n\nexport type ContainerEventListener = (event: ContainerEvent) => void;\n\n// ---------------------------------------------------------------------------\n// Result type\n// ---------------------------------------------------------------------------\n\nexport type ResolveResult<T> = { ok: true; value: T } | { error: unknown; ok: false };\n\n/**\n * Infer the resolved-value tuple type from a `readonly` array of tokens.\n * Mirrors the return type of `resolveMany`.\n *\n * @example\n * const TOKENS = [AuthToken, LoggerToken] as const;\n * type Services = InferTokenTypes<typeof TOKENS>;\n * // → [AuthService, Logger]\n */\nexport type InferTokenTypes<T extends readonly Token<any>[]> = {\n [K in keyof T]: T[K] extends Token<infer U> ? U : never;\n};\n\n/** Interceptor called after every successful resolution. Receives the token and resolved value. */\nexport type ResolveInterceptor = <T>(tok: Token<T>, value: T) => void;\n\n// ---------------------------------------------------------------------------\n// ContainerGraph — inspect() output\n// ---------------------------------------------------------------------------\n\nexport type ContainerNode = {\n /** Statically-declared dependency token descriptions (from `deps:` option). */\n deps?: string[];\n description: string;\n kind: 'factory' | 'value';\n /** 'singleton', 'transient', or 'scope:<name>' for named scopes. */\n lifetime?: 'singleton' | 'transient' | `scope:${string}`;\n};\n\nexport type ContainerGraph = {\n nodes: ContainerNode[];\n};\n\n// ---------------------------------------------------------------------------\n// Container public interface\n// ---------------------------------------------------------------------------\n\nexport interface Container {\n /** Delegates to `dispose()`. Enables `await using` declarations. */\n [Symbol.asyncDispose](): Promise<void>;\n /** Human-readable identifier for this container. Set via createContainer({ name }). */\n readonly name: string;\n\n /** `AbortSignal` aborted when the container is disposed. Use to tie external lifecycles to this container. */\n readonly disposalSignal: AbortSignal;\n\n /** Whether the container has been disposed. */\n readonly disposed: boolean;\n\n /** Register a static value. */\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this;\n\n /**\n * Register a factory. The factory receives a `FactoryResolver` to resolve\n * its own dependencies lazily via `resolver.resolve(Token)`.\n */\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this;\n\n /** Check whether a token is registered (walks parent chain). */\n has<T>(tok: Token<T>): boolean;\n\n /** Resolve a single registered provider. */\n resolve<T>(tok: Token<T>): Promise<T>;\n\n /**\n * Resolve a token synchronously.\n * Works for value registrations and already-resolved singleton/scope instances.\n * Throws `ConduitSyncResolutionError` for transient factories or unresolved singletons.\n * Rethrows the cached rejection if the factory previously failed.\n */\n resolveSync<T>(tok: Token<T>): T;\n\n /**\n * Resolve multiple tokens in parallel, returning a typed tuple.\n */\n resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }>;\n\n /**\n * Eagerly resolve all registered singleton factories across the entire\n * container hierarchy. Useful for startup validation and pre-warming\n * `resolveSync()` hot paths.\n *\n * Pass `{ includeScoped: true }` to also pre-warm named-scope factories\n * registered on the current scope container.\n */\n resolveAll(opts?: { includeScoped?: boolean }): Promise<void>;\n\n /**\n * Return a serializable graph of every registered token.\n * By default traverses the full parent chain (deep: true).\n */\n inspect(opts?: { deep?: boolean }): ContainerGraph;\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this;\n\n /**\n * Freeze the container, locking it against further registrations.\n * After `freeze()`, `value()` and `factory()` throw `ConduitFrozenError`.\n * Validates statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Idempotent — calling `freeze()` again on an already-frozen container is a no-op.\n * Note: cycle detection for lazy (undeclared) deps happens at resolve time.\n */\n freeze(): this;\n\n /**\n * Create a child scope container. If `scopeToken` is provided, factories\n * registered with that token as their lifetime are resolved and cached here.\n * Omit `scopeToken` for a plain child container with no named scope.\n */\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container;\n\n /**\n * Subscribe to container events (register, resolve, dispose).\n * Events propagate up to parent containers. Returns an unsubscribe function.\n */\n on(listener: ContainerEventListener): () => void;\n\n /**\n * Register an interceptor called after every successful resolution.\n * Returns an unsubscribe function. Interceptor errors are swallowed.\n */\n onResolve(interceptor: ResolveInterceptor): () => void;\n\n /** Dispose the container, running all registered cleanup hooks in parallel. */\n dispose(): Promise<void>;\n}\n","import type { Container, ContainerModule, ResolveResult, Token } from './types.js';\n\nimport { ConduitProviderNotFoundError } from './errors.js';\n\n/**\n * Resolve a token, returning `undefined` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOptional<T>(container: Container, tok: Token<T>): Promise<T | undefined> {\n try {\n return await container.resolve(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token, returning `defaultValue` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): Promise<T> {\n const result = await resolveOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitDisposedError` and `ConduitCircularDependencyError`.\n */\nexport async function tryResolve<T>(container: Container, tok: Token<T>): Promise<ResolveResult<T>> {\n try {\n const value = await container.resolve(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `undefined` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOptional<T>(container: Container, tok: Token<T>): T | undefined {\n try {\n return container.resolveSync(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `defaultValue` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): T {\n const result = resolveSyncOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token synchronously, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitSyncResolutionError`, `ConduitDisposedError`, and `ConduitScopedResolutionError`.\n */\nexport function trySyncResolve<T>(container: Container, tok: Token<T>): ResolveResult<T> {\n try {\n const value = container.resolveSync(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Apply container modules sequentially (each module may be async).\n * Returns the container for chaining.\n */\nexport async function loadModules(container: Container, ...modules: ContainerModule[]): Promise<Container> {\n for (const mod of modules) await mod(container);\n\n return container;\n}\n"],"mappings":"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"}
|
package/dist/conduit.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=!globalThis.__CONDUIT_PROD__;function t(t,...n){e&&console.error(`[@vielzeug/conduit] ${t}`,...n)}var n=e=>e.description??`anonymous`,r=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},i=class extends r{cycle;constructor(e){super(`Circular dependency detected: ${e.map(n).join(` -> `)}`),this.cycle=e}},a=class extends r{token;containerName;constructor(e,t=`unknown`){super(`No provider registered for token: ${n(e)} (in container '${t}')`),this.token=e,this.containerName=t}},o=class extends r{token;constructor(e){super(`Token "${n(e)}" is already registered.`),this.token=e}},s=class extends r{token;lifetime;constructor(e,t){let r=t===`transient`?`transient factories are never cached`:typeof t==`symbol`?`named-scope "${t.description??`anonymous`}" instance has not been resolved yet in this scope`:`the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first`;super(`Token "${n(e)}" cannot be resolved synchronously: ${r}.`),this.token=e,this.lifetime=t}},c=class extends r{token;requiredScope;constructor(e,t){let r=t?.description??`anonymous`;super(t?`Token "${n(e)}" requires scope "${r}" but no matching scope container was found in the hierarchy.`:`Token "${n(e)}" requires a scope container but was resolved from the root.`),this.token=e,this.requiredScope=t}},l=class extends r{containerName;constructor(e=`unknown`){super(`Cannot use a disposed container (container '${e}').`),this.containerName=e}},u=class extends r{containerName;constructor(e){super(`Container '${e}' is frozen and cannot accept new registrations.`),this.containerName=e}},d=class e{#e=new Map;#t=new Map;#n;#r;#i=new Set;#a=new Set;#o=new AbortController;#s=!1;#c=!1;name;constructor(e,t={}){this.#n=e,this.#r=t.scopeTag,this.name=t.name??(e?t.scopeTag?`${e.name}:${t.scopeTag.description??`scope`}`:`${e.name}:child`:`root`)}#l(){if(this.#s)throw new l(this.name)}#u(){if(this.#c)throw new u(this.name)}#d(e){for(let t of this.#i)try{t(e)}catch{}this.#n&&this.#n.#d(e)}get disposalSignal(){return this.#o.signal}get disposed(){return this.#s}value(e,t,r){if(this.#l(),this.#u(),this.#e.has(e))throw new o(e);let i={dispose:r?.dispose,kind:`value`,value:t};return this.#e.set(e,i),this.#d({description:n(e),kind:`value`,source:this.name,type:`register`}),this}factory(e,t,r){if(this.#l(),this.#u(),this.#e.has(e))throw new o(e);let i={deps:r?.deps,dispose:r?.dispose,factory:t,kind:`factory`,lifetime:r?.lifetime??`singleton`};return this.#e.set(e,i),this.#d({description:n(e),kind:`factory`,source:this.name,type:`register`}),this}has(e){return this.#l(),this.#p(e)!==void 0}async resolve(e){this.#l();let t=await this.#b(e,new Set,[]);return this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,t),t}resolveSync(e){this.#l();let t=this.#p(e);if(!t)throw new a(e,this.name);let r=this.#S(e,t);return this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,r),r}async resolveMany(e){return Promise.all(e.map(e=>this.resolve(e)))}async resolveAll(e){this.#l();let t=new Set,r=[],i=async e=>{let t=await this.#b(e,new Set,[]);this.#d({description:n(e),source:this.name,type:`resolve`}),this.#f(e,t)};for(let n of this.#h())for(let[a,o]of n.#e)t.has(a)||o.kind!==`factory`||(t.add(a),(o.lifetime===`singleton`||e?.includeScoped&&typeof o.lifetime==`symbol`&&this.#g(o.lifetime))&&r.push(i(a)));await Promise.all(r)}inspect(e){this.#l();let t=e?.deep??!0,r=[],i=new Set;for(let e of this.#h()){for(let[t,a]of e.#e)if(!i.has(t))if(i.add(t),a.kind===`value`)r.push({description:n(t),kind:`value`});else{let e=typeof a.lifetime==`symbol`?`scope:${a.lifetime.description??`anonymous`}`:a.lifetime;r.push({deps:a.deps?.map(e=>n(e)),description:n(t),kind:`factory`,lifetime:e})}if(!t)break}return{nodes:r}}validate(){this.#l();let e=new Set,t=new Map;for(let n of this.#h())for(let[r,i]of n.#e)if(!e.has(r)&&(e.add(r),i.kind===`factory`&&i.deps&&i.deps.length>0)){t.set(r,i.deps);for(let e of i.deps)if(this.#p(e)===void 0)throw new a(e,this.name)}if(t.size>0){let e=new Set,n=new Set,r=(a,o)=>{if(e.has(a))throw new i([...o,a]);if(!n.has(a)){e.add(a);for(let e of t.get(a)??[])r(e,[...o,a]);e.delete(a),n.add(a)}};for(let e of t.keys())n.has(e)||r(e,[])}return this}freeze(){return this.#l(),this.#c?this:(this.validate(),this.#c=!0,this)}createScope(t,n){return this.#l(),new e(this,{name:n?.name,scopeTag:t})}on(e){return this.#l(),this.#i.add(e),()=>this.#i.delete(e)}onResolve(e){return this.#l(),this.#a.add(e),()=>this.#a.delete(e)}async dispose(){if(this.#s)return;this.#s=!0,this.#o.abort(),this.#d({source:this.name,type:`dispose`});let e=[],n=new Set;for(let t of this.#e.values())if(t.kind===`value`)t.dispose&&e.push(Promise.resolve().then(()=>t.dispose(t.value)));else if(n.add(t),t.dispose){let n=this.#t.get(t);n?.resolved&&e.push(Promise.resolve().then(()=>t.dispose(n.instance)))}for(let[t,r]of this.#t)!n.has(t)&&t.dispose&&r.resolved&&e.push(Promise.resolve().then(()=>t.dispose(r.instance)));let r=await Promise.allSettled(e);this.#t.clear(),this.#e.clear(),this.#i.clear(),this.#a.clear();for(let e of r)e.status===`rejected`&&t(`dispose hook failed in container '${this.name}':`,e.reason)}[Symbol.asyncDispose](){return this.dispose()}#f(e,t){for(let n of this.#a)try{n(e,t)}catch{}this.#n&&this.#n.#f(e,t)}#p(e){let t=this.#e.get(e);if(t)return t;if(this.#n)return this.#n.#l(),this.#n.#p(e)}#m(e){for(let t of this.#h())if(t.#e.has(e))return t;return this}*#h(){yield this;let e=this.#n;for(;e;)yield e,e=e.#n}#g(e){if(this.#r===e)return this;if(this.#n)return this.#n.#g(e)}#_(e){let t=this.#t.get(e);return t||(t={resolved:!1},this.#t.set(e,t)),t}#v(e,t){return{resolve:n=>this.#b(n,new Set(e),t),resolveSync:e=>this.resolveSync(e)}}#y(e,t,n,r){return e.resolved?Promise.resolve(e.instance):(e.promise||=Promise.resolve(t.factory(this.#v(n,r))).then(t=>(e.instance=t,e.resolved=!0,t)).catch(t=>{throw e.rejection=t,t}),e.promise)}async#b(e,t,n){if(t.has(e))throw new i([...n,e]);let r=this.#p(e);if(!r)throw new a(e,this.name);t.add(e);let o=await this.#x(e,r,t,[...n,e]);return t.delete(e),o}async#x(e,t,n,r){if(t.kind===`value`)return t.value;let{lifetime:i}=t;if(typeof i==`symbol`){let a=this.#g(i);if(!a)throw new c(e,i);return this.#y(a.#_(t),t,n,r)}if(i===`transient`)return t.factory(this.#v(n,r));let a=this.#m(e);return this.#y(a.#_(t),t,n,r)}#S(e,t){if(t.kind===`value`)return t.value;let{lifetime:n}=t;if(typeof n==`symbol`){let r=this.#g(n);if(!r)throw new c(e,n);let i=r.#t.get(t);if(i?.resolved)return i.instance;throw i?.rejection===void 0?new s(e,n):i.rejection}if(n===`transient`)throw new s(e,n);let r=this.#m(e).#t.get(t);if(r?.resolved)return r.instance;throw r?.rejection===void 0?new s(e,n):r.rejection}};function f(e){return new d(void 0,{name:e?.name??`root`})}function p(e){return Symbol(e)}function m(e){return Symbol(e)}async function h(e,t){try{return await e.resolve(t)}catch(e){if(e instanceof a)return;throw e}}async function g(e,t,n){let r=await h(e,t);return r===void 0?n:r}async function _(e,t){try{return{ok:!0,value:await e.resolve(t)}}catch(e){if(e instanceof a)return{error:e,ok:!1};throw e}}function v(e,t){try{return e.resolveSync(t)}catch(e){if(e instanceof a)return;throw e}}function y(e,t,n){let r=v(e,t);return r===void 0?n:r}function b(e,t){try{return{ok:!0,value:e.resolveSync(t)}}catch(e){if(e instanceof a)return{error:e,ok:!1};throw e}}async function x(e,...t){for(let n of t)await n(e);return e}export{i as ConduitCircularDependencyError,l as ConduitDisposedError,o as ConduitDuplicateRegistrationError,r as ConduitError,u as ConduitFrozenError,a as ConduitProviderNotFoundError,c as ConduitScopedResolutionError,s as ConduitSyncResolutionError,f as createContainer,x as loadModules,h as resolveOptional,g as resolveOrDefault,v as resolveSyncOptional,y as resolveSyncOrDefault,m as scope,p as token,_ as tryResolve,b as trySyncResolve};
|
|
2
|
+
//# sourceMappingURL=conduit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduit.js","names":["#parent","#scopeTag","#disposed","#frozen","#listeners","#emit","#disposeController","#assertNotDisposed","#assertNotFrozen","#registry","#getRegistration","#resolveToken","#fireInterceptors","#resolveSyncReg","#ancestors","#findScope","#resolveInterceptors","#cache","#makeResolver","#resolveReg","#populate","#getCache","#findOwnerContainer"],"sources":["../src/_dev.ts","../src/errors.ts","../src/container.ts","../src/types.ts","../src/utils.ts"],"sourcesContent":["const isDev = !(globalThis as { __CONDUIT_PROD__?: boolean }).__CONDUIT_PROD__;\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/conduit] ${msg}`, ...args);\n}\n","import type { Lifetime, ScopeToken, Token } from './types.js';\n\nexport const tokenName = (t: Token<any>): string => t.description ?? 'anonymous';\n\n/** Base class for all conduit errors. Use `instanceof ConduitError` to catch any conduit-originated error. */\nexport class ConduitError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ConduitError {\n return err instanceof ConduitError;\n }\n}\n\nexport class ConduitCircularDependencyError extends ConduitError {\n /** The token path that forms the cycle. */\n readonly cycle: Token<any>[];\n\n constructor(path: Token<any>[]) {\n super(`Circular dependency detected: ${path.map(tokenName).join(' -> ')}`);\n this.cycle = path;\n }\n}\n\nexport class ConduitProviderNotFoundError extends ConduitError {\n /** The token that could not be found. */\n readonly token: Token<any>;\n /** The container name at the time of the lookup. */\n readonly containerName: string;\n\n constructor(tok: Token<any>, containerName = 'unknown') {\n super(`No provider registered for token: ${tokenName(tok)} (in container '${containerName}')`);\n this.token = tok;\n this.containerName = containerName;\n }\n}\n\nexport class ConduitDuplicateRegistrationError extends ConduitError {\n /** The token that was registered twice. */\n readonly token: Token<any>;\n\n constructor(tok: Token<any>) {\n super(`Token \"${tokenName(tok)}\" is already registered.`);\n this.token = tok;\n }\n}\n\nexport class ConduitSyncResolutionError extends ConduitError {\n /** The token that could not be resolved synchronously. */\n readonly token: Token<any>;\n /** The lifetime that prevented synchronous resolution. */\n readonly lifetime: Lifetime;\n\n constructor(tok: Token<any>, lifetime: Lifetime) {\n const reason =\n lifetime === 'transient'\n ? 'transient factories are never cached'\n : typeof lifetime === 'symbol'\n ? `named-scope \"${(lifetime as symbol).description ?? 'anonymous'}\" instance has not been resolved yet in this scope`\n : 'the instance has not been resolved yet; call await container.resolve() or container.resolveAll() first';\n\n super(`Token \"${tokenName(tok)}\" cannot be resolved synchronously: ${reason}.`);\n this.token = tok;\n this.lifetime = lifetime;\n }\n}\n\nexport class ConduitScopedResolutionError extends ConduitError {\n /** The token that required a scope container. */\n readonly token: Token<any>;\n /** The required scope token, if any. */\n readonly requiredScope: ScopeToken | undefined;\n\n constructor(tok: Token<any>, requiredScope?: ScopeToken) {\n const scopeName = requiredScope?.description ?? 'anonymous';\n\n super(\n requiredScope\n ? `Token \"${tokenName(tok)}\" requires scope \"${scopeName}\" but no matching scope container was found in the hierarchy.`\n : `Token \"${tokenName(tok)}\" requires a scope container but was resolved from the root.`,\n );\n this.token = tok;\n this.requiredScope = requiredScope;\n }\n}\n\nexport class ConduitDisposedError extends ConduitError {\n /** The name of the container that was already disposed. */\n readonly containerName: string;\n\n constructor(containerName = 'unknown') {\n super(`Cannot use a disposed container (container '${containerName}').`);\n this.containerName = containerName;\n }\n}\n\nexport class ConduitFrozenError extends ConduitError {\n /** The name of the container that is frozen. */\n readonly containerName: string;\n\n constructor(containerName: string) {\n super(`Container '${containerName}' is frozen and cannot accept new registrations.`);\n this.containerName = containerName;\n }\n}\n","import type {\n Container,\n ContainerEvent,\n ContainerEventListener,\n ContainerGraph,\n ContainerNode,\n FactoryOptions,\n FactoryResolver,\n Lifetime,\n ResolveInterceptor,\n ScopeToken,\n Token,\n ValueOptions,\n} from './types.js';\n\nimport { error } from './_dev';\nimport {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitFrozenError,\n ConduitDuplicateRegistrationError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n ConduitSyncResolutionError,\n tokenName,\n} from './errors.js';\n\n// ---------------------------------------------------------------------------\n// Internal registration types\n// ---------------------------------------------------------------------------\n\ntype ValueRegistration<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n kind: 'value';\n value: T;\n};\n\ntype FactoryDescriptor<T> = {\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n factory: (resolver: FactoryResolver) => Promise<T> | T;\n kind: 'factory';\n lifetime: Lifetime;\n};\n\ntype Registration<T = unknown> = FactoryDescriptor<T> | ValueRegistration<T>;\n\n// Cache state is separate from the immutable factory descriptor.\ntype CacheEntry<T = unknown> = {\n instance?: T;\n // Retained on failure — subsequent calls rethrow the same rejection (no silent retry).\n promise?: Promise<T>;\n // Stored on rejection so resolveSync() can rethrow the original error synchronously.\n rejection?: unknown;\n resolved: boolean;\n};\n\n// ---------------------------------------------------------------------------\n// ContainerImpl\n// ---------------------------------------------------------------------------\n\nclass ContainerImpl implements Container {\n #registry = new Map<Token<any>, Registration<any>>();\n #cache = new Map<FactoryDescriptor<any>, CacheEntry<any>>();\n #parent?: ContainerImpl;\n #scopeTag?: ScopeToken;\n #listeners = new Set<ContainerEventListener>();\n #resolveInterceptors = new Set<ResolveInterceptor>();\n #disposeController = new AbortController();\n #disposed = false;\n #frozen = false;\n readonly name: string;\n\n constructor(parent?: ContainerImpl, opts: { name?: string; scopeTag?: ScopeToken } = {}) {\n this.#parent = parent;\n this.#scopeTag = opts.scopeTag;\n this.name =\n opts.name ??\n (parent\n ? opts.scopeTag\n ? `${parent.name}:${opts.scopeTag.description ?? 'scope'}`\n : `${parent.name}:child`\n : 'root');\n }\n\n #assertNotDisposed(): void {\n if (this.#disposed) throw new ConduitDisposedError(this.name);\n }\n\n #assertNotFrozen(): void {\n if (this.#frozen) throw new ConduitFrozenError(this.name);\n }\n\n // Emit to local listeners then propagate up to parent.\n #emit(event: ContainerEvent): void {\n for (const listener of this.#listeners) {\n try {\n listener(event);\n } catch {\n // swallowed — listener errors must not disrupt container operation\n }\n }\n\n if (this.#parent) this.#parent.#emit(event);\n }\n\n get disposalSignal(): AbortSignal {\n return this.#disposeController.signal;\n }\n\n get disposed(): boolean {\n return this.#disposed;\n }\n\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: ValueRegistration<T> = { dispose: opts?.dispose, kind: 'value', value: val };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'value', source: this.name, type: 'register' });\n\n return this;\n }\n\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this {\n this.#assertNotDisposed();\n this.#assertNotFrozen();\n\n if (this.#registry.has(tok)) throw new ConduitDuplicateRegistrationError(tok);\n\n const reg: FactoryDescriptor<T> = {\n deps: opts?.deps,\n dispose: opts?.dispose,\n factory: fn,\n kind: 'factory',\n lifetime: opts?.lifetime ?? 'singleton',\n };\n\n this.#registry.set(tok, reg);\n this.#emit({ description: tokenName(tok), kind: 'factory', source: this.name, type: 'register' });\n\n return this;\n }\n\n has<T>(tok: Token<T>): boolean {\n this.#assertNotDisposed();\n\n return this.#getRegistration(tok) !== undefined;\n }\n\n async resolve<T>(tok: Token<T>): Promise<T> {\n this.#assertNotDisposed();\n\n const result = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n resolveSync<T>(tok: Token<T>): T {\n this.#assertNotDisposed();\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n const result = this.#resolveSyncReg(tok, reg);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, result);\n\n return result;\n }\n\n async resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }> {\n return Promise.all(toks.map((t) => this.resolve(t))) as Promise<{\n [K in keyof D]: D[K] extends Token<infer U> ? U : never;\n }>;\n }\n\n async resolveAll(opts?: { includeScoped?: boolean }): Promise<void> {\n this.#assertNotDisposed();\n\n const seen = new Set<Token<any>>();\n const work: Promise<unknown>[] = [];\n\n const resolveAndNotify = async (tok: Token<unknown>): Promise<void> => {\n const value = await this.#resolveToken(tok, new Set(), []);\n\n this.#emit({ description: tokenName(tok), source: this.name, type: 'resolve' });\n this.#fireInterceptors(tok, value);\n };\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (seen.has(tok as Token<any>) || reg.kind !== 'factory') continue;\n\n seen.add(tok as Token<any>);\n\n if (reg.lifetime === 'singleton') {\n work.push(resolveAndNotify(tok as Token<unknown>));\n } else if (opts?.includeScoped && typeof reg.lifetime === 'symbol') {\n const scopeContainer = this.#findScope(reg.lifetime);\n\n if (scopeContainer) work.push(resolveAndNotify(tok as Token<unknown>));\n }\n }\n }\n\n await Promise.all(work);\n }\n\n inspect(opts?: { deep?: boolean }): ContainerGraph {\n this.#assertNotDisposed();\n\n const deep = opts?.deep ?? true;\n const nodes: ContainerNode[] = [];\n const seen = new Set<Token<any>>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (!seen.has(tok as Token<any>)) {\n seen.add(tok as Token<any>);\n\n if (reg.kind === 'value') {\n nodes.push({ description: tokenName(tok as Token<any>), kind: 'value' });\n } else {\n const lifetime: ContainerNode['lifetime'] =\n typeof reg.lifetime === 'symbol'\n ? `scope:${(reg.lifetime as symbol).description ?? 'anonymous'}`\n : (reg.lifetime as 'singleton' | 'transient');\n\n nodes.push({\n deps: reg.deps?.map((d) => tokenName(d)),\n description: tokenName(tok as Token<any>),\n kind: 'factory',\n lifetime,\n });\n }\n }\n }\n\n if (!deep) break;\n }\n\n return { nodes };\n }\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this {\n this.#assertNotDisposed();\n\n const visited = new Set<Token<any>>();\n\n // Build token→deps map for static cycle detection.\n const staticDeps = new Map<Token<any>, readonly Token<any>[]>();\n\n for (const c of this.#ancestors()) {\n for (const [tok, reg] of c.#registry) {\n if (visited.has(tok as Token<any>)) continue;\n\n visited.add(tok as Token<any>);\n\n if (reg.kind === 'factory' && reg.deps && reg.deps.length > 0) {\n staticDeps.set(tok as Token<any>, reg.deps);\n\n for (const dep of reg.deps) {\n if (this.#getRegistration(dep) === undefined) {\n throw new ConduitProviderNotFoundError(dep, this.name);\n }\n }\n }\n }\n }\n\n // Static cycle detection over declared deps.\n if (staticDeps.size > 0) {\n const visiting = new Set<Token<any>>();\n const done = new Set<Token<any>>();\n\n const dfs = (tok: Token<any>, path: Token<any>[]): void => {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n if (done.has(tok)) return;\n\n visiting.add(tok);\n\n for (const dep of staticDeps.get(tok) ?? []) {\n dfs(dep, [...path, tok]);\n }\n\n visiting.delete(tok);\n done.add(tok);\n };\n\n for (const tok of staticDeps.keys()) {\n if (!done.has(tok)) dfs(tok, []);\n }\n }\n\n return this;\n }\n\n freeze(): this {\n this.#assertNotDisposed();\n\n if (this.#frozen) return this;\n\n this.validate();\n this.#frozen = true;\n\n return this;\n }\n\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container {\n this.#assertNotDisposed();\n\n return new ContainerImpl(this, { name: opts?.name, scopeTag: scopeToken });\n }\n\n on(listener: ContainerEventListener): () => void {\n this.#assertNotDisposed();\n this.#listeners.add(listener);\n\n return () => this.#listeners.delete(listener);\n }\n\n onResolve(interceptor: ResolveInterceptor): () => void {\n this.#assertNotDisposed();\n this.#resolveInterceptors.add(interceptor);\n\n return () => this.#resolveInterceptors.delete(interceptor);\n }\n\n async dispose(): Promise<void> {\n if (this.#disposed) return;\n\n this.#disposed = true;\n this.#disposeController.abort();\n this.#emit({ source: this.name, type: 'dispose' });\n\n const hooks: Promise<void>[] = [];\n const ownDescriptors = new Set<FactoryDescriptor<any>>();\n\n for (const reg of this.#registry.values()) {\n if (reg.kind === 'value') {\n if (reg.dispose) hooks.push(Promise.resolve().then(() => reg.dispose!(reg.value)));\n } else {\n ownDescriptors.add(reg);\n\n if (reg.dispose) {\n const entry = this.#cache.get(reg);\n\n if (entry?.resolved) hooks.push(Promise.resolve().then(() => reg.dispose!(entry.instance as any)));\n }\n }\n }\n\n // Inherited scope instances cached locally (not in #registry)\n for (const [descriptor, entry] of this.#cache) {\n if (!ownDescriptors.has(descriptor) && descriptor.dispose && entry.resolved) {\n hooks.push(Promise.resolve().then(() => descriptor.dispose!(entry.instance as any)));\n }\n }\n\n const outcomes = await Promise.allSettled(hooks);\n\n this.#cache.clear();\n this.#registry.clear();\n this.#listeners.clear();\n this.#resolveInterceptors.clear();\n\n for (const outcome of outcomes) {\n if (outcome.status === 'rejected') {\n error(`dispose hook failed in container '${this.name}':`, outcome.reason);\n }\n }\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.dispose();\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n #fireInterceptors<T>(tok: Token<T>, value: T): void {\n for (const interceptor of this.#resolveInterceptors) {\n try {\n interceptor(tok, value);\n } catch {\n // swallowed — interceptor errors must not disrupt resolution\n }\n }\n\n if (this.#parent) this.#parent.#fireInterceptors(tok, value);\n }\n\n #getRegistration<T>(tok: Token<T>): Registration<T> | undefined {\n const local = this.#registry.get(tok) as Registration<T> | undefined;\n\n if (local) return local;\n\n if (!this.#parent) return undefined;\n\n this.#parent.#assertNotDisposed();\n\n return this.#parent.#getRegistration(tok);\n }\n\n #findOwnerContainer<T>(tok: Token<T>): ContainerImpl {\n for (const c of this.#ancestors()) {\n if (c.#registry.has(tok)) return c;\n }\n\n return this;\n }\n\n *#ancestors(): Generator<ContainerImpl> {\n yield this;\n\n let parent = this.#parent;\n\n while (parent) {\n yield parent;\n parent = parent.#parent;\n }\n }\n\n #findScope(scopeToken: ScopeToken): ContainerImpl | undefined {\n if (this.#scopeTag === scopeToken) return this;\n\n if (!this.#parent) return undefined;\n\n return this.#parent.#findScope(scopeToken);\n }\n\n #getCache<T>(descriptor: FactoryDescriptor<T>): CacheEntry<T> {\n let entry = this.#cache.get(descriptor) as CacheEntry<T> | undefined;\n\n if (!entry) {\n entry = { resolved: false };\n this.#cache.set(descriptor, entry);\n }\n\n return entry;\n }\n\n /** Build a FactoryResolver scoped to the current resolution context. */\n #makeResolver(visiting: Set<Token<any>>, path: Token<any>[]): FactoryResolver {\n return {\n resolve: <T>(tok: Token<T>): Promise<T> => this.#resolveToken(tok, new Set(visiting), path),\n resolveSync: <T>(tok: Token<T>): T => this.resolveSync(tok),\n };\n }\n\n /** Populate a cache entry for a factory, deduplicating concurrent calls. */\n #populate<T>(\n entry: CacheEntry<T>,\n reg: FactoryDescriptor<T>,\n visiting: Set<Token<any>>,\n path: Token<any>[],\n ): Promise<T> {\n if (entry.resolved) return Promise.resolve(entry.instance as T);\n\n if (entry.promise) return entry.promise;\n\n entry.promise = Promise.resolve(reg.factory(this.#makeResolver(visiting, path)))\n .then((instance) => {\n entry.instance = instance;\n entry.resolved = true;\n\n return instance;\n })\n .catch((err) => {\n entry.rejection = err;\n throw err;\n });\n\n return entry.promise;\n }\n\n async #resolveToken<T>(tok: Token<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (visiting.has(tok)) throw new ConduitCircularDependencyError([...path, tok]);\n\n const reg = this.#getRegistration(tok) as Registration<T> | undefined;\n\n if (!reg) throw new ConduitProviderNotFoundError(tok, this.name);\n\n visiting.add(tok);\n\n const result = await this.#resolveReg(tok, reg, visiting, [...path, tok]);\n\n visiting.delete(tok);\n\n return result;\n }\n\n async #resolveReg<T>(tok: Token<T>, reg: Registration<T>, visiting: Set<Token<any>>, path: Token<any>[]): Promise<T> {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n // Named scope token\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n return this.#populate(scopeContainer.#getCache(reg), reg, visiting, path);\n }\n\n if (lifetime === 'transient') {\n return reg.factory(this.#makeResolver(visiting, path));\n }\n\n // singleton — cache in owner container\n const cacheContainer = this.#findOwnerContainer(tok);\n\n return this.#populate(cacheContainer.#getCache(reg), reg, visiting, path);\n }\n\n #resolveSyncReg<T>(tok: Token<T>, reg: Registration<T>): T {\n if (reg.kind === 'value') return reg.value;\n\n const { lifetime } = reg;\n\n if (typeof lifetime === 'symbol') {\n const scopeContainer = this.#findScope(lifetime);\n\n if (!scopeContainer) throw new ConduitScopedResolutionError(tok, lifetime);\n\n const entry = scopeContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n\n if (lifetime === 'transient') throw new ConduitSyncResolutionError(tok, lifetime);\n\n const cacheContainer = this.#findOwnerContainer(tok);\n const entry = cacheContainer.#cache.get(reg);\n\n if (entry?.resolved) return entry.instance as T;\n\n if (entry?.rejection !== undefined) throw entry.rejection;\n\n throw new ConduitSyncResolutionError(tok, lifetime);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public factory\n// ---------------------------------------------------------------------------\n\nexport function createContainer(opts?: { name?: string }): Container {\n return new ContainerImpl(undefined, { name: opts?.name ?? 'root' });\n}\n","// ---------------------------------------------------------------------------\n// Token\n// ---------------------------------------------------------------------------\n\nexport type Token<T = unknown> = symbol & { __type?: T };\n\nexport function token<T>(description: string): Token<T> {\n return Symbol(description) as Token<T>;\n}\n\n// ---------------------------------------------------------------------------\n// ScopeToken — named lifecycle scopes\n// ---------------------------------------------------------------------------\n\nexport type ScopeToken = symbol & { __scopeToken?: never };\n\n/**\n * Creates a named scope token. Factories registered with a ScopeToken lifetime\n * are only resolvable from a container created with createScope(scopeToken).\n */\nexport function scope(name: string): ScopeToken {\n return Symbol(name) as ScopeToken;\n}\n\n// ---------------------------------------------------------------------------\n// Lifetime & options\n// ---------------------------------------------------------------------------\n\n/** Caching strategy for factory registrations. Named scopes use a ScopeToken. */\nexport type Lifetime = 'singleton' | 'transient' | ScopeToken;\n\nexport type ValueOptions<T> = {\n dispose?: (instance: T) => Promise<void> | void;\n};\n\nexport type FactoryOptions<T> = {\n /** Optional statically-declared dependencies. Used for early validation in `freeze()`. */\n deps?: readonly Token<any>[];\n dispose?: (instance: T) => Promise<void> | void;\n lifetime?: Lifetime;\n};\n\n// ---------------------------------------------------------------------------\n// Resolver — injected into factories\n// ---------------------------------------------------------------------------\n\n/** Minimal resolver passed to every factory function. */\nexport interface FactoryResolver {\n resolve<T>(tok: Token<T>): Promise<T>;\n /**\n * Resolve synchronously. Works for value providers and already-resolved\n * singleton/scoped instances. Throws `ConduitSyncResolutionError` if the instance\n * has not been resolved yet.\n */\n resolveSync<T>(tok: Token<T>): T;\n}\n\n// ---------------------------------------------------------------------------\n// ContainerModule — grouping and async setup\n// ---------------------------------------------------------------------------\n\nexport type ContainerModule = (container: Container) => Promise<void> | void;\n\n// ---------------------------------------------------------------------------\n// Events — observable container state\n// ---------------------------------------------------------------------------\n\nexport type ContainerEvent =\n | { description: string; kind: 'factory' | 'value'; source: string; type: 'register' }\n | { description: string; source: string; type: 'resolve' }\n | { source: string; type: 'dispose' };\n\nexport type ContainerEventListener = (event: ContainerEvent) => void;\n\n// ---------------------------------------------------------------------------\n// Result type\n// ---------------------------------------------------------------------------\n\nexport type ResolveResult<T> = { ok: true; value: T } | { error: unknown; ok: false };\n\n/**\n * Infer the resolved-value tuple type from a `readonly` array of tokens.\n * Mirrors the return type of `resolveMany`.\n *\n * @example\n * const TOKENS = [AuthToken, LoggerToken] as const;\n * type Services = InferTokenTypes<typeof TOKENS>;\n * // → [AuthService, Logger]\n */\nexport type InferTokenTypes<T extends readonly Token<any>[]> = {\n [K in keyof T]: T[K] extends Token<infer U> ? U : never;\n};\n\n/** Interceptor called after every successful resolution. Receives the token and resolved value. */\nexport type ResolveInterceptor = <T>(tok: Token<T>, value: T) => void;\n\n// ---------------------------------------------------------------------------\n// ContainerGraph — inspect() output\n// ---------------------------------------------------------------------------\n\nexport type ContainerNode = {\n /** Statically-declared dependency token descriptions (from `deps:` option). */\n deps?: string[];\n description: string;\n kind: 'factory' | 'value';\n /** 'singleton', 'transient', or 'scope:<name>' for named scopes. */\n lifetime?: 'singleton' | 'transient' | `scope:${string}`;\n};\n\nexport type ContainerGraph = {\n nodes: ContainerNode[];\n};\n\n// ---------------------------------------------------------------------------\n// Container public interface\n// ---------------------------------------------------------------------------\n\nexport interface Container {\n /** Delegates to `dispose()`. Enables `await using` declarations. */\n [Symbol.asyncDispose](): Promise<void>;\n /** Human-readable identifier for this container. Set via createContainer({ name }). */\n readonly name: string;\n\n /** `AbortSignal` aborted when the container is disposed. Use to tie external lifecycles to this container. */\n readonly disposalSignal: AbortSignal;\n\n /** Whether the container has been disposed. */\n readonly disposed: boolean;\n\n /** Register a static value. */\n value<T>(tok: Token<T>, val: T, opts?: ValueOptions<T>): this;\n\n /**\n * Register a factory. The factory receives a `FactoryResolver` to resolve\n * its own dependencies lazily via `resolver.resolve(Token)`.\n */\n factory<T>(tok: Token<T>, fn: (resolver: FactoryResolver) => Promise<T> | T, opts?: FactoryOptions<T>): this;\n\n /** Check whether a token is registered (walks parent chain). */\n has<T>(tok: Token<T>): boolean;\n\n /** Resolve a single registered provider. */\n resolve<T>(tok: Token<T>): Promise<T>;\n\n /**\n * Resolve a token synchronously.\n * Works for value registrations and already-resolved singleton/scope instances.\n * Throws `ConduitSyncResolutionError` for transient factories or unresolved singletons.\n * Rethrows the cached rejection if the factory previously failed.\n */\n resolveSync<T>(tok: Token<T>): T;\n\n /**\n * Resolve multiple tokens in parallel, returning a typed tuple.\n */\n resolveMany<const D extends Token<any>[]>(\n toks: D,\n ): Promise<{ [K in keyof D]: D[K] extends Token<infer U> ? U : never }>;\n\n /**\n * Eagerly resolve all registered singleton factories across the entire\n * container hierarchy. Useful for startup validation and pre-warming\n * `resolveSync()` hot paths.\n *\n * Pass `{ includeScoped: true }` to also pre-warm named-scope factories\n * registered on the current scope container.\n */\n resolveAll(opts?: { includeScoped?: boolean }): Promise<void>;\n\n /**\n * Return a serializable graph of every registered token.\n * By default traverses the full parent chain (deep: true).\n */\n inspect(opts?: { deep?: boolean }): ContainerGraph;\n\n /**\n * Validate the registration graph without freezing it.\n * Checks statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Throws `ConduitDisposedError` if the container is already disposed.\n */\n validate(): this;\n\n /**\n * Freeze the container, locking it against further registrations.\n * After `freeze()`, `value()` and `factory()` throw `ConduitFrozenError`.\n * Validates statically-declared `deps`: throws `ConduitProviderNotFoundError` if a\n * declared dep is missing, or `ConduitCircularDependencyError` if they form a cycle.\n * Idempotent — calling `freeze()` again on an already-frozen container is a no-op.\n * Note: cycle detection for lazy (undeclared) deps happens at resolve time.\n */\n freeze(): this;\n\n /**\n * Create a child scope container. If `scopeToken` is provided, factories\n * registered with that token as their lifetime are resolved and cached here.\n * Omit `scopeToken` for a plain child container with no named scope.\n */\n createScope(scopeToken?: ScopeToken, opts?: { name?: string }): Container;\n\n /**\n * Subscribe to container events (register, resolve, dispose).\n * Events propagate up to parent containers. Returns an unsubscribe function.\n */\n on(listener: ContainerEventListener): () => void;\n\n /**\n * Register an interceptor called after every successful resolution.\n * Returns an unsubscribe function. Interceptor errors are swallowed.\n */\n onResolve(interceptor: ResolveInterceptor): () => void;\n\n /** Dispose the container, running all registered cleanup hooks in parallel. */\n dispose(): Promise<void>;\n}\n","import type { Container, ContainerModule, ResolveResult, Token } from './types.js';\n\nimport { ConduitProviderNotFoundError } from './errors.js';\n\n/**\n * Resolve a token, returning `undefined` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOptional<T>(container: Container, tok: Token<T>): Promise<T | undefined> {\n try {\n return await container.resolve(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token, returning `defaultValue` when not registered.\n * Re-throws any error other than `ConduitProviderNotFoundError`.\n */\nexport async function resolveOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): Promise<T> {\n const result = await resolveOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitDisposedError` and `ConduitCircularDependencyError`.\n */\nexport async function tryResolve<T>(container: Container, tok: Token<T>): Promise<ResolveResult<T>> {\n try {\n const value = await container.resolve(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `undefined` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOptional<T>(container: Container, tok: Token<T>): T | undefined {\n try {\n return container.resolveSync(tok);\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return undefined;\n\n throw error;\n }\n}\n\n/**\n * Resolve a token synchronously, returning `defaultValue` when not registered.\n * Re-throws `ConduitSyncResolutionError`, `ConduitScopedResolutionError`, and `ConduitDisposedError`.\n */\nexport function resolveSyncOrDefault<T>(container: Container, tok: Token<T>, defaultValue: T): T {\n const result = resolveSyncOptional(container, tok);\n\n return result === undefined ? defaultValue : result;\n}\n\n/**\n * Resolve a token synchronously, returning a result object instead of throwing.\n * Returns `{ ok: true, value }` on success or `{ ok: false, error }` when the\n * token is not registered. Re-throws all other errors — including\n * `ConduitSyncResolutionError`, `ConduitDisposedError`, and `ConduitScopedResolutionError`.\n */\nexport function trySyncResolve<T>(container: Container, tok: Token<T>): ResolveResult<T> {\n try {\n const value = container.resolveSync(tok);\n\n return { ok: true, value };\n } catch (error) {\n if (error instanceof ConduitProviderNotFoundError) return { error, ok: false };\n\n throw error;\n }\n}\n\n/**\n * Apply container modules sequentially (each module may be async).\n * Returns the container for chaining.\n */\nexport async function loadModules(container: Container, ...modules: ContainerModule[]): Promise<Container> {\n for (const mod of modules) await mod(container);\n\n return container;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./_dev.cjs"),t=require("./errors.cjs");var n=class n{#e=new Map;#t=new Map;#n;#r;#i=new Set;#a=new Set;#o=new AbortController;#s=!1;#c=!1;name;constructor(e,t={}){this.#n=e,this.#r=t.scopeTag,this.name=t.name??(e?t.scopeTag?`${e.name}:${t.scopeTag.description??`scope`}`:`${e.name}:child`:`root`)}#l(){if(this.#s)throw new t.ConduitDisposedError(this.name)}#u(){if(this.#c)throw new t.ConduitFrozenError(this.name)}#d(e){for(let t of this.#i)try{t(e)}catch{}this.#n&&this.#n.#d(e)}get disposalSignal(){return this.#o.signal}get disposed(){return this.#s}value(e,n,r){if(this.#l(),this.#u(),this.#e.has(e))throw new t.ConduitDuplicateRegistrationError(e);let i={dispose:r?.dispose,kind:`value`,value:n};return this.#e.set(e,i),this.#d({description:t.tokenName(e),kind:`value`,source:this.name,type:`register`}),this}factory(e,n,r){if(this.#l(),this.#u(),this.#e.has(e))throw new t.ConduitDuplicateRegistrationError(e);let i={deps:r?.deps,dispose:r?.dispose,factory:n,kind:`factory`,lifetime:r?.lifetime??`singleton`};return this.#e.set(e,i),this.#d({description:t.tokenName(e),kind:`factory`,source:this.name,type:`register`}),this}has(e){return this.#l(),this.#p(e)!==void 0}async resolve(e){this.#l();let n=await this.#b(e,new Set,[]);return this.#d({description:t.tokenName(e),source:this.name,type:`resolve`}),this.#f(e,n),n}resolveSync(e){this.#l();let n=this.#p(e);if(!n)throw new t.ConduitProviderNotFoundError(e,this.name);let r=this.#S(e,n);return this.#d({description:t.tokenName(e),source:this.name,type:`resolve`}),this.#f(e,r),r}async resolveMany(e){return Promise.all(e.map(e=>this.resolve(e)))}async resolveAll(e){this.#l();let n=new Set,r=[],i=async e=>{let n=await this.#b(e,new Set,[]);this.#d({description:t.tokenName(e),source:this.name,type:`resolve`}),this.#f(e,n)};for(let t of this.#h())for(let[a,o]of t.#e)n.has(a)||o.kind!==`factory`||(n.add(a),(o.lifetime===`singleton`||e?.includeScoped&&typeof o.lifetime==`symbol`&&this.#g(o.lifetime))&&r.push(i(a)));await Promise.all(r)}inspect(e){this.#l();let n=e?.deep??!0,r=[],i=new Set;for(let e of this.#h()){for(let[n,a]of e.#e)if(!i.has(n))if(i.add(n),a.kind===`value`)r.push({description:t.tokenName(n),kind:`value`});else{let e=typeof a.lifetime==`symbol`?`scope:${a.lifetime.description??`anonymous`}`:a.lifetime;r.push({deps:a.deps?.map(e=>t.tokenName(e)),description:t.tokenName(n),kind:`factory`,lifetime:e})}if(!n)break}return{nodes:r}}validate(){this.#l();let e=new Set,n=new Map;for(let r of this.#h())for(let[i,a]of r.#e)if(!e.has(i)&&(e.add(i),a.kind===`factory`&&a.deps&&a.deps.length>0)){n.set(i,a.deps);for(let e of a.deps)if(this.#p(e)===void 0)throw new t.ConduitProviderNotFoundError(e,this.name)}if(n.size>0){let e=new Set,r=new Set,i=(a,o)=>{if(e.has(a))throw new t.ConduitCircularDependencyError([...o,a]);if(!r.has(a)){e.add(a);for(let e of n.get(a)??[])i(e,[...o,a]);e.delete(a),r.add(a)}};for(let e of n.keys())r.has(e)||i(e,[])}return this}freeze(){return this.#l(),this.#c?this:(this.validate(),this.#c=!0,this)}createScope(e,t){return this.#l(),new n(this,{name:t?.name,scopeTag:e})}on(e){return this.#l(),this.#i.add(e),()=>this.#i.delete(e)}onResolve(e){return this.#l(),this.#a.add(e),()=>this.#a.delete(e)}async dispose(){if(this.#s)return;this.#s=!0,this.#o.abort(),this.#d({source:this.name,type:`dispose`});let t=[],n=new Set;for(let e of this.#e.values())if(e.kind===`value`)e.dispose&&t.push(Promise.resolve().then(()=>e.dispose(e.value)));else if(n.add(e),e.dispose){let n=this.#t.get(e);n?.resolved&&t.push(Promise.resolve().then(()=>e.dispose(n.instance)))}for(let[e,r]of this.#t)!n.has(e)&&e.dispose&&r.resolved&&t.push(Promise.resolve().then(()=>e.dispose(r.instance)));let r=await Promise.allSettled(t);this.#t.clear(),this.#e.clear(),this.#i.clear(),this.#a.clear();for(let t of r)t.status===`rejected`&&e.error(`dispose hook failed in container '${this.name}':`,t.reason)}[Symbol.asyncDispose](){return this.dispose()}#f(e,t){for(let n of this.#a)try{n(e,t)}catch{}this.#n&&this.#n.#f(e,t)}#p(e){let t=this.#e.get(e);if(t)return t;if(this.#n)return this.#n.#l(),this.#n.#p(e)}#m(e){for(let t of this.#h())if(t.#e.has(e))return t;return this}*#h(){yield this;let e=this.#n;for(;e;)yield e,e=e.#n}#g(e){if(this.#r===e)return this;if(this.#n)return this.#n.#g(e)}#_(e){let t=this.#t.get(e);return t||(t={resolved:!1},this.#t.set(e,t)),t}#v(e,t){return{resolve:n=>this.#b(n,new Set(e),t),resolveSync:e=>this.resolveSync(e)}}#y(e,t,n,r){return e.resolved?Promise.resolve(e.instance):(e.promise||=Promise.resolve(t.factory(this.#v(n,r))).then(t=>(e.instance=t,e.resolved=!0,t)).catch(t=>{throw e.rejection=t,t}),e.promise)}async#b(e,n,r){if(n.has(e))throw new t.ConduitCircularDependencyError([...r,e]);let i=this.#p(e);if(!i)throw new t.ConduitProviderNotFoundError(e,this.name);n.add(e);let a=await this.#x(e,i,n,[...r,e]);return n.delete(e),a}async#x(e,n,r,i){if(n.kind===`value`)return n.value;let{lifetime:a}=n;if(typeof a==`symbol`){let o=this.#g(a);if(!o)throw new t.ConduitScopedResolutionError(e,a);return this.#y(o.#_(n),n,r,i)}if(a===`transient`)return n.factory(this.#v(r,i));let o=this.#m(e);return this.#y(o.#_(n),n,r,i)}#S(e,n){if(n.kind===`value`)return n.value;let{lifetime:r}=n;if(typeof r==`symbol`){let i=this.#g(r);if(!i)throw new t.ConduitScopedResolutionError(e,r);let a=i.#t.get(n);if(a?.resolved)return a.instance;throw a?.rejection===void 0?new t.ConduitSyncResolutionError(e,r):a.rejection}if(r===`transient`)throw new t.ConduitSyncResolutionError(e,r);let i=this.#m(e).#t.get(n);if(i?.resolved)return i.instance;throw i?.rejection===void 0?new t.ConduitSyncResolutionError(e,r):i.rejection}};function r(e){return new n(void 0,{name:e?.name??`root`})}exports.createContainer=r;
|
|
2
|
+
//# sourceMappingURL=container.cjs.map
|