@asaidimu/utils-artifacts 7.3.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -41,8 +41,8 @@ type StoreEvent = "update:start" | "update:complete" | "middleware:start" | "mid
41
41
  */
42
42
  type StateUpdater<T> = T | DeepPartial<T> | ((state: T) => DeepPartial<T> | Promise<DeepPartial<T>>);
43
43
  /**
44
- * Core types for the reactive data store
45
- */
44
+ * Core types for the reactive data store
45
+ */
46
46
  /**
47
47
  * Type for a Transform Middleware function.
48
48
  * It modifies (transforms) the incoming changes and must return a `DeepPartial<T>`.
@@ -364,17 +364,17 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
364
364
  */
365
365
  onDispose(callback: ArtifactCleanup): void;
366
366
  /**
367
- * Starts a streaming process for a Singleton artifact.
368
- * The callback receives an `ArtifactStreamContext` to emit values and manage the
369
- * stream's lifecycle. It can return a cleanup function (or a Promise resolving
370
- * to one) to handle resource disposal.
371
- * * @param callback - The streaming logic implementation. Can be synchronous or
372
- * asynchronous, optionally returning a cleanup function.
373
- * @throws {SystemError} If called on a Transient artifact, as they do not
374
- * support persistent streaming states.
375
- */
367
+ * Starts a streaming process for a Singleton artifact.
368
+ * The callback receives an `ArtifactStreamContext` to emit values and manage the
369
+ * stream's lifecycle. It can return a cleanup function (or a Promise resolving
370
+ * to one) to handle resource disposal.
371
+ * * @param callback - The streaming logic implementation. Can be synchronous or
372
+ * asynchronous, optionally returning a cleanup function.
373
+ * @throws {SystemError} If called on a Transient artifact, as they do not
374
+ * support persistent streaming states.
375
+ */
376
+ stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => void | Promise<void>)) | Promise<void | (() => void | Promise<void>)>): void;
376
377
  stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => void | Promise<void>)) | Promise<void | (() => void | Promise<void>)>): void;
377
- stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => (void | Promise<void>))) | Promise<(void | (() => (void | Promise<void>)))>): void;
378
378
  /**
379
379
  * An AbortSignal that indicates if the artifacts has been unregistered
380
380
  */
