@asaidimu/react-store 1.5.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,9 +21,9 @@ This package is currently in **beta**. The API is subject to rapid changes and s
21
21
  * [Persistence](#persistence)
22
22
  * [Middleware](#middleware)
23
23
  * [Observability](#observability)
24
- * [Remote Observability](#remote-observability)
25
24
  * [Transaction Support](#transaction-support)
26
25
  * [Event System](#event-system)
26
+ * [Watching Action Loading States](#watching-action-loading-states)
27
27
  * [Advanced Hook Properties](#advanced-hook-properties)
28
28
  * [Project Architecture](#project-architecture)
29
29
  * [Development & Contributing](#development--contributing)
@@ -51,8 +51,8 @@ Designed with modern React in mind, it leverages `useSyncExternalStore` for opti
51
51
  * šŸ“¦ **Transaction Support**: Group multiple state updates into a single atomic operation, with automatic rollback if any part of the transaction fails.
52
52
  * šŸ’¾ **Built-in Persistence**: Seamlessly integrate with web storage mechanisms like `IndexedDB` and `WebStorage` (localStorage/sessionStorage), including cross-tab synchronization.
53
53
  * šŸ” **Deep Observability**: Gain profound insights into your application's state with built-in metrics, detailed event logging, state history, and time-travel debugging capabilities.
54
- * šŸ“ˆ **Remote Observability**: Extend monitoring by sending collected metrics and traces to external systems like OpenTelemetry, Prometheus, or Grafana Cloud.
55
- * ⚔ **Performance Optimized**: Features intelligent selector caching and debounced actions to prevent rapid successive calls and ensure smooth application performance.
54
+ * ⚔ **Performance Optimized**: Features intelligent selector caching (now using `WeakMap` for enhanced efficiency) and debounced actions with configurable immediate execution to prevent rapid successive calls and ensure smooth application performance.
55
+ * šŸš€ **Action Loading States**: Track the real-time loading status of individual actions, providing immediate feedback on asynchronous operations.
56
56
  * āš›ļø **React 18+ Ready**: Fully compatible with the latest React versions, leveraging modern APIs for enhanced performance and development ergonomics.
57
57
  * šŸ—‘ļø **Explicit Deletions**: Use `Symbol.for("delete")` to explicitly remove properties from nested state objects.
58
58
 
@@ -94,7 +94,6 @@ const myStore = createStore({
94
94
  },
95
95
  });
96
96
 
97
- console.log(myStore().select(s => s.value)); // Should output 'hello'
98
97
  ```
99
98
 
100
99
  If no errors are thrown, the package is correctly installed.
@@ -135,7 +134,7 @@ const myStore = createStore({
135
134
  }),
136
135
  },
137
136
  }, {
138
- debounceTime: 100, // Debounce actions by 100ms
137
+ debounceTime: 0, // Actions execute immediately by default
139
138
  enableConsoleLogging: true, // Enable console logs for store events
140
139
  logEvents: { updates: true, transactions: true, middleware: true },
141
140
  performanceThresholds: { updateTime: 20, middlewareTime: 5 }, // Warn for slow operations
@@ -431,7 +430,7 @@ const useObservedStore = createStore(
431
430
  },
432
431
  maxEvents: 500, // Max number of events to keep in history
433
432
  maxStateHistory: 50, // Max number of state snapshots for time travel
434
- debounceTime: 300, // Debounce actions by 300ms to prevent rapid calls
433
+ debounceTime: 0, // Actions execute immediately by default
435
434
  },
436
435
  );
437
436
 
@@ -737,6 +736,63 @@ function EventMonitor() {
737
736
  }
738
737
  ```
739
738
 
739
+ ### Watching Action Loading States
740
+
741
+ The `watch` function returned by the `useStore` hook allows you to subscribe to the loading status of individual actions. This is particularly useful for displaying loading indicators for asynchronous operations.
742
+
743
+ ```tsx
744
+ import React from 'react';
745
+ import { createStore } from '@asaidimu/react-store';
746
+
747
+ interface DataState {
748
+ items: string[];
749
+ }
750
+
751
+ const useDataStore = createStore({
752
+ state: { items: [] },
753
+ actions: {
754
+ fetchItems: async (state) => {
755
+ // Simulate an API call
756
+ await new Promise(resolve => setTimeout(resolve, 2000));
757
+ return { items: ['Item A', 'Item B', 'Item C'] };
758
+ },
759
+ addItem: async (state, item: string) => {
760
+ // Simulate a quick add operation
761
+ await new Promise(resolve => setTimeout(resolve, 500));
762
+ return { items: [...state.items, item] };
763
+ },
764
+ },
765
+ });
766
+
767
+ function DataLoader() {
768
+ const { actions, select, watch } = useDataStore();
769
+ const items = select(s => s.items);
770
+
771
+ // Watch the loading state of specific actions
772
+ const isFetchingItems = watch('fetchItems');
773
+ const isAddingItem = watch('addItem');
774
+
775
+ return (
776
+ <div>
777
+ <h2>Data Loader</h2>
778
+ <button onClick={() => actions.fetchItems()} disabled={isFetchingItems}>
779
+ {isFetchingItems ? 'Fetching...' : 'Fetch Items'}
780
+ </button>
781
+ <button onClick={() => actions.addItem(`New Item ${items.length + 1}`)} disabled={isAddingItem}>
782
+ {isAddingItem ? 'Adding...' : 'Add Item'}
783
+ </button>
784
+
785
+ <h3>Items:</h3>
786
+ <ul>
787
+ {items.map((item, index) => (
788
+ <li key={index}>{item}</li>
789
+ ))}
790
+ </ul>
791
+ </div>
792
+ );
793
+ }
794
+ ```
795
+
740
796
  ### Advanced Hook Properties
741
797
 
742
798
  The hook returned by `createStore` provides several properties for advanced usage and debugging, beyond the commonly used `select`, `actions`, and `isReady`:
@@ -751,6 +807,7 @@ function MyAdvancedComponent() {
751
807
  observer, // StoreObservability instance (if `enableMetrics` was true)
752
808
  actionTracker, // Instance of ActionTracker for monitoring action executions
753
809
  state, // A hook `() => T` to get the entire reactive state object
810
+ watch, // Function to watch the loading status of actions
754
811
  } = useMyStore(); // Assuming useMyStore is defined from createStore
755
812
 
756
813
  // Example: Accessing the full state (use with caution for performance, `select` is preferred)
@@ -766,6 +823,10 @@ function MyAdvancedComponent() {
766
823
  // Example: Accessing action history
767
824
  console.log("Action executions:", actionTracker.getExecutions());
768
825
 
826
+ // Example: Watching a specific action's loading state
827
+ const isLoadingSomeAction = watch('someActionName');
828
+ console.log("Is 'someActionName' loading?", isLoadingSomeAction);
829
+
769
830
  return (
770
831
  <div>
771
832
  {/* ... your component content ... */}
@@ -778,57 +839,53 @@ function MyAdvancedComponent() {
778
839
 
779
840
  `@asaidimu/react-store` is structured to provide a modular yet integrated state management solution.
780
841
 
842
+ ### Internal Structure
843
+
844
+ The core logic of this package resides directly within the `src/` directory:
845
+
781
846
  ```
782
847
  .
783
848
  ā”œā”€ā”€ src/
784
- │ ā”œā”€ā”€ hooks/
785
- │ │ └── observability.ts # React hook for remote observability
786
- │ ā”œā”€ā”€ persistence/
787
- │ │ ā”œā”€ā”€ indexedb.ts # IndexedDB persistence adapter
788
- │ │ ā”œā”€ā”€ local-storage.ts # WebStorage (localStorage/sessionStorage) persistence adapter
789
- │ │ └── types.ts # Interface for persistence adapters
790
- │ ā”œā”€ā”€ state/
791
- │ │ ā”œā”€ā”€ diff.ts # Utility for deep diffing state objects
792
- │ │ ā”œā”€ā”€ merge.ts # Utility for immutable deep merging state objects
793
- │ │ ā”œā”€ā”€ observability.ts # Core observability logic for ReactiveDataStore
794
- │ │ └── store.ts # Core ReactiveDataStore implementation (the state machine)
795
- │ ā”œā”€ā”€ store/
796
- │ │ ā”œā”€ā”€ compare.ts # Utilities for fast comparison (e.g., array hashing)
797
- │ │ ā”œā”€ā”€ execution.ts # Action tracking interface and class
798
- │ │ ā”œā”€ā”€ hash.ts # Utilities for hashing objects (e.g., for selectors)
799
- │ │ ā”œā”€ā”€ index.ts # Main `createStore` React hook
800
- │ │ ā”œā”€ā”€ paths.ts # Utility for building selector paths
801
- │ │ └── selector.ts # Selector memoization manager
802
- │ ā”œā”€ā”€ types.ts # Core TypeScript types for the library
803
- │ └── utils/
804
- │ ā”œā”€ā”€ destinations.ts # Concrete remote observability destinations (OTel, Prometheus, Grafana)
805
- │ └── remote-observability.ts # Remote observability extension for StoreObservability
806
- ā”œā”€ā”€ index.ts # Main entry point for the library
849
+ │ ā”œā”€ā”€ execution.ts # Action tracking interface and class
850
+ │ ā”œā”€ā”€ hash.ts # Utilities for hashing objects (e.g., for selectors)
851
+ │ ā”œā”€ā”€ paths.ts # Utility for building selector paths
852
+ │ ā”œā”€ā”€ selector.ts # Selector memoization manager
853
+ │ ā”œā”€ā”€ store.ts # Main `createStore` React hook implementation
854
+ │ └── types.ts # Core TypeScript types for the library
855
+ ā”œā”€ā”€ index.ts # Main entry point for the library (re-exports `createStore` and other public APIs)
807
856
  ā”œā”€ā”€ package.json
808
857
  └── tsconfig.json
809
858
  ```
810
859
 
860
+ ### Key External Dependencies
861
+
862
+ This library leverages the following `@asaidimu` packages for its core functionalities:
863
+
864
+ * **`@asaidimu/utils-store`**: Provides the foundational `ReactiveDataStore` for state management, including immutable updates, transactions, and core event emission. It also includes `StoreObservability` for deep insights into state changes.
865
+ * **`@asaidimu/utils-persistence`**: Offers persistence adapters like `WebStoragePersistence` and `IndexedDBPersistence` for saving and loading state.
866
+
811
867
  ### Core Components
812
868
 
813
- * **`ReactiveDataStore` (`src/state/store.ts`)**: The heart of the library. It manages the immutable state, processes updates (including debouncing), handles middleware, transactions, and interacts with persistence adapters. It also emits detailed internal events for observability.
814
- * **`StoreObservability` (`src/state/observability.ts`)**: An extension built on top of `ReactiveDataStore`'s event system. It provides debugging features like event history, state snapshots for time-travel, performance metrics, and utilities to create logging/validation middleware.
815
- * **`createStore` Hook (`src/store/index.ts`)**: The primary React-facing API. It instantiates `ReactiveDataStore` and `StoreObservability`, wraps actions with debouncing and tracking, and provides the `select` hook powered by `useSyncExternalStore` for efficient component updates.
816
- * **Persistence Adapters (`src/persistence/`)**: Implement the `DataStorePersistence` interface. `WebStoragePersistence` (for localStorage/sessionStorage) and `IndexedDBPersistence` provide concrete storage solutions with cross-tab synchronization.
817
- * **`RemoteObservability` (`src/utils/remote-observability.ts`)**: Extends `StoreObservability` to enable sending metrics, logs, and traces to external monitoring systems. It defines a pluggable `RemoteDestination` interface and provides out-of-the-box implementations.
869
+ * **`ReactiveDataStore` (from `@asaidimu/utils-store`)**: The foundational state management layer. This external library manages the immutable state, processes updates, handles middleware, transactions, and interacts with persistence adapters. It also emits detailed internal events for observability.
870
+ * **`StoreObservability` (from `@asaidimu/utils-store`)**: An extension built on top of the external `ReactiveDataStore`'s event system. It provides debugging features like event history, state snapshots for time-travel, performance metrics, and utilities to create logging/validation middleware.
871
+ * **`createStore` Hook (`src/store.ts`)**: The primary React-facing API. It instantiates the external `ReactiveDataStore` and `StoreObservability`, wraps actions with debouncing and tracking, and provides the `select` hook powered by `useSyncExternalStore` for efficient component updates, and the `watch` function for action loading states.
872
+ * **Persistence Adapters (from `@asaidimu/utils-persistence`)**: Implement the `DataStorePersistence` interface. `WebStoragePersistence` and `IndexedDBPersistence` provide concrete storage solutions with cross-tab synchronization.
818
873
 
819
874
  ### Data Flow
820
875
 
821
876
  1. **Action Dispatch**: A React component calls an action (e.g., `actions.increment(1)`). Actions are debounced by default.
822
- 2. **Action Execution Tracking**: The `ActionTracker` records the action's details (name, params, start time).
823
- 3. **State Update Request**: The action, after potential debouncing, initiates a `store.set()` call with a partial state update or a function.
824
- 4. **Transaction Context**: If within a `store.transaction()`, the state is snapshotted for potential rollback.
825
- 5. **Blocking Middleware**: Updates first pass through `blockingMiddleware`. If any middleware returns `false` or throws, the update is halted, and the state is not modified.
826
- 6. **Transform Middleware**: If not blocked, updates then pass through transforming `middleware`. These functions can modify the partial update.
827
- 7. **State Merging**: The final transformed update is immutably merged into the current state using the `merge` utility. `Symbol.for("delete")` is handled here for property removal.
828
- 8. **Change Detection**: The `diff` utility identifies which paths in the state have truly changed.
829
- 9. **Persistence**: If changes occurred, the new state is saved via the configured `DataStorePersistence` adapter (e.g., `localStorage`, `IndexedDB`). External changes from persistence are also subscribed to and applied.
830
- 10. **Listener Notification**: Only `React.useSyncExternalStore` subscribers whose selected paths have changed are notified, triggering re-renders of relevant components.
831
- 11. **Observability Events**: Throughout this flow, the `ReactiveDataStore` emits fine-grained events (`update:start`, `middleware:complete`, `transaction:error`, etc.) that `StoreObservability` captures for debugging, metrics, and remote reporting.
877
+ 2. **Action Loading State Update**: The store immediately updates the loading state for the dispatched action to `true`.
878
+ 3. **Action Execution Tracking**: The `ActionTracker` records the action's details (name, params, start time).
879
+ 4. **State Update Request**: The action, after potential debouncing, initiates a `store.set()` call with a partial state update or a function returning a partial object.
880
+ 5. **Transaction Context**: If within a `store.transaction()`, the state is snapshotted for potential rollback.
881
+ 6. **Blocking Middleware**: Updates first pass through `blockingMiddleware`. If any middleware returns `false` or throws, the update is halted, and the state is not modified.
882
+ 7. **Transform Middleware**: If not blocked, updates then pass through transforming `middleware`. These functions can modify the partial update.
883
+ 8. **State Merging**: The final transformed update is immutably merged into the current state using `ReactiveDataStore`'s internal merge utility.
884
+ 9. **Change Detection**: `ReactiveDataStore`'s internal diffing mechanism identifies which paths in the state have truly changed.
885
+ 10. **Persistence**: If changes occurred, the new state is saved via the configured `DataStorePersistence` adapter (e.g., `localStorage`, `IndexedDB`). External changes from persistence are also subscribed to and applied.
886
+ 11. **Listener Notification**: Only `React.useSyncExternalStore` subscribers whose selected paths have changed are notified, triggering re-renders of relevant components.
887
+ 12. **Action Loading State Reset**: Once the action completes (success or error), the loading state for that action is reset to `false`.
888
+ 13. **Observability Events**: Throughout this flow, the `ReactiveDataStore` emits fine-grained events (`update:start`, `middleware:complete`, `transaction:error`, etc.) that `StoreObservability` captures for debugging, metrics, and remote reporting.
832
889
 
833
890
  ### Extension Points
834
891
 
@@ -861,7 +918,7 @@ We welcome contributions! Please follow the guidelines below.
861
918
  * `bun clean`: Removes the `dist` directory.
862
919
  * `bun prebuild`: Cleans `dist` and runs a sync script (internal).
863
920
  * `bun build`: Compiles the TypeScript source into `dist/` for CJS and ESM formats, generates type definitions, and minifies.
864
- * `bun dev`: Starts a development server (likely for a UI example).
921
+ * `bun dev`: Starts the e-commerce dashboard demonstration.
865
922
  * `bun postbuild`: Copies `README.md`, `LICENSE.md`, and `dist.package.json` into the `dist` folder.
866
923
 
867
924
  ### Testing
@@ -929,7 +986,7 @@ interface StoreOptions<T> {
929
986
  middlewareTime?: number; // default: 20ms
930
987
  };
931
988
  persistence?: DataStorePersistence<T>; // Optional persistence adapter instance
932
- debounceTime?: number; // Time in milliseconds to debounce actions (default: 250ms)
989
+ debounceTime?: number; // Time in milliseconds to debounce actions (default: 0ms)
933
990
  }
934
991
 
935
992
  const useStore = createStore(definition, options);
@@ -943,13 +1000,14 @@ const useStore = createStore(definition, options);
943
1000
  * `actionTracker`: An instance of `ActionTracker` for monitoring the execution history of your actions.
944
1001
  * `state`: A hook `() => T` that returns the entire current state object. Use sparingly as it will cause re-renders on *any* state change.
945
1002
  * `isReady`: A boolean indicating whether the store's persistence layer (if configured) has finished loading its initial state.
1003
+ * `watch`: A function to watch the loading status of actions.
946
1004
 
947
1005
  #### `ReactiveDataStore` (accessed via `useStore().store`)
948
1006
 
949
1007
  * `get(clone?: boolean): T`: Retrieves the current state. Pass `true` to get a deep clone (recommended for mutations outside of actions).
950
1008
  * `set(update: StateUpdater<T>): Promise<void>`: Updates the state with a partial object or a function returning a partial object.
951
1009
  * `subscribe(path: string | string[], listener: (state: T) => void): () => void`: Subscribes a listener to changes at a specific path or array of paths. Returns an unsubscribe function.
952
- * `transaction<R>(operation: () => R | Promise<R>): Promise<R>`: Executes a function as an atomic transaction. Rolls back all changes if an error occurs.
1010
+ * `transaction<R>(operation: () => R | Promise<R>): Promise<R}`: Executes a function as an atomic transaction. Rolls back all changes if an error occurs.
953
1011
  * `use(middleware: Middleware<T>, name?: string): string`: Adds a transforming middleware. Returns its ID.
954
1012
  * `useBlockingMiddleware(middleware: BlockingMiddleware<T>, name?: string): string`: Adds a blocking middleware. Returns its ID.
955
1013
  * `removeMiddleware(id: string): boolean`: Removes a middleware by its ID.
@@ -968,20 +1026,6 @@ const useStore = createStore(definition, options);
968
1026
  * `clearHistory(): void`: Clears the event and state history.
969
1027
  * `disconnect(): void`: Cleans up all listeners and resources.
970
1028
 
971
- #### `RemoteObservability` (accessed via `useRemoteObservability` hook)
972
-
973
- Extends `StoreObservability` with methods for sending metrics and traces externally.
974
-
975
- * `addDestination(destination: RemoteDestination): boolean`: Adds a remote destination for metrics.
976
- * `removeDestination(id: string): boolean`: Removes a remote destination by ID.
977
- * `getDestinations(): Array<{ id: string; name: string }> `: Gets a list of configured destinations.
978
- * `testAllConnections(): Promise<Record<string, boolean>>`: Tests connectivity to all destinations.
979
- * `beginTrace(name: string): string`: Starts a new performance trace, returning its ID.
980
- * `beginSpan(traceId: string, name: string, labels?: Record<string, string>): string`: Starts a new span within a trace, returning its ID.
981
- * `endSpan(traceId: string, spanName: string): void`: Ends a specific span within a trace.
982
- * `endTrace(traceId: string): void`: Ends a performance trace and sends it to remote destinations.
983
- * `trackMetric(metric: RemoteMetricsPayload['metrics'][0]): void`: Manually add a metric to the batch for reporting.
984
-
985
1029
  #### Persistence Adapters
986
1030
 
987
1031
  All adapters implement `DataStorePersistence<T>`:
@@ -1006,7 +1050,7 @@ All adapters implement `DataStorePersistence<T>`:
1006
1050
 
1007
1051
  ### Comparison with Other State Management Solutions
1008
1052
 
1009
- `@asaidimu/react-store` aims to provide a comprehensive, all-in-one solution for React state management. Here's a comparison to popular alternatives:
1053
+ `@asaidimu/react-store` aims to be a comprehensive, all-in-one solution for React state management. Here's a comparison to popular alternatives:
1010
1054
 
1011
1055
  | **Feature** | **@asaidimu/react-store** | **Redux** | **Zustand** | **MobX** | **Recoil** |
1012
1056
  | :--------------------- | :------------------------ | :----------------- | :----------------- | :----------------- | :----------------- |
package/index.cjs CHANGED
@@ -1 +1 @@
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()}},o=e=>Array.isArray(e)?[...e]:{...e};function c(e,t){const r=Symbol.for("delete");if("object"!=typeof e||null===e)return"object"==typeof t&&null!==t?n(t):t===r?{}:t;if("object"!=typeof t||null===t)return e;const s=o(e),a=[{target:s,source:t,path:[]}];for(;a.length>0;){const{target:e,source:t,path:s}=a.pop();for(const i of Object.keys(t)){const c=t[i],d=[...s,i];c!==r?Array.isArray(c)?e[i]=c.map((e=>"object"==typeof e&&null!==e?n(e):e===r?void 0:e)):"object"==typeof c&&null!==c?(e[i]=o(i in e&&"object"==typeof e[i]&&null!==e[i]?e[i]:{}),a.push({target:e[i],source:c,path:d})):e[i]=c:delete e[i]}}return s;function n(e){if(null==e)return e;if(Array.isArray(e))return e.filter((e=>e!==r)).map((e=>"object"==typeof e&&null!==e?n(e):e===r?void 0:e));if("object"==typeof e){const t={};for(const[s,a]of Object.entries(e))t[s]="object"==typeof a&&null!==a?n(a):a===r?void 0:a;return t}return e===r?void 0:e}}var 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=c(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=c(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 o=await Promise.resolve(e(r,t));i.endTime=performance.now(),i.duration=void 0!==i.startTime?i.endTime-i.startTime:0,i.blocked=!1,o&&"object"==typeof o&&(r=c(r,o),s=c(s,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 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}}},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 h(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 f=class{storageKey;eventBus;storage;constructor(e,t=!1){this.storageKey=e,this.storage=t?sessionStorage:localStorage,this.eventBus=this.initializeEventBus(),t||this.setupStorageEventListener()}initializeEventBus(){const e={async:!0,batchSize:5,batchDelay:16,errorHandler:e=>console.error(`Event bus error for ${this.storageKey}:`,e),crossTab:!0,channelName:`storage_${this.storageKey}`};return t.createEventBus(e)}setupStorageEventListener(){window.addEventListener("storage",(e=>{if(e.key===this.storageKey&&e.newValue)try{const t=JSON.parse(e.newValue);this.eventBus.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 this.storage.setItem(this.storageKey,r),this.eventBus.emit({name:"storage:updated",payload:{storageKey:this.storageKey,instanceId:e,state:t}}),!0}catch(e){return console.error(`Failed to persist state to web storage for ${this.storageKey}:`,e),!1}}get(){try{const e=this.storage.getItem(this.storageKey);return e?JSON.parse(e):null}catch(e){return console.error(`Failed to retrieve state from web storage for ${this.storageKey}:`,e),null}}subscribe(e,t){return this.eventBus.subscribe("storage:updated",(({storageKey:r,instanceId:s,state:a})=>{r===this.storageKey&&s!==e&&t(a)}))}clear(){try{return this.storage.removeItem(this.storageKey),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.storageKey}:`,e),!1}}},w=f,b=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=b.getCursor(),this.eventBus=b.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 b.close()}},exports.LocalStoragePersistence=w,exports.ReactiveDataStore=d,exports.RemoteObservability=y,exports.StoreObservability=i,exports.WebStoragePersistence=f,exports.createGrafanaCloudDestination=p,exports.createHttpDestination=g,exports.createOpenTelemetryDestination=h,exports.createPrometheusDestination=m,exports.createStore=function(t,{enableMetrics:r,debounceTime:s=250,...a}={}){const n=new d(t.state,a.persistence),o=r?new i(n,a):void 0,c=new l;t.middleware&&Object.entries(t.middleware).forEach((([e,t])=>n.use(t,e))),t.blockingMiddleware&&Object.entries(t.blockingMiddleware).forEach((([e,t])=>n.useBlockingMiddleware(t,e)));const h=new u,m=new Map,p=Object.entries(t.actions).reduce(((e,[t,r])=>(e[t]=function(e,t){let r=null,s=null;return function(...a){return r&&(clearTimeout(r),s&&s(new Error("Debounced by a newer call"))),new Promise(((n,i)=>{const o=this;s=i,r=setTimeout((()=>{r=null,s=null,e.apply(o,a).then(n).catch(i)}),t)}))}}((async(...e)=>{const s=`${t}-${JSON.stringify(e)}`;if(m.get(s))return;m.set(s,!0);const a=crypto.randomUUID(),i=performance.now(),o={id:a,name:t,params:e,startTime:i};try{return await n.set((async t=>{const s=await r(t,...e);return o.result=s,s})),o.status="success",n.get()}catch(e){throw o.status="error",o.error=e instanceof Error?e:new Error(String(e)),console.error(`Error in action ${t}:`,e),e}finally{o.endTime=performance.now(),o.duration=o.endTime-i,h.track(o),m.delete(s)}}),s),e)),{});function g(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 n.subscribe(r,t)}const y=()=>n.get(),f=e=>(n.isReady()&&e(),n.onStoreEvent("persistence:ready",e)),w=()=>n.isReady();return function(){const t=e.useCallback((t=>{const r=c.create(t);return e.useSyncExternalStore((e=>g(r,e)),(()=>r(n.get())),(()=>r(n.get())))}),[]),r=e.useCallback((()=>e.useSyncExternalStore((e=>n.subscribe("",e)),y,y)),[]),s=e.useSyncExternalStore(f,w,w);return{store:n,observer:o,select:t,actions:p,isReady:s,actionTracker:h,get state(){return r}}}},exports.useRemoteObservability=function(e,t){const r=new y(e,t);return{remote:r,addOpenTelemetryDestination:e=>r.addDestination(h(e)),addPrometheusDestination:e=>r.addDestination(m(e)),addGrafanaCloudDestination:e=>r.addDestination(p(e)),addHttpDestination:e=>r.addDestination(g(e))}};
1
+ "use strict";var e=require("react"),t=require("@asaidimu/utils-store");var r=class{selectorCache=new WeakMap;create(e){return t=>{let r=this.selectorCache.get(e);if(r&&r.lastState===t)return r.lastResult;const n=e(t);return this.selectorCache.set(e,{lastState:t,lastResult:n}),n}}},n=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 s(e,t=new WeakMap){return void 0===e?"undefined":"function"==typeof e||"symbol"==typeof e?"":"string"==typeof e?`"${e}"`:"number"==typeof e||"boolean"==typeof e||null===e?String(e):Array.isArray(e)?`[${e.map((e=>s(e,t))).join(",")}]`:"object"==typeof e?t.has(e)?'"__circular__"':(t.set(e,!0),`{${Object.keys(e).sort().map((r=>`"${r}":${s(e[r],t)}`)).join(",")}}`):""}function o(e){let t=3421674724,r=2216829733;const n=s(e);for(let e=0;e<n.length;e++){r^=n.charCodeAt(e);const s=Math.imul(r,435),o=Math.imul(r,435)+Math.imul(t,435);r=s>>>0,t=o>>>0}return(t>>>0).toString(16)+(r>>>0).toString(16)}exports.createStore=function(s,{enableMetrics:i,debounceTime:a=0,...c}={}){const u=new t.ReactiveDataStore(s.state,c.persistence),l=new t.ReactiveDataStore(Object.fromEntries(Object.keys(s.actions).map((e=>[e,!1])))),h=i?new t.StoreObserver(u,c):void 0,d=new r,f=i?new n:void 0,y=i?new Map:void 0;s.middleware&&Object.entries(s.middleware).forEach((([e,t])=>u.use({name:e,action:t}))),s.blockingMiddleware&&Object.entries(s.blockingMiddleware).forEach((([e,t])=>u.use({block:!0,name:e,action:t})));const m=Object.entries(s.actions).reduce(((e,[t,r])=>(e[t]=function(e,t){if(0===t)return e;let r=null;return function(...n){return new Promise(((s,o)=>{r&&clearTimeout(r);const i=this;r=setTimeout((()=>{r=null,e.apply(i,n).then(s).catch(o)}),t)}))}}((async(...e)=>{const n=`${t}-${o(e)}`;if(y?.get(n))return;y?.set(n,!0);const s=f?crypto.randomUUID():void 0,i=f?performance.now():void 0,a=f?{id:s,name:t,params:e,startTime:i}:{};try{return l.set((e=>({...e,[t]:!0}))),await u.set((async t=>{const n=await r(t,...e);return f&&(a.result=n),n})),f&&(a.status="success"),u.get()}catch(e){throw f&&(a.status="error",a.error=e instanceof Error?e:new Error(String(e))),console.error(`Error in action ${t}:`,e),e}finally{l.set((e=>({...e,[t]:!1}))),f&&(a.endTime=performance.now(),a.duration=a.endTime-i,f.track(a)),y?.delete(n)}}),a),e)),{});function p(e,t){const r=function(e,t="."){const r=[],n={get:(e,t)=>{const s=[];return r.length>0&&s.push(...r[r.length-1]),s.push(t),r.push(s),new Proxy({},n)}};return e(new Proxy({},n)),r.map((e=>e.join(t)))}(e);return u.subscribe(r,t)}const b=()=>u.get(),w=e=>(u.isReady()&&e(),u.onStoreEvent("persistence:ready",e)),g=()=>u.isReady(),S=new Map;return function(){const t=e.useCallback((t=>{S.has(t)||S.set(t,d.create(t));const r=S.get(t);return e.useSyncExternalStore((e=>p(r,e)),(()=>r(u.get())),(()=>r(u.get())))}),[]),r=e.useCallback((()=>e.useSyncExternalStore((e=>u.subscribe("",e)),b,b)),[]),n=e.useSyncExternalStore(w,g,g);return{store:u,observer:h,select:t,actions:m,isReady:n,actionTracker:f,watch:t=>e.useSyncExternalStore((e=>l.subscribe(t,e)),(()=>l.get()[t]),(()=>l.get()[t])),get state(){return r}}}};