@asaidimu/utils-artifacts 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -450,6 +450,9 @@ interface PendingArtifact extends ResolvedArtifactBase {
450
450
  * @template TArtifact The type of the resolved artifact instance.
451
451
  */
452
452
  type ResolvedArtifact<TArtifact> = ReadyArtifact<TArtifact> | ErrorArtifact | PendingArtifact;
453
+ type KeyedResolvedArtifact<TRegistry, K extends keyof TRegistry> = ResolvedArtifact<TRegistry[K]> & {
454
+ [P in K]?: TRegistry[K];
455
+ };
453
456
  /**
454
457
  * The factory function responsible for creating an artifact's instance.
455
458
  * It receives an `ArtifactFactoryContext` to interact with the container
@@ -468,7 +471,7 @@ type ArtifactInstance<R> = R extends PromiseLike<infer T> ? T : R;
468
471
  * Provides a way to get the current resolved artifact and subscribe to updates.
469
472
  * @template TArtifact The type of the artifact being watched.
470
473
  */
471
- interface ArtifactObserver<TArtifact> {
474
+ interface ArtifactObserver<TRegistry, K extends keyof TRegistry> {
472
475
  /** The unique identifier (key) of the artifact being watched. */
473
476
  id: string;
474
477
  /**
@@ -482,7 +485,7 @@ interface ArtifactObserver<TArtifact> {
482
485
  * immediately. Defaults to `false`
483
486
  * @returns The resolved artifact, including its instance and status.
484
487
  */
485
- get(resolve?: boolean): ResolvedArtifact<TArtifact>;
488
+ get(resolve?: boolean): KeyedResolvedArtifact<TRegistry, K>;
486
489
  /**
487
490
  * Subscribes a callback function to be invoked whenever the artifact's
488
491
  * state (instance, error, or readiness) changes.
@@ -491,7 +494,7 @@ interface ArtifactObserver<TArtifact> {
491
494
  * callback after subscription. Defaults to `true`
492
495
  * @returns A function to unsubscribe the callback and stop receiving updates.
493
496
  */
494
- subscribe(callback: (artifact: ResolvedArtifact<TArtifact>) => void, eager?: boolean): () => void;
497
+ subscribe(callback: (artifact: KeyedResolvedArtifact<TRegistry, K>) => void, eager?: boolean): () => void;
495
498
  /**
496
499
  * Resolves another artifact from the container and registers a dependency on it.
497
500
  * If the dependency changes, the current artifact will be invalidated and rebuilt.
@@ -499,7 +502,7 @@ interface ArtifactObserver<TArtifact> {
499
502
  * or an external error.
500
503
  * @throws {SystemError} if resolution fails.
501
504
  */
502
- resolve(): Promise<ResolvedArtifact<TArtifact>>;
505
+ resolve(): Promise<KeyedResolvedArtifact<TRegistry, K>>;
503
506
  }
504
507
  /**
505
508
  * Configuration options for defining an artifact. These options control
@@ -668,7 +671,7 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
668
671
  * @throws {ArtifactNotFoundError} if the artifact is not found
669
672
  * @throws {ArtifactError} if a cycle is detected or other system errors occur
670
673
  */
671
- resolve<K extends keyof TRegistry>(key: K): Promise<ResolvedArtifact<TRegistry[K]>>;
674
+ resolve<K extends keyof TRegistry>(key: K): Promise<KeyedResolvedArtifact<TRegistry, K>>;
672
675
  /**
673
676
  * Resolves an artifact by its key, returning its instance directly.
674
677
  * This is a wrapper around resolve to prevent defensive programming
@@ -686,7 +689,7 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
686
689
  * @param key The unique identifier for the artifact
687
690
  * @returns An ArtifactWatcher instance
688
691
  */
689
- watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry[K]>;
692
+ watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry, K>;
690
693
  /**
691
694
  * Peeks at the resolved instance of an artifact without triggering its resolution
692
695
  * if it's lazy, or registering a dependency.
@@ -730,4 +733,4 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
730
733
  dispose(): Promise<void>;
731
734
  }
732
735
 
733
- export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
736
+ export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type KeyedResolvedArtifact, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
package/index.d.ts CHANGED
@@ -450,6 +450,9 @@ interface PendingArtifact extends ResolvedArtifactBase {
450
450
  * @template TArtifact The type of the resolved artifact instance.
451
451
  */
452
452
  type ResolvedArtifact<TArtifact> = ReadyArtifact<TArtifact> | ErrorArtifact | PendingArtifact;
453
+ type KeyedResolvedArtifact<TRegistry, K extends keyof TRegistry> = ResolvedArtifact<TRegistry[K]> & {
454
+ [P in K]?: TRegistry[K];
455
+ };
453
456
  /**
454
457
  * The factory function responsible for creating an artifact's instance.
455
458
  * It receives an `ArtifactFactoryContext` to interact with the container
@@ -468,7 +471,7 @@ type ArtifactInstance<R> = R extends PromiseLike<infer T> ? T : R;
468
471
  * Provides a way to get the current resolved artifact and subscribe to updates.
469
472
  * @template TArtifact The type of the artifact being watched.
470
473
  */
471
- interface ArtifactObserver<TArtifact> {
474
+ interface ArtifactObserver<TRegistry, K extends keyof TRegistry> {
472
475
  /** The unique identifier (key) of the artifact being watched. */
473
476
  id: string;
474
477
  /**
@@ -482,7 +485,7 @@ interface ArtifactObserver<TArtifact> {
482
485
  * immediately. Defaults to `false`
483
486
  * @returns The resolved artifact, including its instance and status.
484
487
  */
485
- get(resolve?: boolean): ResolvedArtifact<TArtifact>;
488
+ get(resolve?: boolean): KeyedResolvedArtifact<TRegistry, K>;
486
489
  /**
487
490
  * Subscribes a callback function to be invoked whenever the artifact's
488
491
  * state (instance, error, or readiness) changes.
@@ -491,7 +494,7 @@ interface ArtifactObserver<TArtifact> {
491
494
  * callback after subscription. Defaults to `true`
492
495
  * @returns A function to unsubscribe the callback and stop receiving updates.
493
496
  */
494
- subscribe(callback: (artifact: ResolvedArtifact<TArtifact>) => void, eager?: boolean): () => void;
497
+ subscribe(callback: (artifact: KeyedResolvedArtifact<TRegistry, K>) => void, eager?: boolean): () => void;
495
498
  /**
496
499
  * Resolves another artifact from the container and registers a dependency on it.
497
500
  * If the dependency changes, the current artifact will be invalidated and rebuilt.
@@ -499,7 +502,7 @@ interface ArtifactObserver<TArtifact> {
499
502
  * or an external error.
500
503
  * @throws {SystemError} if resolution fails.
501
504
  */
502
- resolve(): Promise<ResolvedArtifact<TArtifact>>;
505
+ resolve(): Promise<KeyedResolvedArtifact<TRegistry, K>>;
503
506
  }
504
507
  /**
505
508
  * Configuration options for defining an artifact. These options control
@@ -668,7 +671,7 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
668
671
  * @throws {ArtifactNotFoundError} if the artifact is not found
669
672
  * @throws {ArtifactError} if a cycle is detected or other system errors occur
670
673
  */
671
- resolve<K extends keyof TRegistry>(key: K): Promise<ResolvedArtifact<TRegistry[K]>>;
674
+ resolve<K extends keyof TRegistry>(key: K): Promise<KeyedResolvedArtifact<TRegistry, K>>;
672
675
  /**
673
676
  * Resolves an artifact by its key, returning its instance directly.
674
677
  * This is a wrapper around resolve to prevent defensive programming
@@ -686,7 +689,7 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
686
689
  * @param key The unique identifier for the artifact
687
690
  * @returns An ArtifactWatcher instance
688
691
  */
689
- watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry[K]>;
692
+ watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry, K>;
690
693
  /**
691
694
  * Peeks at the resolved instance of an artifact without triggering its resolution
692
695
  * if it's lazy, or registering a dependency.
@@ -730,4 +733,4 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
730
733
  dispose(): Promise<void>;
731
734
  }
732
735
 
733
- export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
736
+ export { type ArtifactCleanup, ArtifactContainer, type ArtifactDebugNode, type ArtifactFactory, type ArtifactFactoryContext, type ArtifactInstance, type ArtifactKey, type ArtifactObserver, type ArtifactRegistryType, type ArtifactScope, type ArtifactScopeType, ArtifactScopes, type ArtifactStateType, type ArtifactStreamContext, type ArtifactTemplate, type ArtifactTemplateMap, type ArtifactValue, type ErrorArtifact, type InferRegistry, type KeyedResolvedArtifact, type PendingArtifact, type ReadyArtifact, type ResolvedArtifact, type ResolvedArtifactBase, type UseDependencyContext };
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=(e=>(e.Singleton="singleton",e.Transient="transient",e))(e||{}),t=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},r=class extends t{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},s=class extends t{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system"),this.name="ArtifactKeyConflict"}},i=class extends t{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},n=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...i}){if(this.artifacts.has(e))throw new s(String(e));const{scope:n,...a}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}get(e){if(!this.has(e))throw new r(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}},a=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},o=class extends a{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends a{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},h=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,i)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),i(new o("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},l=class{mutex=new h({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,r="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,i)=>{s=setTimeout((()=>i(new o(r))),t)}))])}},d=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new h({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new c};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new c;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){r=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},u=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];function p(e,t){if(!e.length)return;const r=e.slice(),s=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=r.length-1;e>=0;e--)try{await r[e]()}catch(t){console.error(`${s} Cleanup error at index ${e}:`,t)}}}async function g(e,t){const r=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${r} Cleanup error at index ${t}:`,e)}}var f=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}}),w=class{constructor(e,t,r,s,i){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=i}async build(e,r){const s=this.cache.get(e);if(s&&null!==s.buildOnce&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),a=r?new Set(r):new Set;if(a.has(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(a).join(" -> ")}`,"system");a.add(e);let o=s;if(o||(o=this.createCachedArtifact(n),this.cache.set(e,o)),"transient"===n.scope)return this.executeBuild(n,o,a);try{await o.buildOnce.do((()=>this.executeBuild(n,o,a)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return o.stream&&o.streamOnce.do(o.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}async executeBuild(e,r,s){const n=r.controller.signal,a=e.key,o=String(a),c="transient"===e.scope;r.buildCount++,r.activeDebounceMs=e.debounce??0;const h=[],l=[];let d=null,g=null,f=null;const w=this.graph,y=this.cache,m=this;async function v(e){if(e===a)throw new t(`Artifact "${o}" depends on itself.`,"system");const r=w.wouldCreateCycle(a,e,s);if(r)throw new t(`Adding dependency "${String(e)}" to "${o}" would create a cycle: ${r.join(" -> ")}`,"system");null===g&&(g=new Set),null===f&&(f=new Map),g.add(e);const i=await m.build(e,s),n=y.get(e);return n&&f.set(e,n.version),i}const b={state:()=>m.store.get(!0),previous:r.instance,get signal(){return r.controller.signal},onCleanup:e=>h.push(e),onDispose:e=>l.push(e),use:async e=>e({resolve:v,require:async e=>{const t=await v(e);if(t.error)throw t.error;return t.instance},select:e=>{const t=function(e,t="."){const r=new Set,s=new Map,i=(e="")=>{if(s.has(e))return s.get(e);const n=new Proxy((()=>{}),{get:(s,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic/math/string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(a),i(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions/methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e);return null===d&&(d=new Set),t.forEach((e=>d.add(e))),e(m.store.get(!0))}}),stream:e=>{if(c)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${o}"`,"system");const s=async(e,t=void 0)=>{await r.streamSerializer.do((async()=>{void 0!==r.stream&&(r.instance=e,r.error=t,r.version++,this.cache.invalidatePackage(a),await this.processStream(a))}))},i={value:()=>r.instance,get signal(){return r.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>s(e)};r.stream=async()=>{try{const t=await e(i);t&&r.cleanupFunctions.push(t)}catch(e){await s(void 0,e),await this.invalidate(a,!1,!0)}}}};let S,_,k=0;const A=(e.retries??0)+1;for(;k<A;)try{if(r.controller.signal.aborted)throw new i;const s=e.factory(b);if(s instanceof Promise)if(e.timeout){let t;const r=new Promise(((r,s)=>{t=setTimeout((()=>s(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)}));try{S=await Promise.race([s,r])}finally{clearTimeout(t)}}else S=await s;else S=s;if(r.controller.signal.aborted)throw new i;const n=f?this.detectStaleness(f):null;if(!n){_=void 0;break}if(k++,f?.clear(),k<A)continue;_=new t(`Build stale after all retries: dependency "${String(n)}" changed during build.`,"system")}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;k++,k>=A&&(_=e)}if(c||(this.updateDependencyGraph(a,g??new Set,d??new Set),r.cleanupFunctions=h,r.disposeFunctions=l),_?(r.error=_,r.instance=void 0):(r.instance=S,r.error=void 0),r.version++,this.cache.invalidatePackage(a),c)return{instance:S,cleanup:p(h,String(a)),error:_,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(a)}"`)}}detectStaleness(e){for(const[t,r]of e){const e=this.cache.get(t);if(e&&e.version!==r)return t}return null}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise(((i,n)=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(i).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.iterDependents(e);await Promise.all(Array.from(n).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const a=this.registry.get(e);!a||!t&&a.lazy&&!this.hasWatchers(e)||r||await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.iterDependents(e);await Promise.all(Array.from(t).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){const t="transient"===e.scope,r={instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController};return t?{...r,buildOnce:null,streamOnce:null,streamSerializer:null,invalidationSerializer:null}:{...r,buildOnce:new l({retry:!0,throws:!0}),streamOnce:new l({retry:!0,throws:!0}),streamSerializer:new d({yieldMode:"microtask"}),invalidationSerializer:new d({yieldMode:"macrotask"})}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},y=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??m}iterDependencies(e){return this.dependencies.get(e)??m}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),i=new Map;for(;r.length>0;){const n=r.shift();if(n===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=i.get(s);return r.reverse(),r.unshift(e),r}const a=this.dependencies.get(n);if(a)for(const e of a)s.has(e)||(s.add(e),i.set(e,n),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const i=this.dependents.get(t);if(i)for(const t of i){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,i=new Set,n=[e];i.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)i.has(e)||(i.add(e),s.add(e),n.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},m=new Set,v=class{graph;constructor(){this.graph=new y}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),i=e.slice(s);return i.push(t),i}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},b=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return f;if(r.package)return r.package;const s=String(e);let i=null;const n={instance:r.instance,error:r.error,ready:r.buildOnce?.done(),get cleanup(){return null===i&&(i=p(r.cleanupFunctions,s)??void 0),i},invalidate:t};return r.package=n,n}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const r=this.get(e);if(!r)return;r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0);const s=null===r.buildOnce;s||(r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new l({retry:!0,throws:!0}),t||(r.streamSerializer=new d,r.controller=new AbortController)),await g(r.cleanupFunctions,String(e)),await g(r.disposeFunctions,String(e)),r.cleanupFunctions=[],r.disposeFunctions=[],s||(r.buildOnce=new l({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},S=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);const s="transient"===r.scope?`${t}__watched`:t,i="transient"===r.scope;if(this.watcherCache.has(s))return this.watcherCache.get(s).watcher;const n={count:0,init:new l({retry:!1,throws:!0}),watcher:null},a=()=>n.init.do((async()=>{i&&!this.registry.has(s)&&this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})}));return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(s,(e=>this.container.invalidate(s,e))):f,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(s))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.count++,this.listeners.has(s)||this.listeners.set(s,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(s))).then((()=>{t&&o(),this.listeners.get(s)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e),this.listeners.get(s)?.add(o)})),()=>{this.listeners.get(s)?.delete(o),n.count--,0===n.count&&(this.listeners.delete(s),i&&(this.registry.unregister(s).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${s}":`,e)})),this.cache.delete(s),this.watcherCache.delete(s)),n.init.reset())}}},this.watcherCache.set(s,n),n.watcher}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const r of t)try{r()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return!!this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}};exports.ArtifactContainer=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new n,this.cache=new b,this.graph=new v,this.observer=new S(this.registry,this.cache,this),this.manager=new w(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;let i="idle";s&&(void 0!==s.debounceTimer?i="debouncing":s.buildOnce?.running()?i="building":s.error?i="error":void 0!==s.instance&&(i="active")),e.push({id:t,scope:r.scope??"singleton",status:i,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],buildCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new r(e);return this.manager.build(e)}async require(e){const t=await this.resolve(e);if(t.error)throw t.error;return t.instance}watch(e){if(!this.registry.has(e))throw new r(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((e=>this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}},exports.ArtifactScopes=e;
1
+ "use strict";var e=(e=>(e.Singleton="singleton",e.Transient="transient",e))(e||{}),t=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},r=class extends t{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},s=class extends t{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system"),this.name="ArtifactKeyConflict"}},i=class extends t{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},n=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...i}){if(this.artifacts.has(e))throw new s(String(e));const{scope:n,...a}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}get(e){if(!this.has(e))throw new r(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}},a=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},o=class extends a{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends a{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},h=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,i)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),i(new o("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},l=class{mutex=new h({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,r="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,i)=>{s=setTimeout((()=>i(new o(r))),t)}))])}},d=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new h({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new c};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new c;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){r=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},u=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];function p(e,t){if(!e.length)return;const r=e.slice(),s=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=r.length-1;e>=0;e--)try{await r[e]()}catch(t){console.error(`${s} Cleanup error at index ${e}:`,t)}}}async function g(e,t){const r=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${r} Cleanup error at index ${t}:`,e)}}var f=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}}),w=class{constructor(e,t,r,s,i){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=i}async build(e,r){const s=this.cache.get(e);if(s&&null!==s.buildOnce&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),a=r?new Set(r):new Set;if(a.has(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(a).join(" -> ")}`,"system");a.add(e);let o=s;if(o||(o=this.createCachedArtifact(n),this.cache.set(e,o)),"transient"===n.scope)return this.executeBuild(n,o,a);try{await o.buildOnce.do((()=>this.executeBuild(n,o,a)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return o.stream&&o.streamOnce.do(o.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}async executeBuild(e,r,s){const n=r.controller.signal,a=e.key,o=String(a),c="transient"===e.scope;r.buildCount++,r.activeDebounceMs=e.debounce??0;const h=[],l=[];let d=null,g=null,f=null;const w=this.graph,y=this.cache,m=this;async function v(e){if(e===a)throw new t(`Artifact "${o}" depends on itself.`,"system");const r=w.wouldCreateCycle(a,e,s);if(r)throw new t(`Adding dependency "${String(e)}" to "${o}" would create a cycle: ${r.join(" -> ")}`,"system");null===g&&(g=new Set),null===f&&(f=new Map),g.add(e);const i=await m.build(e,s),n=y.get(e);return n&&f.set(e,n.version),i}const b={state:()=>m.store.get(!0),previous:r.instance,get signal(){return r.controller.signal},onCleanup:e=>h.push(e),onDispose:e=>l.push(e),use:async e=>e({resolve:v,require:async e=>{const t=await v(e);if(t.error)throw t.error;return t.instance},select:e=>{const t=function(e,t="."){const r=new Set,s=new Map,i=(e="")=>{if(s.has(e))return s.get(e);const n=new Proxy((()=>{}),{get:(s,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic/math/string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(a),i(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions/methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e);return null===d&&(d=new Set),t.forEach((e=>d.add(e))),e(m.store.get(!0))}}),stream:e=>{if(c)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${o}"`,"system");const s=async(e,t=void 0)=>{await r.streamSerializer.do((async()=>{void 0!==r.stream&&(r.instance=e,r.error=t,r.version++,this.cache.invalidatePackage(a),await this.processStream(a))}))},i={value:()=>r.instance,get signal(){return r.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>s(e)};r.stream=async()=>{try{const t=await e(i);t&&r.cleanupFunctions.push(t)}catch(e){await s(void 0,e),await this.invalidate(a,!1,!0)}}}};let S,_,k=0;const A=(e.retries??0)+1;for(;k<A;)try{if(r.controller.signal.aborted)throw new i;const s=e.factory(b);if(s instanceof Promise)if(e.timeout){let t;const r=new Promise(((r,s)=>{t=setTimeout((()=>s(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)}));try{S=await Promise.race([s,r])}finally{clearTimeout(t)}}else S=await s;else S=s;if(r.controller.signal.aborted)throw new i;const n=f?this.detectStaleness(f):null;if(!n){_=void 0;break}if(k++,f?.clear(),k<A)continue;_=new t(`Build stale after all retries: dependency "${String(n)}" changed during build.`,"system")}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;k++,k>=A&&(_=e)}if(c||(this.updateDependencyGraph(a,g??new Set,d??new Set),r.cleanupFunctions=h,r.disposeFunctions=l),_?(r.error=_,r.instance=void 0):(r.instance=S,r.error=void 0),r.version++,this.cache.invalidatePackage(a),c)return{instance:S,cleanup:p(h,String(a)),error:_,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(a)}"`)}}detectStaleness(e){for(const[t,r]of e){const e=this.cache.get(t);if(e&&e.version!==r)return t}return null}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise(((i,n)=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(i).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.iterDependents(e);await Promise.all(Array.from(n).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const a=this.registry.get(e);!a||!t&&a.lazy&&!this.hasWatchers(e)||r||await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.iterDependents(e);await Promise.all(Array.from(t).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){const t="transient"===e.scope,r={instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController};return t?{...r,buildOnce:null,streamOnce:null,streamSerializer:null,invalidationSerializer:null}:{...r,buildOnce:new l({retry:!0,throws:!0}),streamOnce:new l({retry:!0,throws:!0}),streamSerializer:new d({yieldMode:"microtask"}),invalidationSerializer:new d({yieldMode:"macrotask"})}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},y=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??m}iterDependencies(e){return this.dependencies.get(e)??m}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),i=new Map;for(;r.length>0;){const n=r.shift();if(n===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=i.get(s);return r.reverse(),r.unshift(e),r}const a=this.dependencies.get(n);if(a)for(const e of a)s.has(e)||(s.add(e),i.set(e,n),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const i=this.dependents.get(t);if(i)for(const t of i){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,i=new Set,n=[e];i.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)i.has(e)||(i.add(e),s.add(e),n.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},m=new Set,v=class{graph;constructor(){this.graph=new y}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),i=e.slice(s);return i.push(t),i}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},b=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return f;if(r.package)return r.package;const s=String(e);let i=null;const n={instance:r.instance,error:r.error,ready:r.buildOnce?.done(),[e]:r.instance,get cleanup(){return null===i&&(i=p(r.cleanupFunctions,s)??void 0),i},invalidate:t};return r.package=n,n}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const r=this.get(e);if(!r)return;r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0);const s=null===r.buildOnce;s||(r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new l({retry:!0,throws:!0}),t||(r.streamSerializer=new d,r.controller=new AbortController)),await g(r.cleanupFunctions,String(e)),await g(r.disposeFunctions,String(e)),r.cleanupFunctions=[],r.disposeFunctions=[],s||(r.buildOnce=new l({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},S=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);const s="transient"===r.scope?`${t}__watched`:t,i="transient"===r.scope;if(this.watcherCache.has(s))return this.watcherCache.get(s).watcher;const n={count:0,init:new l({retry:!1,throws:!0}),watcher:null},a=()=>n.init.do((async()=>{i&&!this.registry.has(s)&&this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})}));return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(s,(e=>this.container.invalidate(s,e))):f,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(s))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.count++,this.listeners.has(s)||this.listeners.set(s,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(s))).then((()=>{t&&o(),this.listeners.get(s)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e),this.listeners.get(s)?.add(o)})),()=>{this.listeners.get(s)?.delete(o),n.count--,0===n.count&&(this.listeners.delete(s),i&&(this.registry.unregister(s).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${s}":`,e)})),this.cache.delete(s),this.watcherCache.delete(s)),n.init.reset())}}},this.watcherCache.set(s,n),n.watcher}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const r of t)try{r()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return!!this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}};exports.ArtifactContainer=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new n,this.cache=new b,this.graph=new v,this.observer=new S(this.registry,this.cache,this),this.manager=new w(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;let i="idle";s&&(void 0!==s.debounceTimer?i="debouncing":s.buildOnce?.running()?i="building":s.error?i="error":void 0!==s.instance&&(i="active")),e.push({id:t,scope:r.scope??"singleton",status:i,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],buildCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new r(e);const t=await this.manager.build(e);return t[e]=t.instance,t}async require(e){const t=await this.resolve(e);if(t.error)throw t.error;return t.instance}watch(e){if(!this.registry.has(e))throw new r(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((e=>this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}},exports.ArtifactScopes=e;
package/index.mjs CHANGED
@@ -1 +1 @@
1
- var e=(e=>(e.Singleton="singleton",e.Transient="transient",e))(e||{}),t=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},r=class extends t{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},s=class extends t{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system"),this.name="ArtifactKeyConflict"}},i=class extends t{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},n=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...i}){if(this.artifacts.has(e))throw new s(String(e));const{scope:n,...a}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}get(e){if(!this.has(e))throw new r(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}},a=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},o=class extends a{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends a{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},h=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,i)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),i(new o("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},l=class{mutex=new h({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,r="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,i)=>{s=setTimeout((()=>i(new o(r))),t)}))])}},d=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new h({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new c};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new c;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){r=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},u=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];function p(e,t){if(!e.length)return;const r=e.slice(),s=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=r.length-1;e>=0;e--)try{await r[e]()}catch(t){console.error(`${s} Cleanup error at index ${e}:`,t)}}}async function g(e,t){const r=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${r} Cleanup error at index ${t}:`,e)}}var f=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}}),w=class{constructor(e,t,r,s,i){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=i}async build(e,r){const s=this.cache.get(e);if(s&&null!==s.buildOnce&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),a=r?new Set(r):new Set;if(a.has(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(a).join(" -> ")}`,"system");a.add(e);let o=s;if(o||(o=this.createCachedArtifact(n),this.cache.set(e,o)),"transient"===n.scope)return this.executeBuild(n,o,a);try{await o.buildOnce.do((()=>this.executeBuild(n,o,a)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return o.stream&&o.streamOnce.do(o.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}async executeBuild(e,r,s){const n=r.controller.signal,a=e.key,o=String(a),c="transient"===e.scope;r.buildCount++,r.activeDebounceMs=e.debounce??0;const h=[],l=[];let d=null,g=null,f=null;const w=this.graph,y=this.cache,m=this;async function v(e){if(e===a)throw new t(`Artifact "${o}" depends on itself.`,"system");const r=w.wouldCreateCycle(a,e,s);if(r)throw new t(`Adding dependency "${String(e)}" to "${o}" would create a cycle: ${r.join(" -> ")}`,"system");null===g&&(g=new Set),null===f&&(f=new Map),g.add(e);const i=await m.build(e,s),n=y.get(e);return n&&f.set(e,n.version),i}const b={state:()=>m.store.get(!0),previous:r.instance,get signal(){return r.controller.signal},onCleanup:e=>h.push(e),onDispose:e=>l.push(e),use:async e=>e({resolve:v,require:async e=>{const t=await v(e);if(t.error)throw t.error;return t.instance},select:e=>{const t=function(e,t="."){const r=new Set,s=new Map,i=(e="")=>{if(s.has(e))return s.get(e);const n=new Proxy((()=>{}),{get:(s,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic/math/string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(a),i(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions/methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e);return null===d&&(d=new Set),t.forEach((e=>d.add(e))),e(m.store.get(!0))}}),stream:e=>{if(c)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${o}"`,"system");const s=async(e,t=void 0)=>{await r.streamSerializer.do((async()=>{void 0!==r.stream&&(r.instance=e,r.error=t,r.version++,this.cache.invalidatePackage(a),await this.processStream(a))}))},i={value:()=>r.instance,get signal(){return r.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>s(e)};r.stream=async()=>{try{const t=await e(i);t&&r.cleanupFunctions.push(t)}catch(e){await s(void 0,e),await this.invalidate(a,!1,!0)}}}};let S,_,k=0;const A=(e.retries??0)+1;for(;k<A;)try{if(r.controller.signal.aborted)throw new i;const s=e.factory(b);if(s instanceof Promise)if(e.timeout){let t;const r=new Promise(((r,s)=>{t=setTimeout((()=>s(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)}));try{S=await Promise.race([s,r])}finally{clearTimeout(t)}}else S=await s;else S=s;if(r.controller.signal.aborted)throw new i;const n=f?this.detectStaleness(f):null;if(!n){_=void 0;break}if(k++,f?.clear(),k<A)continue;_=new t(`Build stale after all retries: dependency "${String(n)}" changed during build.`,"system")}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;k++,k>=A&&(_=e)}if(c||(this.updateDependencyGraph(a,g??new Set,d??new Set),r.cleanupFunctions=h,r.disposeFunctions=l),_?(r.error=_,r.instance=void 0):(r.instance=S,r.error=void 0),r.version++,this.cache.invalidatePackage(a),c)return{instance:S,cleanup:p(h,String(a)),error:_,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(a)}"`)}}detectStaleness(e){for(const[t,r]of e){const e=this.cache.get(t);if(e&&e.version!==r)return t}return null}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise(((i,n)=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(i).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.iterDependents(e);await Promise.all(Array.from(n).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const a=this.registry.get(e);!a||!t&&a.lazy&&!this.hasWatchers(e)||r||await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.iterDependents(e);await Promise.all(Array.from(t).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){const t="transient"===e.scope,r={instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController};return t?{...r,buildOnce:null,streamOnce:null,streamSerializer:null,invalidationSerializer:null}:{...r,buildOnce:new l({retry:!0,throws:!0}),streamOnce:new l({retry:!0,throws:!0}),streamSerializer:new d({yieldMode:"microtask"}),invalidationSerializer:new d({yieldMode:"macrotask"})}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},y=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??m}iterDependencies(e){return this.dependencies.get(e)??m}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),i=new Map;for(;r.length>0;){const n=r.shift();if(n===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=i.get(s);return r.reverse(),r.unshift(e),r}const a=this.dependencies.get(n);if(a)for(const e of a)s.has(e)||(s.add(e),i.set(e,n),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const i=this.dependents.get(t);if(i)for(const t of i){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,i=new Set,n=[e];i.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)i.has(e)||(i.add(e),s.add(e),n.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},m=new Set,v=class{graph;constructor(){this.graph=new y}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),i=e.slice(s);return i.push(t),i}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},b=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return f;if(r.package)return r.package;const s=String(e);let i=null;const n={instance:r.instance,error:r.error,ready:r.buildOnce?.done(),get cleanup(){return null===i&&(i=p(r.cleanupFunctions,s)??void 0),i},invalidate:t};return r.package=n,n}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const r=this.get(e);if(!r)return;r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0);const s=null===r.buildOnce;s||(r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new l({retry:!0,throws:!0}),t||(r.streamSerializer=new d,r.controller=new AbortController)),await g(r.cleanupFunctions,String(e)),await g(r.disposeFunctions,String(e)),r.cleanupFunctions=[],r.disposeFunctions=[],s||(r.buildOnce=new l({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},S=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);const s="transient"===r.scope?`${t}__watched`:t,i="transient"===r.scope;if(this.watcherCache.has(s))return this.watcherCache.get(s).watcher;const n={count:0,init:new l({retry:!1,throws:!0}),watcher:null},a=()=>n.init.do((async()=>{i&&!this.registry.has(s)&&this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})}));return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(s,(e=>this.container.invalidate(s,e))):f,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(s))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.count++,this.listeners.has(s)||this.listeners.set(s,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(s))).then((()=>{t&&o(),this.listeners.get(s)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e),this.listeners.get(s)?.add(o)})),()=>{this.listeners.get(s)?.delete(o),n.count--,0===n.count&&(this.listeners.delete(s),i&&(this.registry.unregister(s).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${s}":`,e)})),this.cache.delete(s),this.watcherCache.delete(s)),n.init.reset())}}},this.watcherCache.set(s,n),n.watcher}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const r of t)try{r()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return!!this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}},_=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new n,this.cache=new b,this.graph=new v,this.observer=new S(this.registry,this.cache,this),this.manager=new w(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;let i="idle";s&&(void 0!==s.debounceTimer?i="debouncing":s.buildOnce?.running()?i="building":s.error?i="error":void 0!==s.instance&&(i="active")),e.push({id:t,scope:r.scope??"singleton",status:i,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],buildCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new r(e);return this.manager.build(e)}async require(e){const t=await this.resolve(e);if(t.error)throw t.error;return t.instance}watch(e){if(!this.registry.has(e))throw new r(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((e=>this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}};export{_ as ArtifactContainer,e as ArtifactScopes};
1
+ var e=(e=>(e.Singleton="singleton",e.Transient="transient",e))(e||{}),t=class e extends Error{category;constructor(t,r,s){super(t,{cause:s}),this.name="ArtifactError",this.category=r,Object.setPrototypeOf(this,e.prototype)}},r=class extends t{constructor(e){super(`[ArtifactContainer] Artifact "${e}" not found.`,"system"),this.name="ArtifactNotFoundError"}},s=class extends t{constructor(e){super(`[ArtifactContainer] An artifact with key:${e} already exists!`,"system"),this.name="ArtifactKeyConflict"}},i=class extends t{constructor(){super("Build superseded by invalidation","system"),this.name="SupersededBuildError"}},n=class{artifacts=new Map;register({key:e,factory:t,lazy:r,...i}){if(this.artifacts.has(e))throw new s(String(e));const{scope:n,...a}=i,o={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}get(e){if(!this.has(e))throw new r(String(e));return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}async unregister(e){this.artifacts.has(e)&&this.artifacts.delete(e)}size(){return this.artifacts.size}keys(){return Array.from(this.artifacts.keys())}clear(){this.artifacts.clear()}},a=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},o=class extends a{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends a{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},h=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,i)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),i(new o("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},l=class{mutex=new h({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,r="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,i)=>{s=setTimeout((()=>i(new o(r))),t)}))])}},d=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new h({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new c};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new c;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){r=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},u=["map","filter","reduce","forEach","find","findIndex","some","every","includes","flatMap","flat","slice","splice"];function p(e,t){if(!e.length)return;const r=e.slice(),s=t?`[${t}]`:"[ArtifactCleanup]";return async()=>{for(let e=r.length-1;e>=0;e--)try{await r[e]()}catch(t){console.error(`${s} Cleanup error at index ${e}:`,t)}}}async function g(e,t){const r=t?`[${t}]`:"[ArtifactCleanup]";for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${r} Cleanup error at index ${t}:`,e)}}var f=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}}),w=class{constructor(e,t,r,s,i){this.registry=e,this.cache=t,this.graph=r,this.store=s,this.observer=i}async build(e,r){const s=this.cache.get(e);if(s&&null!==s.buildOnce&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),a=r?new Set(r):new Set;if(a.has(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${Array.from(a).join(" -> ")}`,"system");a.add(e);let o=s;if(o||(o=this.createCachedArtifact(n),this.cache.set(e,o)),"transient"===n.scope)return this.executeBuild(n,o,a);try{await o.buildOnce.do((()=>this.executeBuild(n,o,a)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return o.stream&&o.streamOnce.do(o.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}async executeBuild(e,r,s){const n=r.controller.signal,a=e.key,o=String(a),c="transient"===e.scope;r.buildCount++,r.activeDebounceMs=e.debounce??0;const h=[],l=[];let d=null,g=null,f=null;const w=this.graph,y=this.cache,m=this;async function v(e){if(e===a)throw new t(`Artifact "${o}" depends on itself.`,"system");const r=w.wouldCreateCycle(a,e,s);if(r)throw new t(`Adding dependency "${String(e)}" to "${o}" would create a cycle: ${r.join(" -> ")}`,"system");null===g&&(g=new Set),null===f&&(f=new Map),g.add(e);const i=await m.build(e,s),n=y.get(e);return n&&f.set(e,n.version),i}const b={state:()=>m.store.get(!0),previous:r.instance,get signal(){return r.controller.signal},onCleanup:e=>h.push(e),onDispose:e=>l.push(e),use:async e=>e({resolve:v,require:async e=>{const t=await v(e);if(t.error)throw t.error;return t.instance},select:e=>{const t=function(e,t="."){const r=new Set,s=new Map,i=(e="")=>{if(s.has(e))return s.get(e);const n=new Proxy((()=>{}),{get:(s,n)=>{if("symbol"==typeof n||"then"===n)return;if("valueOf"===n||"toString"===n)throw new Error("Cannot perform logic/math/string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const a=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(a),i(a)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions/methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. This usually means the selector is too complex. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e);return null===d&&(d=new Set),t.forEach((e=>d.add(e))),e(m.store.get(!0))}}),stream:e=>{if(c)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${o}"`,"system");const s=async(e,t=void 0)=>{await r.streamSerializer.do((async()=>{void 0!==r.stream&&(r.instance=e,r.error=t,r.version++,this.cache.invalidatePackage(a),await this.processStream(a))}))},i={value:()=>r.instance,get signal(){return r.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>s(e)};r.stream=async()=>{try{const t=await e(i);t&&r.cleanupFunctions.push(t)}catch(e){await s(void 0,e),await this.invalidate(a,!1,!0)}}}};let S,_,k=0;const A=(e.retries??0)+1;for(;k<A;)try{if(r.controller.signal.aborted)throw new i;const s=e.factory(b);if(s instanceof Promise)if(e.timeout){let t;const r=new Promise(((r,s)=>{t=setTimeout((()=>s(new Error(`Timeout: ${e.timeout}ms`))),e.timeout)}));try{S=await Promise.race([s,r])}finally{clearTimeout(t)}}else S=await s;else S=s;if(r.controller.signal.aborted)throw new i;const n=f?this.detectStaleness(f):null;if(!n){_=void 0;break}if(k++,f?.clear(),k<A)continue;_=new t(`Build stale after all retries: dependency "${String(n)}" changed during build.`,"system")}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;k++,k>=A&&(_=e)}if(c||(this.updateDependencyGraph(a,g??new Set,d??new Set),r.cleanupFunctions=h,r.disposeFunctions=l),_?(r.error=_,r.instance=void 0):(r.instance=S,r.error=void 0),r.version++,this.cache.invalidatePackage(a),c)return{instance:S,cleanup:p(h,String(a)),error:_,ready:!0,invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${String(a)}"`)}}detectStaleness(e){for(const[t,r]of e){const e=this.cache.get(t);if(e&&e.version!==r)return t}return null}async invalidate(e,t=!1,r=!1){const s=this.cache.get(e);if(s)return s.debounceTimer&&(clearTimeout(s.debounceTimer),s.debounceTimer=void 0),!t&&s.activeDebounceMs>0?new Promise(((i,n)=>{s.debounceTimer=setTimeout((()=>{s.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(i).catch(n)}),s.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e);const n=this.graph.iterDependents(e);await Promise.all(Array.from(n).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Cascade failed for "${String(e)}":`,t)})))));const a=this.registry.get(e);!a||!t&&a.lazy&&!this.hasWatchers(e)||r||await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),this.observer.notify(e)}))}async dispose(e){this.cache.get(e)&&(await this.cache.invalidateInstance(e,!0),this.graph.removeNode(e),this.cache.delete(e))}async processStream(e){try{const t=this.graph.iterDependents(e);await Promise.all(Array.from(t).map((e=>this.invalidate(e).catch((t=>{console.error(`[ArtifactManager] Failed to invalidate dependent "${String(e)}":`,t)}))))),this.observer.notify(e)}catch(t){console.error(`[ArtifactManager] Stream propagation error "${e}":`,t)}}updateDependencyGraph(e,t,r){const s=this.cache.get(e);s&&(this.graph.hasNode(e)||this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0&&(s.stateUnsubscribe=this.store.watch(Array.from(r),(async()=>{await this.invalidate(e)}))))}createCachedArtifact(e){const t="transient"===e.scope,r={instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController};return t?{...r,buildOnce:null,streamOnce:null,streamSerializer:null,invalidationSerializer:null}:{...r,buildOnce:new l({retry:!0,throws:!0}),streamOnce:new l({retry:!0,throws:!0}),streamSerializer:new d({yieldMode:"microtask"}),invalidationSerializer:new d({yieldMode:"macrotask"})}}hasWatchers(e){return this.observer.hasWatchers(e)??!1}},y=class{dependencies=new Map;dependents=new Map;metadata=new Map;registerNode(e,t){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set),void 0!==t&&this.metadata.set(e,t)}removeNode(e){if(!this.hasNode(e))return;const t=this.dependencies.get(e);if(t)for(const r of t)this.dependents.get(r)?.delete(e);const r=this.dependents.get(e);if(r)for(const t of r)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e),this.metadata.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){const t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){const t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??m}iterDependencies(e){return this.dependencies.get(e)??m}getMetadata(e){return this.metadata.get(e)}setMetadata(e,t){this.registerNode(e),this.metadata.set(e,t)}setDependencies(e,t){this.registerNode(e);const r=this.dependencies.get(e),s=new Set(t);for(const t of r)s.has(t)||this.removeDependency(e,t);for(const t of s)r.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];const r=[t],s=new Set([t]),i=new Map;for(;r.length>0;){const n=r.shift();if(n===e){const r=[];let s=e;for(;void 0!==s&&(r.push(s),s!==t);)s=i.get(s);return r.reverse(),r.unshift(e),r}const a=this.dependencies.get(n);if(a)for(const e of a)s.has(e)||(s.add(e),i.set(e,n),r.push(e))}return null}topologicalSort(){const e=new Map,t=Array.from(this.dependencies.keys());for(const r of t)e.set(r,this.dependencies.get(r)?.size??0);const r=[];for(const[t,s]of e)0===s&&r.push(t);const s=[];for(;r.length>0;){const t=r.shift();s.push(t);const i=this.dependents.get(t);if(i)for(const t of i){const s=(e.get(t)||0)-1;e.set(t,s),0===s&&r.push(t)}}if(s.length!==t.length)throw new Error("Cycle detected in graph; topological sort impossible.");return s}getTransitiveDependencies(e,t=!1){return this.bfs(e,"dependencies",t)}getTransitiveDependents(e,t=!1){return this.bfs(e,"dependents",t)}bfs(e,t,r){const s=new Set,i=new Set,n=[e];i.add(e),r&&s.add(e);const a="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=a.get(e);if(t)for(const e of t)i.has(e)||(i.add(e),s.add(e),n.push(e))}return s}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear(),this.metadata.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},m=new Set,v=class{graph;constructor(){this.graph=new y}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){const t=this.graph.getDependents(e);return Array.from(t)}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){const t=this.graph.getDependencies(e);return Array.from(t)}getTransitiveDependents(e){const t=this.graph.getTransitiveDependents(e,!1);return new Set(Array.from(t))}setDependencies(e,t){const r=Array.from(t).map((e=>e));this.graph.setDependencies(e,r)}wouldCreateCycle(e,t,r){if(r?.has(t)){const e=Array.from(r),s=e.indexOf(t),i=e.slice(s);return i.push(t),i}const s=this.graph.wouldCreateCycle(e,t);return s||null}hasNode(e){return this.graph.hasNode(e)}getAllNodes(){return this.graph.getAllNodes()}clear(){this.graph.clear()}size(){return this.graph.size()}toDebugString(){return this.graph.toDebugString()}},b=class{cache=new Map;get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t)}delete(e){this.cache.delete(e)}has(e){return this.cache.has(e)}clear(){this.cache.clear()}size(){return this.cache.size}keys(){return Array.from(this.cache.keys())}package(e,t){const r=this.get(e);if(!r)return f;if(r.package)return r.package;const s=String(e);let i=null;const n={instance:r.instance,error:r.error,ready:r.buildOnce?.done(),[e]:r.instance,get cleanup(){return null===i&&(i=p(r.cleanupFunctions,s)??void 0),i},invalidate:t};return r.package=n,n}invalidatePackage(e){const t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(e,t=!1){const r=this.get(e);if(!r)return;r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0);const s=null===r.buildOnce;s||(r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new l({retry:!0,throws:!0}),t||(r.streamSerializer=new d,r.controller=new AbortController)),await g(r.cleanupFunctions,String(e)),await g(r.disposeFunctions,String(e)),r.cleanupFunctions=[],r.disposeFunctions=[],s||(r.buildOnce=new l({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},S=class{constructor(e,t,r){this.registry=e,this.cache=t,this.container=r}listeners=new Map;watcherCache=new Map;watch(e){const t=String(e),r=this.registry.get(e);if(!r)throw new Error(`Artifact "${t}" not registered`);const s="transient"===r.scope?`${t}__watched`:t,i="transient"===r.scope;if(this.watcherCache.has(s))return this.watcherCache.get(s).watcher;const n={count:0,init:new l({retry:!1,throws:!0}),watcher:null},a=()=>n.init.do((async()=>{i&&!this.registry.has(s)&&this.registry.register({key:s,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})}));return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(s,(e=>this.container.invalidate(s,e))):f,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(s))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.count++,this.listeners.has(s)||this.listeners.set(s,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(s))).then((()=>{t&&o(),this.listeners.get(s)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${s}":`,e),this.listeners.get(s)?.add(o)})),()=>{this.listeners.get(s)?.delete(o),n.count--,0===n.count&&(this.listeners.delete(s),i&&(this.registry.unregister(s).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${s}":`,e)})),this.cache.delete(s),this.watcherCache.delete(s)),n.init.reset())}}},this.watcherCache.set(s,n),n.watcher}notify(e){const t=this.listeners.get(e);if(t&&0!==t.size)for(const r of t)try{r()}catch(t){console.error(`[ArtifactObserver] Listener error for "${e}":`,t)}}hasWatchers(e){return!!this.watcherCache.has(e)||this.watcherCache.has(`${e}__watched`)}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(`${e}__watched`);return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}},_=class{registry;cache;graph;manager;observer;store;constructor(e){this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t)},this.registry=new n,this.cache=new b,this.graph=new v,this.observer=new S(this.registry,this.cache,this),this.manager=new w(this.registry,this.cache,this.graph,this.store,this.observer)}debugInfo(){const e=[];return this.registry.keys().forEach((t=>{const r=this.registry.get(t),s=this.cache.get(t);if(!r)return;let i="idle";s&&(void 0!==s.debounceTimer?i="debouncing":s.buildOnce?.running()?i="building":s.error?i="error":void 0!==s.instance&&(i="active")),e.push({id:t,scope:r.scope??"singleton",status:i,dependencies:this.graph.getDependencies(t).map((e=>String(e))),dependents:this.graph.getDependents(t).map((e=>String(e))),stateDependencies:s?Array.from(s.stateDependencies):[],buildCount:s?.buildCount??0})})),e}register(e){const{key:t}=e,r=t;this.registry.has(t)&&(console.warn(`[ArtifactContainer] Overwriting "${r}".`),this.manager.dispose(t).catch((e=>{console.error(`[ArtifactContainer] Failed to dispose existing artifact "${r}":`,e)}))),this.registry.register(e),this.graph.registerNode(t);const s=e.scope??"singleton";return(e.lazy??!0)||"singleton"!==s||this.resolve(t).catch((e=>{console.error(`[ArtifactContainer] Eager load failed for "${r}":`,e)})),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e){await this.manager.dispose(e),await this.registry.unregister(e)}async resolve(e){if(!this.registry.has(e))throw new r(e);const t=await this.manager.build(e);return t[e]=t.instance,t}async require(e){const t=await this.resolve(e);if(t.error)throw t.error;return t.instance}watch(e){if(!this.registry.has(e))throw new r(e);return this.observer.watch(e)}peek(e){const t=this.cache.get(e);if(void 0!==t?.instance)return t?.instance}async invalidate(e,t=!1){return this.manager.invalidate(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){const e=this.registry.keys();await Promise.allSettled(e.map((e=>this.manager.dispose(e).catch((t=>{console.error(`[ArtifactContainer] Failed to dispose artifact "${String(e)}":`,t)}))))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear()}};export{_ as ArtifactContainer,e as ArtifactScopes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-artifacts",
3
- "version": "7.2.0",
3
+ "version": "7.3.0",
4
4
  "description": "Reactive artifact container.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",