@@ -607,7 +607,7 @@ type InferRegistry<T extends Record<string, {
607
607
  * - ArtifactCache: Stores resolved singleton instances
608
608
  * - ArtifactDependencyGraph: Tracks artifact dependencies using DependencyGraph
609
609
  * - ArtifactManager: Handles lifecycle (build, invalidate, dispose)
610
- * - ArtifactObserver: Manages watchers and subscriptions
610
+ * - ArtifactObserverManager: Manages watchers and subscriptions
611
611
  *
612
612
  * @template TRegistry A type that maps artifact keys to their types
613
613
  * @template TState The type of the global state object
@@ -647,8 +647,8 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
647
647
  */
648
648
  register<K extends keyof TRegistry>(params: ArtifactTemplate<TState, TRegistry[K], TRegistry>): () => void;
649
649
  /**
650
- * Returns a boolean indicating whether a template exists for an artifact
651
- * @template K The key of the artifact to unregister.
650
+ * Returns a boolean indicating whether a template exists for an artifact.
651
+ *
652
652
  * @param key The unique identifier of the artifact.
653
653
  * @returns boolean.
654
654
  */
@@ -657,45 +657,49 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
657
657
  * Unregisters an artifact from the container, disposing of its current instance
658
658
  * and removing all associated resources and dependency links.
659
659
  *
660
+ * Also evicts the observer watcher cache entry so singleton watchers do not
661
+ * outlive the artifact's registration.
662
+ *
660
663
  * @param key The unique identifier of the artifact
661
664
  */
662
665
  unregister<K extends keyof TRegistry>(key: K): Promise<void>;
663
666
  /**
664
667
  * Resolves an artifact by its key, returning its instance or an error.
665
- * This method handles dependency resolution, cycle detection (via graph),
666
- * caching, and retry logic. Traverses the container hierarchy if the artifact
667
- * is not found locally.
668
+ * Handles dependency resolution, cycle detection, caching, and retry logic.
669
+ *
670
+ * The keyed index property (`artifact[key]`) is set inside `cache.package()`
671
+ * so it is always consistent with `artifact.instance`. No post-hoc mutation
672
+ * is needed here.
668
673
  *
669
674
  * @param key The unique identifier for the artifact
670
675
  * @returns A Promise that resolves to a ResolvedArtifact
671
676
  * @throws {ArtifactNotFoundError} if the artifact is not found
672
- * @throws {ArtifactError} if a cycle is detected or other system errors occur
673
677
  */
674
678
  resolve<K extends keyof TRegistry>(key: K): Promise<KeyedResolvedArtifact<TRegistry, K>>;
675
679
  /**
676
680
  * Resolves an artifact by its key, returning its instance directly.
677
- * This is a wrapper around resolve to prevent defensive programming
681
+ * Throws if resolution fails.
678
682
  *
679
683
  * @param key The unique identifier for the artifact
680
- * @returns A Promise that resolves to a ResolvedArtifact
684
+ * @returns A Promise that resolves to the artifact instance
681
685
  * @throws {ArtifactNotFoundError} if the artifact is not found
682
- * @throws {ArtifactError} if a cycle is detected or other system errors occur
686
+ * @throws the artifact's error if resolution failed
683
687
  */
684
688
  require<K extends keyof TRegistry>(key: K): Promise<TRegistry[K]>;
685
689
  /**
686
- * Returns an ArtifactWatcher for a given artifact key.
687
- * The watcher allows subscribing to changes in the artifact's resolved value.
690
+ * Returns an ArtifactObserver for a given artifact key.
691
+ * The observer allows subscribing to changes in the artifact's resolved value.
688
692
  *
689
693
  * @param key The unique identifier for the artifact
690
- * @returns An ArtifactWatcher instance
694
+ * @returns An ArtifactObserver instance
691
695
  */
692
696
  watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry, K>;
693
697
  /**
694
- * Peeks at the resolved instance of an artifact without triggering its resolution
695
- * if it's lazy, or registering a dependency.
698
+ * Peeks at the resolved instance of an artifact without triggering resolution
699
+ * or registering a dependency.
696
700
  *
697
701
  * @param key The unique identifier for the artifact
698
- * @returns The artifact instance if it's already built, otherwise undefined
702
+ * @returns The artifact instance if already built, otherwise undefined
699
703
  */
700
704
  peek<K extends keyof TRegistry>(key: K): TRegistry[K] | undefined;
701
705
  /**
@@ -721,14 +725,11 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
721
725
  */
722
726
  hasWatchers(key: string): boolean;
723
727
  /**
724
- * Disposes of the entire ArtifactContainer and all artifacts registered within it.
725
- * This releases all resources, stops all watchers, and clears all internal state.
726
- * After disposal, the container should no longer be used.
728
+ * Disposes of the entire container and all artifacts registered within it.
729
+ * Releases all resources, stops all watchers, and clears all internal state.
727
730
  *
728
731
  * Returns a Promise that resolves once all artifact teardowns have settled.
729
- * Previously this was synchronous (fire-and-forget), which meant the container
730
- * could be garbage-collected before async cleanup completed. Callers should
731
- * await this method to guarantee full resource release.
732
+ * Callers should await this method to guarantee full resource release.
732
733
  */
733
734
  dispose(): Promise<void>;
734
735
  }
package/index.d.ts CHANGED
@@ -41,8 +41,8 @@ type StoreEvent = "update:start" | "update:complete" | "middleware:start" | "mid
41
41
  */
42
42
  type StateUpdater<T> = T | DeepPartial<T> | ((state: T) => DeepPartial<T> | Promise<DeepPartial<T>>);
43
43
  /**
44
- * Core types for the reactive data store
45
- */
44
+ * Core types for the reactive data store
45
+ */
46
46
  /**
47
47
  * Type for a Transform Middleware function.
48
48
  * It modifies (transforms) the incoming changes and must return a `DeepPartial<T>`.
@@ -364,17 +364,17 @@ interface ArtifactFactoryContext<TRegistry extends Record<string, any>, TState e
364
364
  */
365
365
  onDispose(callback: ArtifactCleanup): void;
