@asaidimu/react-store 4.0.0 → 5.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
@@ -1,10 +1,11 @@
1
1
  # @asaidimu/react-store
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@asaidimu/react-store.svg)](https://www.npmjs.com/package/@asaidimu/react-store)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![Build Status](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/asaidimu/node-react/actions)
3
+ [![npm version](https://img.shields.io/npm/v/@asaidimu/react-store.svg?style=flat-square)](https://www.npmjs.com/package/@asaidimu/react-store)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/asaidimu/node-react/ci.yml?branch=main&style=flat-square)](https://github.com/asaidimu/node-react/actions)
6
+ [![TypeScript](https://img.shields.io/badge/typescript-5.x-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
6
7
 
7
- A performant, type-safe state management solution for React with built-in persistence, extensive observability, and a robust middleware system.
8
+ A performant, type-safe state management solution for React with built-in persistence, extensive observability, and a robust middleware and artifact management system.
8
9
 
9
10
  ⚠️ **Beta Warning**
10
11
  This package is currently in **beta**. The API is subject to rapid changes and should not be considered stable. Breaking changes may occur frequently without notice as we iterate and improve. We’ll update this warning once the package reaches a stable release. Use at your own risk and share feedback or report issues to help us improve!
@@ -20,10 +21,10 @@ This package is currently in **beta**. The API is subject to rapid changes and s
20
21
  * [Using in Components](#using-in-components)
21
22
  * [Handling Deletions](#handling-deletions)
22
23
  * [Persistence](#persistence)
23
- * [Middleware](#middleware)
24
+ * [Middleware (Transform & Validate)](#middleware-transform--validate)
25
+ * [Artifact Management](#artifact-management)
24
26
  * [Observability](#observability)
25
27
  * [Remote Observability](#remote-observability)
26
- * [Transaction Support](#transaction-support)
27
28
  * [Event System](#event-system)
28
29
  * [Watching Action Loading States](#watching-action-loading-states)
29
30
  * [Advanced Hook Properties](#advanced-hook-properties)
@@ -43,20 +44,20 @@ This package is currently in **beta**. The API is subject to rapid changes and s
43
44
 
44
45
  ## Overview & Features
45
46
 
46
- `@asaidimu/react-store` provides an efficient and predictable way to manage complex application state in React applications. It goes beyond basic state management by integrating features typically found in separate libraries, such as data persistence and comprehensive observability tools, directly into its core. This allows developers to build robust, high-performance applications with deep insights into state changes and application behavior.
47
+ `@asaidimu/react-store` provides an efficient and predictable way to manage complex application state in React applications. It goes beyond basic state management by integrating features typically found in separate libraries, such as artifact management, data persistence, and comprehensive observability tools, directly into its core. This allows developers to build robust, high-performance applications with deep insights into state changes and application behavior.
47
48
 
48
- Designed with modern React in mind, it leverages `useSyncExternalStore` for optimal performance and reactivity, ensuring components re-render only when relevant parts of the state change. Its flexible design supports a variety of use cases, from simple counter applications to complex data flows requiring atomic updates and cross-tab synchronization. The library is built with TypeScript from the ground up, offering strong type safety throughout your application's state and actions.
49
+ Designed with modern React in mind, it leverages `useSyncExternalStore` for optimal performance and reactivity, ensuring components re-render only when relevant parts of the state change. Its flexible design supports a variety of use cases, from simple counter applications to complex data flows requiring atomic updates and cross-tab synchronization. The library is built with TypeScript from the ground up, offering strong type safety throughout your application's state, actions, and resolved artifacts.
49
50
 
50
51
  ### Key Features
51
52
 
52
53
  * 📊 **Reactive State Management**: Automatically tracks dependencies to optimize component renders and ensure efficient updates using `useSyncExternalStore`.
53
- * 🛡️ **Type-Safe**: Developed entirely in TypeScript, providing strict type checking for state, actions, and middleware.
54
- * ⚙️ **Middleware Pipeline**: Implement custom logic to transform, validate, or log state changes before they are applied. Supports both transforming and blocking middleware.
55
- * 📦 **Transaction Support**: Group multiple state updates into a single atomic operation, with automatic rollback if any part of the transaction fails.
54
+ * 🛡️ **Type-Safe**: Developed entirely in TypeScript, providing strict type checking for state, actions, artifacts, and middleware.
55
+ * ⚙️ **Middleware Pipeline**: Implement custom logic to `transform` or `validate` state changes before they are applied.
56
56
  * 💾 **Built-in Persistence**: Seamlessly integrate with web storage mechanisms like `IndexedDB` and `WebStorage` (localStorage/sessionStorage), including cross-tab synchronization.
57
- * 🔍 **Deep Observability**: Gain profound insights into your application's state with built-in metrics, detailed event logging, state history, and time-travel debugging capabilities via the `StoreObservability` instance.
58
- * **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.
59
- * 🚀 **Action Loading States**: Track the real-time loading status of individual actions, providing immediate feedback on asynchronous operations.
57
+ * 🔍 **Deep Observability**: Gain profound insights into your application's state with built-in metrics, detailed event logging, state history, and time-travel debugging capabilities via the `StoreObserver` instance.
58
+ * 🚀 **Artifact Management**: Define and reactively resolve asynchronous resources, services, or derived data, enabling advanced dependency injection patterns and lazy loading of complex logic.
59
+ * **Performance Optimized**: Features intelligent selector caching and debounced actions with configurable immediate execution to prevent rapid successive calls and ensure smooth application performance.
60
+ * ⏱️ **Action Loading States**: Track the real-time loading status of individual actions, providing immediate feedback on asynchronous operations.
60
61
  * ⚛️ **React 19+ Ready**: Fully compatible with the latest React versions, leveraging modern APIs for enhanced performance and development ergonomics.
61
62
  * 🗑️ **Explicit Deletions**: Use `Symbol.for("delete")` to explicitly remove properties from nested state objects.
62
63
 
@@ -73,7 +74,7 @@ Designed with modern React in mind, it leverages `useSyncExternalStore` for opti
73
74
  To add `@asaidimu/react-store` to your project, run one of the following commands:
74
75
 
75
76
  ```bash
76
- bun install @asaidimu/react-store
77
+ bun add @asaidimu/react-store
77
78
  # or
78
79
  npm install @asaidimu/react-store
79
80
  # or
@@ -82,7 +83,7 @@ yarn add @asaidimu/react-store
82
83
 
83
84
  ### Configuration
84
85
 
85
- No global configuration is required. All options are passed during store creation via the `createStore` function. Configuration includes enabling metrics, logging, persistence, and performance thresholds.
86
+ No global configuration is required. All options are passed during store creation via the `createStore` function. Configuration includes enabling metrics, persistence, and performance thresholds.
86
87
 
87
88
  ### Verification
88
89
 
@@ -93,35 +94,45 @@ import { createStore } from '@asaidimu/react-store';
93
94
 
94
95
  interface MyState {
95
96
  value: string;
97
+ count: number;
96
98
  }
97
99
 
98
- const myStore = createStore<MyState, any>({
99
- state: { value: 'hello' },
100
+ const useMyStore = createStore<MyState, any, any>({
101
+ state: { value: 'hello', count: 0 },
100
102
  actions: {
101
103
  setValue: (_, newValue: string) => ({ value: newValue }),
104
+ increment: ({ state }) => ({ count: state.count + 1 }),
102
105
  },
103
106
  });
104
107
 
105
- const { select, actions } = myStore(); // Instantiate the hook
108
+ function MyComponent() {
109
+ const { select, actions } = useMyStore(); // Instantiate the hook
110
+ const currentValue = select(s => s.value);
111
+ const currentCount = select(s => s.count);
106
112
 
107
- // Access state
108
- const currentValue = select(s => s.value);
109
- console.log(currentValue); // Expected: 'hello'
113
+ return (
114
+ <div>
115
+ <p>Value: {currentValue}</p>
116
+ <p>Count: {currentCount}</p>
117
+ <button onClick={() => actions.setValue('world')}>Set Value to 'world'</button>
118
+ <button onClick={() => actions.increment()}>Increment Count</button>
119
+ </div>
120
+ );
121
+ }
110
122
 
111
- // Dispatch an action
112
- actions.setValue('world');
123
+ // Render MyComponent in your React app.
124
+ // If no errors are thrown during installation or when running this basic example,
125
+ // the package is correctly installed and configured.
113
126
  ```
114
127
 
115
- If no errors are thrown during installation or when running this basic example, the package is correctly installed and configured.
116
-
117
128
  ## Usage Documentation
118
129
 
119
130
  ### Creating a Store
120
131
 
121
- Define your application state and actions, then create a store using `createStore`. The `actions` object maps action names to functions that receive an `ActionContext` (containing the current `state` and an `resolve` function for artifacts) and any additional arguments.
132
+ Define your application state, actions, and optionally artifacts, then create a store using `createStore`. The `actions` object maps action names to functions that receive an `ActionContext` (containing the current `state` and a `resolve` function for artifacts) and any additional arguments.
122
133
 
123
134
  ```tsx
124
- // ui/store.tsx (Example from codebase)
135
+ // ui/store.tsx (Example)
125
136
  import { createStore } from '@asaidimu/react-store'; // Assuming direct import or wrapper
126
137
 
127
138
  export interface Product {
@@ -149,6 +160,8 @@ export interface ECommerceState extends Record<string, any>{
149
160
  orders: Order[];
150
161
  topSellers: { id: number; name: string; sales: number }[];
151
162
  activeUsers: number;
163
+ // A property to demonstrate artifact dependency
164
+ currency: string;
152
165
  }
153
166
 
154
167
  const initialState: ECommerceState = {
@@ -169,6 +182,7 @@ const initialState: ECommerceState = {
169
182
  { id: 4, name: 'Webcam', sales: 65 },
170
183
  ],
171
184
  activeUsers: 1428,
185
+ currency: 'USD',
172
186
  };
173
187
 
174
188
  const actions = {
@@ -212,7 +226,6 @@ const actions = {
212
226
  }).sort((a, b) => b.sales - a.sales),
213
227
  };
214
228
  },
215
-
216
229
  updateStock: ({state}: {state:ECommerceState}) => ({
217
230
  products: state.products.map((p:any) => ({
218
231
  ...p,
@@ -235,12 +248,40 @@ const actions = {
235
248
  orders: [newOrder, ...state.orders],
236
249
  };
237
250
  },
251
+ setCurrency: ({state}, newCurrency: string) => ({ currency: newCurrency }),
238
252
  };
239
253
 
240
254
  export const useStore = createStore(
241
255
  {
242
256
  state: initialState,
243
257
  actions,
258
+ // Example artifact definition
259
+ artifacts: {
260
+ currencySymbol: {
261
+ factory: async ({ use }) => {
262
+ const currency = await use(({ select }) => select((s: ECommerceState) => s.currency));
263
+ switch (currency) {
264
+ case 'USD': return '$';
265
+ case 'EUR': return '€';
266
+ case 'GBP': return '£';
267
+ default: return currency;
268
+ }
269
+ },
270
+ },
271
+ // Another artifact example, might depend on other artifacts or state
272
+ exchangeRate: {
273
+ factory: async ({ resolve, use }) => {
274
+ const baseCurrency = await use(({ select }) => select((s: ECommerceState) => s.currency));
275
+ const targetCurrency = 'EUR'; // For demonstration
276
+ // In a real app, this would fetch from an API
277
+ await new Promise(r => setTimeout(r, 50)); // Simulate API delay
278
+ if (baseCurrency === 'USD' && targetCurrency === 'EUR') {
279
+ return 0.92; // 1 USD = 0.92 EUR
280
+ }
281
+ return 1.0;
282
+ },
283
+ },
284
+ }
244
285
  },
245
286
  { enableMetrics: true } // Enables metrics for observability
246
287
  );
@@ -251,16 +292,16 @@ export const useStore = createStore(
251
292
  Consume your store's state and actions within your React components using the exported hook. The `select` function allows you to subscribe to specific parts of the state, ensuring that your components only re-render when the selected data changes.
252
293
 
253
294
  ```tsx
254
- // ui/App.tsx (Excerpt from codebase)
295
+ // ui/App.tsx (Excerpt)
255
296
  import { useEffect, useMemo } from 'react';
256
297
  import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
257
- import { useStore, Product, CartItem, Order } from './store'; // Assuming these imports resolve correctly
298
+ import { useStore, Product, CartItem, Order, ECommerceState } from './store';
258
299
 
259
- // ... (ShadCN-like UI Components for brevity) ...
260
300
 
261
301
  const ProductCatalog = () => {
262
- const { select, actions } = useStore();
302
+ const { select, actions, resolve } = useStore();
263
303
  const products = select((state) => state.products); // Granular selection
304
+ const { instance: currencySymbol, ready: currencyReady } = resolve('currencySymbol'); // Reactive artifact resolution
264
305
 
265
306
  return (
266
307
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -272,7 +313,9 @@ const ProductCatalog = () => {
272
313
  <CardContent className="flex-grow">
273
314
  <img src={product.image} alt={product.name} className="w-full h-40 object-cover rounded-lg mb-4" />
274
315
  <div className="flex justify-between items-center">
275
- <p className="text-lg font-semibold text-gray-700">${product.price.toFixed(2)}</p>
316
+ <p className="text-lg font-semibold text-gray-700">
317
+ {currencyReady ? currencySymbol : ''}{product.price.toFixed(2)}
318
+ </p>
276
319
  <p className="text-sm text-gray-500">{product.stock} in stock</p>
277
320
  </div>
278
321
  </CardContent>
@@ -286,7 +329,8 @@ const ProductCatalog = () => {
286
329
  };
287
330
 
288
331
  function App() {
289
- const { actions } = useStore();
332
+ const { actions, select } = useStore();
333
+ const currentCurrency = select((state) => state.currency);
290
334
 
291
335
  useEffect(() => {
292
336
  // Real-time simulations for the dashboard
@@ -299,26 +343,35 @@ function App() {
299
343
  clearInterval(usersInterval);
300
344
  clearInterval(ordersInterval);
301
345
  };
302
- }, [actions]); // `actions` object is stable due to `useMemo` in createStore
346
+ }, [actions]);
303
347
 
304
348
  return (
305
349
  <div className="bg-gray-50 text-gray-900 min-h-screen">
306
350
  <header className="border-b">
307
- <div className="container mx-auto px-4 h-16 flex items-center">
351
+ <div className="container mx-auto px-4 h-16 flex items-center justify-between">
308
352
  <h1 className="text-xl font-bold">E-Commerce Dashboard</h1>
353
+ <select
354
+ value={currentCurrency}
355
+ onChange={(e) => actions.setCurrency(e.target.value)}
356
+ className="p-2 border rounded-md"
357
+ >
358
+ <option value="USD">USD</option>
359
+ <option value="EUR">EUR</option>
360
+ <option value="GBP">GBP</option>
361
+ </select>
309
362
  </div>
310
363
  </header>
311
364
  <main className="container mx-auto p-4 sm:p-6 lg:p-8">
312
365
  <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
313
366
  <div className="lg:col-span-2 space-y-6">
314
367
  <ProductCatalog />
315
- <LiveInventoryChart />
368
+ {/* <LiveInventoryChart /> */}
316
369
  </div>
317
370
  <div className="space-y-6">
318
- <ShoppingCart />
319
- <UserAnalytics />
320
- <TopSellingProducts />
321
- <RecentOrdersFeed />
371
+ {/* <ShoppingCart /> */}
372
+ {/* <UserAnalytics /> */}
373
+ {/* <TopSellingProducts /> */}
374
+ {/* <RecentOrdersFeed /> */}
322
375
  </div>
323
376
  </div>
324
377
  </main>
@@ -395,12 +448,16 @@ Persist your store's state across browser sessions or synchronize it across mult
395
448
 
396
449
  ```tsx
397
450
  import { createStore } from '@asaidimu/react-store';
398
- import { WebStoragePersistence, IndexedDBPersistence } from '@asaidimu/utils-persistence';
451
+ import { WebStoragePersistence, IndexedDBPersistence } from '@asaidimu/utils-persistence';
399
452
  import React, { useEffect } from 'react';
400
453
 
454
+ interface LocalState { sessionCount: number; lastVisited: string; }
455
+ interface SessionState { tabSpecificData: string; }
456
+ interface UserProfileState { userId: string; preferences: { language: string; darkMode: boolean; }; }
457
+
401
458
  // 1. Using WebStoragePersistence (localStorage by default)
402
459
  // Data persists even if the browser tab is closed and reopened.
403
- const localStorePersistence = new WebStoragePersistence('my-app-state-key');
460
+ const localStorePersistence = new WebStoragePersistence<LocalState>('my-app-state-key');
404
461
  const useLocalStore = createStore(
405
462
  {
406
463
  state: { sessionCount: 0, lastVisited: new Date().toISOString() },
@@ -414,12 +471,12 @@ const useLocalStore = createStore(
414
471
 
415
472
  // 2. Using WebStoragePersistence (sessionStorage)
416
473
  // Data only persists for the duration of the browser tab. Clears on tab close.
417
- const sessionStoragePersistence = new WebStoragePersistence('my-session-state-key', true);
474
+ const sessionStoragePersistence = new WebStoragePersistence<SessionState>('my-session-state-key', true);
418
475
  const useSessionStore = createStore(
419
476
  {
420
477
  state: { tabSpecificData: 'initial' },
421
478
  actions: {
422
- updateTabSpecificData: (state, newData: string) => ({ tabSpecificData: newData }),
479
+ updateTabSpecificData: (_, newData: string) => ({ tabSpecificData: newData }),
423
480
  },
424
481
  },
425
482
  { persistence: sessionStoragePersistence },
@@ -427,12 +484,12 @@ const useSessionStore = createStore(
427
484
 
428
485
  // 3. Using IndexedDBPersistence
429
486
  // Ideal for larger amounts of data, offers robust cross-tab synchronization.
430
- const indexedDBPersistence = new IndexedDBPersistence('user-profile-data');
487
+ const indexedDBPersistence = new IndexedDBPersistence<UserProfileState>('user-profile-data');
431
488
  const useUserProfileStore = createStore(
432
489
  {
433
490
  state: { userId: '', preferences: { language: 'en', darkMode: false } },
434
491
  actions: {
435
- setUserId: (state, id: string) => ({ userId: id }),
492
+ setUserId: (_, id: string) => ({ userId: id }),
436
493
  toggleDarkMode: ({state}) => ({ preferences: { darkMode: !state.preferences.darkMode } }),
437
494
  },
438
495
  },
@@ -442,9 +499,13 @@ const useUserProfileStore = createStore(
442
499
  function AppWithPersistence() {
443
500
  const { select: selectLocal, actions: actionsLocal, isReady: localReady } = useLocalStore();
444
501
  const { select: selectProfile, actions: actionsProfile, isReady: profileReady } = useUserProfileStore();
502
+ const { select: selectSession, actions: actionsSession } = useSessionStore();
503
+
445
504
 
446
505
  const sessionCount = selectLocal(s => s.sessionCount);
447
506
  const darkMode = selectProfile(s => s.preferences.darkMode);
507
+ const tabData = selectSession(s => s.tabSpecificData);
508
+
448
509
 
449
510
  useEffect(() => {
450
511
  if (localReady) {
@@ -454,7 +515,7 @@ function AppWithPersistence() {
454
515
  if (profileReady && !selectProfile(s => s.userId)) {
455
516
  actionsProfile.setUserId('user-' + Math.random().toString(36).substring(2, 9));
456
517
  }
457
- }, [localReady, profileReady, actionsLocal, actionsProfile, selectProfile]); // Added dependencies for useEffect
518
+ }, [localReady, profileReady, actionsLocal, actionsProfile, selectProfile]);
458
519
 
459
520
  if (!localReady || !profileReady) {
460
521
  return <div>Loading persisted data...</div>;
@@ -462,9 +523,15 @@ function AppWithPersistence() {
462
523
 
463
524
  return (
464
525
  <div>
465
- <h3>Local Store</h3>
526
+ <h3>Local Store (localStorage)</h3>
466
527
  <p>Session Count: {sessionCount}</p>
467
528
 
529
+ <h3>Session Store (sessionStorage)</h3>
530
+ <p>Tab Specific Data: {tabData}</p>
531
+ <button onClick={() => actionsSession.updateTabSpecificData('updated-for-this-tab')}>
532
+ Update Tab Data
533
+ </button>
534
+
468
535
  <h3>User Profile Store (IndexedDB)</h3>
469
536
  <p>Dark Mode: {darkMode ? 'Enabled' : 'Disabled'}</p>
470
537
  <button onClick={() => actionsProfile.toggleDarkMode()}>Toggle Dark Mode</button>
@@ -473,12 +540,15 @@ function AppWithPersistence() {
473
540
  }
474
541
  ```
475
542
 
476
- ### Middleware
543
+ ### Middleware (Transform & Validate)
544
+
545
+ Middleware functions can intercept and modify or block state updates. The `CHANGELOG.md` indicates a breaking change, moving from generic `middleware` and `blockingMiddleware` to `transform` and `validate` properties in the `StoreDefinition`. These now receive an `ActionContext` with `state` and `resolve` capabilities.
477
546
 
478
- Middleware functions can intercept and modify or block state updates. They are executed in the order they are added. Transforming middleware can alter the state update payload, while blocking middleware can prevent an update from proceeding.
547
+ * `transform`: Functions that run *after* an action's core logic but *before* the state update is committed. They can modify the `DeepPartial<TState>` that will be merged into the state.
548
+ * `validate`: Functions that run *before* the state update is committed. If a validator returns `false` (or a `Promise<false>`), the state update is entirely cancelled.
479
549
 
480
550
  ```typescript
481
- import { createStore, type Middleware, type BlockingMiddleware } from '@asaidimu/react-store';
551
+ import { createStore } from '@asaidimu/react-store';
482
552
  import React from 'react';
483
553
 
484
554
  interface CartState {
@@ -486,28 +556,7 @@ interface CartState {
486
556
  total: number;
487
557
  }
488
558
 
489
- const calculateTotalMiddleware: Middleware<CartState> = (state, update) => {
490
- if (update.items) {
491
- const newItems = update.items as CartState['items'];
492
- const newTotal = newItems.reduce((sum, item) => sum + (item.quantity * item.price), 0);
493
- return { ...update, total: newTotal };
494
- }
495
- return update;
496
- };
497
-
498
- const validateItemMiddleware: BlockingMiddleware<CartState> = (state, update) => {
499
- if (update.items) {
500
- for (const item of update.items as CartState['items']) {
501
- if (item.quantity < 0) {
502
- console.warn('Blocked: Item quantity cannot be negative.');
503
- return false; // Blocks the update
504
- }
505
- }
506
- }
507
- return true; // Allows the update
508
- };
509
-
510
- const useCartStore = createStore({
559
+ const useCartStore = createStore<CartState, any, any>({ // TArtifactsMap and TActions are inferred
511
560
  state: { items: [], total: 0 },
512
561
  actions: {
513
562
  addItem: ({state}, item: { id: string; name: string; price: number }) => {
@@ -527,9 +576,31 @@ const useCartStore = createStore({
527
576
  items: state.items.map(item => (item.id === id ? { ...item, quantity } : item)),
528
577
  }),
529
578
  },
530
- // Middleware now accepts an object mapping names to middleware functions
531
- middleware: { calculateTotal: calculateTotalMiddleware },
532
- blockingMiddleware: { validateItem: validateItemMiddleware },
579
+ transform: {
580
+ // Calculates total based on updated items before state merge
581
+ calculateTotal: async ({ state, resolve }, update) => {
582
+ if (update.items) {
583
+ const newItems = update.items as CartState['items'];
584
+ const newTotal = newItems.reduce((sum, item) => sum + (item.quantity * item.price), 0);
585
+ return { ...update, total: newTotal };
586
+ }
587
+ return update;
588
+ },
589
+ },
590
+ validate: {
591
+ // Blocks update if any item quantity is negative
592
+ validateItemQuantity: async ({ state, resolve }, update) => {
593
+ if (update.items) {
594
+ for (const item of update.items as CartState['items']) {
595
+ if (item.quantity < 0) {
596
+ console.warn('Blocked by validator: Item quantity cannot be negative.');
597
+ return false; // Blocks the update
598
+ }
599
+ }
600
+ }
601
+ return true; // Allows the update
602
+ },
603
+ },
533
604
  });
534
605
 
535
606
  function CartComponent() {
@@ -557,6 +628,124 @@ function CartComponent() {
557
628
  }
558
629
  ```
559
630
 
631
+ ### Artifact Management
632
+
633
+ The store supports defining and reactively resolving "artifacts," which can be any asynchronous resource, service, or derived value. Artifacts are defined in the `artifacts` property of the `StoreDefinition` and resolved using `ctx.resolve()` within actions or the `resolve()` hook in components. They can depend on other artifacts or on the store's reactive state.
634
+
635
+ ```tsx
636
+ import { createStore } from '@asaidimu/react-store';
637
+ import { ArtifactScopes } from '@asaidimu/utils-artifacts';
638
+ import React, { useEffect } from 'react';
639
+
640
+ interface AppState {
641
+ userId: string | null;
642
+ settingsLoaded: boolean;
643
+ theme: string;
644
+ }
645
+
646
+ // Assume this is an API service or similar
647
+ const mockApiService = {
648
+ fetchUserSettings: async (userId: string) => {
649
+ await new Promise(r => setTimeout(r, 200)); // Simulate API delay
650
+ if (userId === 'user-123') {
651
+ return { theme: 'dark', notifications: true };
652
+ }
653
+ return { theme: 'light', notifications: false };
654
+ },
655
+ };
656
+
657
+ const useArtifactStore = createStore<AppState, any, any>({
658
+ state: { userId: null, settingsLoaded: false, theme: 'light' },
659
+ actions: {
660
+ setUserId: (_, id: string) => ({ userId: id, settingsLoaded: false }),
661
+ loadUserSettings: async ({ state, resolve }) => {
662
+ if (!state.userId) return;
663
+
664
+ const { instance: userSettings } = await resolve('userSettings');
665
+ if (userSettings) {
666
+ return {
667
+ settingsLoaded: true,
668
+ theme: userSettings.theme,
669
+ };
670
+ }
671
+ return {};
672
+ },
673
+ toggleTheme: ({state}) => ({ theme: state.theme === 'light' ? 'dark' : 'light' }),
674
+ },
675
+ artifacts: {
676
+ // A singleton artifact that fetches user settings based on the current userId in state
677
+ userSettings: {
678
+ scope: ArtifactScopes.Singleton, // Ensure only one instance is created globally
679
+ factory: async ({ use }) => {
680
+ const userId = await use(({ select }) => select((s: AppState) => s.userId));
681
+ if (userId) {
682
+ console.log(`Fetching settings for user: ${userId}`);
683
+ return mockApiService.fetchUserSettings(userId);
684
+ }
685
+ return null;
686
+ },
687
+ lazy: true, // Only create/resolve when first requested
688
+ },
689
+ // An artifact that provides a simple logger instance
690
+ logger: {
691
+ factory: async () => console,
692
+ scope: ArtifactScopes.Singleton,
693
+ },
694
+ },
695
+ });
696
+
697
+ function ArtifactConsumer() {
698
+ const { actions, select, resolve, isReady } = useArtifactStore();
699
+ const userId = select(s => s.userId);
700
+ const theme = select(s => s.theme);
701
+ const settingsLoaded = select(s => s.settingsLoaded);
702
+
703
+ // Reactively resolve the userSettings artifact in the component
704
+ const { instance: userSettingsArtifact, ready: userSettingsReady } = resolve('userSettings');
705
+ const { instance: logger } = resolve('logger');
706
+
707
+ useEffect(() => {
708
+ // Simulate setting a user ID after initial load
709
+ if (isReady && !userId) {
710
+ actions.setUserId('user-123');
711
+ }
712
+ }, [isReady, userId, actions]);
713
+
714
+ useEffect(() => {
715
+ // Automatically load settings when userId is available and settings not loaded
716
+ if (userId && !settingsLoaded) {
717
+ actions.loadUserSettings();
718
+ }
719
+ }, [userId, settingsLoaded, actions]);
720
+
721
+ useEffect(() => {
722
+ if (logger && userSettingsArtifact) {
723
+ logger.log("User settings artifact updated:", userSettingsArtifact);
724
+ }
725
+ }, [logger, userSettingsArtifact]);
726
+
727
+ if (!isReady) {
728
+ return <div>Loading store...</div>;
729
+ }
730
+
731
+ return (
732
+ <div>
733
+ <h2>Artifact Management Example</h2>
734
+ <p>Current User ID: {userId || 'Not set'}</p>
735
+ <p>Settings Loaded: {settingsLoaded ? 'Yes' : 'No'}</p>
736
+ <p>Current Theme: {theme}</p>
737
+ {userSettingsReady && userSettingsArtifact && (
738
+ <p>Artifact (userSettings) Resolved Theme: {userSettingsArtifact.theme}</p>
739
+ )}
740
+ <button onClick={() => actions.setUserId(userId === 'user-123' ? 'user-456' : 'user-123')}>
741
+ Toggle User ID
742
+ </button>
743
+ <button onClick={() => actions.toggleTheme()}>Toggle App Theme</button>
744
+ </div>
745
+ );
746
+ }
747
+ ```
748
+
560
749
  ### Observability
561
750
 
562
751
  Enable metrics and debugging via the `observer` and `actionTracker` objects. The `enableMetrics` option in `createStore` is crucial for activating these features.
@@ -567,10 +756,15 @@ import React from 'react';
567
756
 
568
757
  const useObservedStore = createStore(
569
758
  {
570
- state: { task: '', completed: false },
759
+ state: { task: '', completed: false, count: 0 },
571
760
  actions: {
572
- addTask: (state, taskName: string) => ({ task: taskName, completed: false }),
573
- completeTask: (state) => ({ completed: true }),
761
+ addTask: (_, taskName: string) => ({ task: taskName, completed: false }),
762
+ completeTask: (_) => ({ completed: true }),
763
+ increment: ({state}) => ({ count: state.count + 1 }),
764
+ longRunningAction: async () => {
765
+ await new Promise(resolve => setTimeout(resolve, 500)); // Simulate async work
766
+ return { count: 100 };
767
+ },
574
768
  },
575
769
  },
576
770
  {
@@ -588,7 +782,8 @@ const useObservedStore = createStore(
588
782
  );
589
783
 
590
784
  function DebugPanel() {
591
- const { actions, observer, actionTracker } = useObservedStore();
785
+ const { actions, observer, actionTracker, select, state: getStateSnapshot } = useObservedStore();
786
+ const count = select(s => s.count);
592
787
 
593
788
  // Access performance metrics
594
789
  const metrics = observer?.getPerformanceMetrics();
@@ -610,9 +805,12 @@ function DebugPanel() {
610
805
  <p>Largest Update Size (paths): {metrics?.largestUpdateSize}</p>
611
806
 
612
807
  <h3>Time Travel</h3>
808
+ <p>Current Count: {count} (via select)</p>
613
809
  <button onClick={() => timeTravel?.undo()} disabled={!timeTravel?.canUndo()}>Undo</button>
614
810
  <button onClick={() => timeTravel?.redo()} disabled={!timeTravel?.canRedo()}>Redo</button>
615
811
  <p>State History: {timeTravel?.getHistoryLength()}</p>
812
+ <p>Current Snapshot (non-reactive): {JSON.stringify(getStateSnapshot())}</p>
813
+
616
814
 
617
815
  <h3>Action History</h3>
618
816
  <ul>
@@ -626,6 +824,8 @@ function DebugPanel() {
626
824
  )}
627
825
  <button onClick={() => actions.addTask('Learn React Store')}>Add Task</button>
628
826
  <button onClick={() => actions.completeTask()}>Complete Task</button>
827
+ <button onClick={() => actions.increment()}>Increment</button>
828
+ <button onClick={() => actions.longRunningAction()}>Long Action</button>
629
829
  </div>
630
830
  );
631
831
  }
@@ -637,7 +837,8 @@ Send collected metrics and traces to external systems like OpenTelemetry, Promet
637
837
 
638
838
  ```tsx
639
839
  import { createStore } from '@asaidimu/react-store';
640
- import { useRemoteObservability } from '@asaidimu/utils-store';
840
+ // Assuming useRemoteObservability is provided by @asaidimu/utils-store or a wrapper
841
+ // import { useRemoteObservability } from '@asaidimu/utils-store';
641
842
  import React, { useEffect } from 'react';
642
843
 
643
844
  const useRemoteStore = createStore(
@@ -650,64 +851,48 @@ const useRemoteStore = createStore(
650
851
  }
651
852
  return { apiCallsMade: state.apiCallsMade + 1, lastApiError: null };
652
853
  },
653
- handleApiError: ({state}, error: string) => ({ lastApiError: error })
854
+ handleApiError: (_, error: string) => ({ lastApiError: error })
654
855
  },
655
856
  },
656
857
  {
657
858
  enableMetrics: true, // Required for RemoteObservability
658
859
  enableConsoleLogging: false,
659
- // collectCategories configuration would typically be passed to useRemoteObservability
660
- // reportingInterval, batchSize, immediateReporting would also be part of useRemoteObservability options
661
860
  }
662
861
  );
663
862
 
664
863
  function MonitoringIntegration() {
665
864
  const { store, observer } = useRemoteStore();
666
- // useRemoteObservability is assumed to be part of utils-store or a separate utility
667
- const { remote, addOpenTelemetryDestination, addPrometheusDestination, addGrafanaCloudDestination } = useRemoteObservability(store, {
668
- serviceName: 'my-react-app',
669
- environment: 'development',
670
- instanceId: `web-client-${Math.random().toString(36).substring(2, 9)}`,
671
- collectCategories: {
672
- performance: true,
673
- errors: true,
674
- stateChanges: true,
675
- middleware: true,
676
- },
677
- reportingInterval: 10000, // Send metrics every 10 seconds
678
- batchSize: 10, // Send after 10 metrics or interval, whichever comes first
679
- immediateReporting: false, // Don't send immediately after each metric
680
- });
865
+
866
+ // Placeholder for actual useRemoteObservability hook
867
+ // const { remote, addOpenTelemetryDestination, addPrometheusDestination, addGrafanaCloudDestination } = useRemoteObservability(store, {
868
+ // serviceName: 'my-react-app',
869
+ // environment: 'development',
870
+ // instanceId: `web-client-${Math.random().toString(36).substring(2, 9)}`,
871
+ // collectCategories: {
872
+ // performance: true,
873
+ // errors: true,
874
+ // stateChanges: true,
875
+ // middleware: true,
876
+ // },
877
+ // reportingInterval: 10000, // Send metrics every 10 seconds
878
+ // batchSize: 10, // Send after 10 metrics or interval, whichever comes first
879
+ // immediateReporting: false, // Don't send immediately after each metric
880
+ // });
681
881
 
682
882
  useEffect(() => {
683
- // Add OpenTelemetry Collector as a destination
684
- addOpenTelemetryDestination({
685
- endpoint: 'http://localhost:4318', // Default OpenTelemetry HTTP endpoint
686
- apiKey: 'your-otel-api-key',
687
- resource: { 'app.version': '1.0.0', 'host.name': 'frontend-server' }
688
- });
689
-
690
- // Add Prometheus Pushgateway as a destination
691
- addPrometheusDestination({
692
- pushgatewayUrl: 'http://localhost:9091', // Default Prometheus Pushgateway
693
- jobName: 'react-store-metrics',
694
- username: 'promuser', // Optional basic auth
695
- password: 'prompassword',
696
- });
883
+ // In a real implementation, you would use the `remote` object
884
+ // to add destinations and configure reporting.
885
+ // Example:
886
+ // addOpenTelemetryDestination({ endpoint: 'http://localhost:4318', apiKey: 'your-otel-api-key' });
887
+ // addPrometheusDestination({ pushgatewayUrl: 'http://localhost:9091', jobName: 'react-store-metrics' });
888
+ // addGrafanaCloudDestination({ url: 'https://loki-prod-us-central1.grafana.net', apiKey: 'your-grafana-cloud-api-key' });
697
889
 
698
- // Add Grafana Cloud Loki as a destination (for logs/traces)
699
- addGrafanaCloudDestination({
700
- url: 'https://loki-prod-us-central1.grafana.net', // Example Loki endpoint
701
- apiKey: 'your-grafana-cloud-api-key',
702
- });
703
-
704
- // Report current store metrics periodically (in addition to event-driven metrics)
705
890
  const interval = setInterval(() => {
706
- observer?.reportCurrentMetrics();
891
+ observer?.reportCurrentMetrics(); // Manually trigger a report if needed
707
892
  }, 5000); // Report every 5 seconds
708
893
 
709
894
  return () => clearInterval(interval);
710
- }, [observer, addOpenTelemetryDestination, addPrometheusDestination, addGrafanaCloudDestination]); // Added dependencies
895
+ }, [observer]); // Removed placeholder dependencies for actual usage
711
896
 
712
897
  return null; // This component doesn't render anything visually
713
898
  }
@@ -725,85 +910,6 @@ function MonitoringIntegration() {
725
910
  // }
726
911
  ```
727
912
 
728
- ### Transaction Support
729
-
730
- Group related updates that should succeed or fail together. If an error occurs within the transaction, all changes made during that transaction are automatically rolled back, maintaining state consistency.
731
-
732
- ```typescript
733
- import { createStore } from '@asaidimu/react-store';
734
- import React from 'react';
735
-
736
- interface BankState {
737
- checking: number;
738
- savings: number;
739
- transactions: string[];
740
- }
741
-
742
- const useBankStore = createStore<BankState, any>({
743
- state: { checking: 1000, savings: 500, transactions: [] },
744
- actions: {
745
- transferFunds: async ({state}, fromAccount: 'checking' | 'savings', toAccount: 'checking' | 'savings', amount: number) => {
746
- if (amount <= 0) {
747
- throw new Error('Transfer amount must be positive.');
748
- }
749
-
750
- const newChecking = fromAccount === 'checking' ? state.checking - amount : state.checking + amount;
751
- const newSavings = fromAccount === 'savings' ? state.savings - amount : state.savings + amount;
752
-
753
- if ((fromAccount === 'checking' && newChecking < 0) || (fromAccount === 'savings' && newSavings < 0)) {
754
- throw new Error('Insufficient funds.');
755
- }
756
-
757
- // Simulate a complex operation that might fail
758
- if (amount > 700 && fromAccount === 'checking') {
759
- throw new Error('Large transfers from checking require additional verification.');
760
- }
761
-
762
- const newTransactions = [...state.transactions, `Transfer ${amount} from ${fromAccount} to ${toAccount}`];
763
- return {
764
- checking: newChecking,
765
- savings: newSavings,
766
- transactions: newTransactions,
767
- };
768
- },
769
- },
770
- });
771
-
772
- function BankApp() {
773
- const { select, actions, store } = useBankStore();
774
- const checkingBalance = select(s => s.checking);
775
- const savingsBalance = select(s => s.savings);
776
- const transactions = select(s => s.transactions);
777
-
778
- const handleTransfer = async (from: 'checking' | 'savings', to: 'checking' | 'savings', amount: number) => {
779
- try {
780
- // Wrap the action call in a store transaction
781
- await store.transaction(() => actions.transferFunds(from, to, amount));
782
- alert(`Successfully transferred ${amount} from ${from} to ${to}.`);
783
- } catch (error) {
784
- alert(`Transfer failed: ${error instanceof Error ? error.message : String(error)}`);
785
- // State is automatically rolled back if an error occurs within the transaction
786
- }
787
- };
788
-
789
- return (
790
- <div>
791
- <h2>Bank Accounts</h2>
792
- <p>Checking: ${checkingBalance.toFixed(2)}</p>
793
- <p>Savings: ${savingsBalance.toFixed(2)}</p>
794
- <h3>Recent Transactions</h3>
795
- <ul>
796
- {transactions.map((t, i) => <li key={i}>{t}</li>)}
797
- </ul>
798
- <button onClick={() => handleTransfer('checking', 'savings', 100)}>Transfer $100 (Checking to Savings)</button>
799
- <button onClick={() => handleTransfer('savings', 'checking', 200)}>Transfer $200 (Savings to Checking)</button>
800
- <button onClick={() => handleTransfer('checking', 'savings', 800)}>Transfer $800 (Will Fail)</button>
801
- <button onClick={() => handleTransfer('checking', 'savings', 1500)}>Transfer $1500 (Insufficient Funds)</button>
802
- </div>
803
- );
804
- }
805
- ```
806
-
807
913
  ### Event System
808
914
 
809
915
  The store emits various events during its lifecycle, which you can subscribe to for logging, analytics, or custom side effects. This is done via `store.onStoreEvent()`.
@@ -819,8 +925,8 @@ const useEventStore = createStore(
819
925
  processData: ({state}, newData: string) => ({ data: newData, processedCount: state.processedCount + 1 }),
820
926
  triggerError: () => { throw new Error("Action failed intentionally"); }
821
927
  },
822
- middleware: {
823
- myLoggingMiddleware: (state, update) => {
928
+ transform: { // Using the new middleware API
929
+ myLoggingMiddleware: async ({state}, update) => {
824
930
  console.log('Middleware processing:', update);
825
931
  return update;
826
932
  }
@@ -913,7 +1019,7 @@ interface DataState {
913
1019
  const useDataStore = createStore({
914
1020
  state: { items: [] },
915
1021
  actions: {
916
- fetchItems: async (state) => {
1022
+ fetchItems: async ({state}) => {
917
1023
  // Simulate an API call
918
1024
  await new Promise(resolve => setTimeout(resolve, 2000));
919
1025
  return { items: ['Item A', 'Item B', 'Item C'] };
@@ -960,7 +1066,7 @@ function DataLoader() {
960
1066
  The hook returned by `createStore` provides several properties for advanced usage and debugging, beyond the commonly used `select`, `actions`, and `isReady`:
961
1067
 
962
1068
  ```tsx
963
- import { useStore as useMyStore } from '../ui/store'; // Assuming this is your store definition
1069
+ import { useStore as useMyStore } from './store'; // Assuming this is your store definition
964
1070
 
965
1071
  function MyAdvancedComponent() {
966
1072
  const {
@@ -968,11 +1074,11 @@ function MyAdvancedComponent() {
968
1074
  actions, // Object containing your defined actions (debounced, promise-returning)
969
1075
  isReady, // Boolean indicating if persistence is ready
970
1076
  store, // Direct access to the ReactiveDataStore instance (from @asaidimu/utils-store)
971
- observer, // StoreObservability instance (from @asaidimu/utils-store, if `enableMetrics` was true)
1077
+ observer, // StoreObserver instance (from @asaidimu/utils-store, if `enableMetrics` was true)
972
1078
  actionTracker, // Instance of ActionTracker for monitoring action executions (if `enableMetrics` was true)
973
1079
  state, // A getter function `() => TState` to get the entire current state object (reactive)
974
1080
  watch, // Function to watch the loading status of actions
975
- resolve, // Function to resolve an artifact (if artifacts are defined)
1081
+ resolve, // Function to reactively resolve an artifact (if artifacts are defined)
976
1082
  } = useMyStore(); // Assuming useMyStore is defined from createStore
977
1083
 
978
1084
  // Example: Accessing the full state (use with caution for performance; `select` is preferred)
@@ -991,14 +1097,14 @@ function MyAdvancedComponent() {
991
1097
  }
992
1098
 
993
1099
  // Example: Watching a specific action's loading state
994
- const isLoadingSomeAction = watch('checkout'); // Assuming 'checkout' is an action
1100
+ const isLoadingSomeAction = watch('checkout'); // Assuming 'checkout' is an action from the example store
995
1101
  console.log("Is 'checkout' action loading?", isLoadingSomeAction);
996
1102
 
997
- // Example: Resolving an artifact (if defined in your store)
998
- // const [myArtifact, isArtifactReady] = resolve('myArtifactKey');
999
- // if (isArtifactReady) {
1000
- // console.log("My artifact is ready:", myArtifact);
1001
- // }
1103
+ // Example: Resolving an artifact (from the example store)
1104
+ const { instance: currencySymbol, ready: isCurrencySymbolReady } = resolve('currencySymbol');
1105
+ if (isCurrencySymbolReady) {
1106
+ console.log("Currency Symbol artifact is ready:", currencySymbol);
1107
+ }
1002
1108
 
1003
1109
  return (
1004
1110
  <div>
@@ -1017,53 +1123,50 @@ function MyAdvancedComponent() {
1017
1123
 
1018
1124
  The core logic of this package integrates and extends external utility packages, with `src/store.ts` serving as the main entry point for the React hook.
1019
1125
 
1020
- ```
1021
- .
1022
- ├── src/
1023
- │ ├── execution.ts # Manages tracking and history of action executions.
1024
- │ ├── store.ts # The main `createStore` function, integrating `ReactiveDataStore` and `StoreObservability` from `@asaidimu/utils-store` with React's `useSyncExternalStore`.
1025
- │ └── types.ts # Defines core TypeScript interfaces for store definitions, actions, middleware, and the store hook.
1026
- ├── index.ts # Main library entry point, re-exporting `createStore` and core types.
1027
- ├── package.json
1028
- └── tsconfig.json
1029
- ```
1126
+ * `src/execution.ts`: Defines `ActionExecution` and `ActionTracker` classes for monitoring and maintaining a history of action dispatches, including their status and performance metrics.
1127
+ * `src/store.ts`: Contains the main `createStore` factory function. This module orchestrates the initialization of the core `ReactiveDataStore`, `StoreObserver`, `ActionTracker`, and `ArtifactContainer`. It also binds actions, applies middleware (`transform`, `validate`), and sets up the React hook using `useSyncExternalStore` for efficient component updates.
1128
+ * `src/types.ts`: Defines all core TypeScript interfaces and types for the store's public API, including `ActionContext`, `StoreDefinition`, `StoreHook`, middleware signatures (`Transformer`, `Validator`), and artifact-related types.
1030
1129
 
1031
1130
  ### Key External Dependencies
1032
1131
 
1033
1132
  This library leverages the following `@asaidimu` packages for its core functionalities:
1034
1133
 
1035
- * **`@asaidimu/utils-store`**: Provides the foundational `ReactiveDataStore` for immutable state management, transactions, core event emission, and the `StoreObservability` instance for deep insights into state changes.
1134
+ * **`@asaidimu/utils-store`**: Provides the foundational `ReactiveDataStore` for immutable state management, transactions, core event emission, and the `StoreObserver` instance for deep insights into state changes.
1036
1135
  * **`@asaidimu/utils-persistence`**: Offers various persistence adapters like `WebStoragePersistence` and `IndexedDBPersistence` for saving and loading state, including cross-tab synchronization.
1136
+ * **`@asaidimu/utils-artifacts`**: Provides the `ArtifactContainer` and related types for defining and resolving asynchronous, reactive dependencies (artifacts) within the store.
1037
1137
 
1038
1138
  ### Core Components
1039
1139
 
1040
1140
  * **`ReactiveDataStore` (from `@asaidimu/utils-store`)**: The heart of the state management. It handles immutable state updates, middleware processing, transaction management, and emits detailed internal events about state changes.
1041
- * **`StoreObservability` (from `@asaidimu/utils-store`)**: Built on top of `ReactiveDataStore`'s event system, this component provides comprehensive debugging and monitoring features. This includes event history, state snapshots for time-travel, performance metrics, and utilities for logging or validation middleware.
1141
+ * **`StoreObserver` (from `@asaidimu/utils-store`)**: Built on top of `ReactiveDataStore`'s event system, this component provides comprehensive debugging and monitoring features. This includes event history, state snapshots for time-travel, performance metrics, and utilities for logging or validation middleware.
1042
1142
  * **`ActionTracker` (`src/execution.ts`)**: A dedicated class for tracking the lifecycle and performance of individual action executions, capturing details like start/end times, duration, parameters, and outcomes (success/error).
1043
- * **`createStore` Hook (`src/store.ts`)**: The primary React-facing API. It instantiates `ReactiveDataStore`, `StoreObservability`, and `ActionTracker`. It wraps user-defined actions with debouncing and tracking, and provides the `select` function (powered by `useSyncExternalStore` for efficient component updates) and the `watch` function for action loading states.
1044
- * **Persistence Adapters (from `@asaidimu/utils-persistence`)**: Implement the `DataStorePersistence` interface. `WebStoragePersistence` (for `localStorage`/`sessionStorage`) and `IndexedDBPersistence` provide concrete, ready-to-use storage solutions with cross-tab synchronization capabilities.
1143
+ * **`ArtifactContainer` (from `@asaidimu/utils-artifacts`)**: Manages the registration and resolution of artifacts. It handles dependencies between artifacts and reacts to state changes for artifacts that depend on store state.
1144
+ * **`createStore` Hook (`src/store.ts`)**: The primary React-facing API. It instantiates `ReactiveDataStore`, `StoreObserver`, `ActionTracker`, and `ArtifactContainer`. It wraps user-defined actions with debouncing and tracking, and provides the `select` function (powered by `useSyncExternalStore` for efficient component updates), the `watch` function for action loading states, and the `resolve` function for artifacts.
1145
+ * **Persistence Adapters (from `@asaidimu/utils-persistence`)**: Implement the `SimplePersistence` interface. `WebStoragePersistence` (for `localStorage`/`sessionStorage`) and `IndexedDBPersistence` provide concrete, ready-to-use storage solutions with cross-tab synchronization capabilities.
1045
1146
 
1046
1147
  ### Data Flow
1047
1148
 
1048
1149
  1. **Action Dispatch**: A React component calls a bound action (e.g., `actions.addItem()`).
1049
1150
  2. **Action Debouncing**: Actions are debounced by default (configurable), preventing rapid successive calls.
1050
- 3. **Action Loading State Update**: The store immediately updates the loading state for the dispatched action to `true` via `ReactiveDataStore`.
1151
+ 3. **Action Loading State Update**: The store immediately updates the loading state for the dispatched action to `true` via an internal `ReactiveDataStore`.
1051
1152
  4. **Action Execution Tracking**: The `ActionTracker` records the action's details (name, parameters, start time).
1052
- 5. **State Update Request**: The action's implementation returns a partial state update or a promise resolving to one.
1153
+ 5. **State Update Request**: The action's implementation (receiving `ActionContext` with `state` and `resolve`) returns a partial state update or a promise resolving to one.
1053
1154
  6. **Transaction Context**: If the action is wrapped within `store.transaction()`, the current state is snapshotted to enable potential rollback.
1054
- 7. **Blocking Middleware**: The update first passes through any registered `blockingMiddleware`. If any middleware returns `false` or throws an error, the update is halted, and the state remains unchanged (and rolled back if in a transaction).
1055
- 8. **Transform Middleware**: If not blocked, the update then passes through transforming `middleware`. These functions can modify the partial update payload.
1155
+ 7. **Validator Middleware**: The update first passes through any registered `validate` middleware. If any validator returns `false` or throws an error, the update is halted, and the state remains unchanged (and rolled back if in a transaction).
1156
+ 8. **Transformer Middleware**: If not blocked, the update then passes through `transform` middleware. These functions can modify the partial update payload.
1056
1157
  9. **State Merging**: The final, possibly transformed, update is immutably merged into the current state using `ReactiveDataStore`'s internal utility.
1057
1158
  10. **Change Detection**: `ReactiveDataStore` performs a deep diff to identify precisely which paths in the state have changed.
1058
- 11. **Persistence**: If changes occurred, the new state is saved via the configured `DataStorePersistence` adapter (e.g., `localStorage`, `IndexedDB`). The system also subscribes to external changes from persistence for cross-tab synchronization.
1059
- 12. **Listener Notification**: `React.useSyncExternalStore` subscribers (used by `select`) whose selected paths have changed are notified, triggering efficient re-renders of only the relevant components.
1060
- 13. **Action Loading State Reset**: Once the action completes (either successfully or with an error), the loading state for that action is reset to `false`.
1061
- 14. **Observability Events**: Throughout this entire flow, `ReactiveDataStore` emits fine-grained events (`update:start`, `middleware:complete`, `transaction:error`, etc.) which `StoreObservability` captures for debugging, metrics collection, and remote reporting.
1159
+ 11. **Persistence**: If changes occurred, the new state is saved via the configured `SimplePersistence` adapter (e.g., `localStorage`, `IndexedDB`). The system also subscribes to external changes from persistence for cross-tab synchronization.
1160
+ 12. **Artifact Re-evaluation**: If state changes affect an artifact that depends on that part of the state, `ArtifactContainer` may re-evaluate and re-resolve that artifact.
1161
+ 13. **Listener Notification**: `React.useSyncExternalStore` subscribers (used by `select` and `resolve`) whose selected paths or resolved artifacts have changed are notified, triggering efficient re-renders of only the relevant components.
1162
+ 14. **Action Loading State Reset**: Once the action completes (either successfully or with an error), the loading state for that action is reset to `false`.
1163
+ 15. **Observability Events**: Throughout this entire flow, `ReactiveDataStore` emits fine-grained events (`update:start`, `middleware:complete`, `transaction:error`, etc.) which `StoreObserver` captures for debugging, metrics collection, and remote reporting.
1062
1164
 
1063
1165
  ### Extension Points
1064
1166
 
1065
- * **Custom Middleware**: Easily add your own `Middleware` or `BlockingMiddleware` functions for custom logic (e.g., advanced logging, validation, side effects).
1066
- * **Custom Persistence Adapters**: Implement the `DataStorePersistence<T>` interface (from `@asaidimu/utils-persistence`) to integrate with any storage solution (e.g., a backend API, WebSockets, or a custom in-memory store).
1167
+ * **Custom Middleware**: Easily add your own `Transformer` or `Validator` functions for custom logic (e.g., advanced logging, analytics, data transformation, or complex validation logic).
1168
+ * **Custom Persistence Adapters**: Implement the `SimplePersistence<T>` interface (from `@asaidimu/utils-persistence`) to integrate with any storage solution (e.g., a backend API, WebSockets, or a custom in-memory store).
1169
+ * **Custom Artifact Factories**: Define factories for any external service, resource, or complex derived state, allowing for clear separation of concerns and reactive dependency injection.
1067
1170
  * **Remote Observability Destinations**: Create new `RemoteDestination` implementations (part of `@asaidimu/utils-store`) to send metrics and traces to any external observability platform not already supported by default.
1068
1171
 
1069
1172
  ## Development & Contributing
@@ -1089,7 +1192,7 @@ We welcome contributions! Please follow the guidelines below.
1089
1192
  * `bun test`: Runs all unit tests using `Vitest` in interactive watch mode.
1090
1193
  * `bun test:ci`: Runs all unit tests once, suitable for CI/CD pipelines.
1091
1194
  * `bun clean`: Removes the `dist` directory, cleaning up previous build artifacts.
1092
- * `bun prebuild`: Pre-build step that cleans the `dist` directory and runs an internal package synchronization script.
1195
+ * `bun prebuild`: Pre-build step that cleans the `dist` directory and runs an internal package synchronization script (`.sync-package.ts`).
1093
1196
  * `bun build`: Compiles the TypeScript source into `dist/` for CJS and ESM formats, generates type definitions, and minifies the code using `Terser`.
1094
1197
  * `bun dev`: Starts the e-commerce dashboard demonstration application using `Vite`.
1095
1198
  * `bun postbuild`: Post-build step that copies `README.md`, `LICENSE.md`, and the specialized `dist.package.json` into the `dist` folder, preparing the package for publishing.
@@ -1127,9 +1230,10 @@ For bugs, feature requests, or questions, please open an issue on the [GitHub Is
1127
1230
  3. **Persistence**:
1128
1231
  * Use unique `storeId` or `storageKey` for each distinct store to avoid data conflicts.
1129
1232
  * Always check the `isReady` flag for UI elements that depend on the initial state loaded from persistence, to prevent rendering incomplete data.
1130
- 4. **Middleware**: Leverage middleware for cross-cutting concerns like logging, analytics, data transformation, or complex validation logic that applies to multiple actions.
1233
+ 4. **Middleware**: Leverage `transform` and `validate` for cross-cutting concerns like logging, analytics, data transformation, or complex validation logic that applies to multiple actions. They now receive `ActionContext`, allowing for advanced logic including artifact resolution.
1131
1234
  5. **`Symbol.for("delete")`**: Use this explicit symbol for property removal to maintain clarity and avoid accidental data mutations or unexpected behavior when merging partial updates.
1132
1235
  6. **Debounce Time**: Adjust the `debounceTime` in `createStore` options for actions that might be called rapidly (e.g., search input, scroll events) to optimize performance. A `debounceTime` of `0` means actions execute immediately.
1236
+ 7. **Artifacts**: Use artifacts to manage external dependencies, services, or complex derived values that might change over time or have their own lifecycle. This promotes better separation of concerns and testability.
1133
1237
 
1134
1238
  ### API Reference
1135
1239
 
@@ -1141,18 +1245,18 @@ The main entry point for creating a store hook.
1141
1245
  // From src/types.ts
1142
1246
  export interface StoreDefinition<
1143
1247
  TState extends object,
1144
- TArtifactsMap extends ArtifactsMap<TState>, // Artifacts can be defined but not shown in this example
1248
+ TArtifactsMap extends ArtifactsMap<TState>,
1145
1249
  TActions extends ActionMap<TState, TArtifactsMap>,
1146
1250
  > {
1147
1251
  state: TState;
1148
1252
  actions: TActions;
1149
1253
  artifacts?: TArtifactsMap; // Optional artifact definitions
1150
- blockingMiddleware?: Record<string, BlockingMiddleware<TState>>; // Optional blocking middleware
1151
- middleware?: Record<string, Middleware<TState>>; // Optional transforming middleware
1254
+ transform?: Record<string, Transformer<TState, TArtifactsMap>>; // Optional transforming middleware
1255
+ validate?: Record<string, Validator<TState, TArtifactsMap>>; // Optional blocking middleware
1152
1256
  }
1153
1257
 
1154
1258
  interface StoreOptions<T> extends ObserverOptions { // ObserverOptions from @asaidimu/utils-store
1155
- enableMetrics?: boolean; // Enable StoreObservability and ActionTracker features (default: false)
1259
+ enableMetrics?: boolean; // Enable StoreObserver and ActionTracker features (default: false)
1156
1260
  persistence?: SimplePersistence<T>; // Optional persistence adapter instance (from @asaidimu/utils-persistence)
1157
1261
  debounceTime?: number; // Time in milliseconds to debounce actions (default: 0ms)
1158
1262
  // Other ObserverOptions for logging, performanceThresholds, maxEvents, maxStateHistory are inherited
@@ -1164,28 +1268,27 @@ const useStoreHook = createStore(definition, options);
1164
1268
  **Returns**: A React hook (`useStoreHook`) which, when called in a component, returns an object with the following properties:
1165
1269
 
1166
1270
  * `store`: Direct access to the underlying `ReactiveDataStore` instance (from `@asaidimu/utils-store`). This provides low-level control and event subscription.
1167
- * `observer`: The `StoreObservability` instance (from `@asaidimu/utils-store`). Available only if `enableMetrics` is `true`. Provides debug, time-travel, and monitoring utilities.
1271
+ * `observer`: The `StoreObserver` instance (from `@asaidimu/utils-store`). Available only if `enableMetrics` is `true`. Provides debug, time-travel, and monitoring utilities.
1168
1272
  * `select`: A memoized selector function `(<S>(selector: (state: TState) => S) => S)`. Extracts specific state slices. Re-renders components only when selected data changes.
1169
1273
  * `actions`: An object containing your defined actions, fully typed and bound to the store. These actions are debounced (if `debounceTime` > 0) and their loading states are tracked. Each action returns a `Promise<TState>` resolving to the new state after the action completes.
1170
1274
  * `actionTracker`: An instance of `ActionTracker` (from `src/execution.ts`). Available only if `enableMetrics` is `true`. Provides methods for monitoring the execution history of your actions.
1171
1275
  * `state`: A getter function `(() => TState)` that returns the entire current state object. Use sparingly, as components relying on this will re-render on *any* state change. `select` is generally preferred for performance.
1172
1276
  * `isReady`: A boolean indicating whether the store's persistence layer (if configured) has finished loading its initial state.
1173
1277
  * `watch`: A function `(<K extends keyof TActions>(action: K) => boolean)` to watch the loading status of individual actions. Returns `true` if the action is currently executing.
1174
- * `resolve`: A reactive artifact resolver `(<K extends keyof TArtifactsMap>(key: K) => readonly [ExtractInstanceFromMap<TArtifactsMap, K>, true] | readonly [ExtractInstanceFromMap<TArtifactsMap, K> | undefined, false])`. If `artifacts` are defined in the store, this hook returns `[instance, isReady]` for a specific artifact, reactively updating if the artifact instance changes or becomes ready.
1278
+ * `resolve`: A reactive artifact resolver `(<K extends keyof TArtifactsMap>(key: K) => ResolvedArtifact<ArtifactValue<TArtifactsMap[K]>>)`. If `artifacts` are defined in the store, this hook returns `ResolvedArtifact` (containing `instance` and `ready` status) for a specific artifact, reactively updating if the artifact instance changes or becomes ready.
1175
1279
 
1176
1280
  #### `ReactiveDataStore` (accessed via `useStoreHook().store` from `@asaidimu/utils-store`)
1177
1281
 
1178
1282
  * `get(clone?: boolean): TState`: Retrieves the current state. Pass `true` to get a deep clone (recommended for mutations outside of actions).
1179
1283
  * `set(update: StateUpdater<TState>): Promise<void>`: Updates the state with a partial object or a function returning a partial object.
1180
- * `subscribe(path: string | string[], listener: (state: TState) => void): () => void`: Subscribes a listener to changes at a specific path or array of paths. Returns an unsubscribe function.
1284
+ * `watch(path: string | string[], callback: (state: TState) => void): () => void`: Subscribes a listener to changes at a specific path or array of paths. Returns an unsubscribe function.
1181
1285
  * `transaction<R>(operation: () => R | Promise<R>): Promise<R>`: Executes a function as an atomic transaction. Rolls back all changes if an error occurs if the operation throws.
1182
- * `use(middleware: Middleware<TState>, name?: string): string`: Adds a transforming middleware. Returns its ID.
1183
- * `useBlockingMiddleware(middleware: BlockingMiddleware<TState>, name?: string): string`: Adds a blocking middleware. Returns its ID.
1286
+ * `use(middleware: StoreMiddleware<TState>): string`: Adds a transforming middleware. Returns its ID. (Note: The `createStore` API uses `transform` and `validate` which internally map to `ReactiveDataStore.use`).
1184
1287
  * `removeMiddleware(id: string): boolean`: Removes a middleware by its ID.
1185
1288
  * `isReady(): boolean`: Checks if the persistence layer has loaded its initial state.
1186
1289
  * `onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void`: Subscribes to internal store events (e.g., `'update:complete'`, `'middleware:error'`, `'transaction:start'`).
1187
1290
 
1188
- #### `StoreObservability` (accessed via `useStoreHook().observer` from `@asaidimu/utils-store`)
1291
+ #### `StoreObserver` (accessed via `useStoreHook().observer` from `@asaidimu/utils-store`)
1189
1292
 
1190
1293
  Available only if `enableMetrics` is `true` in `createStore` options.
1191
1294
 
@@ -1194,8 +1297,6 @@ Available only if `enableMetrics` is `true` in `createStore` options.
1194
1297
  * `getRecentChanges(limit?: number): Array<{ timestamp: number; changedPaths: string[]; from: DeepPartial<TState>; to: DeepPartial<TState>; }>`: Provides a simplified view of recent state changes.
1195
1298
  * `getPerformanceMetrics(): StoreMetrics`: Returns an object containing performance statistics (e.g., `updateCount`, `averageUpdateTime`).
1196
1299
  * `createTimeTravel(): { canUndo: () => boolean; canRedo: () => boolean; undo: () => Promise<void>; redo: () => Promise<void>; getHistoryLength: () => number; clear: () => void; }`: Returns controls for time-travel debugging.
1197
- * `createLoggingMiddleware(options?: object): Middleware<TState>`: A factory for a simple logging middleware.
1198
- * `createValidationMiddleware(validator: (state: TState, update: DeepPartial<TState>) => boolean | { valid: boolean; reason?: string }): BlockingMiddleware<TState>`: A factory for a schema validation middleware.
1199
1300
  * `clearHistory(): void`: Clears the event and state history.
1200
1301
  * `disconnect(): void`: Cleans up all listeners and resources.
1201
1302
 
@@ -1224,10 +1325,10 @@ All adapters implement `SimplePersistence<T>`:
1224
1325
  | **Feature** | **@asaidimu/react-store** | **Redux** | **Zustand** | **MobX** | **Recoil** |
1225
1326
  | :--------------------- | :------------------------ | :----------------- | :----------------- | :----------------- | :----------------- |
1226
1327
  | **Dev Experience** | Intuitive hook-based API with rich tooling. | Verbose setup with reducers and middleware. | Minimalist, hook-friendly API. | Reactive, class-based approach. | Atom-based, React-native feel. |
1227
- | **Learning Curve** | Moderate (middleware, observability add complexity). | Steep (boilerplate-heavy). | Low (simple API). | Moderate (reactive concepts). | Low to moderate (atom model). |
1328
+ | **Learning Curve** | Moderate (artifacts, middleware, observability add complexity). | Steep (boilerplate-heavy). | Low (simple API). | Moderate (reactive concepts). | Low to moderate (atom model). |
1228
1329
  | **API Complexity** | Medium (rich feature set balanced with simplicity). | High (many concepts: actions, reducers, etc.). | Low (straightforward). | Medium (proxies, decorators). | Medium (atom/selectors). |
1229
- | **Scalability** | High (transactions, persistence, remote metrics). | High (structured but verbose). | High (small but flexible). | High (reactive scaling). | High (granular atoms). |
1230
- | **Extensibility** | Excellent (middleware, custom persistence, observability). | Good (middleware, enhancers). | Good (middleware-like). | Moderate (custom reactions). | Moderate (custom selectors). |
1330
+ | **Scalability** | High (transactions, persistence, remote metrics, artifacts). | High (structured but verbose). | High (small but flexible). | High (reactive scaling). | High (granular atoms). |
1331
+ | **Extensibility** | Excellent (middleware, custom persistence, observability, artifacts). | Good (middleware, enhancers). | Good (middleware-like). | Moderate (custom reactions). | Moderate (custom selectors). |
1231
1332
  | **Performance** | Optimized (selectors, reactive updates via `useSyncExternalStore`). | Good (predictable but manual optimization). | Excellent (minimal overhead). | Good (reactive overhead). | Good (granular updates). |
1232
1333
  | **Bundle Size** | Moderate (includes observability, persistence, remote observability framework). | Large (core + toolkit). | Tiny (~1KB). | Moderate (~20KB). | Moderate (~10KB). |
1233
1334
  | **Persistence** | Built-in (IndexedDB, WebStorage, cross-tab). | Manual (via middleware). | Manual (via middleware). | Manual (custom). | Manual (custom). |
@@ -1235,13 +1336,13 @@ All adapters implement `SimplePersistence<T>`:
1235
1336
  | **React Integration** | Native (hooks, `useSyncExternalStore`). | Manual (React-Redux). | Native (hooks). | Native (observers). | Native (atoms). |
1236
1337
 
1237
1338
  #### Where `@asaidimu/react-store` Shines
1238
- * **All-in-One**: It aims to be a single solution for state management, persistence, and observability, reducing the need for multiple external dependencies and their integration complexities.
1339
+ * **All-in-One**: It aims to be a single solution for state management, persistence, observability, and artifact management, reducing the need for multiple external dependencies and their integration complexities.
1239
1340
  * **Flexibility**: The robust middleware system, transaction support, and artifact management make it highly adaptable to complex business logic, asynchronous data flows, and dependency injection patterns.
1240
1341
  * **Modern React**: It leverages `useSyncExternalStore` for direct integration with React's concurrency model, ensuring efficient and up-to-date component renders with minimal overhead.
1241
1342
 
1242
1343
  #### Trade-Offs
1243
1344
  * **Bundle Size**: While comprehensive, it naturally has a larger bundle size compared to minimalist alternatives like Zustand, as it includes a wider range of features out-of-the-box. Tree-shaking is applied, but the rich feature set contributes to the baseline.
1244
- * **Learning Curve**: The rich feature set and advanced concepts (middleware, transactions, observability) might present a slightly steeper initial learning curve for developers new to advanced state management, though the API strives for simplicity and clear documentation.
1345
+ * **Learning Curve**: The rich feature set and advanced concepts (middleware, transactions, observability, artifacts) might present a slightly steeper initial learning curve for developers new to advanced state management, though the API strives for simplicity and clear documentation.
1245
1346
 
1246
1347
  ### Troubleshooting
1247
1348
 
@@ -1257,12 +1358,18 @@ All adapters implement `SimplePersistence<T>`:
1257
1358
  * Check the `debounceTime` option in your `createStore` configuration. If set, actions will be delayed.
1258
1359
  * If actions are `async`, ensure you `await` them where necessary in your components.
1259
1360
  * Use the `watch` function to check if an action is in a loading state.
1260
- * **Middleware not working:**
1261
- * Ensure middleware functions are correctly registered in the `middleware` or `blockingMiddleware` objects in `createStore`.
1361
+ * **Middleware (transform/validate) not working:**
1362
+ * Ensure `transform` and `validate` functions are correctly registered in the `createStore` definition.
1262
1363
  * Check console logs (if `enableConsoleLogging` is `true`) for `middleware:start`, `middleware:complete`, or `middleware:error` events.
1364
+ * Verify the middleware signature matches the `Transformer` or `Validator` types, especially the `ActionContext` parameter.
1365
+ * **Artifacts not resolving or updating:**
1366
+ * Check the `ready` property returned by the `resolve` hook. Artifacts are often asynchronous.
1367
+ * Ensure that any dependencies an artifact has (e.g., other artifacts, state values) are stable or correctly configured for reactivity.
1368
+ * Verify the `factory` function for your artifact is correctly defined and returns the expected value.
1263
1369
  * **TypeScript errors:**
1264
1370
  * Verify your state interfaces match the `initialState` structure.
1265
1371
  * Ensure action return types are `DeepPartial<TState>` as expected.
1372
+ * Make sure `transform` and `validate` functions adhere to their new `ActionContext` signature.
1266
1373
  * Update `@asaidimu/react-store` and `@types/react` to their latest compatible versions.
1267
1374
 
1268
1375
  ### FAQ
@@ -1271,16 +1378,16 @@ All adapters implement `SimplePersistence<T>`:
1271
1378
  A: `useSyncExternalStore` is generally a client-side hook. While the underlying `ReactiveDataStore` is framework-agnostic, the `createStore` hook is designed for client-side React components and is not directly compatible with RSCs for reactive state consumption. You can, however, hydrate the client-side store with initial state from RSCs.
1272
1379
 
1273
1380
  **Q: How do I share state between multiple stores?**
1274
- A: Currently, `@asaidimu/react-store` promotes independent stores. For shared logic or derived state, consider creating a utility function that both stores can call, or a parent component that manages shared data and passes it down. Direct cross-store subscription or merging is not a primary pattern.
1381
+ A: Currently, `@asaidimu/react-store` promotes independent stores. For shared logic or derived state, consider creating an artifact that both stores can resolve, or a utility function that both stores can call, or a parent component that manages shared data and passes it down. Direct cross-store subscription or merging is not a primary pattern.
1275
1382
 
1276
1383
  **Q: Can I use it without React?**
1277
- A: The core state management (`ReactiveDataStore`, `StoreObservability` from `@asaidimu/utils-store`) is framework-agnostic. The `createStore` function is React-specific, but you can use the underlying `ReactiveDataStore` directly in non-React environments.
1384
+ A: The core state management (`ReactiveDataStore`, `StoreObserver` from `@asaidimu/utils-store`) is framework-agnostic. The `createStore` function is React-specific, but you can use the underlying `ReactiveDataStore` directly in non-React environments.
1278
1385
 
1279
1386
  **Q: What about immutability?**
1280
1387
  A: All state updates are handled immutably. The library ensures that direct state mutations within actions are prevented and that new state objects are created for changed paths, preserving reference equality for unchanged parts of the state.
1281
1388
 
1282
1389
  **Q: Is there a dev tools extension?**
1283
- A: Currently, there is no dedicated browser extension. However, the built-in `StoreObservability` (`observer` object) and `ActionTracker` provide extensive programmatic debugging capabilities, including event history, state snapshots, and performance metrics, which can be integrated into your application's dev panel. Console logging can also be enabled for quick insights.
1390
+ A: Currently, there is no dedicated browser extension. However, the built-in `StoreObserver` (`observer` object) and `ActionTracker` provide extensive programmatic debugging capabilities, including event history, state snapshots, and performance metrics, which can be integrated into your application's dev panel. Console logging can also be enabled for quick insights.
1284
1391
 
1285
1392
  ### Changelog
1286
1393
 
@@ -1293,4 +1400,4 @@ This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.m
1293
1400
  ### Acknowledgments
1294
1401
 
1295
1402
  Developed by [Saidimu](https://github.com/asaidimu).
1296
- This library leverages the robust capabilities of [@asaidimu/utils-store](https://github.com/asaidimu/utils-store) and [@asaidimu/utils-persistence](https://github.com/asaidimu/utils-persistence) for its core state management and persistence features.
1403
+ This library leverages the robust capabilities of [@asaidimu/utils-store](https://github.com/asaidimu/utils-store), [@asaidimu/utils-persistence](https://github.com/asaidimu/utils-persistence), and [@asaidimu/utils-artifacts](https://github.com/asaidimu/utils-artifacts) for its core state management, persistence, and artifact management features.