@asaidimu/react-store 1.4.3 → 1.4.4

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.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("react"),t=require("@asaidimu/events"),s=require("uuid"),r=require("@asaidimu/indexed"),a=require("@asaidimu/query");function n(e,t){const s=new Set;function r(e,t){const s=e.split(".");for(let e=0;e<s.length;e++){const r=s.slice(0,e+1).join(".");t.add(r)}}return function e(t,a,n){const i=Symbol.for("delete");if(Array.isArray(a)&&Array.isArray(n))JSON.stringify(a)!==JSON.stringify(n)&&r(t,s);else for(const o of Object.keys(n)){const c=t?`${t}.${o}`:o;if(o in a){const t=a[o],d=n[o];d===i?(r(c,s),e(c,{},n[o])):"object"==typeof t&&null!==t&&"object"==typeof d&&null!==d?e(c,t,d):t!==d&&r(c,s)}else r(c,s),e(c,{},n[o])}}("",e||{},t||{}),Array.from(s)}var i=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;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"];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=>{"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===n(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.store.getMiddlewareExecutions()}getPerformanceMetrics(){return this.store.getPerformanceMetrics()}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],a=n(r,s),i={},o={};for(const e of a){const t=e.split("."),a=(e,t)=>t.reduce(((e,t)=>e&&void 0!==e[t]?e[t]:void 0),e),n=(e,t,s)=>{const r=t.length-1,a=t[r];t.slice(0,r).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[a]=s},c=a(r,t),d=a(s,t);n(i,t,c),n(o,t,d)}let c=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){c=e.timestamp;break}0!==a.length&&t.push({timestamp:c,changedPaths:a,from:i,to:o})}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()}};function o(e,t){const s=Symbol.for("delete");if("object"!=typeof e||null===e)return t;if("object"!=typeof t||null===t)return e;const r=structuredClone(e),a=[{target:r,source:t}];for(;a.length>0;){const{target:e,source:t}=a.pop();Object.keys(t).forEach((r=>{const n=t[r],i=e[r];n===s?delete e[r]:Array.isArray(n)?e[r]=n:"object"==typeof n&&null!==n&&"object"==typeof i&&null!==i?(e.hasOwnProperty(r)||(e[r]=structuredClone(n)),a.push({target:e[r],source:n})):e[r]=n}))}return r}var c=class{metrics;middleware;blockingMiddleware;middlewareExecutions=[];maxExecutionHistory=100;pendingUpdates;isUpdating;updateTimes;cache=null;updateBus=t.createEventBus();eventBus=t.createEventBus();executionState;persistence;instanceID=s.v4();persistenceReady=!1;constructor(e,t){this.middleware=[],this.blockingMiddleware=[],this.pendingUpdates=[],this.isUpdating=!1,this.updateTimes=[],this.metrics={updateCount:0,listenerExecutions:0,averageUpdateTime:0,largestUpdateSize:0,mostActiveListenerPaths:[]},this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.cache=e,t?this.setPersistence(t):this.setPersistenceReady()}setPersistenceReady(){this.persistenceReady=!0,this.eventBus.emit({name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&await this.set(e)}catch(e){console.error("Failed to initialize persistence:",e)}finally{this.setPersistenceReady()}this.persistence.subscribe(this.instanceID,(async e=>{this.isUpdating=!0;try{const t=n(this.get(),e);t.length>0&&(await this.set(e),this.eventBus.emit({name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}}))}finally{this.isUpdating=!1}}))}isReady(){return this.persistenceReady}getExecutionState(){return this.executionState}get(){return this.cache}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.eventBus.emit({name:"update:start",payload:{timestamp:t}});let s=e;if("function"==typeof e){const t=e(structuredClone(this.get()));s=t instanceof Promise?await t:t}try{const e=await this.applyBlockingMiddleware(s);if(e.blocked)return void this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e.error,timestamp:Date.now()}})}catch(e){throw this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}const r=o(this.get(),s),a=await this.applyMiddleware(r,s);try{const e=n(this.get(),a);if(this.metrics.updateCount++,this.metrics.largestUpdateSize=Math.max(this.metrics.largestUpdateSize,e.length),e.length>0){this.cache=a;try{await(this.persistence?.set(this.instanceID,this.get()))||this.eventBus.emit({name:"update:complete",payload:{persistence:!1,timestamp:Date.now()}})}catch(e){this.eventBus.emit({name:"update:complete",payload:{persistence:!1,error:e,timestamp:Date.now()}})}this.notifyListeners(e)}const s=performance.now();this.updateTimes.push(s-t),this.updateTimes.length>100&&this.updateTimes.shift(),this.metrics.averageUpdateTime=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length,this.eventBus.emit({name:"update:complete",payload:{changedPaths:e,duration:s-t,timestamp:Date.now()}})}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)}}}async applyBlockingMiddleware(e){for(const{fn:t,name:s,id:r}of this.blockingMiddleware){const a={id:r,name:s,startTime:performance.now()};this.executionState.runningMiddleware={id:r,name:s,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:r,name:s,type:"blocking",timestamp:Date.now()}});try{const n=await Promise.resolve(t(this.get(),e));if(a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,!1===n)return a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:blocked",payload:{id:r,name:s,duration:a.duration,timestamp:Date.now()}}),{blocked:!0};this.eventBus.emit({name:"middleware:complete",payload:{id:r,name:s,type:"blocking",duration:a.duration,timestamp:Date.now()}}),this.trackMiddlewareExecution({...a,blocked:!1})}catch(e){return a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:error",payload:{id:r,name:s,error:a.error,duration:a.duration,timestamp:Date.now()}}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async applyMiddleware(e,t){let s=e;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.eventBus.emit({name:"middleware:start",payload:{id:a,name:r,type:"transform",timestamp:Date.now()}});try{const i=await Promise.resolve(e(s,t));n.endTime=performance.now(),n.duration=void 0!==n.startTime?n.endTime-n.startTime:0,n.blocked=!1,i&&"object"==typeof i&&(s=o(s,i)),this.trackMiddlewareExecution(n),this.eventBus.emit({name:"middleware:complete",payload:{id:a,name:r,type:"transform",duration:n.duration,timestamp:Date.now()}})}catch(e){n.endTime=performance.now(),n.duration=void 0!==n.startTime?n.endTime-n.startTime:0,n.error=e instanceof Error?e:new Error(String(e)),n.blocked=!1,this.trackMiddlewareExecution(n),this.eventBus.emit({name:"middleware:error",payload:{id:a,name:r,error:n.error,duration:n.duration,timestamp:Date.now()}}),console.error(`Middleware ${r} error:`,e)}finally{this.executionState.runningMiddleware=null}}return s}subscribe(e,t){const s=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(r=>{(s.includes(r)||""===e)&&(t(this.get()),this.metrics.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){const t=structuredClone(this.get());this.executionState.transactionActive=!0,this.eventBus.emit({name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.eventBus.emit({name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.cache=t,this.eventBus.emit({name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}use(e,t="unnamed-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.middleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],s}useBlockingMiddleware(e,t="unnamed-blocking-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.blockingMiddleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],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.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],this.middleware.length+this.blockingMiddleware.length<t}getPerformanceMetrics(){return structuredClone(this.metrics)}getMiddlewareExecutions(){return structuredClone(this.middlewareExecutions)}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}trackMiddlewareExecution(e){this.middlewareExecutions.unshift(e),this.middlewareExecutions.length>this.maxExecutionHistory&&this.middlewareExecutions.pop()}};var d=class{selectorCache=new WeakMap;create(e){return t=>{let s=this.selectorCache.get(e);s||(s=new WeakMap,this.selectorCache.set(e,s));const r=s.get(t);if(r)return r.result;const a=e(t);return s.set(t,{result:a,deps:[]}),a}}},l=class{executions=[];maxHistory=100;listeners=new Set;track(e){this.executions.unshift(e),this.executions.length>this.maxHistory&&this.executions.pop(),this.notify()}getExecutions(){return[...this.executions]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){this.listeners.forEach((e=>e()))}};function u(e){return{id:"opentelemetry",name:"OpenTelemetry Collector",config:e,testConnection:async()=>{try{return(await fetch(`${e.endpoint}/v1/metrics`,{method:"OPTIONS",headers:{...e.apiKey?{"api-key":e.apiKey}:{}}})).ok}catch(e){return!1}},send:async t=>{const s={resourceMetrics:[{resource:{attributes:{"service.name":t.source,...e.resource}},scopeMetrics:[{metrics:t.metrics.map((e=>"counter"===e.type?{name:e.name,unit:e.unit||"1",sum:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asInt:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:"histogram"===e.type?{name:e.name,unit:e.unit||"ms",histogram:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),count:1,sum:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:{name:e.name,unit:e.unit||"1",gauge:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asDouble:"number"==typeof e.value?e.value:1,attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}))}]}]};await fetch(`${e.endpoint}/v1/metrics`,{method:"POST",headers:{"Content-Type":"application/json",...e.apiKey?{"api-key":e.apiKey}:{}},body:JSON.stringify(s)})}}}function h(e){return{id:"prometheus",name:"Prometheus Pushgateway",config:e,testConnection:async()=>{try{const t=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;return(await fetch(e.pushgatewayUrl,{method:"HEAD",headers:{...t?{Authorization:t}:{}}})).ok}catch(e){return!1}},send:async t=>{let s="";for(const e of t.metrics){if("log"===e.type||"trace"===e.type)continue;const r=Object.entries({...e.labels,source:t.source,instance:t.metrics.find((e=>e.labels?.instanceId))?.labels?.instanceId||"unknown"}).map((([e,t])=>`${e}="${t.replace(/"/g,'\\"')}"`)).join(","),a=e.name.replace(/\./g,"_");"counter"===e.type?s+=`# TYPE ${a} counter\n`:s+=`# TYPE ${a} gauge\n`,s+=`${a}{${r}} ${e.value}\n`}const r=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;await fetch(`${e.pushgatewayUrl}/metrics/job/${e.jobName}`,{method:"POST",headers:{"Content-Type":"text/plain",...r?{Authorization:r}:{}},body:s})}}}function m(e){return{id:"grafana-cloud",name:"Grafana Cloud",config:e,testConnection:async()=>{try{return(await fetch(`${e.url}/api/v1/query?query=up`,{method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`}})).ok}catch(e){return!1}},send:async t=>{const s={streams:[{stream:{service:t.source,job:"store-metrics"},values:t.metrics.map((e=>{const s=1e6*t.timestamp;let r="";if("object"==typeof e.value)r=JSON.stringify(e.value);else if(r=`level=info metric=${e.name} value=${e.value} type=${e.type}`,e.labels)for(const[t,s]of Object.entries(e.labels))r+=` ${t}=${s}`;return[String(s),r]}))}]};await fetch(`${e.url}/loki/api/v1/push`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(s)})}}}function p(e){return{id:"http-endpoint",name:"HTTP Metrics Endpoint",config:e,testConnection:async()=>{try{return(await fetch(e.url,{method:"OPTIONS",headers:e.headers})).ok}catch(e){return!1}},send:async t=>{const s=e.transformPayload?e.transformPayload(t):t;await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(s)})}}}var g=class extends i{destinations=new Map;metricsBatch=[];reportingInterval;batchSize;serviceName;environment;instanceId;immediateReporting;collectCategories;compressPayloads;reportingTimer=null;traceIdCounter=0;activeTraces=new Map;constructor(e,t){super(e,t),this.serviceName=t.serviceName,this.environment=t.environment,this.instanceId=t.instanceId||this.generateInstanceId(),this.reportingInterval=t.reportingInterval||3e4,this.batchSize=t.batchSize||100,this.immediateReporting=t.immediateReporting||!1,this.collectCategories=t.collectCategories||{performance:!0,errors:!0,stateChanges:!0,middleware:!0},this.compressPayloads=t.compressPayloads||!1,this.immediateReporting||this.startReportingCycle(),this.setupRemoteEventListeners()}generateInstanceId(){return`${Date.now()}-${Math.random().toString(36).substring(2,9)}`}setupRemoteEventListeners(){this.store.onStoreEvent("update:complete",(e=>{this.collectCategories?.stateChanges&&(this.trackMetric({name:"store.update.duration",type:"histogram",value:e.duration||0,unit:"ms",labels:{pathCount:String(e.changedPaths?.length||0)}}),this.trackMetric({name:"store.update.paths_changed",type:"counter",value:e.changedPaths?.length||0,labels:{blocked:String(!!e.blocked)}}))})),this.store.onStoreEvent("middleware:error",(e=>{this.collectCategories?.errors&&this.trackMetric({name:"store.middleware.error",type:"log",value:{middleware:e.name,error:e.error?.message||"Unknown error",stack:e.error?.stack},labels:{middlewareName:e.name}})})),this.store.onStoreEvent("transaction:start",(e=>{if(!this.collectCategories?.performance)return;const t=this.beginTrace("transaction");e.traceId=t,this.beginSpan(t,"transaction.execution",{transactionId:e.id||String(Date.now())})})),this.store.onStoreEvent("transaction:complete",(e=>{this.collectCategories?.performance&&e.traceId&&(this.endSpan(e.traceId,"transaction.execution"),this.endTrace(e.traceId))}))}beginTrace(e){const t=`trace-${++this.traceIdCounter}-${Date.now()}`;return this.activeTraces.set(t,{startTime:performance.now(),name:e,spans:{}}),t}beginSpan(e,t,s={}){const r=this.activeTraces.get(e);if(!r)return"";const a=`span-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;return r.spans[a]={startTime:performance.now(),name:t,labels:s},a}endSpan(e,t){const s=this.activeTraces.get(e);if(!s)return;const r=Object.entries(s.spans).filter((([e,s])=>s.name===t&&!s.endTime)).map((([e])=>e));if(r.length>0){const e=r[r.length-1];s.spans[e].endTime=performance.now()}}endTrace(e){const t=this.activeTraces.get(e);if(!t)return;const s=performance.now(),r=s-t.startTime;this.trackMetric({name:"store.trace.duration",type:"histogram",value:r,unit:"ms",labels:{traceName:t.name,traceId:e}}),Object.entries(t.spans).forEach((([t,r])=>{r.endTime||(r.endTime=s);const a=r.endTime-r.startTime;this.trackMetric({name:"store.trace.span.duration",type:"trace",value:a,unit:"ms",labels:{...r.labels,spanName:r.name},traceId:e,parentId:t})})),this.activeTraces.delete(e)}addDestination(e){return this.destinations.has(e.id)?(console.warn(`Destination with ID ${e.id} already exists`),!1):(this.destinations.set(e.id,e),!0)}removeDestination(e){return this.destinations.delete(e)}getDestinations(){return Array.from(this.destinations.values()).map((e=>({id:e.id,name:e.name})))}async testAllConnections(){const e={};for(const[t,s]of this.destinations.entries())if(s.testConnection)try{e[t]=await s.testConnection()}catch(s){e[t]=!1}else e[t]=!0;return e}trackMetric(e){e.labels={...e.labels,environment:this.environment,service:this.serviceName,instanceId:this.instanceId},this.metricsBatch.push(e),(this.immediateReporting||this.metricsBatch.length>=this.batchSize)&&this.flushMetrics()}async flushMetrics(){if(0===this.metricsBatch.length)return;const e={timestamp:Date.now(),source:this.serviceName,metrics:[...this.metricsBatch]};this.metricsBatch=[];const t=Array.from(this.destinations.values()).map((async t=>{try{let s=e;if(this.compressPayloads&&"undefined"!=typeof window&&window.CompressionStream){const t=JSON.stringify(e),r=(new TextEncoder).encode(t),a=new CompressionStream("gzip"),n=new Blob([r]).stream().pipeThrough(a);await new Response(n).blob();s._compressed=!0,s._originalSize=t.length}await t.send(s)}catch(s){if(console.error(`Failed to send metrics to destination ${t.name}:`,s),e.metrics.some((e=>"log"===e.type&&e.name.includes("error")))){const t=e.metrics.filter((e=>"log"===e.type&&e.name.includes("error")));this.metricsBatch.push(...t)}}}));await Promise.all(t)}startReportingCycle(){this.reportingTimer&&clearInterval(this.reportingTimer),this.reportingTimer=setInterval((()=>{this.flushMetrics()}),this.reportingInterval)}setReportingInterval(e){this.reportingInterval=e,this.startReportingCycle()}reportCurrentMetrics(){const e=this.store.getPerformanceMetrics();this.trackMetric({name:"store.performance.update_count",type:"counter",value:e.updateCount,labels:{}}),this.trackMetric({name:"store.performance.listener_executions",type:"counter",value:e.listenerExecutions,labels:{}}),this.trackMetric({name:"store.performance.average_update_time",type:"gauge",value:e.averageUpdateTime,unit:"ms",labels:{}}),this.trackMetric({name:"store.performance.largest_update_size",type:"gauge",value:e.largestUpdateSize,unit:"paths",labels:{}})}disconnect(){this.reportingTimer&&(clearInterval(this.reportingTimer),this.reportingTimer=null),this.flushMetrics().catch((e=>console.error("Error flushing metrics during disconnect:",e))),super.disconnect()}};var y=class e{static dbInstance=null;static eventBusMap=new Map;static dbName="ReactiveDataStore";static modelName="stores";static getDatabase(){return e.dbInstance||(e.dbInstance=r.DatabaseConnection({name:e.dbName,enableTelemetry:!1}).then((async t=>{const s={name:e.modelName,version:"1.0.0",fields:{storeId:{type:"string",required:!0},data:{type:"object",required:!0}}};try{await t.createModel(s)}catch(e){if(e instanceof r.DatabaseError&&"SCHEMA_ALREADY_EXISTS"!==e.type)throw e}return t}))),e.dbInstance}static getEventBus(s){const r=`store_${s}`;return e.eventBusMap.has(r)||e.eventBusMap.set(r,t.createEventBus({batchSize:5,async:!0,batchDelay:16,errorHandler:e=>console.error(`Event bus error for ${s}:`,e),crossTab:!0,channelName:r})),e.eventBusMap.get(r)}static async getCursor(){return(await e.getDatabase()).cursor(e.modelName)}static async close(){const t=await e.dbInstance;t&&t.close(),e.dbInstance=null,e.eventBusMap.forEach((e=>e.clear())),e.eventBusMap.clear()}};exports.IndexedDBPersistence=class{cursorPromise;storeId;eventBus;constructor(e){this.storeId=e,this.cursorPromise=y.getCursor(),this.eventBus=y.getEventBus(e)}async set(e,t){try{const s=await this.cursorPromise,r=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),n=await s.find(r.filters),i={storeId:this.storeId,data:t};let o;return n?o=await n.update(i):(await s.create(i),o=!0),o&&this.eventBus.emit({name:"store:updated",payload:{storeId:this.storeId,instanceId:e,state:t}}),o}catch(t){return console.error(`Failed to set state for store ${this.storeId} by instance ${e}:`,t),!1}}async get(){try{const e=await this.cursorPromise,t=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return s?s.read().then((()=>s.data)):null}catch(e){return console.error(`Failed to get state for store ${this.storeId}:`,e),null}}subscribe(e,t){return this.eventBus.subscribe("store:updated",(({storeId:s,instanceId:r,state:a})=>{s===this.storeId&&r!==e&&t(a)}))}async clear(){try{const e=await this.cursorPromise,t=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return!s||await s.delete()}catch(e){return console.error(`Failed to clear state for store ${this.storeId}:`,e),!1}}static async closeAll(){await y.close()}},exports.LocalStoragePersistence=class{storageKey;bus;constructor(e){this.storageKey=e,this.bus=t.createEventBus({async:!0,batchSize:5,batchDelay:16,errorHandler:t=>console.error(`Event bus error for ${e}:`,t),crossTab:!0,channelName:`storage_${e}`}),window.addEventListener("storage",(e=>{if(e.key===this.storageKey&&e.newValue)try{const t=JSON.parse(e.newValue);this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:"external",state:t}})}catch(e){console.error("Failed to parse storage event data:",e)}}))}set(e,t){try{const s=JSON.stringify(t);return localStorage.setItem(this.storageKey,s),this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:e,state:t}}),!0}catch(e){return console.error(`Failed to persist state to localStorage for ${this.storageKey}:`,e),!1}}get(){try{const e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch(e){return console.error(`Failed to retrieve state from localStorage for ${this.storageKey}:`,e),null}}subscribe(e,t){return this.bus.subscribe("storage:updated",(({storageKey:s,instanceId:r,state:a})=>{s===this.storageKey&&r!==e&&t(a)}))}clear(){try{return localStorage.removeItem(this.storageKey),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.storageKey}:`,e),!1}}},exports.ReactiveDataStore=c,exports.RemoteObservability=g,exports.StoreObservability=i,exports.createGrafanaCloudDestination=m,exports.createHttpDestination=p,exports.createOpenTelemetryDestination=u,exports.createPrometheusDestination=h,exports.createStore=function(t,{enableMetrics:s,...r}={}){const a=new c(t.state,r.persistence),n=s?new i(a,r):void 0,o=new d;t.middleware&&Object.entries(t.middleware).forEach((([e,t])=>a.use(t,e))),t.blockingMiddleware&&Object.entries(t.blockingMiddleware).forEach((([e,t])=>a.useBlockingMiddleware(t,e)));const u=new l,h=Object.entries(t.actions).reduce(((e,[t,s])=>(e[t]=async(...e)=>{const r=crypto.randomUUID(),n=performance.now(),i={id:r,name:t,params:e,startTime:n};try{await a.set((async t=>{const r=await s(t,...e);return i.result=r,r})),i.status="success"}catch(e){throw i.status="error",i.error=e instanceof Error?e:new Error(String(e)),console.error(`Error in action ${t}:`,e),e}finally{i.endTime=performance.now(),i.duration=i.endTime-n,u.track(i)}},e)),{});function m(e,t){const s=function(e,t="."){const s=[],r={get:(e,t)=>{const a=[];return s.length>0&&a.push(...s[s.length-1]),a.push(t),s.push(a),new Proxy({},r)}};return e(new Proxy({},r)),s.map((e=>e.join(t)))}(e);return a.subscribe(s,t)}const p=()=>a.get(),g=e=>(a.isReady()&&e(),a.onStoreEvent("persistence:ready",e)),y=()=>a.isReady();return function(){const t=e.useCallback((t=>{const s=o.create(t);return e.useSyncExternalStore((e=>m(s,e)),(()=>s(a.get())),(()=>s(a.get())))}),[]),s=e.useCallback((()=>e.useSyncExternalStore((e=>a.subscribe("",e)),p,p)),[]),r=e.useSyncExternalStore(g,y,y);return{store:a,observer:n,select:t,actions:h,isReady:r,actionTracker:u,get state(){return s}}}},exports.useRemoteObservability=function(e,t){const s=new g(e,t);return{remote:s,addOpenTelemetryDestination:e=>s.addDestination(u(e)),addPrometheusDestination:e=>s.addDestination(h(e)),addGrafanaCloudDestination:e=>s.addDestination(m(e)),addHttpDestination:e=>s.addDestination(p(e))}};
1
+ "use strict";var e=require("react"),t=require("@asaidimu/events"),r=require("uuid"),s=require("@asaidimu/indexed"),a=require("@asaidimu/query");function n(e,t){const r=new Set,s=Symbol.for("delete"),a=e=>r.has(e)||r.add(e);function n(e){if(!e)return;const t=e.split(".");a(e);for(let e=t.length-1;e>0;e--)a(t.slice(0,e).join("."))}const i=[{path:"",orig:e||{},part:t||{}}];for(;i.length>0;){const{path:e,orig:t,part:r}=i.pop();if(null!=r)if(Array.isArray(r))Array.isArray(t)&&JSON.stringify(t)===JSON.stringify(r)||n(e);else if("object"==typeof r)for(const a of Object.keys(r)){const o=e?`${e}.${a}`:a,c=r[a];if(c===s||null==t){n(o);continue}const d=t[a];"object"==typeof c&&null!==c?i.push({path:o,orig:d,part:c}):d!==c&&n(o)}}return Array.from(r)}var i=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;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"];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,(r=>{"transaction:start"===t?this.activeTransactionCount++:"transaction:complete"!==t&&"transaction:error"!==t||(this.activeTransactionCount=Math.max(0,this.activeTransactionCount-1)),r.batchId&&(t.endsWith("start")?this.activeBatches.add(r.batchId):(t.endsWith("complete")||t.endsWith("error"))&&this.activeBatches.delete(r.batchId)),this.recordEvent(t,r),this.enableConsoleLogging&&e&&this.logEventToConsole(t,r),this.checkPerformance(t,r)})))}}recordStateSnapshot(){const e=structuredClone(this.store.get());this.stateHistory.length>0&&0===n(e,this.stateHistory[0]).length||(this.stateHistory.unshift(e),this.stateHistory.length>this.maxStateHistory&&this.stateHistory.pop())}recordEvent(e,t){const r={type:e,timestamp:Date.now(),data:structuredClone(t)};this.eventHistory.unshift(r),this.eventHistory.length>this.maxEvents&&this.eventHistory.pop()}logEventToConsole(e,t){const r=new Date(t.timestamp||Date.now()).toISOString().split("T")[1].replace("Z","");if("update:start"===e)console.group(`%c⚡ Store Update Started [${r}]`,"color: #4a6da7");else if("update:complete"===e){if(t.blocked)console.warn(`%c✋ Update Blocked [${r}]`,"color: #bf8c0a",t.error);else{const e=t.changedPaths||[];e.length>0&&console.log(`%c✅ Update Complete [${r}] - ${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 [${r}] (${t.type})`,"color: #8c8c8c"):"middleware:complete"===e?console.debug(`%c▶ Middleware "${t.name}" completed [${r}] in ${t.duration?.toFixed(2)}ms`,"color: #7c9c7c"):"middleware:error"===e?console.error(`%c❌ Middleware "${t.name}" error [${r}]:`,"color: #e63946",t.error):"middleware:blocked"===e?console.warn(`%c🛑 Middleware "${t.name}" blocked update [${r}]`,"color: #e76f51"):"transaction:start"===e?console.group(`%c📦 Transaction Started [${r}]`,"color: #6d597a"):"transaction:complete"===e?(console.log(`%c📦 Transaction Complete [${r}]`,"color: #355070"),console.groupEnd()):"transaction:error"===e&&(console.error(`%c📦 Transaction Error [${r}]:`,"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.store.getMiddlewareExecutions()}getPerformanceMetrics(){return this.store.getPerformanceMetrics()}getTransactionStatus(){return{activeTransactions:this.activeTransactionCount,activeBatches:Array.from(this.activeBatches)}}createLoggingMiddleware(e={}){const{logLevel:t="debug",logUpdates:r=!0}=e;return(e,s)=>{if(r){(console[t]||console.log)("State Update:",s)}return s}}createValidationMiddleware(e){return(t,r)=>{const s=e(t,r);return"boolean"==typeof s?s:(!s.valid&&s.reason&&console.warn("Validation failed:",s.reason),s.valid)}}clearHistory(){if(this.eventHistory=[],this.stateHistory.length>0){const e=this.stateHistory[0];this.stateHistory=[e]}}getRecentChanges(e=5){const t=[],r=Math.min(e,this.stateHistory.length-1);for(let e=0;e<r;e++){const r=this.stateHistory[e],s=this.stateHistory[e+1],a=n(s,r),i={},o={};for(const e of a){const t=e.split("."),a=(e,t)=>t.reduce(((e,t)=>e&&void 0!==e[t]?e[t]:void 0),e),n=(e,t,r)=>{const s=t.length-1,a=t[s];t.slice(0,s).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[a]=r},c=a(s,t),d=a(r,t);n(i,t,c),n(o,t,d)}let c=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){c=e.timestamp;break}0!==a.length&&t.push({timestamp:c,changedPaths:a,from:i,to:o})}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 r=e+1,s=this.stateHistory[r];t.unshift(this.stateHistory[e]),e=r,await this.store.set(s)}},redo:async()=>{if(t.length>0){const r=t.shift();e=Math.max(0,e-1),await this.store.set(r)}},getHistoryLength:()=>this.stateHistory.length,clear:()=>{t=[],e=0}}}disconnect(){this.unsubscribers.forEach((e=>e())),this.unsubscribers=[],this.clearHistory()}};function o(e,t){const r=Symbol.for("delete");if("object"!=typeof e||null===e)return t;if("object"!=typeof t||null===t)return e;const s=c(e),a=[{target:s,source:t,path:[]}];for(;a.length>0;){const{target:e,source:t,path:s}=a.pop();for(const n of Object.keys(t)){const i=t[n],o=[...s,n];i!==r?Array.isArray(i)?e[n]=[...i]:"object"==typeof i&&null!==i?n in e&&null!==e[n]&&"object"==typeof e[n]?(e[n]=c(e[n]),a.push({target:e[n],source:i,path:o})):e[n]=c(i):e[n]=i:delete e[n]}}return s}var c=e=>Array.isArray(e)?[...e]:{...e},d=class{metrics;middleware;blockingMiddleware;middlewareExecutions=[];maxExecutionHistory=100;pendingUpdates;isUpdating;updateTimes;cache=null;updateBus=t.createEventBus();eventBus=t.createEventBus();executionState;persistence;instanceID=r.v4();persistenceReady=!1;constructor(e,t){this.middleware=[],this.blockingMiddleware=[],this.pendingUpdates=[],this.isUpdating=!1,this.updateTimes=[],this.metrics={updateCount:0,listenerExecutions:0,averageUpdateTime:0,largestUpdateSize:0,mostActiveListenerPaths:[]},this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.cache=e,t?this.setPersistence(t):this.setPersistenceReady()}setPersistenceReady(){this.persistenceReady=!0,this.eventBus.emit({name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&await this.set(e)}catch(e){console.error("Failed to initialize persistence:",e)}finally{this.setPersistenceReady()}this.persistence.subscribe(this.instanceID,(async e=>{this.isUpdating=!0;try{const t=n(this.get(),e);t.length>0&&(await this.set(e),this.eventBus.emit({name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}}))}finally{this.isUpdating=!1}}))}isReady(){return this.persistenceReady}getExecutionState(){return this.executionState}get(e){return e?structuredClone(this.cache):this.cache}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.eventBus.emit({name:"update:start",payload:{timestamp:t}});let r=e;if("function"==typeof e){const t=e(this.get(!0));r=t instanceof Promise?await t:t}try{const e=await this.applyBlockingMiddleware(r);if(e.blocked)return void this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e.error,timestamp:Date.now()}})}catch(e){throw this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}const s=o(this.get(!0),r),a=await this.applyMiddleware(s,r);try{const e=n(this.get(!0),a);if(this.metrics.updateCount++,this.metrics.largestUpdateSize=Math.max(this.metrics.largestUpdateSize,e.length),e.length>0){this.cache=o(this.get(!0),a);try{await(this.persistence?.set(this.instanceID,this.get()))||this.eventBus.emit({name:"update:complete",payload:{persistence:!1,timestamp:Date.now()}})}catch(e){this.eventBus.emit({name:"update:complete",payload:{persistence:!1,error:e,timestamp:Date.now()}})}this.notifyListeners(e)}const r=performance.now();this.updateTimes.push(r-t),this.updateTimes.length>100&&this.updateTimes.shift(),this.metrics.averageUpdateTime=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length,this.eventBus.emit({name:"update:complete",payload:{changedPaths:e,duration:r-t,timestamp:Date.now()}})}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)}}}async applyBlockingMiddleware(e){for(const{fn:t,name:r,id:s}of this.blockingMiddleware){const a={id:s,name:r,startTime:performance.now()};this.executionState.runningMiddleware={id:s,name:r,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:s,name:r,type:"blocking",timestamp:Date.now()}});try{const n=await Promise.resolve(t(this.get(),e));if(a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,!1===n)return a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:blocked",payload:{id:s,name:r,duration:a.duration,timestamp:Date.now()}}),{blocked:!0};this.eventBus.emit({name:"middleware:complete",payload:{id:s,name:r,type:"blocking",duration:a.duration,timestamp:Date.now()}}),this.trackMiddlewareExecution({...a,blocked:!1})}catch(e){return a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:error",payload:{id:s,name:r,error:a.error,duration:a.duration,timestamp:Date.now()}}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async applyMiddleware(e,t){let r=e,s=t;for(const{fn:e,name:a,id:n}of this.middleware){const i={id:n,name:a,startTime:performance.now()};this.executionState.runningMiddleware={id:n,name:a,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:n,name:a,type:"transform",timestamp:Date.now()}});try{const c=await Promise.resolve(e(r,t));i.endTime=performance.now(),i.duration=void 0!==i.startTime?i.endTime-i.startTime:0,i.blocked=!1,c&&"object"==typeof c&&(r=o(r,c),s=o(s,c)),this.trackMiddlewareExecution(i),this.eventBus.emit({name:"middleware:complete",payload:{id:n,name:a,type:"transform",duration:i.duration,timestamp:Date.now()}})}catch(e){i.endTime=performance.now(),i.duration=void 0!==i.startTime?i.endTime-i.startTime:0,i.error=e instanceof Error?e:new Error(String(e)),i.blocked=!1,this.trackMiddlewareExecution(i),this.eventBus.emit({name:"middleware:error",payload:{id:n,name:a,error:i.error,duration:i.duration,timestamp:Date.now()}}),console.error(`Middleware ${a} error:`,e)}finally{this.executionState.runningMiddleware=null}}return s}subscribe(e,t){const r=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(s=>{(r.includes(s)||""===e)&&(t(this.get()),this.metrics.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){const t=this.get(!0);this.executionState.transactionActive=!0,this.eventBus.emit({name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.eventBus.emit({name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.cache=t,this.eventBus.emit({name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}use(e,t="unnamed-middleware"){const r=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.middleware.push({fn:e,name:t,id:r}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],r}useBlockingMiddleware(e,t="unnamed-blocking-middleware"){const r=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.blockingMiddleware.push({fn:e,name:t,id:r}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],r}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.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],this.middleware.length+this.blockingMiddleware.length<t}getPerformanceMetrics(){return structuredClone(this.metrics)}getMiddlewareExecutions(){return structuredClone(this.middlewareExecutions)}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}trackMiddlewareExecution(e){this.middlewareExecutions.unshift(e),this.middlewareExecutions.length>this.maxExecutionHistory&&this.middlewareExecutions.pop()}};var l=class{selectorCache=new WeakMap;create(e){return t=>{let r=this.selectorCache.get(e);r||(r=new WeakMap,this.selectorCache.set(e,r));const s=r.get(t);if(s)return s.result;const a=e(t);return r.set(t,{result:a,deps:[]}),a}}},h=class{executions=[];maxHistory=100;listeners=new Set;track(e){this.executions.unshift(e),this.executions.length>this.maxHistory&&this.executions.pop(),this.notify()}getExecutions(){return[...this.executions]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){this.listeners.forEach((e=>e()))}};function u(e){return{id:"opentelemetry",name:"OpenTelemetry Collector",config:e,testConnection:async()=>{try{return(await fetch(`${e.endpoint}/v1/metrics`,{method:"OPTIONS",headers:{...e.apiKey?{"api-key":e.apiKey}:{}}})).ok}catch(e){return!1}},send:async t=>{const r={resourceMetrics:[{resource:{attributes:{"service.name":t.source,...e.resource}},scopeMetrics:[{metrics:t.metrics.map((e=>"counter"===e.type?{name:e.name,unit:e.unit||"1",sum:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asInt:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:"histogram"===e.type?{name:e.name,unit:e.unit||"ms",histogram:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),count:1,sum:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:{name:e.name,unit:e.unit||"1",gauge:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asDouble:"number"==typeof e.value?e.value:1,attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}))}]}]};await fetch(`${e.endpoint}/v1/metrics`,{method:"POST",headers:{"Content-Type":"application/json",...e.apiKey?{"api-key":e.apiKey}:{}},body:JSON.stringify(r)})}}}function m(e){return{id:"prometheus",name:"Prometheus Pushgateway",config:e,testConnection:async()=>{try{const t=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;return(await fetch(e.pushgatewayUrl,{method:"HEAD",headers:{...t?{Authorization:t}:{}}})).ok}catch(e){return!1}},send:async t=>{let r="";for(const e of t.metrics){if("log"===e.type||"trace"===e.type)continue;const s=Object.entries({...e.labels,source:t.source,instance:t.metrics.find((e=>e.labels?.instanceId))?.labels?.instanceId||"unknown"}).map((([e,t])=>`${e}="${t.replace(/"/g,'\\"')}"`)).join(","),a=e.name.replace(/\./g,"_");"counter"===e.type?r+=`# TYPE ${a} counter\n`:r+=`# TYPE ${a} gauge\n`,r+=`${a}{${s}} ${e.value}\n`}const s=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;await fetch(`${e.pushgatewayUrl}/metrics/job/${e.jobName}`,{method:"POST",headers:{"Content-Type":"text/plain",...s?{Authorization:s}:{}},body:r})}}}function p(e){return{id:"grafana-cloud",name:"Grafana Cloud",config:e,testConnection:async()=>{try{return(await fetch(`${e.url}/api/v1/query?query=up`,{method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`}})).ok}catch(e){return!1}},send:async t=>{const r={streams:[{stream:{service:t.source,job:"store-metrics"},values:t.metrics.map((e=>{const r=1e6*t.timestamp;let s="";if("object"==typeof e.value)s=JSON.stringify(e.value);else if(s=`level=info metric=${e.name} value=${e.value} type=${e.type}`,e.labels)for(const[t,r]of Object.entries(e.labels))s+=` ${t}=${r}`;return[String(r),s]}))}]};await fetch(`${e.url}/loki/api/v1/push`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(r)})}}}function g(e){return{id:"http-endpoint",name:"HTTP Metrics Endpoint",config:e,testConnection:async()=>{try{return(await fetch(e.url,{method:"OPTIONS",headers:e.headers})).ok}catch(e){return!1}},send:async t=>{const r=e.transformPayload?e.transformPayload(t):t;await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(r)})}}}var y=class extends i{destinations=new Map;metricsBatch=[];reportingInterval;batchSize;serviceName;environment;instanceId;immediateReporting;collectCategories;compressPayloads;reportingTimer=null;traceIdCounter=0;activeTraces=new Map;constructor(e,t){super(e,t),this.serviceName=t.serviceName,this.environment=t.environment,this.instanceId=t.instanceId||this.generateInstanceId(),this.reportingInterval=t.reportingInterval||3e4,this.batchSize=t.batchSize||100,this.immediateReporting=t.immediateReporting||!1,this.collectCategories=t.collectCategories||{performance:!0,errors:!0,stateChanges:!0,middleware:!0},this.compressPayloads=t.compressPayloads||!1,this.immediateReporting||this.startReportingCycle(),this.setupRemoteEventListeners()}generateInstanceId(){return`${Date.now()}-${Math.random().toString(36).substring(2,9)}`}setupRemoteEventListeners(){this.store.onStoreEvent("update:complete",(e=>{this.collectCategories?.stateChanges&&(this.trackMetric({name:"store.update.duration",type:"histogram",value:e.duration||0,unit:"ms",labels:{pathCount:String(e.changedPaths?.length||0)}}),this.trackMetric({name:"store.update.paths_changed",type:"counter",value:e.changedPaths?.length||0,labels:{blocked:String(!!e.blocked)}}))})),this.store.onStoreEvent("middleware:error",(e=>{this.collectCategories?.errors&&this.trackMetric({name:"store.middleware.error",type:"log",value:{middleware:e.name,error:e.error?.message||"Unknown error",stack:e.error?.stack},labels:{middlewareName:e.name}})})),this.store.onStoreEvent("transaction:start",(e=>{if(!this.collectCategories?.performance)return;const t=this.beginTrace("transaction");e.traceId=t,this.beginSpan(t,"transaction.execution",{transactionId:e.id||String(Date.now())})})),this.store.onStoreEvent("transaction:complete",(e=>{this.collectCategories?.performance&&e.traceId&&(this.endSpan(e.traceId,"transaction.execution"),this.endTrace(e.traceId))}))}beginTrace(e){const t=`trace-${++this.traceIdCounter}-${Date.now()}`;return this.activeTraces.set(t,{startTime:performance.now(),name:e,spans:{}}),t}beginSpan(e,t,r={}){const s=this.activeTraces.get(e);if(!s)return"";const a=`span-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;return s.spans[a]={startTime:performance.now(),name:t,labels:r},a}endSpan(e,t){const r=this.activeTraces.get(e);if(!r)return;const s=Object.entries(r.spans).filter((([e,r])=>r.name===t&&!r.endTime)).map((([e])=>e));if(s.length>0){const e=s[s.length-1];r.spans[e].endTime=performance.now()}}endTrace(e){const t=this.activeTraces.get(e);if(!t)return;const r=performance.now(),s=r-t.startTime;this.trackMetric({name:"store.trace.duration",type:"histogram",value:s,unit:"ms",labels:{traceName:t.name,traceId:e}}),Object.entries(t.spans).forEach((([t,s])=>{s.endTime||(s.endTime=r);const a=s.endTime-s.startTime;this.trackMetric({name:"store.trace.span.duration",type:"trace",value:a,unit:"ms",labels:{...s.labels,spanName:s.name},traceId:e,parentId:t})})),this.activeTraces.delete(e)}addDestination(e){return this.destinations.has(e.id)?(console.warn(`Destination with ID ${e.id} already exists`),!1):(this.destinations.set(e.id,e),!0)}removeDestination(e){return this.destinations.delete(e)}getDestinations(){return Array.from(this.destinations.values()).map((e=>({id:e.id,name:e.name})))}async testAllConnections(){const e={};for(const[t,r]of this.destinations.entries())if(r.testConnection)try{e[t]=await r.testConnection()}catch(r){e[t]=!1}else e[t]=!0;return e}trackMetric(e){e.labels={...e.labels,environment:this.environment,service:this.serviceName,instanceId:this.instanceId},this.metricsBatch.push(e),(this.immediateReporting||this.metricsBatch.length>=this.batchSize)&&this.flushMetrics()}async flushMetrics(){if(0===this.metricsBatch.length)return;const e={timestamp:Date.now(),source:this.serviceName,metrics:[...this.metricsBatch]};this.metricsBatch=[];const t=Array.from(this.destinations.values()).map((async t=>{try{let r=e;if(this.compressPayloads&&"undefined"!=typeof window&&window.CompressionStream){const t=JSON.stringify(e),s=(new TextEncoder).encode(t),a=new CompressionStream("gzip"),n=new Blob([s]).stream().pipeThrough(a);await new Response(n).blob();r._compressed=!0,r._originalSize=t.length}await t.send(r)}catch(r){if(console.error(`Failed to send metrics to destination ${t.name}:`,r),e.metrics.some((e=>"log"===e.type&&e.name.includes("error")))){const t=e.metrics.filter((e=>"log"===e.type&&e.name.includes("error")));this.metricsBatch.push(...t)}}}));await Promise.all(t)}startReportingCycle(){this.reportingTimer&&clearInterval(this.reportingTimer),this.reportingTimer=setInterval((()=>{this.flushMetrics()}),this.reportingInterval)}setReportingInterval(e){this.reportingInterval=e,this.startReportingCycle()}reportCurrentMetrics(){const e=this.store.getPerformanceMetrics();this.trackMetric({name:"store.performance.update_count",type:"counter",value:e.updateCount,labels:{}}),this.trackMetric({name:"store.performance.listener_executions",type:"counter",value:e.listenerExecutions,labels:{}}),this.trackMetric({name:"store.performance.average_update_time",type:"gauge",value:e.averageUpdateTime,unit:"ms",labels:{}}),this.trackMetric({name:"store.performance.largest_update_size",type:"gauge",value:e.largestUpdateSize,unit:"paths",labels:{}})}disconnect(){this.reportingTimer&&(clearInterval(this.reportingTimer),this.reportingTimer=null),this.flushMetrics().catch((e=>console.error("Error flushing metrics during disconnect:",e))),super.disconnect()}};var w=class e{static dbInstance=null;static eventBusMap=new Map;static dbName="ReactiveDataStore";static modelName="stores";static getDatabase(){return e.dbInstance||(e.dbInstance=s.DatabaseConnection({name:e.dbName,enableTelemetry:!1}).then((async t=>{const r={name:e.modelName,version:"1.0.0",fields:{storeId:{type:"string",required:!0},data:{type:"object",required:!0}}};try{await t.createModel(r)}catch(e){if(e instanceof s.DatabaseError&&"SCHEMA_ALREADY_EXISTS"!==e.type)throw e}return t}))),e.dbInstance}static getEventBus(r){const s=`store_${r}`;return e.eventBusMap.has(s)||e.eventBusMap.set(s,t.createEventBus({batchSize:5,async:!0,batchDelay:16,errorHandler:e=>console.error(`Event bus error for ${r}:`,e),crossTab:!0,channelName:s})),e.eventBusMap.get(s)}static async getCursor(){return(await e.getDatabase()).cursor(e.modelName)}static async close(){const t=await e.dbInstance;t&&t.close(),e.dbInstance=null,e.eventBusMap.forEach((e=>e.clear())),e.eventBusMap.clear()}};exports.IndexedDBPersistence=class{cursorPromise;storeId;eventBus;constructor(e){this.storeId=e,this.cursorPromise=w.getCursor(),this.eventBus=w.getEventBus(e)}async set(e,t){try{const r=await this.cursorPromise,s=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),n=await r.find(s.filters),i={storeId:this.storeId,data:t};let o;return n?o=await n.update(i):(await r.create(i),o=!0),o&&this.eventBus.emit({name:"store:updated",payload:{storeId:this.storeId,instanceId:e,state:t}}),o}catch(t){return console.error(`Failed to set state for store ${this.storeId} by instance ${e}:`,t),!1}}async get(){try{const e=await this.cursorPromise,t=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),r=await e.find(t.filters);return r?r.read().then((()=>r.data)):null}catch(e){return console.error(`Failed to get state for store ${this.storeId}:`,e),null}}subscribe(e,t){return this.eventBus.subscribe("store:updated",(({storeId:r,instanceId:s,state:a})=>{r===this.storeId&&s!==e&&t(a)}))}async clear(){try{const e=await this.cursorPromise,t=(new a.QueryBuilder).where({field:"storeId",operator:"eq",value:this.storeId}).build(),r=await e.find(t.filters);return!r||await r.delete()}catch(e){return console.error(`Failed to clear state for store ${this.storeId}:`,e),!1}}static async closeAll(){await w.close()}},exports.LocalStoragePersistence=class{storageKey;bus;constructor(e){this.storageKey=e,this.bus=t.createEventBus({async:!0,batchSize:5,batchDelay:16,errorHandler:t=>console.error(`Event bus error for ${e}:`,t),crossTab:!0,channelName:`storage_${e}`}),window.addEventListener("storage",(e=>{if(e.key===this.storageKey&&e.newValue)try{const t=JSON.parse(e.newValue);this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:"external",state:t}})}catch(e){console.error("Failed to parse storage event data:",e)}}))}set(e,t){try{const r=JSON.stringify(t);return localStorage.setItem(this.storageKey,r),this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:e,state:t}}),!0}catch(e){return console.error(`Failed to persist state to localStorage for ${this.storageKey}:`,e),!1}}get(){try{const e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch(e){return console.error(`Failed to retrieve state from localStorage for ${this.storageKey}:`,e),null}}subscribe(e,t){return this.bus.subscribe("storage:updated",(({storageKey:r,instanceId:s,state:a})=>{r===this.storageKey&&s!==e&&t(a)}))}clear(){try{return localStorage.removeItem(this.storageKey),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.storageKey}:`,e),!1}}},exports.ReactiveDataStore=d,exports.RemoteObservability=y,exports.StoreObservability=i,exports.createGrafanaCloudDestination=p,exports.createHttpDestination=g,exports.createOpenTelemetryDestination=u,exports.createPrometheusDestination=m,exports.createStore=function(t,{enableMetrics:r,...s}={}){const a=new d(t.state,s.persistence),n=r?new i(a,s):void 0,o=new l;t.middleware&&Object.entries(t.middleware).forEach((([e,t])=>a.use(t,e))),t.blockingMiddleware&&Object.entries(t.blockingMiddleware).forEach((([e,t])=>a.useBlockingMiddleware(t,e)));const c=new h,u=Object.entries(t.actions).reduce(((e,[t,r])=>(e[t]=async(...e)=>{const s=crypto.randomUUID(),n=performance.now(),i={id:s,name:t,params:e,startTime:n};try{await a.set((async t=>{const s=await r(t,...e);return i.result=s,s})),i.status="success"}catch(e){throw i.status="error",i.error=e instanceof Error?e:new Error(String(e)),console.error(`Error in action ${t}:`,e),e}finally{i.endTime=performance.now(),i.duration=i.endTime-n,c.track(i)}},e)),{});function m(e,t){const r=function(e,t="."){const r=[],s={get:(e,t)=>{const a=[];return r.length>0&&a.push(...r[r.length-1]),a.push(t),r.push(a),new Proxy({},s)}};return e(new Proxy({},s)),r.map((e=>e.join(t)))}(e);return a.subscribe(r,t)}const p=()=>a.get(),g=e=>(a.isReady()&&e(),a.onStoreEvent("persistence:ready",e)),y=()=>a.isReady();return function(){const t=e.useCallback((t=>{const r=o.create(t);return e.useSyncExternalStore((e=>m(r,e)),(()=>r(a.get())),(()=>r(a.get())))}),[]),r=e.useCallback((()=>e.useSyncExternalStore((e=>a.subscribe("",e)),p,p)),[]),s=e.useSyncExternalStore(g,y,y);return{store:a,observer:n,select:t,actions:u,isReady:s,actionTracker:c,get state(){return r}}}},exports.useRemoteObservability=function(e,t){const r=new y(e,t);return{remote:r,addOpenTelemetryDestination:e=>r.addDestination(u(e)),addPrometheusDestination:e=>r.addDestination(m(e)),addGrafanaCloudDestination:e=>r.addDestination(p(e)),addHttpDestination:e=>r.addDestination(g(e))}};
package/index.d.cts CHANGED
@@ -102,7 +102,7 @@ type StateUpdater<T> = DeepPartial<T> | ((state: T) => DeepPartial<T> | Promise<
102
102
  * Interface defining the contract for the data state.
103
103
  */
104
104
  interface DataStore<T extends object> {
105
- get(): T;
105
+ get(clone?: boolean): T;
106
106
  set(update: StateUpdater<T>): Promise<void>;
107
107
  subscribe(path: string, listener: (state: T) => void): () => void;
108
108
  transaction<R>(operation: () => R | Promise<R>): Promise<R>;
@@ -146,7 +146,7 @@ declare class ReactiveDataStore<T extends object> implements DataStore<T> {
146
146
  * Gets a specific part of the state at the given path.
147
147
  * @returns The current state
148
148
  */
149
- get(): T;
149
+ get(clone?: boolean): T;
150
150
  /**
151
151
  * Updates the state with the provided partial state.
152
152
  * @param update The partial state to update with.
package/index.d.ts CHANGED
@@ -102,7 +102,7 @@ type StateUpdater<T> = DeepPartial<T> | ((state: T) => DeepPartial<T> | Promise<
102
102
  * Interface defining the contract for the data state.
103
103
  */
104
104
  interface DataStore<T extends object> {
105
- get(): T;
105
+ get(clone?: boolean): T;
106
106
  set(update: StateUpdater<T>): Promise<void>;
107
107
  subscribe(path: string, listener: (state: T) => void): () => void;
108
108
  transaction<R>(operation: () => R | Promise<R>): Promise<R>;
@@ -146,7 +146,7 @@ declare class ReactiveDataStore<T extends object> implements DataStore<T> {
146
146
  * Gets a specific part of the state at the given path.
147
147
  * @returns The current state
148
148
  */
149
- get(): T;
149
+ get(clone?: boolean): T;
150
150
  /**
151
151
  * Updates the state with the provided partial state.
152
152
  * @param update The partial state to update with.
package/index.js CHANGED
@@ -1 +1 @@
1
- import{useCallback as e,useSyncExternalStore as t}from"react";import{createEventBus as s}from"@asaidimu/events";import{v4 as r}from"uuid";import{DatabaseConnection as a,DatabaseError as n}from"@asaidimu/indexed";import{QueryBuilder as i}from"@asaidimu/query";function o(e,t){const s=new Set;function r(e,t){const s=e.split(".");for(let e=0;e<s.length;e++){const r=s.slice(0,e+1).join(".");t.add(r)}}return function e(t,a,n){const i=Symbol.for("delete");if(Array.isArray(a)&&Array.isArray(n))JSON.stringify(a)!==JSON.stringify(n)&&r(t,s);else for(const o of Object.keys(n)){const c=t?`${t}.${o}`:o;if(o in a){const t=a[o],d=n[o];d===i?(r(c,s),e(c,{},n[o])):"object"==typeof t&&null!==t&&"object"==typeof d&&null!==d?e(c,t,d):t!==d&&r(c,s)}else r(c,s),e(c,{},n[o])}}("",e||{},t||{}),Array.from(s)}var c=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;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"];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=>{"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===o(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.store.getMiddlewareExecutions()}getPerformanceMetrics(){return this.store.getPerformanceMetrics()}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],a=o(r,s),n={},i={};for(const e of a){const t=e.split("."),a=(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,a=t[r];t.slice(0,r).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[a]=s},c=a(r,t),d=a(s,t);o(n,t,c),o(i,t,d)}let c=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){c=e.timestamp;break}0!==a.length&&t.push({timestamp:c,changedPaths:a,from:n,to:i})}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()}};function d(e,t){const s=Symbol.for("delete");if("object"!=typeof e||null===e)return t;if("object"!=typeof t||null===t)return e;const r=structuredClone(e),a=[{target:r,source:t}];for(;a.length>0;){const{target:e,source:t}=a.pop();Object.keys(t).forEach((r=>{const n=t[r],i=e[r];n===s?delete e[r]:Array.isArray(n)?e[r]=n:"object"==typeof n&&null!==n&&"object"==typeof i&&null!==i?(e.hasOwnProperty(r)||(e[r]=structuredClone(n)),a.push({target:e[r],source:n})):e[r]=n}))}return r}var l=class{metrics;middleware;blockingMiddleware;middlewareExecutions=[];maxExecutionHistory=100;pendingUpdates;isUpdating;updateTimes;cache=null;updateBus=s();eventBus=s();executionState;persistence;instanceID=r();persistenceReady=!1;constructor(e,t){this.middleware=[],this.blockingMiddleware=[],this.pendingUpdates=[],this.isUpdating=!1,this.updateTimes=[],this.metrics={updateCount:0,listenerExecutions:0,averageUpdateTime:0,largestUpdateSize:0,mostActiveListenerPaths:[]},this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.cache=e,t?this.setPersistence(t):this.setPersistenceReady()}setPersistenceReady(){this.persistenceReady=!0,this.eventBus.emit({name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&await this.set(e)}catch(e){console.error("Failed to initialize persistence:",e)}finally{this.setPersistenceReady()}this.persistence.subscribe(this.instanceID,(async e=>{this.isUpdating=!0;try{const t=o(this.get(),e);t.length>0&&(await this.set(e),this.eventBus.emit({name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}}))}finally{this.isUpdating=!1}}))}isReady(){return this.persistenceReady}getExecutionState(){return this.executionState}get(){return this.cache}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.eventBus.emit({name:"update:start",payload:{timestamp:t}});let s=e;if("function"==typeof e){const t=e(structuredClone(this.get()));s=t instanceof Promise?await t:t}try{const e=await this.applyBlockingMiddleware(s);if(e.blocked)return void this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e.error,timestamp:Date.now()}})}catch(e){throw this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}const r=d(this.get(),s),a=await this.applyMiddleware(r,s);try{const e=o(this.get(),a);if(this.metrics.updateCount++,this.metrics.largestUpdateSize=Math.max(this.metrics.largestUpdateSize,e.length),e.length>0){this.cache=a;try{await(this.persistence?.set(this.instanceID,this.get()))||this.eventBus.emit({name:"update:complete",payload:{persistence:!1,timestamp:Date.now()}})}catch(e){this.eventBus.emit({name:"update:complete",payload:{persistence:!1,error:e,timestamp:Date.now()}})}this.notifyListeners(e)}const s=performance.now();this.updateTimes.push(s-t),this.updateTimes.length>100&&this.updateTimes.shift(),this.metrics.averageUpdateTime=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length,this.eventBus.emit({name:"update:complete",payload:{changedPaths:e,duration:s-t,timestamp:Date.now()}})}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)}}}async applyBlockingMiddleware(e){for(const{fn:t,name:s,id:r}of this.blockingMiddleware){const a={id:r,name:s,startTime:performance.now()};this.executionState.runningMiddleware={id:r,name:s,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:r,name:s,type:"blocking",timestamp:Date.now()}});try{const n=await Promise.resolve(t(this.get(),e));if(a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,!1===n)return a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:blocked",payload:{id:r,name:s,duration:a.duration,timestamp:Date.now()}}),{blocked:!0};this.eventBus.emit({name:"middleware:complete",payload:{id:r,name:s,type:"blocking",duration:a.duration,timestamp:Date.now()}}),this.trackMiddlewareExecution({...a,blocked:!1})}catch(e){return a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:error",payload:{id:r,name:s,error:a.error,duration:a.duration,timestamp:Date.now()}}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async applyMiddleware(e,t){let s=e;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.eventBus.emit({name:"middleware:start",payload:{id:a,name:r,type:"transform",timestamp:Date.now()}});try{const i=await Promise.resolve(e(s,t));n.endTime=performance.now(),n.duration=void 0!==n.startTime?n.endTime-n.startTime:0,n.blocked=!1,i&&"object"==typeof i&&(s=d(s,i)),this.trackMiddlewareExecution(n),this.eventBus.emit({name:"middleware:complete",payload:{id:a,name:r,type:"transform",duration:n.duration,timestamp:Date.now()}})}catch(e){n.endTime=performance.now(),n.duration=void 0!==n.startTime?n.endTime-n.startTime:0,n.error=e instanceof Error?e:new Error(String(e)),n.blocked=!1,this.trackMiddlewareExecution(n),this.eventBus.emit({name:"middleware:error",payload:{id:a,name:r,error:n.error,duration:n.duration,timestamp:Date.now()}}),console.error(`Middleware ${r} error:`,e)}finally{this.executionState.runningMiddleware=null}}return s}subscribe(e,t){const s=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(r=>{(s.includes(r)||""===e)&&(t(this.get()),this.metrics.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){const t=structuredClone(this.get());this.executionState.transactionActive=!0,this.eventBus.emit({name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.eventBus.emit({name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.cache=t,this.eventBus.emit({name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}use(e,t="unnamed-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.middleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],s}useBlockingMiddleware(e,t="unnamed-blocking-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.blockingMiddleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],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.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],this.middleware.length+this.blockingMiddleware.length<t}getPerformanceMetrics(){return structuredClone(this.metrics)}getMiddlewareExecutions(){return structuredClone(this.middlewareExecutions)}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}trackMiddlewareExecution(e){this.middlewareExecutions.unshift(e),this.middlewareExecutions.length>this.maxExecutionHistory&&this.middlewareExecutions.pop()}};var h=class{selectorCache=new WeakMap;create(e){return t=>{let s=this.selectorCache.get(e);s||(s=new WeakMap,this.selectorCache.set(e,s));const r=s.get(t);if(r)return r.result;const a=e(t);return s.set(t,{result:a,deps:[]}),a}}},u=class{executions=[];maxHistory=100;listeners=new Set;track(e){this.executions.unshift(e),this.executions.length>this.maxHistory&&this.executions.pop(),this.notify()}getExecutions(){return[...this.executions]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){this.listeners.forEach((e=>e()))}};function m(s,{enableMetrics:r,...a}={}){const n=new l(s.state,a.persistence),i=r?new c(n,a):void 0,o=new h;s.middleware&&Object.entries(s.middleware).forEach((([e,t])=>n.use(t,e))),s.blockingMiddleware&&Object.entries(s.blockingMiddleware).forEach((([e,t])=>n.useBlockingMiddleware(t,e)));const d=new u,m=Object.entries(s.actions).reduce(((e,[t,s])=>(e[t]=async(...e)=>{const r=crypto.randomUUID(),a=performance.now(),i={id:r,name:t,params:e,startTime:a};try{await n.set((async t=>{const r=await s(t,...e);return i.result=r,r})),i.status="success"}catch(e){throw i.status="error",i.error=e instanceof Error?e:new Error(String(e)),console.error(`Error in action ${t}:`,e),e}finally{i.endTime=performance.now(),i.duration=i.endTime-a,d.track(i)}},e)),{});function p(e,t){const s=function(e,t="."){const s=[],r={get:(e,t)=>{const a=[];return s.length>0&&a.push(...s[s.length-1]),a.push(t),s.push(a),new Proxy({},r)}};return e(new Proxy({},r)),s.map((e=>e.join(t)))}(e);return n.subscribe(s,t)}const g=()=>n.get(),y=e=>(n.isReady()&&e(),n.onStoreEvent("persistence:ready",e)),w=()=>n.isReady();return function(){const s=e((e=>{const s=o.create(e);return t((e=>p(s,e)),(()=>s(n.get())),(()=>s(n.get())))}),[]),r=e((()=>t((e=>n.subscribe("",e)),g,g)),[]),a=t(y,w,w);return{store:n,observer:i,select:s,actions:m,isReady:a,actionTracker:d,get state(){return r}}}}function p(e){return{id:"opentelemetry",name:"OpenTelemetry Collector",config:e,testConnection:async()=>{try{return(await fetch(`${e.endpoint}/v1/metrics`,{method:"OPTIONS",headers:{...e.apiKey?{"api-key":e.apiKey}:{}}})).ok}catch(e){return!1}},send:async t=>{const s={resourceMetrics:[{resource:{attributes:{"service.name":t.source,...e.resource}},scopeMetrics:[{metrics:t.metrics.map((e=>"counter"===e.type?{name:e.name,unit:e.unit||"1",sum:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asInt:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:"histogram"===e.type?{name:e.name,unit:e.unit||"ms",histogram:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),count:1,sum:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:{name:e.name,unit:e.unit||"1",gauge:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asDouble:"number"==typeof e.value?e.value:1,attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}))}]}]};await fetch(`${e.endpoint}/v1/metrics`,{method:"POST",headers:{"Content-Type":"application/json",...e.apiKey?{"api-key":e.apiKey}:{}},body:JSON.stringify(s)})}}}function g(e){return{id:"prometheus",name:"Prometheus Pushgateway",config:e,testConnection:async()=>{try{const t=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;return(await fetch(e.pushgatewayUrl,{method:"HEAD",headers:{...t?{Authorization:t}:{}}})).ok}catch(e){return!1}},send:async t=>{let s="";for(const e of t.metrics){if("log"===e.type||"trace"===e.type)continue;const r=Object.entries({...e.labels,source:t.source,instance:t.metrics.find((e=>e.labels?.instanceId))?.labels?.instanceId||"unknown"}).map((([e,t])=>`${e}="${t.replace(/"/g,'\\"')}"`)).join(","),a=e.name.replace(/\./g,"_");"counter"===e.type?s+=`# TYPE ${a} counter\n`:s+=`# TYPE ${a} gauge\n`,s+=`${a}{${r}} ${e.value}\n`}const r=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;await fetch(`${e.pushgatewayUrl}/metrics/job/${e.jobName}`,{method:"POST",headers:{"Content-Type":"text/plain",...r?{Authorization:r}:{}},body:s})}}}function y(e){return{id:"grafana-cloud",name:"Grafana Cloud",config:e,testConnection:async()=>{try{return(await fetch(`${e.url}/api/v1/query?query=up`,{method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`}})).ok}catch(e){return!1}},send:async t=>{const s={streams:[{stream:{service:t.source,job:"store-metrics"},values:t.metrics.map((e=>{const s=1e6*t.timestamp;let r="";if("object"==typeof e.value)r=JSON.stringify(e.value);else if(r=`level=info metric=${e.name} value=${e.value} type=${e.type}`,e.labels)for(const[t,s]of Object.entries(e.labels))r+=` ${t}=${s}`;return[String(s),r]}))}]};await fetch(`${e.url}/loki/api/v1/push`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(s)})}}}function w(e){return{id:"http-endpoint",name:"HTTP Metrics Endpoint",config:e,testConnection:async()=>{try{return(await fetch(e.url,{method:"OPTIONS",headers:e.headers})).ok}catch(e){return!1}},send:async t=>{const s=e.transformPayload?e.transformPayload(t):t;await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(s)})}}}var f=class extends c{destinations=new Map;metricsBatch=[];reportingInterval;batchSize;serviceName;environment;instanceId;immediateReporting;collectCategories;compressPayloads;reportingTimer=null;traceIdCounter=0;activeTraces=new Map;constructor(e,t){super(e,t),this.serviceName=t.serviceName,this.environment=t.environment,this.instanceId=t.instanceId||this.generateInstanceId(),this.reportingInterval=t.reportingInterval||3e4,this.batchSize=t.batchSize||100,this.immediateReporting=t.immediateReporting||!1,this.collectCategories=t.collectCategories||{performance:!0,errors:!0,stateChanges:!0,middleware:!0},this.compressPayloads=t.compressPayloads||!1,this.immediateReporting||this.startReportingCycle(),this.setupRemoteEventListeners()}generateInstanceId(){return`${Date.now()}-${Math.random().toString(36).substring(2,9)}`}setupRemoteEventListeners(){this.store.onStoreEvent("update:complete",(e=>{this.collectCategories?.stateChanges&&(this.trackMetric({name:"store.update.duration",type:"histogram",value:e.duration||0,unit:"ms",labels:{pathCount:String(e.changedPaths?.length||0)}}),this.trackMetric({name:"store.update.paths_changed",type:"counter",value:e.changedPaths?.length||0,labels:{blocked:String(!!e.blocked)}}))})),this.store.onStoreEvent("middleware:error",(e=>{this.collectCategories?.errors&&this.trackMetric({name:"store.middleware.error",type:"log",value:{middleware:e.name,error:e.error?.message||"Unknown error",stack:e.error?.stack},labels:{middlewareName:e.name}})})),this.store.onStoreEvent("transaction:start",(e=>{if(!this.collectCategories?.performance)return;const t=this.beginTrace("transaction");e.traceId=t,this.beginSpan(t,"transaction.execution",{transactionId:e.id||String(Date.now())})})),this.store.onStoreEvent("transaction:complete",(e=>{this.collectCategories?.performance&&e.traceId&&(this.endSpan(e.traceId,"transaction.execution"),this.endTrace(e.traceId))}))}beginTrace(e){const t=`trace-${++this.traceIdCounter}-${Date.now()}`;return this.activeTraces.set(t,{startTime:performance.now(),name:e,spans:{}}),t}beginSpan(e,t,s={}){const r=this.activeTraces.get(e);if(!r)return"";const a=`span-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;return r.spans[a]={startTime:performance.now(),name:t,labels:s},a}endSpan(e,t){const s=this.activeTraces.get(e);if(!s)return;const r=Object.entries(s.spans).filter((([e,s])=>s.name===t&&!s.endTime)).map((([e])=>e));if(r.length>0){const e=r[r.length-1];s.spans[e].endTime=performance.now()}}endTrace(e){const t=this.activeTraces.get(e);if(!t)return;const s=performance.now(),r=s-t.startTime;this.trackMetric({name:"store.trace.duration",type:"histogram",value:r,unit:"ms",labels:{traceName:t.name,traceId:e}}),Object.entries(t.spans).forEach((([t,r])=>{r.endTime||(r.endTime=s);const a=r.endTime-r.startTime;this.trackMetric({name:"store.trace.span.duration",type:"trace",value:a,unit:"ms",labels:{...r.labels,spanName:r.name},traceId:e,parentId:t})})),this.activeTraces.delete(e)}addDestination(e){return this.destinations.has(e.id)?(console.warn(`Destination with ID ${e.id} already exists`),!1):(this.destinations.set(e.id,e),!0)}removeDestination(e){return this.destinations.delete(e)}getDestinations(){return Array.from(this.destinations.values()).map((e=>({id:e.id,name:e.name})))}async testAllConnections(){const e={};for(const[t,s]of this.destinations.entries())if(s.testConnection)try{e[t]=await s.testConnection()}catch(s){e[t]=!1}else e[t]=!0;return e}trackMetric(e){e.labels={...e.labels,environment:this.environment,service:this.serviceName,instanceId:this.instanceId},this.metricsBatch.push(e),(this.immediateReporting||this.metricsBatch.length>=this.batchSize)&&this.flushMetrics()}async flushMetrics(){if(0===this.metricsBatch.length)return;const e={timestamp:Date.now(),source:this.serviceName,metrics:[...this.metricsBatch]};this.metricsBatch=[];const t=Array.from(this.destinations.values()).map((async t=>{try{let s=e;if(this.compressPayloads&&"undefined"!=typeof window&&window.CompressionStream){const t=JSON.stringify(e),r=(new TextEncoder).encode(t),a=new CompressionStream("gzip"),n=new Blob([r]).stream().pipeThrough(a);await new Response(n).blob();s._compressed=!0,s._originalSize=t.length}await t.send(s)}catch(s){if(console.error(`Failed to send metrics to destination ${t.name}:`,s),e.metrics.some((e=>"log"===e.type&&e.name.includes("error")))){const t=e.metrics.filter((e=>"log"===e.type&&e.name.includes("error")));this.metricsBatch.push(...t)}}}));await Promise.all(t)}startReportingCycle(){this.reportingTimer&&clearInterval(this.reportingTimer),this.reportingTimer=setInterval((()=>{this.flushMetrics()}),this.reportingInterval)}setReportingInterval(e){this.reportingInterval=e,this.startReportingCycle()}reportCurrentMetrics(){const e=this.store.getPerformanceMetrics();this.trackMetric({name:"store.performance.update_count",type:"counter",value:e.updateCount,labels:{}}),this.trackMetric({name:"store.performance.listener_executions",type:"counter",value:e.listenerExecutions,labels:{}}),this.trackMetric({name:"store.performance.average_update_time",type:"gauge",value:e.averageUpdateTime,unit:"ms",labels:{}}),this.trackMetric({name:"store.performance.largest_update_size",type:"gauge",value:e.largestUpdateSize,unit:"paths",labels:{}})}disconnect(){this.reportingTimer&&(clearInterval(this.reportingTimer),this.reportingTimer=null),this.flushMetrics().catch((e=>console.error("Error flushing metrics during disconnect:",e))),super.disconnect()}};function b(e,t){const s=new f(e,t);return{remote:s,addOpenTelemetryDestination:e=>s.addDestination(p(e)),addPrometheusDestination:e=>s.addDestination(g(e)),addGrafanaCloudDestination:e=>s.addDestination(y(e)),addHttpDestination:e=>s.addDestination(w(e))}}var v=class{storageKey;bus;constructor(e){this.storageKey=e,this.bus=s({async:!0,batchSize:5,batchDelay:16,errorHandler:t=>console.error(`Event bus error for ${e}:`,t),crossTab:!0,channelName:`storage_${e}`}),window.addEventListener("storage",(e=>{if(e.key===this.storageKey&&e.newValue)try{const t=JSON.parse(e.newValue);this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:"external",state:t}})}catch(e){console.error("Failed to parse storage event data:",e)}}))}set(e,t){try{const s=JSON.stringify(t);return localStorage.setItem(this.storageKey,s),this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:e,state:t}}),!0}catch(e){return console.error(`Failed to persist state to localStorage for ${this.storageKey}:`,e),!1}}get(){try{const e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch(e){return console.error(`Failed to retrieve state from localStorage for ${this.storageKey}:`,e),null}}subscribe(e,t){return this.bus.subscribe("storage:updated",(({storageKey:s,instanceId:r,state:a})=>{s===this.storageKey&&r!==e&&t(a)}))}clear(){try{return localStorage.removeItem(this.storageKey),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.storageKey}:`,e),!1}}},T=class e{static dbInstance=null;static eventBusMap=new Map;static dbName="ReactiveDataStore";static modelName="stores";static getDatabase(){return e.dbInstance||(e.dbInstance=a({name:e.dbName,enableTelemetry:!1}).then((async t=>{const s={name:e.modelName,version:"1.0.0",fields:{storeId:{type:"string",required:!0},data:{type:"object",required:!0}}};try{await t.createModel(s)}catch(e){if(e instanceof n&&"SCHEMA_ALREADY_EXISTS"!==e.type)throw e}return t}))),e.dbInstance}static getEventBus(t){const r=`store_${t}`;return e.eventBusMap.has(r)||e.eventBusMap.set(r,s({batchSize:5,async:!0,batchDelay:16,errorHandler:e=>console.error(`Event bus error for ${t}:`,e),crossTab:!0,channelName:r})),e.eventBusMap.get(r)}static async getCursor(){return(await e.getDatabase()).cursor(e.modelName)}static async close(){const t=await e.dbInstance;t&&t.close(),e.dbInstance=null,e.eventBusMap.forEach((e=>e.clear())),e.eventBusMap.clear()}},S=class{cursorPromise;storeId;eventBus;constructor(e){this.storeId=e,this.cursorPromise=T.getCursor(),this.eventBus=T.getEventBus(e)}async set(e,t){try{const s=await this.cursorPromise,r=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),a=await s.find(r.filters),n={storeId:this.storeId,data:t};let o;return a?o=await a.update(n):(await s.create(n),o=!0),o&&this.eventBus.emit({name:"store:updated",payload:{storeId:this.storeId,instanceId:e,state:t}}),o}catch(t){return console.error(`Failed to set state for store ${this.storeId} by instance ${e}:`,t),!1}}async get(){try{const e=await this.cursorPromise,t=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return s?s.read().then((()=>s.data)):null}catch(e){return console.error(`Failed to get state for store ${this.storeId}:`,e),null}}subscribe(e,t){return this.eventBus.subscribe("store:updated",(({storeId:s,instanceId:r,state:a})=>{s===this.storeId&&r!==e&&t(a)}))}async clear(){try{const e=await this.cursorPromise,t=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return!s||await s.delete()}catch(e){return console.error(`Failed to clear state for store ${this.storeId}:`,e),!1}}static async closeAll(){await T.close()}};export{S as IndexedDBPersistence,v as LocalStoragePersistence,l as ReactiveDataStore,f as RemoteObservability,c as StoreObservability,y as createGrafanaCloudDestination,w as createHttpDestination,p as createOpenTelemetryDestination,g as createPrometheusDestination,m as createStore,b as useRemoteObservability};
1
+ import{useCallback as e,useSyncExternalStore as t}from"react";import{createEventBus as s}from"@asaidimu/events";import{v4 as r}from"uuid";import{DatabaseConnection as a,DatabaseError as n}from"@asaidimu/indexed";import{QueryBuilder as i}from"@asaidimu/query";function o(e,t){const s=new Set,r=Symbol.for("delete"),a=e=>s.has(e)||s.add(e);function n(e){if(!e)return;const t=e.split(".");a(e);for(let e=t.length-1;e>0;e--)a(t.slice(0,e).join("."))}const i=[{path:"",orig:e||{},part:t||{}}];for(;i.length>0;){const{path:e,orig:t,part:s}=i.pop();if(null!=s)if(Array.isArray(s))Array.isArray(t)&&JSON.stringify(t)===JSON.stringify(s)||n(e);else if("object"==typeof s)for(const a of Object.keys(s)){const o=e?`${e}.${a}`:a,c=s[a];if(c===r||null==t){n(o);continue}const d=t[a];"object"==typeof c&&null!==c?i.push({path:o,orig:d,part:c}):d!==c&&n(o)}}return Array.from(s)}var c=class{store;eventHistory=[];maxEvents;enableConsoleLogging;logEvents;performanceThresholds;unsubscribers=[];stateHistory=[];maxStateHistory=20;activeTransactionCount=0;activeBatches=new Set;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"];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=>{"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===o(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.store.getMiddlewareExecutions()}getPerformanceMetrics(){return this.store.getPerformanceMetrics()}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],a=o(r,s),n={},i={};for(const e of a){const t=e.split("."),a=(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,a=t[r];t.slice(0,r).reduce(((e,t)=>(e[t]=e[t]??{},e[t])),e)[a]=s},c=a(r,t),d=a(s,t);o(n,t,c),o(i,t,d)}let c=Date.now();for(const e of this.eventHistory)if("update:complete"===e.type&&e.data.changedPaths?.length>0){c=e.timestamp;break}0!==a.length&&t.push({timestamp:c,changedPaths:a,from:n,to:i})}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()}};function d(e,t){const s=Symbol.for("delete");if("object"!=typeof e||null===e)return t;if("object"!=typeof t||null===t)return e;const r=l(e),a=[{target:r,source:t,path:[]}];for(;a.length>0;){const{target:e,source:t,path:r}=a.pop();for(const n of Object.keys(t)){const i=t[n],o=[...r,n];i!==s?Array.isArray(i)?e[n]=[...i]:"object"==typeof i&&null!==i?n in e&&null!==e[n]&&"object"==typeof e[n]?(e[n]=l(e[n]),a.push({target:e[n],source:i,path:o})):e[n]=l(i):e[n]=i:delete e[n]}}return r}var l=e=>Array.isArray(e)?[...e]:{...e},h=class{metrics;middleware;blockingMiddleware;middlewareExecutions=[];maxExecutionHistory=100;pendingUpdates;isUpdating;updateTimes;cache=null;updateBus=s();eventBus=s();executionState;persistence;instanceID=r();persistenceReady=!1;constructor(e,t){this.middleware=[],this.blockingMiddleware=[],this.pendingUpdates=[],this.isUpdating=!1,this.updateTimes=[],this.metrics={updateCount:0,listenerExecutions:0,averageUpdateTime:0,largestUpdateSize:0,mostActiveListenerPaths:[]},this.executionState={executing:!1,changes:null,pendingChanges:[],middlewares:[],runningMiddleware:null,transactionActive:!1},this.cache=e,t?this.setPersistence(t):this.setPersistenceReady()}setPersistenceReady(){this.persistenceReady=!0,this.eventBus.emit({name:"persistence:ready",payload:{timestamp:Date.now()}})}async setPersistence(e){this.persistence=e;try{const e=await this.persistence.get();e&&await this.set(e)}catch(e){console.error("Failed to initialize persistence:",e)}finally{this.setPersistenceReady()}this.persistence.subscribe(this.instanceID,(async e=>{this.isUpdating=!0;try{const t=o(this.get(),e);t.length>0&&(await this.set(e),this.eventBus.emit({name:"update:complete",payload:{changedPaths:t,source:"external",timestamp:Date.now()}}))}finally{this.isUpdating=!1}}))}isReady(){return this.persistenceReady}getExecutionState(){return this.executionState}get(e){return e?structuredClone(this.cache):this.cache}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.eventBus.emit({name:"update:start",payload:{timestamp:t}});let s=e;if("function"==typeof e){const t=e(this.get(!0));s=t instanceof Promise?await t:t}try{const e=await this.applyBlockingMiddleware(s);if(e.blocked)return void this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e.error,timestamp:Date.now()}})}catch(e){throw this.eventBus.emit({name:"update:complete",payload:{blocked:!0,error:e,timestamp:Date.now()}}),e}const r=d(this.get(!0),s),a=await this.applyMiddleware(r,s);try{const e=o(this.get(!0),a);if(this.metrics.updateCount++,this.metrics.largestUpdateSize=Math.max(this.metrics.largestUpdateSize,e.length),e.length>0){this.cache=d(this.get(!0),a);try{await(this.persistence?.set(this.instanceID,this.get()))||this.eventBus.emit({name:"update:complete",payload:{persistence:!1,timestamp:Date.now()}})}catch(e){this.eventBus.emit({name:"update:complete",payload:{persistence:!1,error:e,timestamp:Date.now()}})}this.notifyListeners(e)}const s=performance.now();this.updateTimes.push(s-t),this.updateTimes.length>100&&this.updateTimes.shift(),this.metrics.averageUpdateTime=this.updateTimes.reduce(((e,t)=>e+t),0)/this.updateTimes.length,this.eventBus.emit({name:"update:complete",payload:{changedPaths:e,duration:s-t,timestamp:Date.now()}})}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)}}}async applyBlockingMiddleware(e){for(const{fn:t,name:s,id:r}of this.blockingMiddleware){const a={id:r,name:s,startTime:performance.now()};this.executionState.runningMiddleware={id:r,name:s,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:r,name:s,type:"blocking",timestamp:Date.now()}});try{const n=await Promise.resolve(t(this.get(),e));if(a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,!1===n)return a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:blocked",payload:{id:r,name:s,duration:a.duration,timestamp:Date.now()}}),{blocked:!0};this.eventBus.emit({name:"middleware:complete",payload:{id:r,name:s,type:"blocking",duration:a.duration,timestamp:Date.now()}}),this.trackMiddlewareExecution({...a,blocked:!1})}catch(e){return a.endTime=performance.now(),a.duration=void 0!==a.startTime?a.endTime-a.startTime:0,a.error=e instanceof Error?e:new Error(String(e)),a.blocked=!0,this.trackMiddlewareExecution(a),this.eventBus.emit({name:"middleware:error",payload:{id:r,name:s,error:a.error,duration:a.duration,timestamp:Date.now()}}),{blocked:!0,error:a.error}}finally{this.executionState.runningMiddleware=null}}return{blocked:!1}}async applyMiddleware(e,t){let s=e,r=t;for(const{fn:e,name:a,id:n}of this.middleware){const i={id:n,name:a,startTime:performance.now()};this.executionState.runningMiddleware={id:n,name:a,startTime:performance.now()},this.eventBus.emit({name:"middleware:start",payload:{id:n,name:a,type:"transform",timestamp:Date.now()}});try{const o=await Promise.resolve(e(s,t));i.endTime=performance.now(),i.duration=void 0!==i.startTime?i.endTime-i.startTime:0,i.blocked=!1,o&&"object"==typeof o&&(s=d(s,o),r=d(r,o)),this.trackMiddlewareExecution(i),this.eventBus.emit({name:"middleware:complete",payload:{id:n,name:a,type:"transform",duration:i.duration,timestamp:Date.now()}})}catch(e){i.endTime=performance.now(),i.duration=void 0!==i.startTime?i.endTime-i.startTime:0,i.error=e instanceof Error?e:new Error(String(e)),i.blocked=!1,this.trackMiddlewareExecution(i),this.eventBus.emit({name:"middleware:error",payload:{id:n,name:a,error:i.error,duration:i.duration,timestamp:Date.now()}}),console.error(`Middleware ${a} error:`,e)}finally{this.executionState.runningMiddleware=null}}return r}subscribe(e,t){const s=Array.isArray(e)?e:[e];return this.updateBus.subscribe("update",(r=>{(s.includes(r)||""===e)&&(t(this.get()),this.metrics.listenerExecutions++)}))}id(){return this.instanceID}async transaction(e){const t=this.get(!0);this.executionState.transactionActive=!0,this.eventBus.emit({name:"transaction:start",payload:{timestamp:Date.now()}});try{const t=await Promise.resolve(e());return this.eventBus.emit({name:"transaction:complete",payload:{timestamp:Date.now()}}),this.executionState.transactionActive=!1,t}catch(e){throw this.cache=t,this.eventBus.emit({name:"transaction:error",payload:{error:e instanceof Error?e:new Error(String(e)),timestamp:Date.now()}}),this.executionState.transactionActive=!1,e}}use(e,t="unnamed-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.middleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],s}useBlockingMiddleware(e,t="unnamed-blocking-middleware"){const s=crypto.randomUUID?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2,15)}`;return this.blockingMiddleware.push({fn:e,name:t,id:s}),this.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],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.executionState.middlewares=[...this.middleware.map((e=>e.name)),...this.blockingMiddleware.map((e=>e.name))],this.middleware.length+this.blockingMiddleware.length<t}getPerformanceMetrics(){return structuredClone(this.metrics)}getMiddlewareExecutions(){return structuredClone(this.middlewareExecutions)}onStoreEvent(e,t){return this.eventBus.subscribe(e,t)}notifyListeners(e){e.forEach((e=>this.updateBus.emit({name:"update",payload:e})))}trackMiddlewareExecution(e){this.middlewareExecutions.unshift(e),this.middlewareExecutions.length>this.maxExecutionHistory&&this.middlewareExecutions.pop()}};var u=class{selectorCache=new WeakMap;create(e){return t=>{let s=this.selectorCache.get(e);s||(s=new WeakMap,this.selectorCache.set(e,s));const r=s.get(t);if(r)return r.result;const a=e(t);return s.set(t,{result:a,deps:[]}),a}}},m=class{executions=[];maxHistory=100;listeners=new Set;track(e){this.executions.unshift(e),this.executions.length>this.maxHistory&&this.executions.pop(),this.notify()}getExecutions(){return[...this.executions]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}notify(){this.listeners.forEach((e=>e()))}};function p(s,{enableMetrics:r,...a}={}){const n=new h(s.state,a.persistence),i=r?new c(n,a):void 0,o=new u;s.middleware&&Object.entries(s.middleware).forEach((([e,t])=>n.use(t,e))),s.blockingMiddleware&&Object.entries(s.blockingMiddleware).forEach((([e,t])=>n.useBlockingMiddleware(t,e)));const d=new m,l=Object.entries(s.actions).reduce(((e,[t,s])=>(e[t]=async(...e)=>{const r=crypto.randomUUID(),a=performance.now(),i={id:r,name:t,params:e,startTime:a};try{await n.set((async t=>{const r=await s(t,...e);return i.result=r,r})),i.status="success"}catch(e){throw i.status="error",i.error=e instanceof Error?e:new Error(String(e)),console.error(`Error in action ${t}:`,e),e}finally{i.endTime=performance.now(),i.duration=i.endTime-a,d.track(i)}},e)),{});function p(e,t){const s=function(e,t="."){const s=[],r={get:(e,t)=>{const a=[];return s.length>0&&a.push(...s[s.length-1]),a.push(t),s.push(a),new Proxy({},r)}};return e(new Proxy({},r)),s.map((e=>e.join(t)))}(e);return n.subscribe(s,t)}const g=()=>n.get(),y=e=>(n.isReady()&&e(),n.onStoreEvent("persistence:ready",e)),f=()=>n.isReady();return function(){const s=e((e=>{const s=o.create(e);return t((e=>p(s,e)),(()=>s(n.get())),(()=>s(n.get())))}),[]),r=e((()=>t((e=>n.subscribe("",e)),g,g)),[]),a=t(y,f,f);return{store:n,observer:i,select:s,actions:l,isReady:a,actionTracker:d,get state(){return r}}}}function g(e){return{id:"opentelemetry",name:"OpenTelemetry Collector",config:e,testConnection:async()=>{try{return(await fetch(`${e.endpoint}/v1/metrics`,{method:"OPTIONS",headers:{...e.apiKey?{"api-key":e.apiKey}:{}}})).ok}catch(e){return!1}},send:async t=>{const s={resourceMetrics:[{resource:{attributes:{"service.name":t.source,...e.resource}},scopeMetrics:[{metrics:t.metrics.map((e=>"counter"===e.type?{name:e.name,unit:e.unit||"1",sum:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asInt:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:"histogram"===e.type?{name:e.name,unit:e.unit||"ms",histogram:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),count:1,sum:Number(e.value),attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}:{name:e.name,unit:e.unit||"1",gauge:{dataPoints:[{timeUnixNano:BigInt(1e6*t.timestamp),asDouble:"number"==typeof e.value?e.value:1,attributes:Object.entries(e.labels||{}).map((([e,t])=>({key:e,value:{stringValue:t}})))}]}}))}]}]};await fetch(`${e.endpoint}/v1/metrics`,{method:"POST",headers:{"Content-Type":"application/json",...e.apiKey?{"api-key":e.apiKey}:{}},body:JSON.stringify(s)})}}}function y(e){return{id:"prometheus",name:"Prometheus Pushgateway",config:e,testConnection:async()=>{try{const t=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;return(await fetch(e.pushgatewayUrl,{method:"HEAD",headers:{...t?{Authorization:t}:{}}})).ok}catch(e){return!1}},send:async t=>{let s="";for(const e of t.metrics){if("log"===e.type||"trace"===e.type)continue;const r=Object.entries({...e.labels,source:t.source,instance:t.metrics.find((e=>e.labels?.instanceId))?.labels?.instanceId||"unknown"}).map((([e,t])=>`${e}="${t.replace(/"/g,'\\"')}"`)).join(","),a=e.name.replace(/\./g,"_");"counter"===e.type?s+=`# TYPE ${a} counter\n`:s+=`# TYPE ${a} gauge\n`,s+=`${a}{${r}} ${e.value}\n`}const r=e.username&&e.password?`Basic ${btoa(`${e.username}:${e.password}`)}`:void 0;await fetch(`${e.pushgatewayUrl}/metrics/job/${e.jobName}`,{method:"POST",headers:{"Content-Type":"text/plain",...r?{Authorization:r}:{}},body:s})}}}function f(e){return{id:"grafana-cloud",name:"Grafana Cloud",config:e,testConnection:async()=>{try{return(await fetch(`${e.url}/api/v1/query?query=up`,{method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`}})).ok}catch(e){return!1}},send:async t=>{const s={streams:[{stream:{service:t.source,job:"store-metrics"},values:t.metrics.map((e=>{const s=1e6*t.timestamp;let r="";if("object"==typeof e.value)r=JSON.stringify(e.value);else if(r=`level=info metric=${e.name} value=${e.value} type=${e.type}`,e.labels)for(const[t,s]of Object.entries(e.labels))r+=` ${t}=${s}`;return[String(s),r]}))}]};await fetch(`${e.url}/loki/api/v1/push`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(s)})}}}function w(e){return{id:"http-endpoint",name:"HTTP Metrics Endpoint",config:e,testConnection:async()=>{try{return(await fetch(e.url,{method:"OPTIONS",headers:e.headers})).ok}catch(e){return!1}},send:async t=>{const s=e.transformPayload?e.transformPayload(t):t;await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(s)})}}}var b=class extends c{destinations=new Map;metricsBatch=[];reportingInterval;batchSize;serviceName;environment;instanceId;immediateReporting;collectCategories;compressPayloads;reportingTimer=null;traceIdCounter=0;activeTraces=new Map;constructor(e,t){super(e,t),this.serviceName=t.serviceName,this.environment=t.environment,this.instanceId=t.instanceId||this.generateInstanceId(),this.reportingInterval=t.reportingInterval||3e4,this.batchSize=t.batchSize||100,this.immediateReporting=t.immediateReporting||!1,this.collectCategories=t.collectCategories||{performance:!0,errors:!0,stateChanges:!0,middleware:!0},this.compressPayloads=t.compressPayloads||!1,this.immediateReporting||this.startReportingCycle(),this.setupRemoteEventListeners()}generateInstanceId(){return`${Date.now()}-${Math.random().toString(36).substring(2,9)}`}setupRemoteEventListeners(){this.store.onStoreEvent("update:complete",(e=>{this.collectCategories?.stateChanges&&(this.trackMetric({name:"store.update.duration",type:"histogram",value:e.duration||0,unit:"ms",labels:{pathCount:String(e.changedPaths?.length||0)}}),this.trackMetric({name:"store.update.paths_changed",type:"counter",value:e.changedPaths?.length||0,labels:{blocked:String(!!e.blocked)}}))})),this.store.onStoreEvent("middleware:error",(e=>{this.collectCategories?.errors&&this.trackMetric({name:"store.middleware.error",type:"log",value:{middleware:e.name,error:e.error?.message||"Unknown error",stack:e.error?.stack},labels:{middlewareName:e.name}})})),this.store.onStoreEvent("transaction:start",(e=>{if(!this.collectCategories?.performance)return;const t=this.beginTrace("transaction");e.traceId=t,this.beginSpan(t,"transaction.execution",{transactionId:e.id||String(Date.now())})})),this.store.onStoreEvent("transaction:complete",(e=>{this.collectCategories?.performance&&e.traceId&&(this.endSpan(e.traceId,"transaction.execution"),this.endTrace(e.traceId))}))}beginTrace(e){const t=`trace-${++this.traceIdCounter}-${Date.now()}`;return this.activeTraces.set(t,{startTime:performance.now(),name:e,spans:{}}),t}beginSpan(e,t,s={}){const r=this.activeTraces.get(e);if(!r)return"";const a=`span-${Date.now()}-${Math.random().toString(36).substring(2,9)}`;return r.spans[a]={startTime:performance.now(),name:t,labels:s},a}endSpan(e,t){const s=this.activeTraces.get(e);if(!s)return;const r=Object.entries(s.spans).filter((([e,s])=>s.name===t&&!s.endTime)).map((([e])=>e));if(r.length>0){const e=r[r.length-1];s.spans[e].endTime=performance.now()}}endTrace(e){const t=this.activeTraces.get(e);if(!t)return;const s=performance.now(),r=s-t.startTime;this.trackMetric({name:"store.trace.duration",type:"histogram",value:r,unit:"ms",labels:{traceName:t.name,traceId:e}}),Object.entries(t.spans).forEach((([t,r])=>{r.endTime||(r.endTime=s);const a=r.endTime-r.startTime;this.trackMetric({name:"store.trace.span.duration",type:"trace",value:a,unit:"ms",labels:{...r.labels,spanName:r.name},traceId:e,parentId:t})})),this.activeTraces.delete(e)}addDestination(e){return this.destinations.has(e.id)?(console.warn(`Destination with ID ${e.id} already exists`),!1):(this.destinations.set(e.id,e),!0)}removeDestination(e){return this.destinations.delete(e)}getDestinations(){return Array.from(this.destinations.values()).map((e=>({id:e.id,name:e.name})))}async testAllConnections(){const e={};for(const[t,s]of this.destinations.entries())if(s.testConnection)try{e[t]=await s.testConnection()}catch(s){e[t]=!1}else e[t]=!0;return e}trackMetric(e){e.labels={...e.labels,environment:this.environment,service:this.serviceName,instanceId:this.instanceId},this.metricsBatch.push(e),(this.immediateReporting||this.metricsBatch.length>=this.batchSize)&&this.flushMetrics()}async flushMetrics(){if(0===this.metricsBatch.length)return;const e={timestamp:Date.now(),source:this.serviceName,metrics:[...this.metricsBatch]};this.metricsBatch=[];const t=Array.from(this.destinations.values()).map((async t=>{try{let s=e;if(this.compressPayloads&&"undefined"!=typeof window&&window.CompressionStream){const t=JSON.stringify(e),r=(new TextEncoder).encode(t),a=new CompressionStream("gzip"),n=new Blob([r]).stream().pipeThrough(a);await new Response(n).blob();s._compressed=!0,s._originalSize=t.length}await t.send(s)}catch(s){if(console.error(`Failed to send metrics to destination ${t.name}:`,s),e.metrics.some((e=>"log"===e.type&&e.name.includes("error")))){const t=e.metrics.filter((e=>"log"===e.type&&e.name.includes("error")));this.metricsBatch.push(...t)}}}));await Promise.all(t)}startReportingCycle(){this.reportingTimer&&clearInterval(this.reportingTimer),this.reportingTimer=setInterval((()=>{this.flushMetrics()}),this.reportingInterval)}setReportingInterval(e){this.reportingInterval=e,this.startReportingCycle()}reportCurrentMetrics(){const e=this.store.getPerformanceMetrics();this.trackMetric({name:"store.performance.update_count",type:"counter",value:e.updateCount,labels:{}}),this.trackMetric({name:"store.performance.listener_executions",type:"counter",value:e.listenerExecutions,labels:{}}),this.trackMetric({name:"store.performance.average_update_time",type:"gauge",value:e.averageUpdateTime,unit:"ms",labels:{}}),this.trackMetric({name:"store.performance.largest_update_size",type:"gauge",value:e.largestUpdateSize,unit:"paths",labels:{}})}disconnect(){this.reportingTimer&&(clearInterval(this.reportingTimer),this.reportingTimer=null),this.flushMetrics().catch((e=>console.error("Error flushing metrics during disconnect:",e))),super.disconnect()}};function v(e,t){const s=new b(e,t);return{remote:s,addOpenTelemetryDestination:e=>s.addDestination(g(e)),addPrometheusDestination:e=>s.addDestination(y(e)),addGrafanaCloudDestination:e=>s.addDestination(f(e)),addHttpDestination:e=>s.addDestination(w(e))}}var T=class{storageKey;bus;constructor(e){this.storageKey=e,this.bus=s({async:!0,batchSize:5,batchDelay:16,errorHandler:t=>console.error(`Event bus error for ${e}:`,t),crossTab:!0,channelName:`storage_${e}`}),window.addEventListener("storage",(e=>{if(e.key===this.storageKey&&e.newValue)try{const t=JSON.parse(e.newValue);this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:"external",state:t}})}catch(e){console.error("Failed to parse storage event data:",e)}}))}set(e,t){try{const s=JSON.stringify(t);return localStorage.setItem(this.storageKey,s),this.bus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:e,state:t}}),!0}catch(e){return console.error(`Failed to persist state to localStorage for ${this.storageKey}:`,e),!1}}get(){try{const e=localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch(e){return console.error(`Failed to retrieve state from localStorage for ${this.storageKey}:`,e),null}}subscribe(e,t){return this.bus.subscribe("storage:updated",(({storageKey:s,instanceId:r,state:a})=>{s===this.storageKey&&r!==e&&t(a)}))}clear(){try{return localStorage.removeItem(this.storageKey),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.storageKey}:`,e),!1}}},S=class e{static dbInstance=null;static eventBusMap=new Map;static dbName="ReactiveDataStore";static modelName="stores";static getDatabase(){return e.dbInstance||(e.dbInstance=a({name:e.dbName,enableTelemetry:!1}).then((async t=>{const s={name:e.modelName,version:"1.0.0",fields:{storeId:{type:"string",required:!0},data:{type:"object",required:!0}}};try{await t.createModel(s)}catch(e){if(e instanceof n&&"SCHEMA_ALREADY_EXISTS"!==e.type)throw e}return t}))),e.dbInstance}static getEventBus(t){const r=`store_${t}`;return e.eventBusMap.has(r)||e.eventBusMap.set(r,s({batchSize:5,async:!0,batchDelay:16,errorHandler:e=>console.error(`Event bus error for ${t}:`,e),crossTab:!0,channelName:r})),e.eventBusMap.get(r)}static async getCursor(){return(await e.getDatabase()).cursor(e.modelName)}static async close(){const t=await e.dbInstance;t&&t.close(),e.dbInstance=null,e.eventBusMap.forEach((e=>e.clear())),e.eventBusMap.clear()}},M=class{cursorPromise;storeId;eventBus;constructor(e){this.storeId=e,this.cursorPromise=S.getCursor(),this.eventBus=S.getEventBus(e)}async set(e,t){try{const s=await this.cursorPromise,r=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),a=await s.find(r.filters),n={storeId:this.storeId,data:t};let o;return a?o=await a.update(n):(await s.create(n),o=!0),o&&this.eventBus.emit({name:"store:updated",payload:{storeId:this.storeId,instanceId:e,state:t}}),o}catch(t){return console.error(`Failed to set state for store ${this.storeId} by instance ${e}:`,t),!1}}async get(){try{const e=await this.cursorPromise,t=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return s?s.read().then((()=>s.data)):null}catch(e){return console.error(`Failed to get state for store ${this.storeId}:`,e),null}}subscribe(e,t){return this.eventBus.subscribe("store:updated",(({storeId:s,instanceId:r,state:a})=>{s===this.storeId&&r!==e&&t(a)}))}async clear(){try{const e=await this.cursorPromise,t=(new i).where({field:"storeId",operator:"eq",value:this.storeId}).build(),s=await e.find(t.filters);return!s||await s.delete()}catch(e){return console.error(`Failed to clear state for store ${this.storeId}:`,e),!1}}static async closeAll(){await S.close()}};export{M as IndexedDBPersistence,T as LocalStoragePersistence,h as ReactiveDataStore,b as RemoteObservability,c as StoreObservability,f as createGrafanaCloudDestination,w as createHttpDestination,g as createOpenTelemetryDestination,y as createPrometheusDestination,p as createStore,v as useRemoteObservability};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/react-store",
3
- "version": "1.4.3",
3
+ "version": "1.4.4",
4
4
  "description": "Efficient react state manager.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",