366
366
  /**
367
- * Starts a streaming process for a Singleton artifact.
368
- * The callback receives an `ArtifactStreamContext` to emit values and manage the
369
- * stream's lifecycle. It can return a cleanup function (or a Promise resolving
370
- * to one) to handle resource disposal.
371
- * * @param callback - The streaming logic implementation. Can be synchronous or
372
- * asynchronous, optionally returning a cleanup function.
373
- * @throws {SystemError} If called on a Transient artifact, as they do not
374
- * support persistent streaming states.
375
- */
367
+ * Starts a streaming process for a Singleton artifact.
368
+ * The callback receives an `ArtifactStreamContext` to emit values and manage the
369
+ * stream's lifecycle. It can return a cleanup function (or a Promise resolving
370
+ * to one) to handle resource disposal.
371
+ * * @param callback - The streaming logic implementation. Can be synchronous or
372
+ * asynchronous, optionally returning a cleanup function.
373
+ * @throws {SystemError} If called on a Transient artifact, as they do not
374
+ * support persistent streaming states.
375
+ */
376
+ stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => void | Promise<void>)) | Promise<void | (() => void | Promise<void>)>): void;
376
377
  stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => void | Promise<void>)) | Promise<void | (() => void | Promise<void>)>): void;
377
- stream(callback: (ctx: ArtifactStreamContext<TState, TArtifact>) => (void | (() => (void | Promise<void>))) | Promise<(void | (() => (void | Promise<void>)))>): void;
378
378
  /**
379
379
  * An AbortSignal that indicates if the artifacts has been unregistered
380
380
  */
