@asaidimu/utils-artifacts 8.2.13 → 8.2.15

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.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import { DataStore, StateUpdater, SubscribeOptions } from "@asaidimu/utils-store";
1
2
  import { Issue, Severity, SystemError, SystemError as SystemError$1 } from "@asaidimu/utils-error";
3
+ import { EventBus } from "@asaidimu/utils-events";
2
4
  import { SystemLogger } from "@asaidimu/utils-logger";
3
- import { DataStore, StateUpdater, SubscribeOptions } from "@asaidimu/utils-store/types";
4
- import { EventBus } from "@asaidimu/utils-events/types";
5
5
 
6
6
  //#region src/artifacts/types.d.ts
7
7
  /**
package/index.js CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@asaidimu/utils-sync"),t=require("@asaidimu/utils-store/selector"),n=require("@asaidimu/utils-error"),r=require("@asaidimu/utils-events"),i=require("@asaidimu/utils-logger");function a(e,t){if(!e.length)return;let n=e.slice(),r=t?`[${t}]`:`[ArtifactCleanup]`;return async()=>{for(let e=n.length-1;e>=0;e--)try{await n[e]()}catch(t){console.error(`${r} Cleanup error at index ${e}:`,t)}}}async function o(e,t){let n=t?`[${t}]`:`[ArtifactCleanup]`;for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${n} Cleanup error at index ${t}:`,e)}}function s(e){return`${e}__watched`}const c=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function l(e,t){let n,r=new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Timeout: ${t}ms`)),t)});try{return Promise.race([e,r])}finally{clearTimeout(n)}}async function u(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}var d=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,n){let r=this.get(e);if(!r)return c;if(r.package)return r.package;let i=e,o=a(r.cleanupFunctions,i),s=r.scope===`singleton`?r.instance!==void 0:!0,l={instance:r.instance,error:r.error,ready:s,[n||e]:r.instance,cleanup:o,invalidate:t};return r.package=l,l}invalidatePackage(e){let t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(t,n=!1){let r=this.get(t);if(!r)return;let i=t;r.scope===`singleton`&&(r.stateUnsubscribe&&=(r.stateUnsubscribe(),void 0),r.debounceTimer&&=(clearTimeout(r.debounceTimer),void 0),r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new e.Once({retry:!0,throws:!0}),n||(r.streamSerializer=new e.Serializer,r.controller=new AbortController)),await o(r.cleanupFunctions,i),await o(r.disposeFunctions,i),r.cleanupFunctions=[],r.disposeFunctions=[],r.scope===`singleton`&&(r.buildOnce=new e.Once({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},f=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;let t=this.dependencies.get(e);if(t)for(let n of t)this.dependents.get(n)?.delete(e);let n=this.dependents.get(e);if(n)for(let t of n)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){let t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){let t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??p}setDependencies(e,t){this.registerNode(e);let n=this.dependencies.get(e),r=new Set(t);for(let t of n)r.has(t)||this.removeDependency(e,t);for(let t of r)n.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];let n=[t],r=new Set([t]),i=new Map;for(;n.length>0;){let a=n.shift();if(a===e){let n=[],r=e;for(;r!==void 0&&(n.push(r),r!==t);)r=i.get(r);return n.reverse(),n.unshift(e),n}let o=this.dependencies.get(a);if(o)for(let e of o)r.has(e)||(r.add(e),i.set(e,a),n.push(e))}return null}topologicalSort(){let e=new Map,t=Array.from(this.dependencies.keys());for(let n of t)e.set(n,this.dependencies.get(n)?.size??0);let n=[];for(let[t,r]of e)r===0&&n.push(t);let r=[];for(;n.length>0;){let t=n.shift();r.push(t);let i=this.dependents.get(t);if(i)for(let t of i){let r=(e.get(t)||0)-1;e.set(t,r),r===0&&n.push(t)}}if(r.length!==t.length)throw Error(`Cycle detected in graph; topological sort impossible.`);return r}getTransitiveDependencies(e,t=!1){return this.bfs(e,`dependencies`,t)}getTransitiveDependents(e,t=!1){return this.bfs(e,`dependents`,t)}bfs(e,t,n){let r=new Set,i=new Set,a=[e];i.add(e),n&&r.add(e);let o=t===`dependencies`?this.dependencies:this.dependents;for(;a.length>0;){let e=a.shift(),t=o.get(e);if(t)for(let e of t)i.has(e)||(i.add(e),r.add(e),a.push(e))}return r}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map(([e,t])=>{let n=Array.from(t).join(`, `);return`${String(e)} → [${n||`∅`}]`}).join(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@asaidimu/utils-sync"),t=require("@asaidimu/utils-store"),n=require("@asaidimu/utils-error"),r=require("@asaidimu/utils-events"),i=require("@asaidimu/utils-logger");function a(e,t){if(!e.length)return;let n=e.slice(),r=t?`[${t}]`:`[ArtifactCleanup]`;return async()=>{for(let e=n.length-1;e>=0;e--)try{await n[e]()}catch(t){console.error(`${r} Cleanup error at index ${e}:`,t)}}}async function o(e,t){let n=t?`[${t}]`:`[ArtifactCleanup]`;for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${n} Cleanup error at index ${t}:`,e)}}function s(e){return`${e}__watched`}const c=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function l(e,t){let n,r=new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Timeout: ${t}ms`)),t)});try{return Promise.race([e,r])}finally{clearTimeout(n)}}async function u(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}var d=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,n){let r=this.get(e);if(!r)return c;if(r.package)return r.package;let i=e,o=a(r.cleanupFunctions,i),s=r.scope===`singleton`?r.instance!==void 0:!0,l={instance:r.instance,error:r.error,ready:s,[n||e]:r.instance,cleanup:o,invalidate:t};return r.package=l,l}invalidatePackage(e){let t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(t,n=!1){let r=this.get(t);if(!r)return;let i=t;r.scope===`singleton`&&(r.stateUnsubscribe&&=(r.stateUnsubscribe(),void 0),r.debounceTimer&&=(clearTimeout(r.debounceTimer),void 0),r.controller.abort(),await r.streamOnce.current(),r.streamSerializer.close(),r.stream=void 0,r.streamOnce=new e.Once({retry:!0,throws:!0}),n||(r.streamSerializer=new e.Serializer,r.controller=new AbortController)),await o(r.cleanupFunctions,i),await o(r.disposeFunctions,i),r.cleanupFunctions=[],r.disposeFunctions=[],r.scope===`singleton`&&(r.buildOnce=new e.Once({retry:!0,throws:!0})),r.instance=void 0,r.error=void 0}},f=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;let t=this.dependencies.get(e);if(t)for(let n of t)this.dependents.get(n)?.delete(e);let n=this.dependents.get(e);if(n)for(let t of n)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){let t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){let t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??p}setDependencies(e,t){this.registerNode(e);let n=this.dependencies.get(e),r=new Set(t);for(let t of n)r.has(t)||this.removeDependency(e,t);for(let t of r)n.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];let n=[t],r=new Set([t]),i=new Map;for(;n.length>0;){let a=n.shift();if(a===e){let n=[],r=e;for(;r!==void 0&&(n.push(r),r!==t);)r=i.get(r);return n.reverse(),n.unshift(e),n}let o=this.dependencies.get(a);if(o)for(let e of o)r.has(e)||(r.add(e),i.set(e,a),n.push(e))}return null}topologicalSort(){let e=new Map,t=Array.from(this.dependencies.keys());for(let n of t)e.set(n,this.dependencies.get(n)?.size??0);let n=[];for(let[t,r]of e)r===0&&n.push(t);let r=[];for(;n.length>0;){let t=n.shift();r.push(t);let i=this.dependents.get(t);if(i)for(let t of i){let r=(e.get(t)||0)-1;e.set(t,r),r===0&&n.push(t)}}if(r.length!==t.length)throw Error(`Cycle detected in graph; topological sort impossible.`);return r}getTransitiveDependencies(e,t=!1){return this.bfs(e,`dependencies`,t)}getTransitiveDependents(e,t=!1){return this.bfs(e,`dependents`,t)}bfs(e,t,n){let r=new Set,i=new Set,a=[e];i.add(e),n&&r.add(e);let o=t===`dependencies`?this.dependencies:this.dependents;for(;a.length>0;){let e=a.shift(),t=o.get(e);if(t)for(let e of t)i.has(e)||(i.add(e),r.add(e),a.push(e))}return r}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map(([e,t])=>{let n=Array.from(t).join(`, `);return`${String(e)} → [${n||`∅`}]`}).join(`
2
2
  `)}};const p=new Set;var m=class{graph;constructor(){this.graph=new f}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){let n=Array.from(t).map(e=>e);this.graph.setDependencies(e,n)}wouldCreateCycle(e,t,n){if(n?.has(t)){let e=Array.from(n),r=e.indexOf(t),i=e.slice(r);return i.push(t),i}return this.graph.wouldCreateCycle(e,t)||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()}};const h={NOT_FOUND:n.CommonErrors.NOT_FOUND,DUPLICATE_KEY:n.CommonErrors.DUPLICATE_KEY,INVALID_COMMAND:n.CommonErrors.INVALID_COMMAND,INTERNAL_ERROR:n.CommonErrors.INTERNAL_ERROR,CONCURRENCY_ERROR:n.CommonErrors.CONCURRENCY_ERROR},g=`[ArtifactContainer]`;function _(e){return new n.SystemError({code:h.NOT_FOUND,message:`${g} Artifact "${e}" not found.`,operation:`artifact:resolve`})}function v(e){return new n.SystemError({code:h.INTERNAL_ERROR,message:`${g} Cycle detected: ${e.join(` -> `)}`,operation:`artifact:resolve`})}function y(e){return new n.SystemError({code:h.INVALID_COMMAND,message:`${g} ${e}`,operation:`artifact:build`})}function b(e){return new n.SystemError({code:h.INTERNAL_ERROR,message:`${g} Artifact with key:${e} has already been disposed`,operation:`artifact:watch`})}function x(e){return new n.SystemError({code:h.CONCURRENCY_ERROR,message:`${g} Operation timed out: ${e}`,operation:`artifact:build`})}function S(e){return new n.SystemError({code:h.DUPLICATE_KEY,message:`${g} An artifact with key:"${e}" already exists!`,operation:`artifact:register`})}function C(e){return new n.SystemError({code:h.INVALID_COMMAND,message:`${g} Artifact "${e}" is not parameterized.`,operation:`artifact:resolve`})}function w(e,t){return new n.SystemError({code:h.DUPLICATE_KEY,message:`${g} Parameterized artifact "${e}" with params resolves to key "${t}" which is already registered as a static artifact.`,operation:`artifact:resolve`})}function T(e){return new n.SystemError({code:h.INTERNAL_ERROR,message:`${g} Artifact "${e}" depends on itself.`,operation:`artifact:build`})}function E(e){return new n.SystemError({code:h.CONCURRENCY_ERROR,message:`${g} Build stale after all retries: dependency "${String(e)}" changed during build.`,operation:`artifact:build`})}function D(e){return new n.SystemError({code:h.INVALID_COMMAND,message:e,operation:`artifact:import`})}function O(e){return new n.SystemError({code:h.INTERNAL_ERROR,message:`${g} Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,operation:`artifact:export`})}var k=class extends Error{constructor(){super(`Build superseded by invalidation`),this.name=`SupersededBuildError`}};const A=new AbortController().signal;var j=class{registry;cache;graph;store;observer;logger;events;constructor(e,t,n,r,i,a,o){this.registry=e,this.cache=t,this.graph=n,this.store=r,this.observer=i,this.logger=a,this.events=o}async build(e,t,n){let r=this.cache.get(e);if(r?.scope===`singleton`&&r.buildOnce.done())return this.cache.package(e,(t,n)=>this.invalidate(e,t,n),n);let i=this.registry.getByString(e);if(!i)throw _(e);let a=t??[];if(a.includes(e))throw v([...a,e].map(String));a.push(e);let o=r;o||(o=this.createCachedArtifact(i),this.cache.set(e,o)),this.events?.emit({name:`build:start`,payload:{key:e,templateKey:n}});try{if(o.scope===`transient`)return this.executeBuild(i,o,a);let r=o;try{await r.buildOnce.do(()=>this.executeBuild(i,r,a))}catch(r){if(r instanceof k)return this.build(e,t,n);throw r}return r.stream&&r.streamOnce.do(r.stream),this.events?.emit({name:`build:complete`,payload:{key:e,instance:o.instance}}),this.cache.package(e,(t,n)=>this.invalidate(e,t,n),n)}catch(t){throw t instanceof k||this.events?.emit({name:`build:error`,payload:{key:e,error:t}}),t}finally{a.pop()}}async executeBuild(e,t,n){let r=e.key,i=String(r),o=t.scope===`transient`;t.buildCount++,t.scope===`singleton`&&(t.activeDebounceMs=e.debounce??0);let s={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},c=this.buildContext(e,t,n,i,s),l=await this.runWithRetries(e,c,s.dependencyVersions);if(this.commitResult(r,t,o,l,s),o){let e=l.ok?l.value:void 0;return{instance:e,error:l.ok?void 0:l.error,ready:l.ok,[r]:e,cleanup:a(s.cleanupFunctions,i),invalidate:async()=>this.logger.warn(`Cannot invalidate transient "${i}"`)}}}buildContext(e,n,r,i,a){let o=e.key,s=n.scope===`transient`,{cleanupFunctions:c,disposeFunctions:l,capturedArtifactDeps:u,dependencyVersions:d,capturedStateSelectors:f}=a,p=async(e,t)=>{let n=t?this.computeParamKey(e,t):e;if(n===o)throw T(i);let a=this.graph.wouldCreateCycle(o,n);if(a)throw v(a);u.add(n);let s=await(t?this.resolveParameterized(e,t):this.build(e,r)),c=this.cache.get(n);return c&&d.set(n,c.version),s},m=n.scope===`singleton`?n.controller.signal:A,h=async(e,t)=>{let n=await p(e,t);if(n.error)throw n.error;return n.instance},g=(e,n)=>{let r=(0,t.buildPaths)(e);return f.push({paths:r,options:n}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:n.instance,signal:m,onCleanup:e=>c.push(e),onDispose:e=>l.push(e),use:e=>e({resolve:p,require:h,select:g}),stream:e=>{if(s)throw y(`Illegal stream on transient artifact "${i}"`);let t=n,r=async(e,n=void 0)=>{await t.streamSerializer.do(async()=>{t.stream!==void 0&&(t.instance=e,t.error=n,t.version++,this.cache.invalidatePackage(o),await this.processStream(i),this.events?.emit({name:`stream:emit`,payload:{key:i,value:e}}))})},a={value:()=>t.instance,get signal(){return t.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};t.stream=async()=>{try{let n=await e(a);n&&t.cleanupFunctions.push(n)}catch(e){await r(void 0,e),await this.invalidate(o,!1,!0)}}}}}async runWithRetries(e,t,r){let i=t.signal,a=(e.retries??0)+1,o=0;for(;o<a;)try{if(i.aborted)throw new k;let n=e.factory(t),s;if(s=n instanceof Promise?e.timeout?await l(n,e.timeout):await n:n,i.aborted)throw new k;let c=this.detectStaleness(r);if(c){if(o++,r.clear(),o<a)continue;return{ok:!1,error:E(String(c))}}return{ok:!0,value:s}}catch(e){if(i.aborted||e instanceof k)throw new k;if(e instanceof n.SystemError)throw e;if(o++,o>=a)return{ok:!1,error:e}}return{ok:!1,error:Error(`Build exhausted retry budget unexpectedly.`)}}commitResult(e,t,n,r,i){let{cleanupFunctions:a,disposeFunctions:o,capturedArtifactDeps:s,capturedStateSelectors:c}=i;n||(this.updateDependencyGraph(e,s,c),t.cleanupFunctions=a,t.disposeFunctions=o,t.artifactDependencies=new Set(s),t.stateGroups=c.map(({paths:e,options:t})=>({paths:e,options:t}))),r.ok?(t.instance=r.value,t.error=void 0):(t.instance=void 0,t.error=r.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(let[t,n]of e){let e=this.cache.get(t);if(e&&e.version!==n)return t}return null}async invalidate(e,t=!1,n=!1){let r=this.cache.get(e);if(!r)return;if(r.scope!==`singleton`)return this.executeInvalidation(e,t,n);let i=r;return i.debounceTimer&&=(clearTimeout(i.debounceTimer),void 0),!t&&i.activeDebounceMs>0?new Promise((r,a)=>{i.debounceTimer=setTimeout(()=>{i.debounceTimer=void 0,this.executeInvalidation(e,t,n).then(r).catch(a)},i.activeDebounceMs)}):this.executeInvalidation(e,t,n)}async executeInvalidation(e,t,n=!1){let r=this.cache.get(e);!r||r.scope!==`singleton`||await r.invalidationSerializer.do(async()=>{r.version++,await this.cache.invalidateInstance(e);let i=this.graph.iterDependents(e),a=i.size>0;await this.cascadeInvalidation(i),this.events?.emit({name:`artifact:invalidated`,payload:{key:e,cascade:a,replace:t}});let o=this.registry.get(e),s=o&&(t||!o.lazy||this.observer.hasWatchers(e))&&!n;s&&await this.build(e).catch(t=>{t instanceof k||this.logger.error(`Rebuild failed for "${String(e)}"`,t)}),(s||n)&&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),this.events?.emit({name:`artifact:disposed`,payload:{key:e}}))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(e.size===0)return;let t=[];for(let n of e)t.push(this.invalidate(n).catch(e=>{this.logger.error(`Cascade failed for "${String(n)}"`,e)}));await Promise.all(t)}updateDependencyGraph(e,t,n){let r=this.cache.get(e);if(!r||r.scope!==`singleton`)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),r.stateDependencies=new Set;for(let{paths:e}of n)for(let t of e)r.stateDependencies.add(t);if(r.stateUnsubscribe&&=(r.stateUnsubscribe(),void 0),n.length===0)return;let i=()=>this.invalidate(e),a=new Map;for(let{paths:e,options:t}of n){let n=t===void 0?`undefined`:JSON.stringify(t),r=a.get(n);r||(r={options:t,paths:new Set},a.set(n,r));for(let t of e)r.paths.add(t)}let o=[];for(let{options:e,paths:t}of a.values()){if(t.size===0)continue;let n=Array.from(t);e===void 0?o.push(this.store.watch(n,i)):o.push(this.store.watch(n,i,e))}o.length===0?r.stateUnsubscribe=void 0:o.length===1?r.stateUnsubscribe=o[0]:r.stateUnsubscribe=()=>{for(let e of o)e()}}createCachedArtifact(t){return t.scope===`transient`?{scope:`transient`,instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:`singleton`,instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:t.debounce?t.debounce:0,controller:new AbortController,buildOnce:new e.Once({retry:!0,throws:!0}),streamOnce:new e.Once({retry:!0,throws:!0}),streamSerializer:new e.Serializer({yieldMode:`microtask`}),invalidationSerializer:new e.Serializer({yieldMode:`macrotask`}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.getByString(e))throw _(e);return this.build(e)}async resolveParameterized(e,t){let n=this.registry.getByString(e);if(!n)throw _(String(e));if(!n.paramKey)throw C(String(e));let r=n.paramKey(t),i=this.registry.getByString(r);if(i&&!i.paramKey&&!i.virtual)throw w(String(e),r);return this.registry.hasString(r)||this.registry.setVirtual(r,{key:r,factory:e=>n.factory({...e,params:t}),scope:n.scope,lazy:n.lazy,timeout:n.timeout,retries:n.retries,debounce:n.debounce,virtual:!0}),this.build(r,void 0,e)}computeParamKey(e,t){let n=this.registry.getByString(e);if(!n||!n.paramKey)throw C(String(e));return n.paramKey(t)}},M=class{registry;cache;container;logger;listeners=new Map;watchers=new Map;constructor(e,t,n,r){this.registry=e,this.cache=t,this.container=n,this.logger=r}watch(e,t=60*1e3){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,n=60*1e3){let r=this.registry.get(e);if(!r.paramKey)throw Error(`Artifact "${String(e)}" is not parameterized.`);let i=r.paramKey(t);return this.watchForKey(i,r,n,t)}watchForKey(t,n,r,i){let a=n.scope===`transient`,o=a?s(t):t,l=this.watchers.get(o);if(l)return l.observer;let u=new e.SharedResource(async()=>{(a||i!==void 0)&&!this.registry.hasString(t)&&this.registry.setVirtual(t,{key:t,factory:a?n.factory:e=>n.factory({...e,params:i}),scope:a?`singleton`:n.scope,lazy:n.lazy,timeout:n.timeout,retries:n.retries,debounce:n.debounce,paramKey:n.paramKey,virtual:!0})},async()=>{a||i!==void 0?(await this.registry.unregister(o).catch(()=>{}),this.cache.delete(o),this.watchers.delete(o)):this.cache.invalidatePackage(o),this.listeners.delete(o)},{gracePeriod:a&&i===void 0?`sync`:r}),d,f={id:o,get count(){return u.subscribers},get:(e=!1)=>u.subscribers===0&&!e?c:this.cache.package(o,(e,t)=>this.container.invalidate(o,e,t),t),resolve:()=>d||(d=(async()=>{await u.acquire();try{return await this.container.resolve(o)}finally{u.release(),d=void 0}})(),d),subscribe:(e,t=!0)=>{let n=()=>e(f.get());return u.acquire().then(()=>{this.container.resolve(o).then(()=>{this.listeners.has(o)||this.listeners.set(o,new Set),t&&n(),this.listeners.get(o).add(n)})}).catch(e=>{this.logger.error(`Resolution failed for "${o}"`,e),this.listeners.get(o)?.add(n)}),()=>{this.listeners.get(o)?.delete(n),u.release()}}};return this.watchers.set(o,{resource:u,observer:f}),f}evictWatcher(e){[e,s(e)].forEach(e=>{let t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))})}notify(e){let t=this.listeners.get(e);if(!(!t||t.size===0))for(let n of t)try{n()}catch(t){this.logger.error(`Listener error for "${e}"`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(s(e))}getWatcherCount(e){return(this.watchers.get(e)||this.watchers.get(s(e)))?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}};let N=function(e){return e.Singleton=`singleton`,e.Transient=`transient`,e}({});var P=class{artifacts=new Map;register({key:e,factory:t,lazy:n,...r}){let{scope:i,...a}=r,o={key:e,factory:t,scope:r.scope??`singleton`,lazy:n===void 0?!0:n,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw _(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},F=class t{registry;cache;graph;manager;observer;logger;store;events;constructor(e,t){this.logger=t?.logger??new i.Logger([new i.ConsoleSink],{module:`artifacts`}),this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.events=(0,r.createEventBus)({errorHandler:e=>this.logger.error(`Lifecycle event error`,e)}),this.registry=new P,this.cache=new d,this.graph=new m,this.observer=new M(this.registry,this.cache,this,this.logger),this.manager=new j(this.registry,this.cache,this.graph,this.store,this.observer,this.logger,this.events)}debugInfo(){let e=[];return this.registry.keys().forEach(t=>{let n=t,r=this.registry.getByString(n),i=this.cache.get(n);if(!r)return;let a=`idle`;i&&(i.scope===`singleton`&&i.debounceTimer!==void 0?a=`debouncing`:i.scope===`singleton`&&i.buildOnce.running()?a=`building`:i.error?a=`error`:i.instance!==void 0&&(a=`active`)),e.push({id:n,scope:r.scope??`singleton`,status:a,dependencies:this.graph.getDependencies(n).map(e=>String(e)),dependents:this.graph.getDependents(n).map(e=>String(e)),stateDependencies:i?.scope===`singleton`?Array.from(i.stateDependencies):[],buildCount:i?.buildCount??0})}),e}register(e){let{key:t}=e,n=t;this.registry.has(t)&&(this.logger.warn(`Overwriting artifact "${n}".`),this.manager.dispose(t).catch(e=>{this.logger.error(`Failed to dispose existing artifact "${n}"`,e)})),this.registry.register(e),this.graph.registerNode(t);let r=e.scope??`singleton`,i=e.lazy??!0;return this.events.emit({name:`artifact:registered`,payload:{key:n,scope:r}}),!i&&r===`singleton`&&this.resolve(t).catch(e=>{this.logger.error(`Eager load failed for "${n}"`,e)}),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){let n=t===void 0?e:this.manager.computeParamKey(e,t);await this.manager.dispose(n),await this.registry.unregister(n),this.observer.evictWatcher(n)}async resolve(e,t){return t===void 0?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){let n=await this.resolve(e,t);if(n.error)throw n.error;return n.instance}watch(e,t,n){return t===void 0?this.observer.watch(e,n):this.observer.watchParameterized(e,t,n)}peek(e,t){let n=t===void 0?e:this.manager.computeParamKey(e,t);return this.cache.get(n)?.instance}async invalidate(e,t){let n=t?.params,r=t?.replace??!1,i=n===void 0?e:this.manager.computeParamKey(e,n);return this.manager.invalidate(i,r)}on(e,t){return this.events.subscribe(e,t)}once(e,t){return this.events.once(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){let e=this.registry.keys();await Promise.allSettled(e.map(e=>this.manager.dispose(e).catch(t=>{this.logger.error(`Failed to dispose artifact "${String(e)}"`,t)}))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear(),this.events.emit({name:`container:dispose`,payload:{}}),this.events.clear({permanent:!0})}async export(){let e=[];for(let t of this.cache.keys()){let n=this.cache.get(t);if(!n||n.scope!==`singleton`||n.instance===void 0)continue;let r=new Set;for(let e of n.stateGroups)for(let t of e.paths)r.add(t);let i=Array.from(r).sort(),a=this.store.subset(i),o=await u(JSON.stringify(a,Object.keys(a).sort())),s;try{s=structuredClone(n.instance)}catch{throw O(t)}e.push({key:t,instance:s,state:{groups:n.stateGroups.map(e=>({paths:e.paths,options:e.options})),hash:o},dependencies:Array.from(n.artifactDependencies)})}let t={version:`1.0`,timestamp:Date.now(),artifacts:e},n=await u(JSON.stringify(t));return{...t,checksum:n}}async restore(t){let{checksum:n,...r}=t;if(await u(JSON.stringify(r))!==n)throw D(`Bundle checksum mismatch – data corrupted`);if(t.version!==`1.0`)throw D(`Unsupported bundle version: ${t.version}`);let i=new Map;for(let e of t.artifacts)i.set(e.key,e);let a=new Set,o=new Map;for(let e of t.artifacts)for(let t of e.dependencies)o.has(t)||o.set(t,new Set),o.get(t).add(e.key);let s=async e=>{let t=new Set;for(let n of e.state.groups)for(let e of n.paths)t.add(e);let n=Array.from(t).sort(),r=this.store.subset(n);return u(JSON.stringify(r,Object.keys(r).sort()))};for(let e of t.artifacts)await s(e)!==e.state.hash&&a.add(e.key);let c=Array.from(a);for(;c.length;){let e=c.shift(),t=o.get(e);if(t)for(let e of t)a.has(e)||(a.add(e),c.push(e))}for(let n of t.artifacts){if(a.has(n.key))continue;this.cache.get(n.key)&&await this.cache.invalidateInstance(n.key,!1);let t={scope:`singleton`,instance:n.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(n.state.groups.flatMap(e=>e.paths)),activeDebounceMs:0,buildOnce:new e.Once({retry:!0,throws:!0}),streamSerializer:new e.Serializer({yieldMode:`microtask`}),invalidationSerializer:new e.Serializer({yieldMode:`macrotask`}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new e.Once({retry:!0,throws:!0}),stream:void 0,stateGroups:n.state.groups,artifactDependencies:new Set(n.dependencies)};t.buildOnce.resolve(n.instance),this.cache.set(n.key,t);let r=[];for(let e of n.state.groups){let t=this.store.watch(e.paths,()=>this.invalidate(n.key),e.options);r.push(t)}t.stateUnsubscribe=()=>{for(let e of r)e()},this.graph.setDependencies(n.key,n.dependencies)}}static async from(e){let n=new t(e.store,{logger:e.logger});if(e.bundle){if(typeof e.bundle!=`object`||!e.bundle.version||!Array.isArray(e.bundle.artifacts))throw D(`Invalid bundle: missing version or artifacts array`);await n.restore(e.bundle)}for(let t of e.templates)n.register(t);return n}};exports.ArtifactContainer=F,exports.ArtifactScopes=N,exports.ErrorCodes=h,exports.SupersededBuildError=k,Object.defineProperty(exports,"SystemError",{enumerable:!0,get:function(){return n.SystemError}}),exports.artifactNotFound=_,exports.buildStaleAfterRetries=E,exports.cycleDetected=v,exports.illegalScope=y,exports.invalidExport=O,exports.invalidImport=D,exports.keyConflict=S,exports.notParameterized=C,exports.paramKeyCollision=w,exports.selfDependency=T,exports.timeoutError=x,exports.watcherDisposed=b;
package/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{Once as e,Serializer as t,SharedResource as n}from"@asaidimu/utils-sync";import{buildPaths as r}from"@asaidimu/utils-store/selector";import{CommonErrors as i,SystemError as a,SystemError as o}from"@asaidimu/utils-error";import{createEventBus as s}from"@asaidimu/utils-events";import{ConsoleSink as c,Logger as l}from"@asaidimu/utils-logger";function u(e,t){if(!e.length)return;let n=e.slice(),r=t?`[${t}]`:`[ArtifactCleanup]`;return async()=>{for(let e=n.length-1;e>=0;e--)try{await n[e]()}catch(t){console.error(`${r} Cleanup error at index ${e}:`,t)}}}async function d(e,t){let n=t?`[${t}]`:`[ArtifactCleanup]`;for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${n} Cleanup error at index ${t}:`,e)}}function f(e){return`${e}__watched`}const p=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function m(e,t){let n,r=new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Timeout: ${t}ms`)),t)});try{return Promise.race([e,r])}finally{clearTimeout(n)}}async function h(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}var g=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,n){let r=this.get(e);if(!r)return p;if(r.package)return r.package;let i=e,a=u(r.cleanupFunctions,i),o=r.scope===`singleton`?r.instance!==void 0:!0,s={instance:r.instance,error:r.error,ready:o,[n||e]:r.instance,cleanup:a,invalidate:t};return r.package=s,s}invalidatePackage(e){let t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(n,r=!1){let i=this.get(n);if(!i)return;let a=n;i.scope===`singleton`&&(i.stateUnsubscribe&&=(i.stateUnsubscribe(),void 0),i.debounceTimer&&=(clearTimeout(i.debounceTimer),void 0),i.controller.abort(),await i.streamOnce.current(),i.streamSerializer.close(),i.stream=void 0,i.streamOnce=new e({retry:!0,throws:!0}),r||(i.streamSerializer=new t,i.controller=new AbortController)),await d(i.cleanupFunctions,a),await d(i.disposeFunctions,a),i.cleanupFunctions=[],i.disposeFunctions=[],i.scope===`singleton`&&(i.buildOnce=new e({retry:!0,throws:!0})),i.instance=void 0,i.error=void 0}},_=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;let t=this.dependencies.get(e);if(t)for(let n of t)this.dependents.get(n)?.delete(e);let n=this.dependents.get(e);if(n)for(let t of n)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){let t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){let t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??v}setDependencies(e,t){this.registerNode(e);let n=this.dependencies.get(e),r=new Set(t);for(let t of n)r.has(t)||this.removeDependency(e,t);for(let t of r)n.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];let n=[t],r=new Set([t]),i=new Map;for(;n.length>0;){let a=n.shift();if(a===e){let n=[],r=e;for(;r!==void 0&&(n.push(r),r!==t);)r=i.get(r);return n.reverse(),n.unshift(e),n}let o=this.dependencies.get(a);if(o)for(let e of o)r.has(e)||(r.add(e),i.set(e,a),n.push(e))}return null}topologicalSort(){let e=new Map,t=Array.from(this.dependencies.keys());for(let n of t)e.set(n,this.dependencies.get(n)?.size??0);let n=[];for(let[t,r]of e)r===0&&n.push(t);let r=[];for(;n.length>0;){let t=n.shift();r.push(t);let i=this.dependents.get(t);if(i)for(let t of i){let r=(e.get(t)||0)-1;e.set(t,r),r===0&&n.push(t)}}if(r.length!==t.length)throw Error(`Cycle detected in graph; topological sort impossible.`);return r}getTransitiveDependencies(e,t=!1){return this.bfs(e,`dependencies`,t)}getTransitiveDependents(e,t=!1){return this.bfs(e,`dependents`,t)}bfs(e,t,n){let r=new Set,i=new Set,a=[e];i.add(e),n&&r.add(e);let o=t===`dependencies`?this.dependencies:this.dependents;for(;a.length>0;){let e=a.shift(),t=o.get(e);if(t)for(let e of t)i.has(e)||(i.add(e),r.add(e),a.push(e))}return r}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map(([e,t])=>{let n=Array.from(t).join(`, `);return`${String(e)} → [${n||`∅`}]`}).join(`
1
+ import{Once as e,Serializer as t,SharedResource as n}from"@asaidimu/utils-sync";import{buildPaths as r}from"@asaidimu/utils-store";import{CommonErrors as i,SystemError as a,SystemError as o}from"@asaidimu/utils-error";import{createEventBus as s}from"@asaidimu/utils-events";import{ConsoleSink as c,Logger as l}from"@asaidimu/utils-logger";function u(e,t){if(!e.length)return;let n=e.slice(),r=t?`[${t}]`:`[ArtifactCleanup]`;return async()=>{for(let e=n.length-1;e>=0;e--)try{await n[e]()}catch(t){console.error(`${r} Cleanup error at index ${e}:`,t)}}}async function d(e,t){let n=t?`[${t}]`:`[ArtifactCleanup]`;for(let t=e.length-1;t>=0;t--)try{await e[t]()}catch(e){console.error(`${n} Cleanup error at index ${t}:`,e)}}function f(e){return`${e}__watched`}const p=Object.freeze({instance:void 0,error:void 0,ready:!1,cleanup:void 0,invalidate:async(e,t)=>{}});function m(e,t){let n,r=new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Timeout: ${t}ms`)),t)});try{return Promise.race([e,r])}finally{clearTimeout(n)}}async function h(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}var g=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,n){let r=this.get(e);if(!r)return p;if(r.package)return r.package;let i=e,a=u(r.cleanupFunctions,i),o=r.scope===`singleton`?r.instance!==void 0:!0,s={instance:r.instance,error:r.error,ready:o,[n||e]:r.instance,cleanup:a,invalidate:t};return r.package=s,s}invalidatePackage(e){let t=this.get(e);t&&(t.package=void 0)}async invalidateInstance(n,r=!1){let i=this.get(n);if(!i)return;let a=n;i.scope===`singleton`&&(i.stateUnsubscribe&&=(i.stateUnsubscribe(),void 0),i.debounceTimer&&=(clearTimeout(i.debounceTimer),void 0),i.controller.abort(),await i.streamOnce.current(),i.streamSerializer.close(),i.stream=void 0,i.streamOnce=new e({retry:!0,throws:!0}),r||(i.streamSerializer=new t,i.controller=new AbortController)),await d(i.cleanupFunctions,a),await d(i.disposeFunctions,a),i.cleanupFunctions=[],i.disposeFunctions=[],i.scope===`singleton`&&(i.buildOnce=new e({retry:!0,throws:!0})),i.instance=void 0,i.error=void 0}},_=class{dependencies=new Map;dependents=new Map;registerNode(e){this.dependencies.has(e)||this.dependencies.set(e,new Set),this.dependents.has(e)||this.dependents.set(e,new Set)}removeNode(e){if(!this.hasNode(e))return;let t=this.dependencies.get(e);if(t)for(let n of t)this.dependents.get(n)?.delete(e);let n=this.dependents.get(e);if(n)for(let t of n)this.dependencies.get(t)?.delete(e);this.dependencies.delete(e),this.dependents.delete(e)}hasNode(e){return this.dependencies.has(e)}addDependency(e,t){this.registerNode(e),this.registerNode(t),this.dependencies.get(e).add(t),this.dependents.get(t).add(e)}removeDependency(e,t){this.dependencies.get(e)?.delete(t),this.dependents.get(t)?.delete(e)}getDependencies(e){let t=this.dependencies.get(e);return t?new Set(t):new Set}getDependents(e){let t=this.dependents.get(e);return t?new Set(t):new Set}iterDependents(e){return this.dependents.get(e)??v}setDependencies(e,t){this.registerNode(e);let n=this.dependencies.get(e),r=new Set(t);for(let t of n)r.has(t)||this.removeDependency(e,t);for(let t of r)n.has(t)||this.addDependency(e,t)}wouldCreateCycle(e,t){if(e===t)return[e,t];let n=[t],r=new Set([t]),i=new Map;for(;n.length>0;){let a=n.shift();if(a===e){let n=[],r=e;for(;r!==void 0&&(n.push(r),r!==t);)r=i.get(r);return n.reverse(),n.unshift(e),n}let o=this.dependencies.get(a);if(o)for(let e of o)r.has(e)||(r.add(e),i.set(e,a),n.push(e))}return null}topologicalSort(){let e=new Map,t=Array.from(this.dependencies.keys());for(let n of t)e.set(n,this.dependencies.get(n)?.size??0);let n=[];for(let[t,r]of e)r===0&&n.push(t);let r=[];for(;n.length>0;){let t=n.shift();r.push(t);let i=this.dependents.get(t);if(i)for(let t of i){let r=(e.get(t)||0)-1;e.set(t,r),r===0&&n.push(t)}}if(r.length!==t.length)throw Error(`Cycle detected in graph; topological sort impossible.`);return r}getTransitiveDependencies(e,t=!1){return this.bfs(e,`dependencies`,t)}getTransitiveDependents(e,t=!1){return this.bfs(e,`dependents`,t)}bfs(e,t,n){let r=new Set,i=new Set,a=[e];i.add(e),n&&r.add(e);let o=t===`dependencies`?this.dependencies:this.dependents;for(;a.length>0;){let e=a.shift(),t=o.get(e);if(t)for(let e of t)i.has(e)||(i.add(e),r.add(e),a.push(e))}return r}getAllNodes(){return Array.from(this.dependencies.keys())}size(){return this.dependencies.size}clear(){this.dependencies.clear(),this.dependents.clear()}toDebugString(){return Array.from(this.dependencies.entries()).map(([e,t])=>{let n=Array.from(t).join(`, `);return`${String(e)} → [${n||`∅`}]`}).join(`
2
2
  `)}};const v=new Set;var y=class{graph;constructor(){this.graph=new _}registerNode(e){this.graph.registerNode(e)}removeNode(e){this.graph.removeNode(e)}addDependency(e,t){this.graph.addDependency(e,t)}removeDependency(e,t){this.graph.removeDependency(e,t)}getDependents(e){return Array.from(this.graph.getDependents(e))}iterDependents(e){return this.graph.iterDependents(e)}getDependencies(e){return Array.from(this.graph.getDependencies(e))}getTransitiveDependents(e){return new Set(Array.from(this.graph.getTransitiveDependents(e,!1)))}setDependencies(e,t){let n=Array.from(t).map(e=>e);this.graph.setDependencies(e,n)}wouldCreateCycle(e,t,n){if(n?.has(t)){let e=Array.from(n),r=e.indexOf(t),i=e.slice(r);return i.push(t),i}return this.graph.wouldCreateCycle(e,t)||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()}};const b={NOT_FOUND:i.NOT_FOUND,DUPLICATE_KEY:i.DUPLICATE_KEY,INVALID_COMMAND:i.INVALID_COMMAND,INTERNAL_ERROR:i.INTERNAL_ERROR,CONCURRENCY_ERROR:i.CONCURRENCY_ERROR},x=`[ArtifactContainer]`;function S(e){return new o({code:b.NOT_FOUND,message:`${x} Artifact "${e}" not found.`,operation:`artifact:resolve`})}function C(e){return new o({code:b.INTERNAL_ERROR,message:`${x} Cycle detected: ${e.join(` -> `)}`,operation:`artifact:resolve`})}function w(e){return new o({code:b.INVALID_COMMAND,message:`${x} ${e}`,operation:`artifact:build`})}function T(e){return new o({code:b.INTERNAL_ERROR,message:`${x} Artifact with key:${e} has already been disposed`,operation:`artifact:watch`})}function E(e){return new o({code:b.CONCURRENCY_ERROR,message:`${x} Operation timed out: ${e}`,operation:`artifact:build`})}function D(e){return new o({code:b.DUPLICATE_KEY,message:`${x} An artifact with key:"${e}" already exists!`,operation:`artifact:register`})}function O(e){return new o({code:b.INVALID_COMMAND,message:`${x} Artifact "${e}" is not parameterized.`,operation:`artifact:resolve`})}function k(e,t){return new o({code:b.DUPLICATE_KEY,message:`${x} Parameterized artifact "${e}" with params resolves to key "${t}" which is already registered as a static artifact.`,operation:`artifact:resolve`})}function A(e){return new o({code:b.INTERNAL_ERROR,message:`${x} Artifact "${e}" depends on itself.`,operation:`artifact:build`})}function j(e){return new o({code:b.CONCURRENCY_ERROR,message:`${x} Build stale after all retries: dependency "${String(e)}" changed during build.`,operation:`artifact:build`})}function M(e){return new o({code:b.INVALID_COMMAND,message:e,operation:`artifact:import`})}function N(e){return new o({code:b.INTERNAL_ERROR,message:`${x} Artifact "${e}" instance is not JSON-serializable (POJO are required for persistence)`,operation:`artifact:export`})}var P=class extends Error{constructor(){super(`Build superseded by invalidation`),this.name=`SupersededBuildError`}};const F=new AbortController().signal;var I=class{registry;cache;graph;store;observer;logger;events;constructor(e,t,n,r,i,a,o){this.registry=e,this.cache=t,this.graph=n,this.store=r,this.observer=i,this.logger=a,this.events=o}async build(e,t,n){let r=this.cache.get(e);if(r?.scope===`singleton`&&r.buildOnce.done())return this.cache.package(e,(t,n)=>this.invalidate(e,t,n),n);let i=this.registry.getByString(e);if(!i)throw S(e);let a=t??[];if(a.includes(e))throw C([...a,e].map(String));a.push(e);let o=r;o||(o=this.createCachedArtifact(i),this.cache.set(e,o)),this.events?.emit({name:`build:start`,payload:{key:e,templateKey:n}});try{if(o.scope===`transient`)return this.executeBuild(i,o,a);let r=o;try{await r.buildOnce.do(()=>this.executeBuild(i,r,a))}catch(r){if(r instanceof P)return this.build(e,t,n);throw r}return r.stream&&r.streamOnce.do(r.stream),this.events?.emit({name:`build:complete`,payload:{key:e,instance:o.instance}}),this.cache.package(e,(t,n)=>this.invalidate(e,t,n),n)}catch(t){throw t instanceof P||this.events?.emit({name:`build:error`,payload:{key:e,error:t}}),t}finally{a.pop()}}async executeBuild(e,t,n){let r=e.key,i=String(r),a=t.scope===`transient`;t.buildCount++,t.scope===`singleton`&&(t.activeDebounceMs=e.debounce??0);let o={cleanupFunctions:[],disposeFunctions:[],capturedArtifactDeps:new Set,capturedStateSelectors:[],dependencyVersions:new Map},s=this.buildContext(e,t,n,i,o),c=await this.runWithRetries(e,s,o.dependencyVersions);if(this.commitResult(r,t,a,c,o),a){let e=c.ok?c.value:void 0;return{instance:e,error:c.ok?void 0:c.error,ready:c.ok,[r]:e,cleanup:u(o.cleanupFunctions,i),invalidate:async()=>this.logger.warn(`Cannot invalidate transient "${i}"`)}}}buildContext(e,t,n,i,a){let o=e.key,s=t.scope===`transient`,{cleanupFunctions:c,disposeFunctions:l,capturedArtifactDeps:u,dependencyVersions:d,capturedStateSelectors:f}=a,p=async(e,t)=>{let r=t?this.computeParamKey(e,t):e;if(r===o)throw A(i);let a=this.graph.wouldCreateCycle(o,r);if(a)throw C(a);u.add(r);let s=await(t?this.resolveParameterized(e,t):this.build(e,n)),c=this.cache.get(r);return c&&d.set(r,c.version),s},m=t.scope===`singleton`?t.controller.signal:F,h=async(e,t)=>{let n=await p(e,t);if(n.error)throw n.error;return n.instance},g=(e,t)=>{let n=r(e);return f.push({paths:n,options:t}),e(this.store.get(!0))};return{state:()=>this.store.get(!0),previous:t.instance,signal:m,onCleanup:e=>c.push(e),onDispose:e=>l.push(e),use:e=>e({resolve:p,require:h,select:g}),stream:e=>{if(s)throw w(`Illegal stream on transient artifact "${i}"`);let n=t,r=async(e,t=void 0)=>{await n.streamSerializer.do(async()=>{n.stream!==void 0&&(n.instance=e,n.error=t,n.version++,this.cache.invalidatePackage(o),await this.processStream(i),this.events?.emit({name:`stream:emit`,payload:{key:i,value:e}}))})},a={value:()=>n.instance,get signal(){return n.controller.signal},set:(...e)=>this.store.set(...e),emit:e=>r(e)};n.stream=async()=>{try{let t=await e(a);t&&n.cleanupFunctions.push(t)}catch(e){await r(void 0,e),await this.invalidate(o,!1,!0)}}}}}async runWithRetries(e,t,n){let r=t.signal,i=(e.retries??0)+1,o=0;for(;o<i;)try{if(r.aborted)throw new P;let a=e.factory(t),s;if(s=a instanceof Promise?e.timeout?await m(a,e.timeout):await a:a,r.aborted)throw new P;let c=this.detectStaleness(n);if(c){if(o++,n.clear(),o<i)continue;return{ok:!1,error:j(String(c))}}return{ok:!0,value:s}}catch(e){if(r.aborted||e instanceof P)throw new P;if(e instanceof a)throw e;if(o++,o>=i)return{ok:!1,error:e}}return{ok:!1,error:Error(`Build exhausted retry budget unexpectedly.`)}}commitResult(e,t,n,r,i){let{cleanupFunctions:a,disposeFunctions:o,capturedArtifactDeps:s,capturedStateSelectors:c}=i;n||(this.updateDependencyGraph(e,s,c),t.cleanupFunctions=a,t.disposeFunctions=o,t.artifactDependencies=new Set(s),t.stateGroups=c.map(({paths:e,options:t})=>({paths:e,options:t}))),r.ok?(t.instance=r.value,t.error=void 0):(t.instance=void 0,t.error=r.error),t.version++,this.cache.invalidatePackage(e)}detectStaleness(e){for(let[t,n]of e){let e=this.cache.get(t);if(e&&e.version!==n)return t}return null}async invalidate(e,t=!1,n=!1){let r=this.cache.get(e);if(!r)return;if(r.scope!==`singleton`)return this.executeInvalidation(e,t,n);let i=r;return i.debounceTimer&&=(clearTimeout(i.debounceTimer),void 0),!t&&i.activeDebounceMs>0?new Promise((r,a)=>{i.debounceTimer=setTimeout(()=>{i.debounceTimer=void 0,this.executeInvalidation(e,t,n).then(r).catch(a)},i.activeDebounceMs)}):this.executeInvalidation(e,t,n)}async executeInvalidation(e,t,n=!1){let r=this.cache.get(e);!r||r.scope!==`singleton`||await r.invalidationSerializer.do(async()=>{r.version++,await this.cache.invalidateInstance(e);let i=this.graph.iterDependents(e),a=i.size>0;await this.cascadeInvalidation(i),this.events?.emit({name:`artifact:invalidated`,payload:{key:e,cascade:a,replace:t}});let o=this.registry.get(e),s=o&&(t||!o.lazy||this.observer.hasWatchers(e))&&!n;s&&await this.build(e).catch(t=>{t instanceof P||this.logger.error(`Rebuild failed for "${String(e)}"`,t)}),(s||n)&&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),this.events?.emit({name:`artifact:disposed`,payload:{key:e}}))}async processStream(e){await this.cascadeInvalidation(this.graph.iterDependents(e)),this.observer.notify(e)}async cascadeInvalidation(e){if(e.size===0)return;let t=[];for(let n of e)t.push(this.invalidate(n).catch(e=>{this.logger.error(`Cascade failed for "${String(n)}"`,e)}));await Promise.all(t)}updateDependencyGraph(e,t,n){let r=this.cache.get(e);if(!r||r.scope!==`singleton`)return;this.graph.registerNode(e),this.graph.setDependencies(e,t),r.stateDependencies=new Set;for(let{paths:e}of n)for(let t of e)r.stateDependencies.add(t);if(r.stateUnsubscribe&&=(r.stateUnsubscribe(),void 0),n.length===0)return;let i=()=>this.invalidate(e),a=new Map;for(let{paths:e,options:t}of n){let n=t===void 0?`undefined`:JSON.stringify(t),r=a.get(n);r||(r={options:t,paths:new Set},a.set(n,r));for(let t of e)r.paths.add(t)}let o=[];for(let{options:e,paths:t}of a.values()){if(t.size===0)continue;let n=Array.from(t);e===void 0?o.push(this.store.watch(n,i)):o.push(this.store.watch(n,i,e))}o.length===0?r.stateUnsubscribe=void 0:o.length===1?r.stateUnsubscribe=o[0]:r.stateUnsubscribe=()=>{for(let e of o)e()}}createCachedArtifact(n){return n.scope===`transient`?{scope:`transient`,instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0}:{scope:`singleton`,instance:void 0,error:void 0,version:0,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set,activeDebounceMs:n.debounce?n.debounce:0,controller:new AbortController,buildOnce:new e({retry:!0,throws:!0}),streamOnce:new e({retry:!0,throws:!0}),streamSerializer:new t({yieldMode:`microtask`}),invalidationSerializer:new t({yieldMode:`macrotask`}),stateGroups:[],artifactDependencies:new Set}}resolveStatic(e){if(!this.registry.getByString(e))throw S(e);return this.build(e)}async resolveParameterized(e,t){let n=this.registry.getByString(e);if(!n)throw S(String(e));if(!n.paramKey)throw O(String(e));let r=n.paramKey(t),i=this.registry.getByString(r);if(i&&!i.paramKey&&!i.virtual)throw k(String(e),r);return this.registry.hasString(r)||this.registry.setVirtual(r,{key:r,factory:e=>n.factory({...e,params:t}),scope:n.scope,lazy:n.lazy,timeout:n.timeout,retries:n.retries,debounce:n.debounce,virtual:!0}),this.build(r,void 0,e)}computeParamKey(e,t){let n=this.registry.getByString(e);if(!n||!n.paramKey)throw O(String(e));return n.paramKey(t)}},L=class{registry;cache;container;logger;listeners=new Map;watchers=new Map;constructor(e,t,n,r){this.registry=e,this.cache=t,this.container=n,this.logger=r}watch(e,t=60*1e3){return this.watchForKey(e,this.registry.get(e),t)}watchParameterized(e,t,n=60*1e3){let r=this.registry.get(e);if(!r.paramKey)throw Error(`Artifact "${String(e)}" is not parameterized.`);let i=r.paramKey(t);return this.watchForKey(i,r,n,t)}watchForKey(e,t,r,i){let a=t.scope===`transient`,o=a?f(e):e,s=this.watchers.get(o);if(s)return s.observer;let c=new n(async()=>{(a||i!==void 0)&&!this.registry.hasString(e)&&this.registry.setVirtual(e,{key:e,factory:a?t.factory:e=>t.factory({...e,params:i}),scope:a?`singleton`:t.scope,lazy:t.lazy,timeout:t.timeout,retries:t.retries,debounce:t.debounce,paramKey:t.paramKey,virtual:!0})},async()=>{a||i!==void 0?(await this.registry.unregister(o).catch(()=>{}),this.cache.delete(o),this.watchers.delete(o)):this.cache.invalidatePackage(o),this.listeners.delete(o)},{gracePeriod:a&&i===void 0?`sync`:r}),l,u={id:o,get count(){return c.subscribers},get:(t=!1)=>c.subscribers===0&&!t?p:this.cache.package(o,(e,t)=>this.container.invalidate(o,e,t),e),resolve:()=>l||(l=(async()=>{await c.acquire();try{return await this.container.resolve(o)}finally{c.release(),l=void 0}})(),l),subscribe:(e,t=!0)=>{let n=()=>e(u.get());return c.acquire().then(()=>{this.container.resolve(o).then(()=>{this.listeners.has(o)||this.listeners.set(o,new Set),t&&n(),this.listeners.get(o).add(n)})}).catch(e=>{this.logger.error(`Resolution failed for "${o}"`,e),this.listeners.get(o)?.add(n)}),()=>{this.listeners.get(o)?.delete(n),c.release()}}};return this.watchers.set(o,{resource:c,observer:u}),u}evictWatcher(e){[e,f(e)].forEach(e=>{let t=this.watchers.get(e);t&&(t.resource.forceCleanup(),this.watchers.delete(e))})}notify(e){let t=this.listeners.get(e);if(!(!t||t.size===0))for(let n of t)try{n()}catch(t){this.logger.error(`Listener error for "${e}"`,t)}}hasWatchers(e){return this.watchers.has(e)||this.watchers.has(f(e))}getWatcherCount(e){return(this.watchers.get(e)||this.watchers.get(f(e)))?.resource.subscribers??0}clear(){this.watchers.clear(),this.listeners.clear()}};let R=function(e){return e.Singleton=`singleton`,e.Transient=`transient`,e}({});var z=class{artifacts=new Map;register({key:e,factory:t,lazy:n,...r}){let{scope:i,...a}=r,o={key:e,factory:t,scope:r.scope??`singleton`,lazy:n===void 0?!0:n,...a};return this.artifacts.set(e,o),()=>this.unregister(e)}setVirtual(e,t){this.artifacts.set(e,t)}get(e){if(!this.has(e))throw S(String(e));return this.artifacts.get(e)}getByString(e){return this.artifacts.get(e)}has(e){return this.artifacts.has(e)}hasString(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()}},B=class n{registry;cache;graph;manager;observer;logger;store;events;constructor(e,t){this.logger=t?.logger??new l([new c],{module:`artifacts`}),this.store={watch:(...t)=>e.watch(...t),get:()=>e.get(!0),set:(...t)=>e.set(...t),subset:(...t)=>e.subset(...t)},this.events=s({errorHandler:e=>this.logger.error(`Lifecycle event error`,e)}),this.registry=new z,this.cache=new g,this.graph=new y,this.observer=new L(this.registry,this.cache,this,this.logger),this.manager=new I(this.registry,this.cache,this.graph,this.store,this.observer,this.logger,this.events)}debugInfo(){let e=[];return this.registry.keys().forEach(t=>{let n=t,r=this.registry.getByString(n),i=this.cache.get(n);if(!r)return;let a=`idle`;i&&(i.scope===`singleton`&&i.debounceTimer!==void 0?a=`debouncing`:i.scope===`singleton`&&i.buildOnce.running()?a=`building`:i.error?a=`error`:i.instance!==void 0&&(a=`active`)),e.push({id:n,scope:r.scope??`singleton`,status:a,dependencies:this.graph.getDependencies(n).map(e=>String(e)),dependents:this.graph.getDependents(n).map(e=>String(e)),stateDependencies:i?.scope===`singleton`?Array.from(i.stateDependencies):[],buildCount:i?.buildCount??0})}),e}register(e){let{key:t}=e,n=t;this.registry.has(t)&&(this.logger.warn(`Overwriting artifact "${n}".`),this.manager.dispose(t).catch(e=>{this.logger.error(`Failed to dispose existing artifact "${n}"`,e)})),this.registry.register(e),this.graph.registerNode(t);let r=e.scope??`singleton`,i=e.lazy??!0;return this.events.emit({name:`artifact:registered`,payload:{key:n,scope:r}}),!i&&r===`singleton`&&this.resolve(t).catch(e=>{this.logger.error(`Eager load failed for "${n}"`,e)}),()=>this.unregister(t)}has(e){return this.registry.has(e)}async unregister(e,t){let n=t===void 0?e:this.manager.computeParamKey(e,t);await this.manager.dispose(n),await this.registry.unregister(n),this.observer.evictWatcher(n)}async resolve(e,t){return t===void 0?this.manager.resolveStatic(e):this.manager.resolveParameterized(e,t)}async require(e,t){let n=await this.resolve(e,t);if(n.error)throw n.error;return n.instance}watch(e,t,n){return t===void 0?this.observer.watch(e,n):this.observer.watchParameterized(e,t,n)}peek(e,t){let n=t===void 0?e:this.manager.computeParamKey(e,t);return this.cache.get(n)?.instance}async invalidate(e,t){let n=t?.params,r=t?.replace??!1,i=n===void 0?e:this.manager.computeParamKey(e,n);return this.manager.invalidate(i,r)}on(e,t){return this.events.subscribe(e,t)}once(e,t){return this.events.once(e,t)}notifyObservers(e){this.observer.notify(e)}hasWatchers(e){return this.observer.hasWatchers(e)}async dispose(){let e=this.registry.keys();await Promise.allSettled(e.map(e=>this.manager.dispose(e).catch(t=>{this.logger.error(`Failed to dispose artifact "${String(e)}"`,t)}))),this.registry.clear(),this.cache.clear(),this.graph.clear(),this.observer.clear(),this.events.emit({name:`container:dispose`,payload:{}}),this.events.clear({permanent:!0})}async export(){let e=[];for(let t of this.cache.keys()){let n=this.cache.get(t);if(!n||n.scope!==`singleton`||n.instance===void 0)continue;let r=new Set;for(let e of n.stateGroups)for(let t of e.paths)r.add(t);let i=Array.from(r).sort(),a=this.store.subset(i),o=await h(JSON.stringify(a,Object.keys(a).sort())),s;try{s=structuredClone(n.instance)}catch{throw N(t)}e.push({key:t,instance:s,state:{groups:n.stateGroups.map(e=>({paths:e.paths,options:e.options})),hash:o},dependencies:Array.from(n.artifactDependencies)})}let t={version:`1.0`,timestamp:Date.now(),artifacts:e},n=await h(JSON.stringify(t));return{...t,checksum:n}}async restore(n){let{checksum:r,...i}=n;if(await h(JSON.stringify(i))!==r)throw M(`Bundle checksum mismatch – data corrupted`);if(n.version!==`1.0`)throw M(`Unsupported bundle version: ${n.version}`);let a=new Map;for(let e of n.artifacts)a.set(e.key,e);let o=new Set,s=new Map;for(let e of n.artifacts)for(let t of e.dependencies)s.has(t)||s.set(t,new Set),s.get(t).add(e.key);let c=async e=>{let t=new Set;for(let n of e.state.groups)for(let e of n.paths)t.add(e);let n=Array.from(t).sort(),r=this.store.subset(n);return h(JSON.stringify(r,Object.keys(r).sort()))};for(let e of n.artifacts)await c(e)!==e.state.hash&&o.add(e.key);let l=Array.from(o);for(;l.length;){let e=l.shift(),t=s.get(e);if(t)for(let e of t)o.has(e)||(o.add(e),l.push(e))}for(let r of n.artifacts){if(o.has(r.key))continue;this.cache.get(r.key)&&await this.cache.invalidateInstance(r.key,!1);let n={scope:`singleton`,instance:r.instance,error:void 0,version:1,cleanupFunctions:[],disposeFunctions:[],buildCount:0,stateDependencies:new Set(r.state.groups.flatMap(e=>e.paths)),activeDebounceMs:0,buildOnce:new e({retry:!0,throws:!0}),streamSerializer:new t({yieldMode:`microtask`}),invalidationSerializer:new t({yieldMode:`macrotask`}),stateUnsubscribe:void 0,debounceTimer:void 0,controller:new AbortController,streamOnce:new e({retry:!0,throws:!0}),stream:void 0,stateGroups:r.state.groups,artifactDependencies:new Set(r.dependencies)};n.buildOnce.resolve(r.instance),this.cache.set(r.key,n);let i=[];for(let e of r.state.groups){let t=this.store.watch(e.paths,()=>this.invalidate(r.key),e.options);i.push(t)}n.stateUnsubscribe=()=>{for(let e of i)e()},this.graph.setDependencies(r.key,r.dependencies)}}static async from(e){let t=new n(e.store,{logger:e.logger});if(e.bundle){if(typeof e.bundle!=`object`||!e.bundle.version||!Array.isArray(e.bundle.artifacts))throw M(`Invalid bundle: missing version or artifacts array`);await t.restore(e.bundle)}for(let n of e.templates)t.register(n);return t}};export{B as ArtifactContainer,R as ArtifactScopes,b as ErrorCodes,P as SupersededBuildError,a as SystemError,S as artifactNotFound,j as buildStaleAfterRetries,C as cycleDetected,w as illegalScope,N as invalidExport,M as invalidImport,D as keyConflict,O as notParameterized,k as paramKeyCollision,A as selfDependency,E as timeoutError,T as watcherDisposed};
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-artifacts",
3
- "version": "8.2.13",
3
+ "version": "8.2.15",
4
4
  "description": "Reactive artifact container.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
7
7
  "types": "index.d.ts",
8
8
  "dependencies": {
9
- "@asaidimu/utils-events": "^1.0.0",
9
+ "@asaidimu/utils-events": "^1.2.4",
10
10
  "@asaidimu/utils-error": "^1.0.0",
11
- "@asaidimu/utils-logger": "^1.0.4",
12
- "@asaidimu/utils-sync": "^1.0.0",
13
- "@asaidimu/utils-store": "^10.2.5"
11
+ "@asaidimu/utils-logger": "^1.0.6",
12
+ "@asaidimu/utils-sync": "^2.3.3",
13
+ "@asaidimu/utils-store": "^10.2.8"
14
14
  },
15
15
  "keywords": [
16
16
  "typescript",