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