@@ -607,7 +607,7 @@ type InferRegistry<T extends Record<string, {
607
607
  * - ArtifactCache: Stores resolved singleton instances
608
608
  * - ArtifactDependencyGraph: Tracks artifact dependencies using DependencyGraph
609
609
  * - ArtifactManager: Handles lifecycle (build, invalidate, dispose)
610
- * - ArtifactObserver: Manages watchers and subscriptions
610
+ * - ArtifactObserverManager: Manages watchers and subscriptions
611
611
  *
612
612
  * @template TRegistry A type that maps artifact keys to their types
613
613
  * @template TState The type of the global state object
@@ -647,8 +647,8 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
647
647
  */
648
648
  register<K extends keyof TRegistry>(params: ArtifactTemplate<TState, TRegistry[K], TRegistry>): () => void;
649
649
  /**
650
- * Returns a boolean indicating whether a template exists for an artifact
651
- * @template K The key of the artifact to unregister.
650
+ * Returns a boolean indicating whether a template exists for an artifact.
651
+ *
652
652
  * @param key The unique identifier of the artifact.
653
653
  * @returns boolean.
654
654
  */
@@ -657,45 +657,49 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
657
657
  * Unregisters an artifact from the container, disposing of its current instance
658
658
  * and removing all associated resources and dependency links.
659
659
  *
660
+ * Also evicts the observer watcher cache entry so singleton watchers do not
661
+ * outlive the artifact's registration.
662
+ *
660
663
  * @param key The unique identifier of the artifact
661
664
  */
662
665
  unregister<K extends keyof TRegistry>(key: K): Promise<void>;
663
666
  /**
664
667
  * Resolves an artifact by its key, returning its instance or an error.
665
- * This method handles dependency resolution, cycle detection (via graph),
666
- * caching, and retry logic. Traverses the container hierarchy if the artifact
667
- * is not found locally.
668
+ * Handles dependency resolution, cycle detection, caching, and retry logic.
669
+ *
670
+ * The keyed index property (`artifact[key]`) is set inside `cache.package()`
671
+ * so it is always consistent with `artifact.instance`. No post-hoc mutation
672
+ * is needed here.
668
673
  *
669
674
  * @param key The unique identifier for the artifact
670
675
  * @returns A Promise that resolves to a ResolvedArtifact
671
676
  * @throws {ArtifactNotFoundError} if the artifact is not found
672
- * @throws {ArtifactError} if a cycle is detected or other system errors occur
673
677
  */
674
678
  resolve<K extends keyof TRegistry>(key: K): Promise<KeyedResolvedArtifact<TRegistry, K>>;
675
679
  /**
676
680
  * Resolves an artifact by its key, returning its instance directly.
677
- * This is a wrapper around resolve to prevent defensive programming
681
+ * Throws if resolution fails.
678
682
  *
679
683
  * @param key The unique identifier for the artifact
680
- * @returns A Promise that resolves to a ResolvedArtifact
684
+ * @returns A Promise that resolves to the artifact instance
681
685
  * @throws {ArtifactNotFoundError} if the artifact is not found
682
- * @throws {ArtifactError} if a cycle is detected or other system errors occur
686
+ * @throws the artifact's error if resolution failed
683
687
  */
684
688
  require<K extends keyof TRegistry>(key: K): Promise<TRegistry[K]>;
685
689
  /**
686
- * Returns an ArtifactWatcher for a given artifact key.
687
- * The watcher allows subscribing to changes in the artifact's resolved value.
690
+ * Returns an ArtifactObserver for a given artifact key.
691
+ * The observer allows subscribing to changes in the artifact's resolved value.
688
692
  *
689
693
  * @param key The unique identifier for the artifact
690
- * @returns An ArtifactWatcher instance
694
+ * @returns An ArtifactObserver instance
691
695
  */
692
696
  watch<K extends keyof TRegistry>(key: K): ArtifactObserver<TRegistry, K>;
693
697
  /**
694
- * Peeks at the resolved instance of an artifact without triggering its resolution
695
- * if it's lazy, or registering a dependency.
698
+ * Peeks at the resolved instance of an artifact without triggering resolution
699
+ * or registering a dependency.
696
700
  *
697
701
  * @param key The unique identifier for the artifact
698
- * @returns The artifact instance if it's already built, otherwise undefined
702
+ * @returns The artifact instance if already built, otherwise undefined
699
703
  */
700
704
  peek<K extends keyof TRegistry>(key: K): TRegistry[K] | undefined;
701
705
  /**
@@ -721,14 +725,11 @@ declare class ArtifactContainer<TRegistry extends Record<string, any> = Record<s
721
725
  */
722
726
  hasWatchers(key: string): boolean;
723
727
  /**
724
- * Disposes of the entire ArtifactContainer and all artifacts registered within it.
725
- * This releases all resources, stops all watchers, and clears all internal state.
726
- * After disposal, the container should no longer be used.
728
+ * Disposes of the entire container and all artifacts registered within it.
729
+ * Releases all resources, stops all watchers, and clears all internal state.
727
730
  *
728
731
  * Returns a Promise that resolves once all artifact teardowns have settled.
729
- * Previously this was synchronous (fire-and-forget), which meant the container
730
- * could be garbage-collected before async cleanup completed. Callers should
731
- * await this method to guarantee full resource release.
732
+ * Callers should await this method to guarantee full resource release.
732
733
  */
733
734
  dispose(): Promise<void>;
734
735
  }
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(),[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;
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,...o}=i,a={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...o};return this.artifacts.set(e,a),()=>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()}},o=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},a=class extends o{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends o{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 a("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}},d=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 a(r))),t)}))])}},l=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)}}function f(e){return`${e}__watched`}var w=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function y(e,t){let r;const s=new Promise(((e,s)=>{r=setTimeout((()=>s(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,s])}finally{clearTimeout(r)}}var m=(new AbortController).signal,v=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("singleton"===s?.scope&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),o=r??[];if(o.includes(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...o,e].join(" -> ")}`,"system");o.push(e);let a=s;a||(a=this.createCachedArtifact(n),this.cache.set(e,a));try{if("transient"===a.scope)return this.executeBuild(n,a,o);const t=a;try{await t.buildOnce.do((()=>this.executeBuild(n,t,o)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return t.stream&&t.streamOnce.do(t.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}finally{o.pop()}}async executeBuild(e,t,r){const s=e.key,i=String(s),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const o={cleanupFunctions:[],disposeFunctions:[],capturedStateDeps:new Set,capturedArtifactDeps:new Set,dependencyVersions:new Map},a=this.buildContext(e,t,r,i,o),c=await this.runWithRetries(e,a,o.dependencyVersions);if(this.commitResult(s,t,n,c,o),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[s]:e,cleanup:p(o.cleanupFunctions,i),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${i}"`)}}}buildContext(e,r,s,i,n){const o=e.key,a="transient"===r.scope,{cleanupFunctions:c,disposeFunctions:h,capturedStateDeps:d,capturedArtifactDeps:l,dependencyVersions:p}=n,g=async e=>{if(e===o)throw new t(`Artifact "${i}" depends on itself.`,"system");const r=this.graph.wouldCreateCycle(o,e);if(r)throw new t(`Adding dependency "${String(e)}" to "${i}" would create a cycle: ${r.join(" -> ")}`,"system");l.add(e);const n=await this.build(e,s),a=this.cache.get(e);return a&&p.set(e,a.version),n},f="singleton"===r.scope?r.controller.signal:m,w=async e=>{const t=await g(e);if(t.error)throw t.error;return t.instance},y=e=>(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, arithmetic, or string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const o=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(o),i(o)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e).forEach((e=>d.add(e))),e(this.store.get(!0)));return{state:()=>this.store.get(!0),previous:r.instance,signal:f,onCleanup:e=>c.push(e),onDispose:e=>h.push(e),use:e=>e({resolve:g,require:w,select:y}),stream:e=>{if(a)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=r,n=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(o),await this.processStream(i))}))},c={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>n(e)};s.stream=async()=>{try{const t=await e(c);t&&s.cleanupFunctions.push(t)}catch(e){await n(void 0,e),await this.invalidate(o,!1,!0)}}}}}async runWithRetries(e,r,s){const n=r.signal,o=(e.retries??0)+1;let a=0;for(;a<o;)try{if(n.aborted)throw new i;const c=e.factory(r);let h;if(h=c instanceof Promise?e.timeout?await y(c,e.timeout):await c:c,n.aborted)throw new i;const d=this.detectStaleness(s);if(d){if(a++,s.clear(),a<o)continue;return{ok:!1,error:new t(`Build stale after all retries: dependency "${String(d)}" changed during build.`,"system")}}return{ok:!0,value:h}}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;if(a++,a>=o)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,r,s,i){const{cleanupFunctions:n,disposeFunctions:o,capturedArtifactDeps:a,capturedStateDeps:c}=i;r||(this.updateDependencyGraph(e,a,c),t.cleanupFunctions=n,t.disposeFunctions=o),s.ok?(t.instance=s.value,t.error=void 0):(t.instance=void 0,t.error=s.error),t.version++,this.cache.invalidatePackage(e)}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;if("singleton"!==s.scope)return this.executeInvalidation(e,t,r);const i=s;return i.debounceTimer&&(clearTimeout(i.debounceTimer),i.debounceTimer=void 0),!t&&i.activeDebounceMs>0?new Promise(((s,n)=>{i.debounceTimer=setTimeout((()=>{i.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(s).catch(n)}),i.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&"singleton"===s.scope&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const n=this.registry.get(e),o=n&&(t||!n.lazy||this.observer.hasWatchers(e))&&!r;o&&await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(o||r)&&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){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const r of e)t.push(this.invalidate(r).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(r)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,r){const s=this.cache.get(e);if(s&&"singleton"===s.scope&&(this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0)){const t=Array.from(r),i=()=>this.invalidate(e);s.stateUnsubscribe=this.store.watch(t,i)}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController,buildOnce:new d({retry:!0,throws:!0}),streamOnce:new d({retry:!0,throws:!0}),streamSerializer:new l({yieldMode:"microtask"}),invalidationSerializer:new l({yieldMode:"macrotask"})}}},b=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}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)}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)??k}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 o=this.dependencies.get(n);if(o)for(const e of o)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 o="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=o.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()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},k=new Set,_=class{graph;constructor(){this.graph=new b}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}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()}},S=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 w;if(r.package)return r.package;const s=e,i=p(r.cleanupFunctions,s),n="singleton"!==r.scope||r.buildOnce.done(),o={instance:r.instance,error:r.error,ready:n,[e]:r.instance,cleanup:i,invalidate:t};return r.package=o,o}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;const s=e;"singleton"===r.scope&&(r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new d({retry:!0,throws:!0}),t||(r.streamSerializer=new l,r.controller=new AbortController)),await g(r.cleanupFunctions,s),await g(r.disposeFunctions,s),r.cleanupFunctions=[],r.disposeFunctions=[],"singleton"===r.scope&&(r.buildOnce=new d({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},C=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,i=s?f(t):t;if(this.watcherCache.has(i))return this.watcherCache.get(i).watcher;const n={count:0,init:new d({retry:!1,throws:!0}),watcher:null,pendingReset:!1},o=async()=>{s&&!this.registry.has(i)&&this.registry.register({key:i,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})},a=()=>n.init.do(o);return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(i,(e=>this.container.invalidate(i,e))):w,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(i))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.pendingReset=!1,n.count++,this.listeners.has(i)||this.listeners.set(i,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(i))).then((()=>{t&&o(),this.listeners.get(i)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${i}":`,e),this.listeners.get(i)?.add(o)})),()=>{if(this.listeners.get(i)?.delete(o),n.count--,0===n.count){if(this.listeners.delete(i),s)return this.registry.unregister(i).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${i}":`,e)})),this.cache.delete(i),void this.watcherCache.delete(i);n.pendingReset=!0,queueMicrotask((()=>{n.pendingReset&&(n.pendingReset=!1,this.cache.invalidatePackage(i),n.init.running()||n.init.reset())}))}}}},this.watcherCache.set(i,n),n.watcher}evictWatcher(e){this.watcherCache.has(e)&&(this.watcherCache.delete(e),this.listeners.delete(e));const t=f(e);this.watcherCache.has(t)&&(this.watcherCache.delete(t),this.listeners.delete(t))}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(f(e))}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(f(e));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 S,this.graph=new _,this.observer=new C(this.registry,this.cache,this),this.manager=new v(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&&("singleton"===s.scope&&void 0!==s.debounceTimer?i="debouncing":"singleton"===s.scope&&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:"singleton"===s?.scope?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),this.observer.evictWatcher(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){return this.cache.get(e)?.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(),[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};
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,...o}=i,a={key:e,factory:t,scope:i.scope??"singleton",lazy:void 0===r||r,...o};return this.artifacts.set(e,a),()=>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()}},o=class e extends Error{constructor(t,r){super(t,{cause:r}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},a=class extends o{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},c=class extends o{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 a("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}},d=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 a(r))),t)}))])}},l=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)}}function f(e){return`${e}__watched`}var w=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function y(e,t){let r;const s=new Promise(((e,s)=>{r=setTimeout((()=>s(new Error(`Timeout: ${t}ms`))),t)}));try{return Promise.race([e,s])}finally{clearTimeout(r)}}var m=(new AbortController).signal,v=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("singleton"===s?.scope&&s.buildOnce.done())return this.cache.package(e,((t,r)=>this.invalidate(e,t,r)));const n=this.registry.get(e),o=r??[];if(o.includes(e))throw new t(`Cycle detected: Artifact "${String(e)}" depends on itself via path: ${[...o,e].join(" -> ")}`,"system");o.push(e);let a=s;a||(a=this.createCachedArtifact(n),this.cache.set(e,a));try{if("transient"===a.scope)return this.executeBuild(n,a,o);const t=a;try{await t.buildOnce.do((()=>this.executeBuild(n,t,o)))}catch(t){if(t instanceof i)return this.build(e,r);throw t}return t.stream&&t.streamOnce.do(t.stream),this.cache.package(e,((t,r)=>this.invalidate(e,t,r)))}finally{o.pop()}}async executeBuild(e,t,r){const s=e.key,i=String(s),n="transient"===t.scope;t.buildCount++,"singleton"===t.scope&&(t.activeDebounceMs=e.debounce??0);const o={cleanupFunctions:[],disposeFunctions:[],capturedStateDeps:new Set,capturedArtifactDeps:new Set,dependencyVersions:new Map},a=this.buildContext(e,t,r,i,o),c=await this.runWithRetries(e,a,o.dependencyVersions);if(this.commitResult(s,t,n,c,o),n){const e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[s]:e,cleanup:p(o.cleanupFunctions,i),invalidate:async()=>console.warn(`[ArtifactManager] Cannot invalidate transient "${i}"`)}}}buildContext(e,r,s,i,n){const o=e.key,a="transient"===r.scope,{cleanupFunctions:c,disposeFunctions:h,capturedStateDeps:d,capturedArtifactDeps:l,dependencyVersions:p}=n,g=async e=>{if(e===o)throw new t(`Artifact "${i}" depends on itself.`,"system");const r=this.graph.wouldCreateCycle(o,e);if(r)throw new t(`Adding dependency "${String(e)}" to "${i}" would create a cycle: ${r.join(" -> ")}`,"system");l.add(e);const n=await this.build(e,s),a=this.cache.get(e);return a&&p.set(e,a.version),n},f="singleton"===r.scope?r.controller.signal:m,w=async e=>{const t=await g(e);if(t.error)throw t.error;return t.instance},y=e=>(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, arithmetic, or string operations inside a selector.");if(u.includes(n))throw new Error(`Array method .${n}() is not allowed in selectors.`);const o=e?`${e}${t}${n}`:n;return e&&r.delete(e),r.add(o),i(o)},has:()=>{throw new Error("The 'in' operator is not allowed in selectors.")},apply:()=>{throw new Error("Selectors cannot call functions or methods.")}});return s.set(e,n),n};try{e(i())}catch(e){throw new Error(`Selector failed during path analysis. Selectors must be simple property accessors only. Error: ${e instanceof Error?e.message:String(e)}`)}return Array.from(r)}(e).forEach((e=>d.add(e))),e(this.store.get(!0)));return{state:()=>this.store.get(!0),previous:r.instance,signal:f,onCleanup:e=>c.push(e),onDispose:e=>h.push(e),use:e=>e({resolve:g,require:w,select:y}),stream:e=>{if(a)throw new t(`[ArtifactManager] Illegal stream on transient artifact "${i}"`,"system");const s=r,n=async(e,t=void 0)=>{await s.streamSerializer.do((async()=>{void 0!==s.stream&&(s.instance=e,s.error=t,s.version++,this.cache.invalidatePackage(o),await this.processStream(i))}))},c={value:()=>s.instance,get signal(){return s.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>n(e)};s.stream=async()=>{try{const t=await e(c);t&&s.cleanupFunctions.push(t)}catch(e){await n(void 0,e),await this.invalidate(o,!1,!0)}}}}}async runWithRetries(e,r,s){const n=r.signal,o=(e.retries??0)+1;let a=0;for(;a<o;)try{if(n.aborted)throw new i;const c=e.factory(r);let h;if(h=c instanceof Promise?e.timeout?await y(c,e.timeout):await c:c,n.aborted)throw new i;const d=this.detectStaleness(s);if(d){if(a++,s.clear(),a<o)continue;return{ok:!1,error:new t(`Build stale after all retries: dependency "${String(d)}" changed during build.`,"system")}}return{ok:!0,value:h}}catch(e){if(n.aborted||e instanceof i)throw new i;if(e instanceof t)throw e;if(a++,a>=o)return{ok:!1,error:e}}return{ok:!1,error:new Error("Build exhausted retry budget unexpectedly.")}}commitResult(e,t,r,s,i){const{cleanupFunctions:n,disposeFunctions:o,capturedArtifactDeps:a,capturedStateDeps:c}=i;r||(this.updateDependencyGraph(e,a,c),t.cleanupFunctions=n,t.disposeFunctions=o),s.ok?(t.instance=s.value,t.error=void 0):(t.instance=void 0,t.error=s.error),t.version++,this.cache.invalidatePackage(e)}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;if("singleton"!==s.scope)return this.executeInvalidation(e,t,r);const i=s;return i.debounceTimer&&(clearTimeout(i.debounceTimer),i.debounceTimer=void 0),!t&&i.activeDebounceMs>0?new Promise(((s,n)=>{i.debounceTimer=setTimeout((()=>{i.debounceTimer=void 0,this.executeInvalidation(e,t,r).then(s).catch(n)}),i.activeDebounceMs)})):this.executeInvalidation(e,t,r)}async executeInvalidation(e,t,r=!1){const s=this.cache.get(e);s&&"singleton"===s.scope&&await s.invalidationSerializer.do((async()=>{s.version++,await this.cache.invalidateInstance(e),await this.cascadeInvalidation(this.graph.iterDependents(e));const n=this.registry.get(e),o=n&&(t||!n.lazy||this.observer.hasWatchers(e))&&!r;o&&await this.build(e).catch((t=>{t instanceof i||console.error(`[ArtifactManager] Rebuild failed for "${String(e)}":`,t)})),(o||r)&&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){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(0===e.size)return;const t=[];for(const r of e)t.push(this.invalidate(r).catch((e=>{console.error(`[ArtifactManager] Cascade failed for "${String(r)}":`,e)})));await Promise.all(t)}updateDependencyGraph(e,t,r){const s=this.cache.get(e);if(s&&"singleton"===s.scope&&(this.graph.registerNode(e),this.graph.setDependencies(e,t),s.stateUnsubscribe&&(s.stateUnsubscribe(),s.stateUnsubscribe=void 0),s.stateDependencies=r,r.size>0)){const t=Array.from(r),i=()=>this.invalidate(e);s.stateUnsubscribe=this.store.watch(t,i)}}createCachedArtifact(e){return"transient"===e.scope?{scope:"transient",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:"singleton",instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:e.debounce??0,controller:new AbortController,buildOnce:new d({retry:!0,throws:!0}),streamOnce:new d({retry:!0,throws:!0}),streamSerializer:new l({yieldMode:"microtask"}),invalidationSerializer:new l({yieldMode:"macrotask"})}}},b=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}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)}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)??k}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 o=this.dependencies.get(n);if(o)for(const e of o)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 o="dependencies"===t?this.dependencies:this.dependents;for(;n.length>0;){const e=n.shift(),t=o.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()}toDebugString(){return Array.from(this.dependencies.entries()).map((([e,t])=>{const r=Array.from(t).join(", ");return`${String(e)} → [${r||"∅"}]`})).join("\n")}},k=new Set,_=class{graph;constructor(){this.graph=new b}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){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}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()}},S=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 w;if(r.package)return r.package;const s=e,i=p(r.cleanupFunctions,s),n="singleton"!==r.scope||r.buildOnce.done(),o={instance:r.instance,error:r.error,ready:n,[e]:r.instance,cleanup:i,invalidate:t};return r.package=o,o}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;const s=e;"singleton"===r.scope&&(r.stateUnsubscribe&&(r.stateUnsubscribe(),r.stateUnsubscribe=void 0),r.debounceTimer&&(clearTimeout(r.debounceTimer),r.debounceTimer=void 0),r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new d({retry:!0,throws:!0}),t||(r.streamSerializer=new l,r.controller=new AbortController)),await g(r.cleanupFunctions,s),await g(r.disposeFunctions,s),r.cleanupFunctions=[],r.disposeFunctions=[],"singleton"===r.scope&&(r.buildOnce=new d({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},C=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,i=s?f(t):t;if(this.watcherCache.has(i))return this.watcherCache.get(i).watcher;const n={count:0,init:new d({retry:!1,throws:!0}),watcher:null,pendingReset:!1},o=async()=>{s&&!this.registry.has(i)&&this.registry.register({key:i,factory:r.factory,scope:"singleton",lazy:r.lazy,timeout:r.timeout,retries:r.retries,debounce:r.debounce})},a=()=>n.init.do(o);return n.watcher={id:t,get count(){return n.count},get:(e=!1)=>0!==n.count||e?this.cache.package(i,(e=>this.container.invalidate(i,e))):w,resolve:()=>(n.resolve||(n.resolve=a().then((()=>this.container.resolve(i))).finally((()=>{n.resolve=void 0}))),n.resolve),subscribe:(e,t=!0)=>{const r=a();n.pendingReset=!1,n.count++,this.listeners.has(i)||this.listeners.set(i,new Set);const o=()=>e(n.watcher.get());return r.then((()=>this.container.resolve(i))).then((()=>{t&&o(),this.listeners.get(i)?.add(o)})).catch((e=>{console.error(`[ArtifactObserver] Background resolution failed for "${i}":`,e),this.listeners.get(i)?.add(o)})),()=>{if(this.listeners.get(i)?.delete(o),n.count--,0===n.count){if(this.listeners.delete(i),s)return this.registry.unregister(i).catch((e=>{console.error(`[ArtifactObserver] Cleanup failed for "${i}":`,e)})),this.cache.delete(i),void this.watcherCache.delete(i);n.pendingReset=!0,queueMicrotask((()=>{n.pendingReset&&(n.pendingReset=!1,this.cache.invalidatePackage(i),n.init.running()||n.init.reset())}))}}}},this.watcherCache.set(i,n),n.watcher}evictWatcher(e){this.watcherCache.has(e)&&(this.watcherCache.delete(e),this.listeners.delete(e));const t=f(e);this.watcherCache.has(t)&&(this.watcherCache.delete(t),this.listeners.delete(t))}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(f(e))}getWatcherCount(e){const t=this.watcherCache.get(e)||this.watcherCache.get(f(e));return t?.count??0}clear(){this.watcherCache.clear(),this.listeners.clear()}},A=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 S,this.graph=new _,this.observer=new C(this.registry,this.cache,this),this.manager=new v(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&&("singleton"===s.scope&&void 0!==s.debounceTimer?i="debouncing":"singleton"===s.scope&&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:"singleton"===s?.scope?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),this.observer.evictWatcher(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){return this.cache.get(e)?.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{A as ArtifactContainer,e as ArtifactScopes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-artifacts",
3
- "version": "7.3.0",
3
+ "version": "8.1.0",
4
4
  "description": "Reactive artifact container.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",