@asaidimu/utils-store 2.3.2 → 2.3.3
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.js +1 -1
- package/index.mjs +1 -1
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./store"),t=require("./observability"),r=require("./types");Object.keys(e).forEach((function(t){"default"===t||Object.prototype.hasOwnProperty.call(exports,t)||Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})})),Object.keys(t).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return t[e]}})})),Object.keys(r).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return r[e]}})}));
|
|
1
|
+
"use strict";var e,t,s=require("uuid"),r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,d=(e,t,s)=>(s=null!=e?r(o(e)):{},((e,t,s,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let o of n(t))c.call(e,o)||o===s||i(e,o,{get:()=>t[o],enumerable:!(r=a(t,o))||r.enumerable});return e})(e&&e.__esModule?s:i(s,"default",{value:e,enumerable:!0}),e)),h=(e={"node_modules/@asaidimu/events/index.js"(e,t){var s,r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var s in t)r(e,s,{get:t[s],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(s=o,((e,t,s,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of a(t))n.call(e,c)||c===s||r(e,c,{get:()=>t[c],enumerable:!(o=i(t,c))||o.enumerable});return e})(r({},"__esModule",{value:!0}),s));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let s=[],r=0,i=0;const a=new Map,n=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{r++,i+=t,a.set(e,(a.get(e)||0)+1)},d=()=>{const t=s;s=[],t.forEach((({name:t,payload:s})=>{const r=performance.now();try{(n.get(t)||[]).forEach((e=>e(s)))}catch(r){e.errorHandler({...r,eventName:t,payload:s})}c(t,performance.now()-r)}))},h=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(d,e.batchDelay)}})(),l=e=>{const s=t.get(e);s?n.set(e,Array.from(s)):n.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:s}=e.data;(n.get(t)||[]).forEach((e=>e(s)))}),{subscribe:(e,s)=>{t.has(e)||t.set(e,new Set);const r=t.get(e);return r.add(s),l(e),()=>{r.delete(s),0===r.size?(t.delete(e),n.delete(e)):l(e)}},emit:({name:t,payload:r})=>{if(e.async)return s.push({name:t,payload:r}),s.length>=e.batchSize?d():h(),void(o&&o.postMessage({name:t,payload:r}));const i=performance.now();try{(n.get(t)||[]).forEach((e=>e(r))),o&&o.postMessage({name:t,payload:r})}catch(s){e.errorHandler({...s,eventName:t,payload:r})}c(t,performance.now()-i)},getMetrics:()=>({totalEvents:r,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:a,averageEmitDuration:r>0?i/r:0}),clear:()=>{t.clear(),n.clear(),s=[],r=0,i=0,a.clear(),o&&(o.close(),o=null)}}}}},function(){return t||(0,e[n(e)[0]])((t={exports:{}}).exports,t),t.exports}),l=d(h()),u=Symbol.for("delete"),p=e=>Array.isArray(e)?[...e]:{...e};function m(e){const t=e?.deleteMarker||u;return function(e,s){if("object"!=typeof e||null===e)return"object"==typeof s&&null!==s?a(s):s===t?{}:s;if("object"!=typeof s||null===s)return e;const r=p(e),i=[{target:r,source:s}];for(;i.length>0;){const{target:e,source:s}=i.pop();for(const r of Object.keys(s)){if(!Object.prototype.hasOwnProperty.call(s,r))continue;const n=s[r];n!==t?Array.isArray(n)?e[r]=n.map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e===t?void 0:e:a(e))):"object"==typeof n&&null!==n?(e[r]=p(r in e&&"object"==typeof e[r]&&null!==e[r]?e[r]:{}),i.push({target:e[r],source:n})):e[r]=n:delete e[r]}}return r;function a(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e===t?void 0:e:a(e)));if("object"==typeof e){const s={};for(const[r,i]of Object.entries(e))if(i!==t)if("object"==typeof i&&null!==i){const e=a(i);void 0!==e&&(s[r]=e)}else s[r]=i;return s}return e===t?void 0:e}}}function g(e,t){if(e===t)return!0;if(e&&t&&"object"==typeof e&&"object"==typeof t){if(e.constructor!==t.constructor)return!1;let s,r;if(Array.isArray(e)){if(s=e.length,s!=t.length)return!1;for(r=s;r-- >0;)if(!g(e[r],t[r]))return!1;return!0}const i=Object.keys(e);if(s=i.length,s!==Object.keys(t).length)return!1;for(r=s;r-- >0;){const s=i[r];if(!Object.prototype.hasOwnProperty.call(t,s)||!g(e[s],t[s]))return!1}return!0}return e!=e&&t!=t}function f(e){const t=e?.deleteMarker||u;return function(e,s){const r=new Set,i=[{pathArray:[],pathStr:"",orig:e||{},part:s||{}}];for(;i.length>0;){const{pathArray:e,pathStr:s,orig:a,part:n}=i.pop();if(null!=n&&!g(a,n))if("object"!=typeof n||Array.isArray(n))s&&r.add(s);else for(const o of Object.keys(n)){const c=[...e,o],d=s?s+"."+o:o,h=n[o],l=a&&"object"==typeof a?a[o]:void 0;h!==t?"object"==typeof h&&null!==h?i.push({pathArray:c,pathStr:d,orig:l,part:h}):g(l,h)||r.add(d):void 0===l&&a&&"object"==typeof a||r.add(d)}}const a=new Set(r);for(const e of r){let t=e.lastIndexOf(".");for(;t>0;){const s=e.slice(0,t);if(a.has(s))break;a.add(s),t=e.lastIndexOf(".",t-1)}}return Array.from(a)}}m(),f();var y=class{constructor(e,t,s){this.updateBus=t,this.diff=s,this.cache=structuredClone(e)}cache;get(e){return e?structuredClone(this.cache):this.cache}applyChanges(e){const t=this.diff(this.get(!0),e);return t.length>0&&(this.cache=structuredClone(e),this.notifyListeners(t)),t}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}};d(h());var w=class{constructor(e,t,s){this.eventBus=e,this.executionState=t,this.merge=s}middleware=[];blockingMiddleware=[];async executeBlocking(e,t){for(const{fn:s,name:r,id:i}of this.blockingMiddleware){const a={id:i,name:r,startTime:performance.now()};this.executionState.runningMiddleware={id:i,name:r,startTime:performance.now()},this.emitMiddlewareLifecycle("start",{id:i,name:r,type:"blocking"});try{const n=await Promise.resolve(s(e,t));if(a.endTime=performance.now(),a.duration=a.endTime-a.startTime,!1===n)return a.blocked=!0,this.emitMiddlewareLifecycle("blocked",{id:i,name:r,duration:a.duration}),this.emit(this.eventBus,{name:"middleware:executed",payload:a}),{blocked:!0};this.emitMiddlewareLifecycle("complete",{id:i,name:r,type:"blocking",duration:a.duration}),this.emit(this.eventBus,{name:"middleware:executed",payload:{...a,blocked:!1}})}catch(e){return a.endTime=performance.now(),a.duration=a.endTime-a.startTime,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.emitMiddlewareError(i,r,a.error,a.duration),this.emit(this.eventBus,{name:"middleware:executed",payload:a}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async executeTransform(e,t){let s=e,r=t;for(const{fn:e,name:i,id:a}of this.middleware){const n={id:a,name:i,startTime:performance.now()};this.executionState.runningMiddleware={id:a,name:i,startTime:performance.now()},this.emitMiddlewareLifecycle("start",{id:a,name:i,type:"transform"});try{const o=await Promise.resolve(e(s,t));n.endTime=performance.now(),n.duration=n.endTime-n.startTime,n.blocked=!1,o&&"object"==typeof o&&(s=this.merge(s,o),r=this.merge(r,o)),this.emit(this.eventBus,{name:"middleware:executed",payload:n}),this.emitMiddlewareLifecycle("complete",{id:a,name:i,type:"transform",duration:n.duration})}catch(e){n.endTime=performance.now(),n.duration=n.endTime-n.startTime,n.error=e instanceof Error?e:new Error(String(e)),n.blocked=!1,this.emit(this.eventBus,{name:"middleware:executed",payload:n}),this.emitMiddlewareError(a,i,n.error,n.duration),console.error(`Middleware ${i} error:`,e)}finally{this.executionState.runningMiddleware=null}}return r}addMiddleware(e,t="unnamed-middleware"){const s=this.generateId();return this.middleware.push({fn:e,name:t,id:s}),this.updateExecutionState(),s}addBlockingMiddleware(e,t="unnamed-blocking-middleware"){const s=this.generateId();return this.blockingMiddleware.push({fn:e,name:t,id:s}),this.updateExecutionState(),s}removeMiddleware(e){const t=this.middleware.length+this.blockingMiddleware.length;return this.middleware=this.middleware.filter((t=>t.id!==e)),this.blockingMiddleware=this.blockingMiddleware.filter((t=>t.id!==e)),this.updateExecutionState(),this.middleware.length+this.blockingMiddleware.length<t}updateExecutionState(){this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))]}emitMiddlewareLifecycle(e,t){this.emit(this.eventBus,{name:`middleware:${e}`,payload:{...t,timestamp:Date.now()}})}emitMiddlewareError(e,t,s,r){this.emit(this.eventBus,{name:"middleware:error",payload:{id:e,name:t,error:s,duration:r,timestamp:Date.now()}})}generateId(){return crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var b=class{constructor(e,t,s,r){this.eventBus=e,this.coreState=t,this.instanceID=s,this.maxRetries=r?.maxRetries??3,this.retryDelay=r?.retryDelay??1e3}persistence;instanceID;persistenceReady=!1;backgroundQueue=[];isProcessingQueue=!1;maxRetries=3;retryDelay=1e3;queueProcessor;async initialize(e){e?await this.setPersistence(e):this.setPersistenceReady()}isReady(){return this.persistenceReady}handleStateChange(e,t){if(!this.persistence||0===e.length)return;const s={id:`${Date.now()}-${Math.random().toString(36).substr(2,9)}`,state:structuredClone(t),changedPaths:[...e],timestamp:Date.now(),retries:0};this.backgroundQueue.push(s),this.scheduleQueueProcessing(),this.emit(this.eventBus,{name:"persistence:queued",payload:{taskId:s.id,changedPaths:e,queueSize:this.backgroundQueue.length,timestamp:s.timestamp}})}getQueueStatus(){return{queueSize:this.backgroundQueue.length,isProcessing:this.isProcessingQueue,oldestTask:this.backgroundQueue[0]?.timestamp}}async flush(){this.isProcessingQueue||await this.processQueue()}clearQueue(){const e=this.backgroundQueue.length;this.backgroundQueue=[],this.queueProcessor&&(clearTimeout(this.queueProcessor),this.queueProcessor=void 0),this.emit(this.eventBus,{name:"persistence:queue_cleared",payload:{clearedTasks:e,timestamp:Date.now()}})}scheduleQueueProcessing(){this.queueProcessor||this.isProcessingQueue||(this.queueProcessor=setTimeout((()=>{this.processQueue().catch((e=>{console.error("Queue processing failed:",e)}))}),10))}async processQueue(){if(!this.isProcessingQueue&&0!==this.backgroundQueue.length){this.isProcessingQueue=!0,this.queueProcessor=void 0;try{for(;this.backgroundQueue.length>0;){const e=this.backgroundQueue.shift();await this.processTask(e)}}finally{this.isProcessingQueue=!1}}}async processTask(e){try{await this.persistence.set(this.instanceID,e.state)?this.emit(this.eventBus,{name:"persistence:success",payload:{taskId:e.id,changedPaths:e.changedPaths,duration:Date.now()-e.timestamp,timestamp:Date.now()}}):await this.handleTaskFailure(e,new Error("Persistence returned false"))}catch(t){await this.handleTaskFailure(e,t)}}async handleTaskFailure(e,t){if(e.retries++,e.retries<=this.maxRetries){const s=this.retryDelay*Math.pow(2,e.retries-1);this.emit(this.eventBus,{name:"persistence:retry",payload:{taskId:e.id,attempt:e.retries,maxRetries:this.maxRetries,nextRetryIn:s,error:t,timestamp:Date.now()}}),setTimeout((()=>{this.backgroundQueue.unshift(e),this.scheduleQueueProcessing()}),s)}else this.emit(this.eventBus,{name:"persistence:failed",payload:{taskId:e.id,changedPaths:e.changedPaths,attempts:e.retries,error:t,timestamp:Date.now()}})}setPersistenceReady(){this.persistenceReady=!0,this.emit(this.eventBus,{name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&this.coreState.applyChanges(e)}catch(e){console.error("Failed to initialize persistence:",e),this.emit(this.eventBus,{name:"persistence:init_error",payload:{error:e,timestamp:Date.now()}})}finally{this.setPersistenceReady()}this.persistence.subscribe&&this.persistence.subscribe(this.instanceID,(async e=>{const t=this.coreState.applyChanges(e);t.length>0&&this.emit(this.eventBus,{name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}})}))}dispose(){this.clearQueue(),this.isProcessingQueue=!1,this.persistenceReady=!1}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var v=class{constructor(e,t,s){this.eventBus=e,this.coreState=t,this.executionState=s}async execute(e){const t=this.coreState.get(!0);this.executionState.transactionActive=!0,this.emit(this.eventBus,{name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.emit(this.eventBus,{name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.coreState.applyChanges(t),this.emit(this.eventBus,{name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var x=class{updateCount=0;listenerExecutions=0;averageUpdateTime=0;largestUpdateSize=0;mostActiveListenerPaths=[];totalUpdates=0;blockedUpdates=0;averageUpdateDuration=0;middlewareExecutions=0;transactionCount=0;totalEventsFired=0;updateTimes=[];pathExecutionCounts=new Map;constructor(e){this.setupEventListeners(e)}getMetrics(){return{updateCount:this.updateCount,listenerExecutions:this.listenerExecutions,averageUpdateTime:this.averageUpdateTime,largestUpdateSize:this.largestUpdateSize,mostActiveListenerPaths:[...this.mostActiveListenerPaths],totalUpdates:this.totalUpdates,blockedUpdates:this.blockedUpdates,averageUpdateDuration:this.averageUpdateDuration,middlewareExecutions:this.middlewareExecutions,transactionCount:this.transactionCount,totalEventsFired:this.totalEventsFired}}setupEventListeners(e){const t=e.emit;e.emit=s=>(this.totalEventsFired++,t.call(e,s)),e.subscribe("update:complete",(e=>{if(this.totalUpdates++,e.blocked)this.blockedUpdates++;else{if(e.duration){this.updateTimes.push(e.duration),this.updateTimes.length>100&&this.updateTimes.shift();const t=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length;this.averageUpdateTime=t,this.averageUpdateDuration=t}e.changedPaths?.length&&(this.updateCount++,this.largestUpdateSize=Math.max(this.largestUpdateSize,e.changedPaths.length),e.changedPaths.forEach((e=>{const t=this.pathExecutionCounts.get(e)||0;this.pathExecutionCounts.set(e,t+1)})),this.mostActiveListenerPaths=Array.from(this.pathExecutionCounts.entries()).sort((([,e],[,t])=>t-e)).slice(0,5).map((([e])=>e)))}})),e.subscribe("middleware:start",(()=>{this.middlewareExecutions++})),e.subscribe("transaction:start",(()=>{this.transactionCount++}))}reset(){this.updateCount=0,this.listenerExecutions=0,this.averageUpdateTime=0,this.largestUpdateSize=0,this.mostActiveListenerPaths=[],this.totalUpdates=0,this.blockedUpdates=0,this.averageUpdateDuration=0,this.middlewareExecutions=0,this.transactionCount=0,this.totalEventsFired=0,this.updateTimes=[],this.pathExecutionCounts.clear()}getDetailedMetrics(){return{pathExecutionCounts:new Map(this.pathExecutionCounts),recentUpdateTimes:[...this.updateTimes],successRate:this.totalUpdates>0?(this.totalUpdates-this.blockedUpdates)/this.totalUpdates:1,averagePathsPerUpdate:this.updateCount>0?Array.from(this.pathExecutionCounts.values()).reduce(((e,t)=>e+t),0)/this.updateCount:0}}dispose(){this.reset()}},E=f();exports.DELETE_SYMBOL=u,exports.ReactiveDataStore=class{coreState;middlewareEngine;persistenceHandler;transactionManager;metricsCollector;pendingUpdates=[];isUpdating=!1;updateBus=(0,l.createEventBus)();eventBus=(0,l.createEventBus)();executionState;instanceID=s.v4();merge;diff;constructor(e,t,s=u,r){this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.merge=m({deleteMarker:s}),this.diff=f({deleteMarker:s}),this.coreState=new y(e,this.updateBus,this.diff),this.middlewareEngine=new w(this.eventBus,this.executionState,this.merge),this.persistenceHandler=new b(this.eventBus,this.coreState,this.instanceID,{maxRetries:r?.persistenceMaxRetries,retryDelay:r?.persistenceRetryDelay}),this.transactionManager=new v(this.eventBus,this.coreState,this.executionState),this.metricsCollector=new x(this.eventBus),this.persistenceHandler.initialize(t)}isReady(){return this.persistenceHandler.isReady()}state(){return this.executionState}get(e){return this.coreState.get(e)}async set(e){if(this.isUpdating)return this.pendingUpdates.push(e),void(this.executionState.pendingChanges=[...this.pendingUpdates]);this.isUpdating=!0,this.executionState.executing=!0;const t=performance.now();this.emit(this.eventBus,{name:"update:start",payload:{timestamp:t}});try{let s=e;if("function"==typeof e){const t=e(this.get(!0));s=t instanceof Promise?await t:t}const r=await this.middlewareEngine.executeBlocking(this.get(),s);if(r.blocked)return void this.emit(this.eventBus,{name:"update:complete",payload:{blocked:!0,error:r.error,timestamp:Date.now()}});const i=this.merge(this.get(!0),s),a=await this.middlewareEngine.executeTransform(i,s),n=this.merge(this.get(!0),a),o=this.coreState.applyChanges(n),c=performance.now();this.emit(this.eventBus,{name:"update:complete",payload:{changedPaths:o,duration:c-t,timestamp:Date.now()}}),o.length>0&&this.persistenceHandler.handleStateChange(o,this.get())}catch(e){throw this.emit(this.eventBus,{name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}finally{if(this.isUpdating=!1,this.executionState.executing=!1,this.executionState.changes=null,this.executionState.runningMiddleware=null,this.pendingUpdates.length>0){const e=this.pendingUpdates.shift();if(this.executionState.pendingChanges=[...this.pendingUpdates],e)return this.set(e)}}}subscribe(e,t){const s=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(r=>{(s.includes(r)||""===e)&&(t(this.get(!0)),this.metricsCollector.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){return this.transactionManager.execute(e)}use(e){return e.block?this.middlewareEngine.addBlockingMiddleware(e.action,e.name):this.middlewareEngine.addMiddleware(e.action,e.name)}unuse(e){return this.middlewareEngine.removeMiddleware(e)}metrics(){return this.metricsCollector.getMetrics()}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}getPersistenceStatus(){return this.persistenceHandler.getQueueStatus()}async flushPersistence(){return this.persistenceHandler.flush()}clearPersistenceQueue(){this.persistenceHandler.clearQueue()}dispose(){this.persistenceHandler.dispose(),this.metricsCollector.dispose?.()}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}},exports.StoreObserver=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;middlewareExecutions=[];constructor(e,t={}){this.store=e,this.maxEvents=t.maxEvents??500,this.maxStateHistory=t.maxStateHistory??20,this.enableConsoleLogging=t.enableConsoleLogging??!1,this.logEvents={updates:t.logEvents?.updates??!0,middleware:t.logEvents?.middleware??!0,transactions:t.logEvents?.transactions??!0},this.performanceThresholds={updateTime:t.performanceThresholds?.updateTime??50,middlewareTime:t.performanceThresholds?.middlewareTime??20},this.recordStateSnapshot(),this.setupEventListeners()}setupEventListeners(){const e=["update:start","update:complete","middleware:start","middleware:complete","middleware:error","middleware:blocked","transaction:start","transaction:complete","transaction:error","middleware:executed"];this.unsubscribers.push(this.store.subscribe("",(()=>{this.recordStateSnapshot()})));for(const t of e){const e=t.startsWith("update")&&this.logEvents.updates||t.startsWith("middleware")&&this.logEvents.middleware||t.startsWith("transaction")&&this.logEvents.transactions;this.unsubscribers.push(this.store.onStoreEvent(t,(s=>{"middleware:executed"===t?this.middlewareExecutions.push(s):"transaction:start"===t?this.activeTransactionCount++:"transaction:complete"!==t&&"transaction:error"!==t||(this.activeTransactionCount=Math.max(0,this.activeTransactionCount-1)),s.batchId&&(t.endsWith("start")?this.activeBatches.add(s.batchId):(t.endsWith("complete")||t.endsWith("error"))&&this.activeBatches.delete(s.batchId)),this.recordEvent(t,s),this.enableConsoleLogging&&e&&this.logEventToConsole(t,s),this.checkPerformance(t,s)})))}}recordStateSnapshot(){const e=structuredClone(this.store.get());this.stateHistory.length>0&&0===E(e,this.stateHistory[0]).length||(this.stateHistory.unshift(e),this.stateHistory.length>this.maxStateHistory&&this.stateHistory.pop())}recordEvent(e,t){const s={type:e,timestamp:Date.now(),data:structuredClone(t)};this.eventHistory.unshift(s),this.eventHistory.length>this.maxEvents&&this.eventHistory.pop()}logEventToConsole(e,t){const s=new Date(t.timestamp||Date.now()).toISOString().split("T")[1].replace("Z","");if("update:start"===e)console.group(`%c⚡ Store Update Started [${s}]`,"color: #4a6da7");else if("update:complete"===e){if(t.blocked)console.warn(`%c✋ Update Blocked [${s}]`,"color: #bf8c0a",t.error);else{const e=t.changedPaths||[];e.length>0&&console.log(`%c✅ Update Complete [${s}] - ${e.length} paths changed in ${t.duration?.toFixed(2)}ms`,"color: #2a9d8f",e)}console.groupEnd()}else"middleware:start"===e?console.debug(`%c◀ Middleware "${t.name}" started [${s}] (${t.type})`,"color: #8c8c8c"):"middleware:complete"===e?console.debug(`%c▶ Middleware "${t.name}" completed [${s}] in ${t.duration?.toFixed(2)}ms`,"color: #7c9c7c"):"middleware:error"===e?console.error(`%c❌ Middleware "${t.name}" error [${s}]:`,"color: #e63946",t.error):"middleware:blocked"===e?console.warn(`%c🛑 Middleware "${t.name}" blocked update [${s}]`,"color: #e76f51"):"transaction:start"===e?console.group(`%c📦 Transaction Started [${s}]`,"color: #6d597a"):"transaction:complete"===e?(console.log(`%c📦 Transaction Complete [${s}]`,"color: #355070"),console.groupEnd()):"transaction:error"===e&&(console.error(`%c📦 Transaction Error [${s}]:`,"color: #e56b6f",t.error),console.groupEnd())}checkPerformance(e,t){this.enableConsoleLogging&&("update:complete"===e&&!t.blocked&&t.duration>this.performanceThresholds.updateTime&&console.warn(`%c⚠️ Slow update detected [${t.duration.toFixed(2)}ms]`,"color: #ff9f1c",{changedPaths:t.changedPaths,threshold:this.performanceThresholds.updateTime}),"middleware:complete"===e&&t.duration>this.performanceThresholds.middlewareTime&&console.warn(`%c⚠️ Slow middleware "${t.name}" [${t.duration.toFixed(2)}ms]`,"color: #ff9f1c",{threshold:this.performanceThresholds.middlewareTime}))}getEventHistory(){return structuredClone(this.eventHistory)}getStateHistory(){return structuredClone(this.stateHistory)}getMiddlewareExecutions(){return this.middlewareExecutions}getPerformanceMetrics(){return this.store.metrics()}getTransactionStatus(){return{activeTransactions:this.activeTransactionCount,activeBatches:Array.from(this.activeBatches)}}createLoggingMiddleware(e={}){const{logLevel:t="debug",logUpdates:s=!0}=e;return(e,r)=>{if(s){(console[t]||console.log)("State Update:",r)}return r}}createValidationMiddleware(e){return(t,s)=>{const r=e(t,s);return"boolean"==typeof r?r:(!r.valid&&r.reason&&console.warn("Validation failed:",r.reason),r.valid)}}clearHistory(){if(this.eventHistory=[],this.stateHistory.length>0){const e=this.stateHistory[0];this.stateHistory=[e]}}getRecentChanges(e=5){const t=[],s=Math.min(e,this.stateHistory.length-1);for(let e=0;e<s;e++){const s=this.stateHistory[e],r=this.stateHistory[e+1],i=E(r,s),a={},n={};for(const e of i){const t=e.split("."),i=(e,t)=>t.reduce(((e,t)=>e&&void 0!==e[t]?e[t]:void 0),e),o=(e,t,s)=>{const r=t.length-1,i=t[r];t.slice(0,r).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[i]=s},c=i(r,t),d=i(s,t);o(a,t,c),o(n,t,d)}let o=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){o=e.timestamp;break}0!==i.length&&t.push({timestamp:o,changedPaths:i,from:a,to:n})}return t}createTimeTravel(){let e=0,t=[];return{canUndo:()=>e<this.stateHistory.length-1,canRedo:()=>t.length>0,undo:async()=>{if(e<this.stateHistory.length-1){const s=e+1,r=this.stateHistory[s];t.unshift(this.stateHistory[e]),e=s,await this.store.set(r)}},redo:async()=>{if(t.length>0){const s=t.shift();e=Math.max(0,e-1),await this.store.set(s)}},getHistoryLength:()=>this.stateHistory.length,clear:()=>{t=[],e=0}}}disconnect(){this.unsubscribers.forEach((e=>e())),this.unsubscribers=[],this.clearHistory()}},exports.author="https://github.com/asaidimu";
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./store";export*from"./observability";export*from"./types";
|
|
1
|
+
import{v4 as e}from"uuid";var t,s,i=Object.create,r=Object.defineProperty,a=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,d=(e,t,s)=>(s=null!=e?i(o(e)):{},((e,t,s,i)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let o of n(t))c.call(e,o)||o===s||r(e,o,{get:()=>t[o],enumerable:!(i=a(t,o))||i.enumerable});return e})(e&&e.__esModule?s:r(s,"default",{value:e,enumerable:!0}),e)),h=(t={"node_modules/@asaidimu/events/index.js"(e,t){var s,i=Object.defineProperty,r=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,o={};((e,t)=>{for(var s in t)i(e,s,{get:t[s],enumerable:!0})})(o,{createEventBus:()=>c}),t.exports=(s=o,((e,t,s,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of a(t))n.call(e,c)||c===s||i(e,c,{get:()=>t[c],enumerable:!(o=r(t,c))||o.enumerable});return e})(i({},"__esModule",{value:!0}),s));var c=(e={async:!1,batchSize:1e3,batchDelay:16,errorHandler:e=>console.error("EventBus Error:",e),crossTab:!1,channelName:"event-bus-channel"})=>{const t=new Map;let s=[],i=0,r=0;const a=new Map,n=new Map;let o=null;e.crossTab&&"undefined"!=typeof BroadcastChannel?o=new BroadcastChannel(e.channelName):e.crossTab&&console.warn("BroadcastChannel is not supported in this browser. Cross-tab notifications are disabled.");const c=(e,t)=>{i++,r+=t,a.set(e,(a.get(e)||0)+1)},d=()=>{const t=s;s=[],t.forEach((({name:t,payload:s})=>{const i=performance.now();try{(n.get(t)||[]).forEach((e=>e(s)))}catch(i){e.errorHandler({...i,eventName:t,payload:s})}c(t,performance.now()-i)}))},h=(()=>{let t;return()=>{clearTimeout(t),t=setTimeout(d,e.batchDelay)}})(),l=e=>{const s=t.get(e);s?n.set(e,Array.from(s)):n.delete(e)};return o&&(o.onmessage=e=>{const{name:t,payload:s}=e.data;(n.get(t)||[]).forEach((e=>e(s)))}),{subscribe:(e,s)=>{t.has(e)||t.set(e,new Set);const i=t.get(e);return i.add(s),l(e),()=>{i.delete(s),0===i.size?(t.delete(e),n.delete(e)):l(e)}},emit:({name:t,payload:i})=>{if(e.async)return s.push({name:t,payload:i}),s.length>=e.batchSize?d():h(),void(o&&o.postMessage({name:t,payload:i}));const r=performance.now();try{(n.get(t)||[]).forEach((e=>e(i))),o&&o.postMessage({name:t,payload:i})}catch(s){e.errorHandler({...s,eventName:t,payload:i})}c(t,performance.now()-r)},getMetrics:()=>({totalEvents:i,activeSubscriptions:Array.from(t.values()).reduce(((e,t)=>e+t.size),0),eventCounts:a,averageEmitDuration:i>0?r/i:0}),clear:()=>{t.clear(),n.clear(),s=[],i=0,r=0,a.clear(),o&&(o.close(),o=null)}}}}},function(){return s||(0,t[n(t)[0]])((s={exports:{}}).exports,s),s.exports}),l=d(h()),u=Symbol.for("delete"),p="https://github.com/asaidimu",m=e=>Array.isArray(e)?[...e]:{...e};function g(e){const t=e?.deleteMarker||u;return function(e,s){if("object"!=typeof e||null===e)return"object"==typeof s&&null!==s?a(s):s===t?{}:s;if("object"!=typeof s||null===s)return e;const i=m(e),r=[{target:i,source:s}];for(;r.length>0;){const{target:e,source:s}=r.pop();for(const i of Object.keys(s)){if(!Object.prototype.hasOwnProperty.call(s,i))continue;const n=s[i];n!==t?Array.isArray(n)?e[i]=n.map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e===t?void 0:e:a(e))):"object"==typeof n&&null!==n?(e[i]=m(i in e&&"object"==typeof e[i]&&null!==e[i]?e[i]:{}),r.push({target:e[i],source:n})):e[i]=n:delete e[i]}}return i;function a(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==t)).map((e=>"object"!=typeof e||null===e||Array.isArray(e)?e===t?void 0:e:a(e)));if("object"==typeof e){const s={};for(const[i,r]of Object.entries(e))if(r!==t)if("object"==typeof r&&null!==r){const e=a(r);void 0!==e&&(s[i]=e)}else s[i]=r;return s}return e===t?void 0:e}}}function f(e,t){if(e===t)return!0;if(e&&t&&"object"==typeof e&&"object"==typeof t){if(e.constructor!==t.constructor)return!1;let s,i;if(Array.isArray(e)){if(s=e.length,s!=t.length)return!1;for(i=s;i-- >0;)if(!f(e[i],t[i]))return!1;return!0}const r=Object.keys(e);if(s=r.length,s!==Object.keys(t).length)return!1;for(i=s;i-- >0;){const s=r[i];if(!Object.prototype.hasOwnProperty.call(t,s)||!f(e[s],t[s]))return!1}return!0}return e!=e&&t!=t}function y(e){const t=e?.deleteMarker||u;return function(e,s){const i=new Set,r=[{pathArray:[],pathStr:"",orig:e||{},part:s||{}}];for(;r.length>0;){const{pathArray:e,pathStr:s,orig:a,part:n}=r.pop();if(null!=n&&!f(a,n))if("object"!=typeof n||Array.isArray(n))s&&i.add(s);else for(const o of Object.keys(n)){const c=[...e,o],d=s?s+"."+o:o,h=n[o],l=a&&"object"==typeof a?a[o]:void 0;h!==t?"object"==typeof h&&null!==h?r.push({pathArray:c,pathStr:d,orig:l,part:h}):f(l,h)||i.add(d):void 0===l&&a&&"object"==typeof a||i.add(d)}}const a=new Set(i);for(const e of i){let t=e.lastIndexOf(".");for(;t>0;){const s=e.slice(0,t);if(a.has(s))break;a.add(s),t=e.lastIndexOf(".",t-1)}}return Array.from(a)}}g(),y();var w=class{constructor(e,t,s){this.updateBus=t,this.diff=s,this.cache=structuredClone(e)}cache;get(e){return e?structuredClone(this.cache):this.cache}applyChanges(e){const t=this.diff(this.get(!0),e);return t.length>0&&(this.cache=structuredClone(e),this.notifyListeners(t)),t}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}};d(h());var b=class{constructor(e,t,s){this.eventBus=e,this.executionState=t,this.merge=s}middleware=[];blockingMiddleware=[];async executeBlocking(e,t){for(const{fn:s,name:i,id:r}of this.blockingMiddleware){const a={id:r,name:i,startTime:performance.now()};this.executionState.runningMiddleware={id:r,name:i,startTime:performance.now()},this.emitMiddlewareLifecycle("start",{id:r,name:i,type:"blocking"});try{const n=await Promise.resolve(s(e,t));if(a.endTime=performance.now(),a.duration=a.endTime-a.startTime,!1===n)return a.blocked=!0,this.emitMiddlewareLifecycle("blocked",{id:r,name:i,duration:a.duration}),this.emit(this.eventBus,{name:"middleware:executed",payload:a}),{blocked:!0};this.emitMiddlewareLifecycle("complete",{id:r,name:i,type:"blocking",duration:a.duration}),this.emit(this.eventBus,{name:"middleware:executed",payload:{...a,blocked:!1}})}catch(e){return a.endTime=performance.now(),a.duration=a.endTime-a.startTime,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.emitMiddlewareError(r,i,a.error,a.duration),this.emit(this.eventBus,{name:"middleware:executed",payload:a}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async executeTransform(e,t){let s=e,i=t;for(const{fn:e,name:r,id:a}of this.middleware){const n={id:a,name:r,startTime:performance.now()};this.executionState.runningMiddleware={id:a,name:r,startTime:performance.now()},this.emitMiddlewareLifecycle("start",{id:a,name:r,type:"transform"});try{const o=await Promise.resolve(e(s,t));n.endTime=performance.now(),n.duration=n.endTime-n.startTime,n.blocked=!1,o&&"object"==typeof o&&(s=this.merge(s,o),i=this.merge(i,o)),this.emit(this.eventBus,{name:"middleware:executed",payload:n}),this.emitMiddlewareLifecycle("complete",{id:a,name:r,type:"transform",duration:n.duration})}catch(e){n.endTime=performance.now(),n.duration=n.endTime-n.startTime,n.error=e instanceof Error?e:new Error(String(e)),n.blocked=!1,this.emit(this.eventBus,{name:"middleware:executed",payload:n}),this.emitMiddlewareError(a,r,n.error,n.duration),console.error(`Middleware ${r} error:`,e)}finally{this.executionState.runningMiddleware=null}}return i}addMiddleware(e,t="unnamed-middleware"){const s=this.generateId();return this.middleware.push({fn:e,name:t,id:s}),this.updateExecutionState(),s}addBlockingMiddleware(e,t="unnamed-blocking-middleware"){const s=this.generateId();return this.blockingMiddleware.push({fn:e,name:t,id:s}),this.updateExecutionState(),s}removeMiddleware(e){const t=this.middleware.length+this.blockingMiddleware.length;return this.middleware=this.middleware.filter((t=>t.id!==e)),this.blockingMiddleware=this.blockingMiddleware.filter((t=>t.id!==e)),this.updateExecutionState(),this.middleware.length+this.blockingMiddleware.length<t}updateExecutionState(){this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))]}emitMiddlewareLifecycle(e,t){this.emit(this.eventBus,{name:`middleware:${e}`,payload:{...t,timestamp:Date.now()}})}emitMiddlewareError(e,t,s,i){this.emit(this.eventBus,{name:"middleware:error",payload:{id:e,name:t,error:s,duration:i,timestamp:Date.now()}})}generateId(){return crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var v=class{constructor(e,t,s,i){this.eventBus=e,this.coreState=t,this.instanceID=s,this.maxRetries=i?.maxRetries??3,this.retryDelay=i?.retryDelay??1e3}persistence;instanceID;persistenceReady=!1;backgroundQueue=[];isProcessingQueue=!1;maxRetries=3;retryDelay=1e3;queueProcessor;async initialize(e){e?await this.setPersistence(e):this.setPersistenceReady()}isReady(){return this.persistenceReady}handleStateChange(e,t){if(!this.persistence||0===e.length)return;const s={id:`${Date.now()}-${Math.random().toString(36).substr(2,9)}`,state:structuredClone(t),changedPaths:[...e],timestamp:Date.now(),retries:0};this.backgroundQueue.push(s),this.scheduleQueueProcessing(),this.emit(this.eventBus,{name:"persistence:queued",payload:{taskId:s.id,changedPaths:e,queueSize:this.backgroundQueue.length,timestamp:s.timestamp}})}getQueueStatus(){return{queueSize:this.backgroundQueue.length,isProcessing:this.isProcessingQueue,oldestTask:this.backgroundQueue[0]?.timestamp}}async flush(){this.isProcessingQueue||await this.processQueue()}clearQueue(){const e=this.backgroundQueue.length;this.backgroundQueue=[],this.queueProcessor&&(clearTimeout(this.queueProcessor),this.queueProcessor=void 0),this.emit(this.eventBus,{name:"persistence:queue_cleared",payload:{clearedTasks:e,timestamp:Date.now()}})}scheduleQueueProcessing(){this.queueProcessor||this.isProcessingQueue||(this.queueProcessor=setTimeout((()=>{this.processQueue().catch((e=>{console.error("Queue processing failed:",e)}))}),10))}async processQueue(){if(!this.isProcessingQueue&&0!==this.backgroundQueue.length){this.isProcessingQueue=!0,this.queueProcessor=void 0;try{for(;this.backgroundQueue.length>0;){const e=this.backgroundQueue.shift();await this.processTask(e)}}finally{this.isProcessingQueue=!1}}}async processTask(e){try{await this.persistence.set(this.instanceID,e.state)?this.emit(this.eventBus,{name:"persistence:success",payload:{taskId:e.id,changedPaths:e.changedPaths,duration:Date.now()-e.timestamp,timestamp:Date.now()}}):await this.handleTaskFailure(e,new Error("Persistence returned false"))}catch(t){await this.handleTaskFailure(e,t)}}async handleTaskFailure(e,t){if(e.retries++,e.retries<=this.maxRetries){const s=this.retryDelay*Math.pow(2,e.retries-1);this.emit(this.eventBus,{name:"persistence:retry",payload:{taskId:e.id,attempt:e.retries,maxRetries:this.maxRetries,nextRetryIn:s,error:t,timestamp:Date.now()}}),setTimeout((()=>{this.backgroundQueue.unshift(e),this.scheduleQueueProcessing()}),s)}else this.emit(this.eventBus,{name:"persistence:failed",payload:{taskId:e.id,changedPaths:e.changedPaths,attempts:e.retries,error:t,timestamp:Date.now()}})}setPersistenceReady(){this.persistenceReady=!0,this.emit(this.eventBus,{name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&this.coreState.applyChanges(e)}catch(e){console.error("Failed to initialize persistence:",e),this.emit(this.eventBus,{name:"persistence:init_error",payload:{error:e,timestamp:Date.now()}})}finally{this.setPersistenceReady()}this.persistence.subscribe&&this.persistence.subscribe(this.instanceID,(async e=>{const t=this.coreState.applyChanges(e);t.length>0&&this.emit(this.eventBus,{name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}})}))}dispose(){this.clearQueue(),this.isProcessingQueue=!1,this.persistenceReady=!1}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var x=class{constructor(e,t,s){this.eventBus=e,this.coreState=t,this.executionState=s}async execute(e){const t=this.coreState.get(!0);this.executionState.transactionActive=!0,this.emit(this.eventBus,{name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.emit(this.eventBus,{name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.coreState.applyChanges(t),this.emit(this.eventBus,{name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}};d(h());var E=class{updateCount=0;listenerExecutions=0;averageUpdateTime=0;largestUpdateSize=0;mostActiveListenerPaths=[];totalUpdates=0;blockedUpdates=0;averageUpdateDuration=0;middlewareExecutions=0;transactionCount=0;totalEventsFired=0;updateTimes=[];pathExecutionCounts=new Map;constructor(e){this.setupEventListeners(e)}getMetrics(){return{updateCount:this.updateCount,listenerExecutions:this.listenerExecutions,averageUpdateTime:this.averageUpdateTime,largestUpdateSize:this.largestUpdateSize,mostActiveListenerPaths:[...this.mostActiveListenerPaths],totalUpdates:this.totalUpdates,blockedUpdates:this.blockedUpdates,averageUpdateDuration:this.averageUpdateDuration,middlewareExecutions:this.middlewareExecutions,transactionCount:this.transactionCount,totalEventsFired:this.totalEventsFired}}setupEventListeners(e){const t=e.emit;e.emit=s=>(this.totalEventsFired++,t.call(e,s)),e.subscribe("update:complete",(e=>{if(this.totalUpdates++,e.blocked)this.blockedUpdates++;else{if(e.duration){this.updateTimes.push(e.duration),this.updateTimes.length>100&&this.updateTimes.shift();const t=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length;this.averageUpdateTime=t,this.averageUpdateDuration=t}e.changedPaths?.length&&(this.updateCount++,this.largestUpdateSize=Math.max(this.largestUpdateSize,e.changedPaths.length),e.changedPaths.forEach((e=>{const t=this.pathExecutionCounts.get(e)||0;this.pathExecutionCounts.set(e,t+1)})),this.mostActiveListenerPaths=Array.from(this.pathExecutionCounts.entries()).sort((([,e],[,t])=>t-e)).slice(0,5).map((([e])=>e)))}})),e.subscribe("middleware:start",(()=>{this.middlewareExecutions++})),e.subscribe("transaction:start",(()=>{this.transactionCount++}))}reset(){this.updateCount=0,this.listenerExecutions=0,this.averageUpdateTime=0,this.largestUpdateSize=0,this.mostActiveListenerPaths=[],this.totalUpdates=0,this.blockedUpdates=0,this.averageUpdateDuration=0,this.middlewareExecutions=0,this.transactionCount=0,this.totalEventsFired=0,this.updateTimes=[],this.pathExecutionCounts.clear()}getDetailedMetrics(){return{pathExecutionCounts:new Map(this.pathExecutionCounts),recentUpdateTimes:[...this.updateTimes],successRate:this.totalUpdates>0?(this.totalUpdates-this.blockedUpdates)/this.totalUpdates:1,averagePathsPerUpdate:this.updateCount>0?Array.from(this.pathExecutionCounts.values()).reduce(((e,t)=>e+t),0)/this.updateCount:0}}dispose(){this.reset()}},S=class{coreState;middlewareEngine;persistenceHandler;transactionManager;metricsCollector;pendingUpdates=[];isUpdating=!1;updateBus=(0,l.createEventBus)();eventBus=(0,l.createEventBus)();executionState;instanceID=e();merge;diff;constructor(e,t,s=u,i){this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.merge=g({deleteMarker:s}),this.diff=y({deleteMarker:s}),this.coreState=new w(e,this.updateBus,this.diff),this.middlewareEngine=new b(this.eventBus,this.executionState,this.merge),this.persistenceHandler=new v(this.eventBus,this.coreState,this.instanceID,{maxRetries:i?.persistenceMaxRetries,retryDelay:i?.persistenceRetryDelay}),this.transactionManager=new x(this.eventBus,this.coreState,this.executionState),this.metricsCollector=new E(this.eventBus),this.persistenceHandler.initialize(t)}isReady(){return this.persistenceHandler.isReady()}state(){return this.executionState}get(e){return this.coreState.get(e)}async set(e){if(this.isUpdating)return this.pendingUpdates.push(e),void(this.executionState.pendingChanges=[...this.pendingUpdates]);this.isUpdating=!0,this.executionState.executing=!0;const t=performance.now();this.emit(this.eventBus,{name:"update:start",payload:{timestamp:t}});try{let s=e;if("function"==typeof e){const t=e(this.get(!0));s=t instanceof Promise?await t:t}const i=await this.middlewareEngine.executeBlocking(this.get(),s);if(i.blocked)return void this.emit(this.eventBus,{name:"update:complete",payload:{blocked:!0,error:i.error,timestamp:Date.now()}});const r=this.merge(this.get(!0),s),a=await this.middlewareEngine.executeTransform(r,s),n=this.merge(this.get(!0),a),o=this.coreState.applyChanges(n),c=performance.now();this.emit(this.eventBus,{name:"update:complete",payload:{changedPaths:o,duration:c-t,timestamp:Date.now()}}),o.length>0&&this.persistenceHandler.handleStateChange(o,this.get())}catch(e){throw this.emit(this.eventBus,{name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}finally{if(this.isUpdating=!1,this.executionState.executing=!1,this.executionState.changes=null,this.executionState.runningMiddleware=null,this.pendingUpdates.length>0){const e=this.pendingUpdates.shift();if(this.executionState.pendingChanges=[...this.pendingUpdates],e)return this.set(e)}}}subscribe(e,t){const s=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(i=>{(s.includes(i)||""===e)&&(t(this.get(!0)),this.metricsCollector.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){return this.transactionManager.execute(e)}use(e){return e.block?this.middlewareEngine.addBlockingMiddleware(e.action,e.name):this.middlewareEngine.addMiddleware(e.action,e.name)}unuse(e){return this.middlewareEngine.removeMiddleware(e)}metrics(){return this.metricsCollector.getMetrics()}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}getPersistenceStatus(){return this.persistenceHandler.getQueueStatus()}async flushPersistence(){return this.persistenceHandler.flush()}clearPersistenceQueue(){this.persistenceHandler.clearQueue()}dispose(){this.persistenceHandler.dispose(),this.metricsCollector.dispose?.()}emit(e,t){queueMicrotask((()=>{e.emit(t)}))}},k=y(),T=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;middlewareExecutions=[];constructor(e,t={}){this.store=e,this.maxEvents=t.maxEvents??500,this.maxStateHistory=t.maxStateHistory??20,this.enableConsoleLogging=t.enableConsoleLogging??!1,this.logEvents={updates:t.logEvents?.updates??!0,middleware:t.logEvents?.middleware??!0,transactions:t.logEvents?.transactions??!0},this.performanceThresholds={updateTime:t.performanceThresholds?.updateTime??50,middlewareTime:t.performanceThresholds?.middlewareTime??20},this.recordStateSnapshot(),this.setupEventListeners()}setupEventListeners(){const e=["update:start","update:complete","middleware:start","middleware:complete","middleware:error","middleware:blocked","transaction:start","transaction:complete","transaction:error","middleware:executed"];this.unsubscribers.push(this.store.subscribe("",(()=>{this.recordStateSnapshot()})));for(const t of e){const e=t.startsWith("update")&&this.logEvents.updates||t.startsWith("middleware")&&this.logEvents.middleware||t.startsWith("transaction")&&this.logEvents.transactions;this.unsubscribers.push(this.store.onStoreEvent(t,(s=>{"middleware:executed"===t?this.middlewareExecutions.push(s):"transaction:start"===t?this.activeTransactionCount++:"transaction:complete"!==t&&"transaction:error"!==t||(this.activeTransactionCount=Math.max(0,this.activeTransactionCount-1)),s.batchId&&(t.endsWith("start")?this.activeBatches.add(s.batchId):(t.endsWith("complete")||t.endsWith("error"))&&this.activeBatches.delete(s.batchId)),this.recordEvent(t,s),this.enableConsoleLogging&&e&&this.logEventToConsole(t,s),this.checkPerformance(t,s)})))}}recordStateSnapshot(){const e=structuredClone(this.store.get());this.stateHistory.length>0&&0===k(e,this.stateHistory[0]).length||(this.stateHistory.unshift(e),this.stateHistory.length>this.maxStateHistory&&this.stateHistory.pop())}recordEvent(e,t){const s={type:e,timestamp:Date.now(),data:structuredClone(t)};this.eventHistory.unshift(s),this.eventHistory.length>this.maxEvents&&this.eventHistory.pop()}logEventToConsole(e,t){const s=new Date(t.timestamp||Date.now()).toISOString().split("T")[1].replace("Z","");if("update:start"===e)console.group(`%c⚡ Store Update Started [${s}]`,"color: #4a6da7");else if("update:complete"===e){if(t.blocked)console.warn(`%c✋ Update Blocked [${s}]`,"color: #bf8c0a",t.error);else{const e=t.changedPaths||[];e.length>0&&console.log(`%c✅ Update Complete [${s}] - ${e.length} paths changed in ${t.duration?.toFixed(2)}ms`,"color: #2a9d8f",e)}console.groupEnd()}else"middleware:start"===e?console.debug(`%c◀ Middleware "${t.name}" started [${s}] (${t.type})`,"color: #8c8c8c"):"middleware:complete"===e?console.debug(`%c▶ Middleware "${t.name}" completed [${s}] in ${t.duration?.toFixed(2)}ms`,"color: #7c9c7c"):"middleware:error"===e?console.error(`%c❌ Middleware "${t.name}" error [${s}]:`,"color: #e63946",t.error):"middleware:blocked"===e?console.warn(`%c🛑 Middleware "${t.name}" blocked update [${s}]`,"color: #e76f51"):"transaction:start"===e?console.group(`%c📦 Transaction Started [${s}]`,"color: #6d597a"):"transaction:complete"===e?(console.log(`%c📦 Transaction Complete [${s}]`,"color: #355070"),console.groupEnd()):"transaction:error"===e&&(console.error(`%c📦 Transaction Error [${s}]:`,"color: #e56b6f",t.error),console.groupEnd())}checkPerformance(e,t){this.enableConsoleLogging&&("update:complete"===e&&!t.blocked&&t.duration>this.performanceThresholds.updateTime&&console.warn(`%c⚠️ Slow update detected [${t.duration.toFixed(2)}ms]`,"color: #ff9f1c",{changedPaths:t.changedPaths,threshold:this.performanceThresholds.updateTime}),"middleware:complete"===e&&t.duration>this.performanceThresholds.middlewareTime&&console.warn(`%c⚠️ Slow middleware "${t.name}" [${t.duration.toFixed(2)}ms]`,"color: #ff9f1c",{threshold:this.performanceThresholds.middlewareTime}))}getEventHistory(){return structuredClone(this.eventHistory)}getStateHistory(){return structuredClone(this.stateHistory)}getMiddlewareExecutions(){return this.middlewareExecutions}getPerformanceMetrics(){return this.store.metrics()}getTransactionStatus(){return{activeTransactions:this.activeTransactionCount,activeBatches:Array.from(this.activeBatches)}}createLoggingMiddleware(e={}){const{logLevel:t="debug",logUpdates:s=!0}=e;return(e,i)=>{if(s){(console[t]||console.log)("State Update:",i)}return i}}createValidationMiddleware(e){return(t,s)=>{const i=e(t,s);return"boolean"==typeof i?i:(!i.valid&&i.reason&&console.warn("Validation failed:",i.reason),i.valid)}}clearHistory(){if(this.eventHistory=[],this.stateHistory.length>0){const e=this.stateHistory[0];this.stateHistory=[e]}}getRecentChanges(e=5){const t=[],s=Math.min(e,this.stateHistory.length-1);for(let e=0;e<s;e++){const s=this.stateHistory[e],i=this.stateHistory[e+1],r=k(i,s),a={},n={};for(const e of r){const t=e.split("."),r=(e,t)=>t.reduce(((e,t)=>e&&void 0!==e[t]?e[t]:void 0),e),o=(e,t,s)=>{const i=t.length-1,r=t[i];t.slice(0,i).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[r]=s},c=r(i,t),d=r(s,t);o(a,t,c),o(n,t,d)}let o=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){o=e.timestamp;break}0!==r.length&&t.push({timestamp:o,changedPaths:r,from:a,to:n})}return t}createTimeTravel(){let e=0,t=[];return{canUndo:()=>e<this.stateHistory.length-1,canRedo:()=>t.length>0,undo:async()=>{if(e<this.stateHistory.length-1){const s=e+1,i=this.stateHistory[s];t.unshift(this.stateHistory[e]),e=s,await this.store.set(i)}},redo:async()=>{if(t.length>0){const s=t.shift();e=Math.max(0,e-1),await this.store.set(s)}},getHistoryLength:()=>this.stateHistory.length,clear:()=>{t=[],e=0}}}disconnect(){this.unsubscribers.forEach((e=>e())),this.unsubscribers=[],this.clearHistory()}};export{u as DELETE_SYMBOL,S as ReactiveDataStore,T as StoreObserver,p as author};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asaidimu/utils-store",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "A reactive data store",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@asaidimu/events": "^1.1.1",
|
|
33
|
-
"@asaidimu/utils-persistence": "2.2.
|
|
33
|
+
"@asaidimu/utils-persistence": "2.2.1",
|
|
34
34
|
"uuid": "^11.1.0"
|
|
35
35
|
},
|
|
36
36
|
"exports": {
|