@asaidimu/react-store 2.0.0 → 3.0.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
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@asaidimu/react-store.svg)](https://www.npmjs.com/package/@asaidimu/react-store)
4
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)
5
6
 
6
7
  A performant, type-safe state management solution for React with built-in persistence, extensive observability, and a robust middleware system.
7
8
 
@@ -24,6 +25,7 @@ This package is currently in **beta**. The API is subject to rapid changes and s
24
25
  * [Remote Observability](#remote-observability)
25
26
  * [Transaction Support](#transaction-support)
26
27
  * [Event System](#event-system)
28
+ * [Watching Action Loading States](#watching-action-loading-states)
27
29
  * [Advanced Hook Properties](#advanced-hook-properties)
28
30
  * [Project Architecture](#project-architecture)
29
31
  * [Development & Contributing](#development--contributing)
@@ -31,6 +33,8 @@ This package is currently in **beta**. The API is subject to rapid changes and s
31
33
  * [Best Practices](#best-practices)
32
34
  * [API Reference](#api-reference)
33
35
  * [Comparison with Other State Management Solutions](#comparison-with-other-state-management-solutions)
36
+ * [Troubleshooting](#troubleshooting)
37
+ * [FAQ](#faq)
34
38
  * [Changelog](#changelog)
35
39
  * [License](#license)
36
40
  * [Acknowledgments](#acknowledgments)
@@ -41,19 +45,19 @@ This package is currently in **beta**. The API is subject to rapid changes and s
41
45
 
42
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.
43
47
 
44
- 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.
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.
45
49
 
46
50
  ### Key Features
47
51
 
48
- * 📊 **Reactive State Management**: Automatically tracks dependencies to optimize component renders and ensure efficient updates.
49
- * 🛡️ **Type-Safe**: Built with TypeScript from the ground up, providing strict type checking and a safer development experience.
52
+ * 📊 **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.
50
54
  * ⚙️ **Middleware Pipeline**: Implement custom logic to transform, validate, or log state changes before they are applied. Supports both transforming and blocking middleware.
51
55
  * 📦 **Transaction Support**: Group multiple state updates into a single atomic operation, with automatic rollback if any part of the transaction fails.
52
56
  * 💾 **Built-in Persistence**: Seamlessly integrate with web storage mechanisms like `IndexedDB` and `WebStorage` (localStorage/sessionStorage), including cross-tab synchronization.
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.
56
- * ⚛️ **React 18+ Ready**: Fully compatible with the latest React versions, leveraging modern APIs for enhanced performance and development ergonomics.
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.
60
+ * ⚛️ **React 19+ Ready**: Fully compatible with the latest React versions, leveraging modern APIs for enhanced performance and development ergonomics.
57
61
  * 🗑️ **Explicit Deletions**: Use `Symbol.for("delete")` to explicitly remove properties from nested state objects.
58
62
 
59
63
  ## Installation & Setup
@@ -61,8 +65,8 @@ Designed with modern React in mind, it leverages `useSyncExternalStore` for opti
61
65
  ### Prerequisites
62
66
 
63
67
  * Node.js (v18 or higher recommended)
64
- * React (v18 or higher recommended)
65
- * A package manager like `bun`, `npm`, or `yarn`.
68
+ * React (v19 or higher recommended)
69
+ * A package manager like `bun`, `npm`, or `yarn`. This project explicitly uses `bun`.
66
70
 
67
71
  ### Installation Steps
68
72
 
@@ -78,7 +82,7 @@ yarn add @asaidimu/react-store
78
82
 
79
83
  ### Configuration
80
84
 
81
- No global configuration is required. All options are passed during store creation.
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.
82
86
 
83
87
  ### Verification
84
88
 
@@ -87,99 +91,242 @@ You can verify the installation by importing `createStore` and setting up a basi
87
91
  ```typescript
88
92
  import { createStore } from '@asaidimu/react-store';
89
93
 
90
- const myStore = createStore({
94
+ interface MyState {
95
+ value: string;
96
+ }
97
+
98
+ const myStore = createStore<MyState, any>({
91
99
  state: { value: 'hello' },
92
100
  actions: {
93
- setValue: (state, newValue: string) => ({ value: newValue }),
101
+ setValue: (_, newValue: string) => ({ value: newValue }),
94
102
  },
95
103
  });
96
104
 
97
- console.log(myStore().select(s => s.value)); // Should output 'hello'
105
+ const { select, actions } = myStore(); // Instantiate the hook
106
+
107
+ // Access state
108
+ const currentValue = select(s => s.value);
109
+ console.log(currentValue); // Expected: 'hello'
110
+
111
+ // Dispatch an action
112
+ actions.setValue('world');
98
113
  ```
99
114
 
100
- If no errors are thrown, the package is correctly installed.
115
+ If no errors are thrown during installation or when running this basic example, the package is correctly installed and configured.
101
116
 
102
117
  ## Usage Documentation
103
118
 
104
119
  ### Creating a Store
105
120
 
106
- Define your application state and actions, then create a store using `createStore`.
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.
107
122
 
108
123
  ```tsx
109
- // src/stores/myStore.ts
110
- import { createStore } from '@asaidimu/react-store';
124
+ // ui/store.tsx (Example from codebase)
125
+ import { createStore } from '@asaidimu/react-store'; // Assuming direct import or wrapper
126
+
127
+ export interface Product {
128
+ id: number;
129
+ name: string;
130
+ price: number;
131
+ stock: number;
132
+ image: string;
133
+ }
111
134
 
112
- interface AppState {
113
- count: number;
114
- user: { name: string; loggedIn: boolean; email?: string };
115
- settings: { theme: 'light' | 'dark'; notifications: boolean };
135
+ export interface CartItem extends Product {
136
+ quantity: number;
116
137
  }
117
138
 
118
- const initialState: AppState = {
119
- count: 0,
120
- user: { name: 'Guest', loggedIn: false },
121
- settings: { theme: 'light', notifications: true },
139
+ export interface Order {
140
+ id: string;
141
+ items: CartItem[];
142
+ total: number;
143
+ date: Date;
144
+ }
145
+
146
+ export interface ECommerceState extends Record<string, any>{
147
+ products: Product[];
148
+ cart: CartItem[];
149
+ orders: Order[];
150
+ topSellers: { id: number; name: string; sales: number }[];
151
+ activeUsers: number;
152
+ }
153
+
154
+ const initialState: ECommerceState = {
155
+ products: [
156
+ { id: 1, name: 'Wireless Mouse', price: 25.99, stock: 150, image: 'https://placehold.co/600x400/white/black?text=Mouse' },
157
+ { id: 2, name: 'Mechanical Keyboard', price: 79.99, stock: 100, image: 'https://placehold.co/600x400/white/black?text=Keyboard' },
158
+ { id: 3, name: '4K Monitor', price: 349.99, stock: 75, image: 'https://placehold.co/600x400/white/black?text=Monitor' },
159
+ { id: 4, name: 'Webcam', price: 45.50, stock: 120, image: 'https://placehold.co/600x400/white/black?text=Webcam' },
160
+ { id: 5, name: 'USB-C Hub', price: 39.99, stock: 200, image: 'https://placehold.co/600x400/white/black?text=Hub' },
161
+ ],
162
+ cart: [],
163
+ orders: [],
164
+ topSellers: [
165
+ { id: 2, name: 'Mechanical Keyboard', sales: 120 },
166
+ { id: 3, name: '4K Monitor', sales: 85 },
167
+ { id: 1, name: 'Wireless Mouse', sales: 80 },
168
+ { id: 5, name: 'USB-C Hub', sales: 70 },
169
+ { id: 4, name: 'Webcam', sales: 65 },
170
+ ],
171
+ activeUsers: 1428,
122
172
  };
123
173
 
124
- const myStore = createStore({
125
- state: initialState,
126
- actions: {
127
- increment: (state, amount: number) => ({ count: state.count + amount }),
128
- login: async (state, username: string, email: string) => {
129
- // Simulate an asynchronous API call
130
- await new Promise(resolve => setTimeout(resolve, 500));
131
- return { user: { name: username, loggedIn: true, email } };
132
- },
133
- toggleTheme: (state) => ({
134
- settings: { theme: state.settings.theme === 'light' ? 'dark' : 'light' },
135
- }),
174
+ const actions = {
175
+ addToCart: ({ state }: any, product: Product) => {
176
+ const existingItem = state.cart.find((item:any) => item.id === product.id);
177
+ if (existingItem) {
178
+ return {
179
+ cart: state.cart.map((item:any) =>
180
+ item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
181
+ ),
182
+ };
183
+ }
184
+ return { cart: [...state.cart, { ...product, quantity: 1 }] };
185
+ },
186
+ removeFromCart: ({state}: {state:ECommerceState}, productId: number) => ({
187
+ cart: state.cart.filter((item) => item.id !== productId),
188
+ }),
189
+ updateQuantity: ({state}: {state:ECommerceState}, { productId, quantity }: { productId: number; quantity: number }) => ({
190
+ cart: state.cart.map((item) =>
191
+ item.id === productId ? { ...item, quantity } : item
192
+ ).filter(item => item.quantity > 0),
193
+ }),
194
+ checkout: ({state}: {state:ECommerceState}) => {
195
+ const total = state.cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
196
+ const newOrder: Order = {
197
+ id: crypto.randomUUID(),
198
+ items: state.cart,
199
+ total,
200
+ date: new Date(),
201
+ };
202
+ return {
203
+ cart: [],
204
+ orders: [newOrder, ...state.orders],
205
+ products: state.products.map(p => {
206
+ const cartItem = state.cart.find(item => item.id === p.id);
207
+ return cartItem ? { ...p, stock: p.stock - cartItem.quantity } : p;
208
+ }),
209
+ topSellers: state.topSellers.map(s => {
210
+ const cartItem = state.cart.find(item => item.id === s.id);
211
+ return cartItem ? { ...s, sales: s.sales + cartItem.quantity } : s;
212
+ }).sort((a, b) => b.sales - a.sales),
213
+ };
136
214
  },
137
- }, {
138
- debounceTime: 100, // Debounce actions by 100ms
139
- enableConsoleLogging: true, // Enable console logs for store events
140
- logEvents: { updates: true, transactions: true, middleware: true },
141
- performanceThresholds: { updateTime: 20, middlewareTime: 5 }, // Warn for slow operations
142
- });
143
215
 
144
- // Export the hook for use in components
145
- export const useMyStore = myStore;
216
+ updateStock: ({state}: {state:ECommerceState}) => ({
217
+ products: state.products.map((p:any) => ({
218
+ ...p,
219
+ stock: Math.max(0, p.stock + Math.floor(Math.random() * 10) - 5)
220
+ }))
221
+ }),
222
+ updateActiveUsers: ({state}: {state:ECommerceState}) => ({
223
+ activeUsers: state.activeUsers + Math.floor(Math.random() * 20) - 10,
224
+ }),
225
+ addRandomOrder: ({state}: {state:ECommerceState}) => {
226
+ const randomProduct = state.products[Math.floor(Math.random() * state.products.length)];
227
+ const quantity = Math.floor(Math.random() * 3) + 1;
228
+ const newOrder: Order = {
229
+ id: crypto.randomUUID(),
230
+ items: [{ ...randomProduct, quantity }],
231
+ total: randomProduct.price * quantity,
232
+ date: new Date(),
233
+ };
234
+ return {
235
+ orders: [newOrder, ...state.orders],
236
+ };
237
+ },
238
+ };
239
+
240
+ export const useStore = createStore(
241
+ {
242
+ state: initialState,
243
+ actions,
244
+ },
245
+ { enableMetrics: true } // Enables metrics for observability
246
+ );
146
247
  ```
147
248
 
148
249
  ### Using in Components
149
250
 
150
- Consume your store's state and actions within your React components using the exported hook.
251
+ 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.
151
252
 
152
253
  ```tsx
153
- // src/components/MyComponent.tsx
154
- import React from 'react';
155
- import { useMyStore } from '../stores/myStore';
254
+ // ui/App.tsx (Excerpt from codebase)
255
+ import { useEffect, useMemo } from 'react';
256
+ import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
257
+ import { useStore, Product, CartItem, Order } from './store'; // Assuming these imports resolve correctly
156
258
 
157
- function MyComponent() {
158
- const { select, actions, isReady } = useMyStore();
259
+ // ... (ShadCN-like UI Components for brevity) ...
159
260
 
160
- // Select specific parts of the state for granular re-renders
161
- const count = select((state) => state.count);
162
- const userName = select((state) => state.user.name);
163
- const theme = select((state) => state.settings.theme);
261
+ const ProductCatalog = () => {
262
+ const { select, actions } = useStore();
263
+ const products = select((state) => state.products); // Granular selection
164
264
 
165
- // isReady indicates if persistence has loaded initial state
166
- if (!isReady) {
167
- return <div>Loading store data...</div>;
168
- }
265
+ return (
266
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
267
+ {products.map((product: Product) => (
268
+ <Card key={product.id}>
269
+ <CardHeader>
270
+ <CardTitle>{product.name}</CardTitle>
271
+ </CardHeader>
272
+ <CardContent className="flex-grow">
273
+ <img src={product.image} alt={product.name} className="w-full h-40 object-cover rounded-lg mb-4" />
274
+ <div className="flex justify-between items-center">
275
+ <p className="text-lg font-semibold text-gray-700">${product.price.toFixed(2)}</p>
276
+ <p className="text-sm text-gray-500">{product.stock} in stock</p>
277
+ </div>
278
+ </CardContent>
279
+ <CardFooter>
280
+ <Button onClick={() => actions.addToCart(product)} className="w-full">Add to Cart</Button>
281
+ </CardFooter>
282
+ </Card>
283
+ ))}
284
+ </div>
285
+ );
286
+ };
287
+
288
+ function App() {
289
+ const { actions } = useStore();
290
+
291
+ useEffect(() => {
292
+ // Real-time simulations for the dashboard
293
+ const stockInterval = setInterval(() => actions.updateStock(), 2000);
294
+ const usersInterval = setInterval(() => actions.updateActiveUsers(), 3000);
295
+ const ordersInterval = setInterval(() => actions.addRandomOrder(), 5000);
296
+
297
+ return () => {
298
+ clearInterval(stockInterval);
299
+ clearInterval(usersInterval);
300
+ clearInterval(ordersInterval);
301
+ };
302
+ }, [actions]); // `actions` object is stable due to `useMemo` in createStore
169
303
 
170
304
  return (
171
- <div style={{ background: theme === 'dark' ? '#333' : '#FFF', color: theme === 'dark' ? '#FFF' : '#333' }}>
172
- <h1>Welcome, {userName}!</h1>
173
- <p>Current Count: {count}</p>
174
- <button onClick={() => actions.increment(1)}>Increment</button>
175
- <button onClick={() => actions.increment(5)}>Increment by 5 (debounced)</button>
176
- <button onClick={() => actions.login('Alice', 'alice@example.com')}>Login as Alice</button>
177
- <button onClick={() => actions.toggleTheme()}>Toggle Theme</button>
305
+ <div className="bg-gray-50 text-gray-900 min-h-screen">
306
+ <header className="border-b">
307
+ <div className="container mx-auto px-4 h-16 flex items-center">
308
+ <h1 className="text-xl font-bold">E-Commerce Dashboard</h1>
309
+ </div>
310
+ </header>
311
+ <main className="container mx-auto p-4 sm:p-6 lg:p-8">
312
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
313
+ <div className="lg:col-span-2 space-y-6">
314
+ <ProductCatalog />
315
+ <LiveInventoryChart />
316
+ </div>
317
+ <div className="space-y-6">
318
+ <ShoppingCart />
319
+ <UserAnalytics />
320
+ <TopSellingProducts />
321
+ <RecentOrdersFeed />
322
+ </div>
323
+ </div>
324
+ </main>
178
325
  </div>
179
326
  );
180
327
  }
181
328
 
182
- export default MyComponent;
329
+ export default App;
183
330
  ```
184
331
 
185
332
  ### Handling Deletions
@@ -203,12 +350,12 @@ const deleteStore = createStore({
203
350
  tags: ['electronics', 'new']
204
351
  },
205
352
  actions: {
206
- removeDetails: (state) => ({ details: Symbol.for("delete") }),
207
- removeDimensions: (state) => ({ details: { dimensions: Symbol.for("delete") } }),
208
- removeTag: (state, tagToRemove: string) => ({
353
+ removeDetails: (ctx) => ({ details: Symbol.for("delete") }),
354
+ removeDimensions: (ctx) => ({ details: { dimensions: Symbol.for("delete") } }),
355
+ removeTag: ({state}, tagToRemove: string) => ({
209
356
  tags: state.tags.filter(tag => tag !== tagToRemove)
210
357
  }),
211
- clearAllExceptId: (state) => ({
358
+ clearAllExceptId: (ctx) => ({
212
359
  name: Symbol.for("delete"),
213
360
  details: Symbol.for("delete"),
214
361
  tags: Symbol.for("delete")
@@ -244,10 +391,12 @@ runDeleteExample();
244
391
 
245
392
  ### Persistence
246
393
 
247
- Persist your store's state across browser sessions or synchronize it across multiple tabs.
394
+ Persist your store's state across browser sessions or synchronize it across multiple tabs using persistence adapters from `@asaidimu/utils-persistence`. You can choose between `WebStoragePersistence` (for `localStorage` or `sessionStorage`) and `IndexedDBPersistence` for more robust storage.
248
395
 
249
396
  ```tsx
250
- import { createStore, WebStoragePersistence, IndexedDBPersistence } from '@asaidimu/react-store';
397
+ import { createStore } from '@asaidimu/react-store';
398
+ import { WebStoragePersistence, IndexedDBPersistence } from '@asaidimu/utils-persistence';
399
+ import React, { useEffect } from 'react';
251
400
 
252
401
  // 1. Using WebStoragePersistence (localStorage by default)
253
402
  // Data persists even if the browser tab is closed and reopened.
@@ -256,7 +405,7 @@ const useLocalStore = createStore(
256
405
  {
257
406
  state: { sessionCount: 0, lastVisited: new Date().toISOString() },
258
407
  actions: {
259
- incrementSessionCount: (state) => ({ sessionCount: state.sessionCount + 1 }),
408
+ incrementSessionCount: ({state}) => ({ sessionCount: state.sessionCount + 1 }),
260
409
  updateLastVisited: () => ({ lastVisited: new Date().toISOString() }),
261
410
  },
262
411
  },
@@ -284,7 +433,7 @@ const useUserProfileStore = createStore(
284
433
  state: { userId: '', preferences: { language: 'en', darkMode: false } },
285
434
  actions: {
286
435
  setUserId: (state, id: string) => ({ userId: id }),
287
- toggleDarkMode: (state) => ({ preferences: { darkMode: !state.preferences.darkMode } }),
436
+ toggleDarkMode: ({state}) => ({ preferences: { darkMode: !state.preferences.darkMode } }),
288
437
  },
289
438
  },
290
439
  { persistence: indexedDBPersistence },
@@ -297,7 +446,7 @@ function AppWithPersistence() {
297
446
  const sessionCount = selectLocal(s => s.sessionCount);
298
447
  const darkMode = selectProfile(s => s.preferences.darkMode);
299
448
 
300
- React.useEffect(() => {
449
+ useEffect(() => {
301
450
  if (localReady) {
302
451
  actionsLocal.incrementSessionCount();
303
452
  actionsLocal.updateLastVisited();
@@ -305,7 +454,7 @@ function AppWithPersistence() {
305
454
  if (profileReady && !selectProfile(s => s.userId)) {
306
455
  actionsProfile.setUserId('user-' + Math.random().toString(36).substring(2, 9));
307
456
  }
308
- }, [localReady, profileReady]);
457
+ }, [localReady, profileReady, actionsLocal, actionsProfile, selectProfile]); // Added dependencies for useEffect
309
458
 
310
459
  if (!localReady || !profileReady) {
311
460
  return <div>Loading persisted data...</div>;
@@ -326,10 +475,11 @@ function AppWithPersistence() {
326
475
 
327
476
  ### Middleware
328
477
 
329
- Middleware functions can intercept and modify or block state updates. They are executed in the order they are added.
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.
330
479
 
331
480
  ```typescript
332
- import { createStore, Middleware, BlockingMiddleware } from '@asaidimu/react-store';
481
+ import { createStore, type Middleware, type BlockingMiddleware } from '@asaidimu/react-store';
482
+ import React from 'react';
333
483
 
334
484
  interface CartState {
335
485
  items: Array<{ id: string; name: string; quantity: number; price: number }>;
@@ -360,7 +510,7 @@ const validateItemMiddleware: BlockingMiddleware<CartState> = (state, update) =>
360
510
  const useCartStore = createStore({
361
511
  state: { items: [], total: 0 },
362
512
  actions: {
363
- addItem: (state, item: { id: string; name: string; price: number }) => {
513
+ addItem: ({state}, item: { id: string; name: string; price: number }) => {
364
514
  const existingItem = state.items.find(i => i.id === item.id);
365
515
  if (existingItem) {
366
516
  return {
@@ -373,10 +523,11 @@ const useCartStore = createStore({
373
523
  items: [...state.items, { ...item, quantity: 1 }],
374
524
  };
375
525
  },
376
- updateQuantity: (state, id: string, quantity: number) => ({
526
+ updateQuantity: ({state}, id: string, quantity: number) => ({
377
527
  items: state.items.map(item => (item.id === id ? { ...item, quantity } : item)),
378
528
  }),
379
529
  },
530
+ // Middleware now accepts an object mapping names to middleware functions
380
531
  middleware: { calculateTotal: calculateTotalMiddleware },
381
532
  blockingMiddleware: { validateItem: validateItemMiddleware },
382
533
  });
@@ -408,10 +559,11 @@ function CartComponent() {
408
559
 
409
560
  ### Observability
410
561
 
411
- Enable metrics and debugging via the `store` and `observer` objects:
562
+ Enable metrics and debugging via the `observer` and `actionTracker` objects. The `enableMetrics` option in `createStore` is crucial for activating these features.
412
563
 
413
564
  ```tsx
414
565
  import { createStore } from '@asaidimu/react-store';
566
+ import React from 'react';
415
567
 
416
568
  const useObservedStore = createStore(
417
569
  {
@@ -422,7 +574,7 @@ const useObservedStore = createStore(
422
574
  },
423
575
  },
424
576
  {
425
- enableMetrics: true, // Crucial for enabling the 'observer' object
577
+ enableMetrics: true, // Crucial for enabling the 'observer' and 'actionTracker' objects
426
578
  enableConsoleLogging: true, // Log events directly to browser console
427
579
  logEvents: { updates: true, middleware: true, transactions: true }, // Which event types to log
428
580
  performanceThresholds: {
@@ -431,7 +583,7 @@ const useObservedStore = createStore(
431
583
  },
432
584
  maxEvents: 500, // Max number of events to keep in history
433
585
  maxStateHistory: 50, // Max number of state snapshots for time travel
434
- debounceTime: 300, // Debounce actions by 300ms to prevent rapid calls
586
+ debounceTime: 0, // Actions execute immediately by default
435
587
  },
436
588
  );
437
589
 
@@ -441,16 +593,16 @@ function DebugPanel() {
441
593
  // Access performance metrics
442
594
  const metrics = observer?.getPerformanceMetrics();
443
595
 
444
- // Access state history for time travel
596
+ // Access state history for time travel (if maxStateHistory > 0)
445
597
  const timeTravel = observer?.createTimeTravel();
446
598
 
447
599
  // Access action execution history
448
- const actionHistory = actionTracker.getExecutions();
600
+ const actionHistory = actionTracker?.getExecutions() || []; // actionTracker is only available if enableMetrics is true
449
601
 
450
602
  return (
451
603
  <div>
452
604
  <h2>Debug Panel</h2>
453
- {observer && (
605
+ {observer && ( // Check if observer is enabled
454
606
  <>
455
607
  <h3>Performance Metrics</h3>
456
608
  <p>Update Count: {metrics?.updateCount}</p>
@@ -481,47 +633,50 @@ function DebugPanel() {
481
633
 
482
634
  ### Remote Observability
483
635
 
484
- Send collected metrics and traces to external systems like OpenTelemetry, Prometheus, or Grafana Cloud for centralized monitoring.
636
+ Send collected metrics and traces to external systems like OpenTelemetry, Prometheus, or Grafana Cloud for centralized monitoring. This functionality typically resides in the `@asaidimu/utils-store` ecosystem.
485
637
 
486
638
  ```tsx
487
- import { createStore, useRemoteObservability } from '@asaidimu/react-store';
639
+ import { createStore } from '@asaidimu/react-store';
640
+ import { useRemoteObservability } from '@asaidimu/utils-store';
488
641
  import React, { useEffect } from 'react';
489
642
 
490
643
  const useRemoteStore = createStore(
491
644
  {
492
645
  state: { apiCallsMade: 0, lastApiError: null },
493
646
  actions: {
494
- simulateApiCall: async (state) => {
495
- // Simulate an error 10% of the time
647
+ simulateApiCall: async ({state}) => {
496
648
  if (Math.random() < 0.1) {
497
649
  throw new Error('API request failed');
498
650
  }
499
651
  return { apiCallsMade: state.apiCallsMade + 1, lastApiError: null };
500
652
  },
501
- handleApiError: (state, error: string) => ({ lastApiError: error })
653
+ handleApiError: ({state}, error: string) => ({ lastApiError: error })
502
654
  },
503
655
  },
504
656
  {
505
657
  enableMetrics: true, // Required for RemoteObservability
506
658
  enableConsoleLogging: false,
507
- collectCategories: {
508
- performance: true,
509
- errors: true,
510
- stateChanges: true,
511
- middleware: true,
512
- },
513
- reportingInterval: 10000, // Send metrics every 10 seconds
514
- batchSize: 10, // Send after 10 metrics or interval, whichever comes first
515
- immediateReporting: false, // Don't send immediately after each metric
659
+ // collectCategories configuration would typically be passed to useRemoteObservability
660
+ // reportingInterval, batchSize, immediateReporting would also be part of useRemoteObservability options
516
661
  }
517
662
  );
518
663
 
519
664
  function MonitoringIntegration() {
520
665
  const { store, observer } = useRemoteStore();
666
+ // useRemoteObservability is assumed to be part of utils-store or a separate utility
521
667
  const { remote, addOpenTelemetryDestination, addPrometheusDestination, addGrafanaCloudDestination } = useRemoteObservability(store, {
522
668
  serviceName: 'my-react-app',
523
669
  environment: 'development',
524
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
525
680
  });
526
681
 
527
682
  useEffect(() => {
@@ -552,24 +707,31 @@ function MonitoringIntegration() {
552
707
  }, 5000); // Report every 5 seconds
553
708
 
554
709
  return () => clearInterval(interval);
555
- }, []);
710
+ }, [observer, addOpenTelemetryDestination, addPrometheusDestination, addGrafanaCloudDestination]); // Added dependencies
556
711
 
557
712
  return null; // This component doesn't render anything visually
558
713
  }
559
714
 
560
- // In your App component:
561
- // <MonitoringIntegration />
562
- // <button onClick={() => useRemoteStore().actions.simulateApiCall().catch(e => useRemoteStore().actions.handleApiError(e.message))}>
563
- // Simulate API Call
564
- // </button>
715
+ // In your App component, you would use it like:
716
+ // function MyApp() {
717
+ // return (
718
+ // <>
719
+ // <MonitoringIntegration />
720
+ // <button onClick={() => useRemoteStore().actions.simulateApiCall().catch(e => useRemoteStore().actions.handleApiError(e.message))}>
721
+ // Simulate API Call
722
+ // </button>
723
+ // </>
724
+ // );
725
+ // }
565
726
  ```
566
727
 
567
728
  ### Transaction Support
568
729
 
569
- 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.
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.
570
731
 
571
732
  ```typescript
572
733
  import { createStore } from '@asaidimu/react-store';
734
+ import React from 'react';
573
735
 
574
736
  interface BankState {
575
737
  checking: number;
@@ -580,7 +742,7 @@ interface BankState {
580
742
  const useBankStore = createStore<BankState, any>({
581
743
  state: { checking: 1000, savings: 500, transactions: [] },
582
744
  actions: {
583
- transferFunds: async (state, fromAccount: 'checking' | 'savings', toAccount: 'checking' | 'savings', amount: number) => {
745
+ transferFunds: async ({state}, fromAccount: 'checking' | 'savings', toAccount: 'checking' | 'savings', amount: number) => {
584
746
  if (amount <= 0) {
585
747
  throw new Error('Transfer amount must be positive.');
586
748
  }
@@ -608,14 +770,15 @@ const useBankStore = createStore<BankState, any>({
608
770
  });
609
771
 
610
772
  function BankApp() {
611
- const { select, actions } = useBankStore();
773
+ const { select, actions, store } = useBankStore();
612
774
  const checkingBalance = select(s => s.checking);
613
775
  const savingsBalance = select(s => s.savings);
614
776
  const transactions = select(s => s.transactions);
615
777
 
616
778
  const handleTransfer = async (from: 'checking' | 'savings', to: 'checking' | 'savings', amount: number) => {
617
779
  try {
618
- await actions.transferFunds(from, to, amount);
780
+ // Wrap the action call in a store transaction
781
+ await store.transaction(() => actions.transferFunds(from, to, amount));
619
782
  alert(`Successfully transferred ${amount} from ${from} to ${to}.`);
620
783
  } catch (error) {
621
784
  alert(`Transfer failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -643,7 +806,7 @@ function BankApp() {
643
806
 
644
807
  ### Event System
645
808
 
646
- The store emits various events during its lifecycle, which you can subscribe to for logging, analytics, or custom side effects.
809
+ 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()`.
647
810
 
648
811
  ```typescript
649
812
  import { createStore } from '@asaidimu/react-store';
@@ -653,7 +816,7 @@ const useEventStore = createStore(
653
816
  {
654
817
  state: { data: 'initial', processedCount: 0 },
655
818
  actions: {
656
- processData: (state, newData: string) => ({ data: newData, processedCount: state.processedCount + 1 }),
819
+ processData: ({state}, newData: string) => ({ data: newData, processedCount: state.processedCount + 1 }),
657
820
  triggerError: () => { throw new Error("Action failed intentionally"); }
658
821
  },
659
822
  middleware: {
@@ -666,7 +829,7 @@ const useEventStore = createStore(
666
829
  );
667
830
 
668
831
  function EventMonitor() {
669
- const { store } = useEventStore();
832
+ const { store, actions } = useEventStore();
670
833
  const [eventLogs, setEventLogs] = React.useState<string[]>([]);
671
834
 
672
835
  useEffect(() => {
@@ -719,8 +882,6 @@ function EventMonitor() {
719
882
  };
720
883
  }, [store]); // Re-subscribe if store instance changes (unlikely)
721
884
 
722
- const { actions } = useEventStore();
723
-
724
885
  return (
725
886
  <div>
726
887
  <h3>Store Event Log</h3>
@@ -737,23 +898,84 @@ function EventMonitor() {
737
898
  }
738
899
  ```
739
900
 
901
+ ### Watching Action Loading States
902
+
903
+ 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.
904
+
905
+ ```tsx
906
+ import React from 'react';
907
+ import { createStore } from '@asaidimu/react-store';
908
+
909
+ interface DataState {
910
+ items: string[];
911
+ }
912
+
913
+ const useDataStore = createStore({
914
+ state: { items: [] },
915
+ actions: {
916
+ fetchItems: async (state) => {
917
+ // Simulate an API call
918
+ await new Promise(resolve => setTimeout(resolve, 2000));
919
+ return { items: ['Item A', 'Item B', 'Item C'] };
920
+ },
921
+ addItem: async ({state}, item: string) => {
922
+ // Simulate a quick add operation
923
+ await new Promise(resolve => setTimeout(resolve, 500));
924
+ return { items: [...state.items, item] };
925
+ },
926
+ },
927
+ });
928
+
929
+ function DataLoader() {
930
+ const { actions, select, watch } = useDataStore();
931
+ const items = select(s => s.items);
932
+
933
+ // Watch the loading state of specific actions
934
+ const isFetchingItems = watch('fetchItems');
935
+ const isAddingItem = watch('addItem');
936
+
937
+ return (
938
+ <div>
939
+ <h2>Data Loader</h2>
940
+ <button onClick={() => actions.fetchItems()} disabled={isFetchingItems}>
941
+ {isFetchingItems ? 'Fetching...' : 'Fetch Items'}
942
+ </button>
943
+ <button onClick={() => actions.addItem(`New Item ${items.length + 1}`)} disabled={isAddingItem}>
944
+ {isAddingItem ? 'Adding...' : 'Add Item'}
945
+ </button>
946
+
947
+ <h3>Items:</h3>
948
+ <ul>
949
+ {items.map((item, index) => (
950
+ <li key={index}>{item}</li>
951
+ ))}
952
+ </ul>
953
+ </div>
954
+ );
955
+ }
956
+ ```
957
+
740
958
  ### Advanced Hook Properties
741
959
 
742
960
  The hook returned by `createStore` provides several properties for advanced usage and debugging, beyond the commonly used `select`, `actions`, and `isReady`:
743
961
 
744
962
  ```tsx
963
+ import { useStore as useMyStore } from '../ui/store'; // Assuming this is your store definition
964
+
745
965
  function MyAdvancedComponent() {
746
966
  const {
747
- select, // Function to select state parts (memoized)
748
- actions, // Object containing your defined actions (debounced)
967
+ select, // Function to select state parts (memoized, reactive)
968
+ actions, // Object containing your defined actions (debounced, promise-returning)
749
969
  isReady, // Boolean indicating if persistence is ready
750
- store, // Direct access to the ReactiveDataStore instance
751
- observer, // StoreObservability instance (if `enableMetrics` was true)
752
- actionTracker, // Instance of ActionTracker for monitoring action executions
753
- state, // A hook `() => T` to get the entire reactive state object
970
+ store, // Direct access to the ReactiveDataStore instance (from @asaidimu/utils-store)
971
+ observer, // StoreObservability instance (from @asaidimu/utils-store, if `enableMetrics` was true)
972
+ actionTracker, // Instance of ActionTracker for monitoring action executions (if `enableMetrics` was true)
973
+ state, // A getter function `() => TState` to get the entire current state object (reactive)
974
+ watch, // Function to watch the loading status of actions
975
+ resolve, // Function to resolve an artifact (if artifacts are defined)
754
976
  } = useMyStore(); // Assuming useMyStore is defined from createStore
755
977
 
756
- // Example: Accessing the full state (use with caution for performance, `select` is preferred)
978
+ // Example: Accessing the full state (use with caution for performance; `select` is preferred)
757
979
  const fullCurrentState = state();
758
980
  console.log("Full reactive state:", fullCurrentState);
759
981
 
@@ -764,11 +986,24 @@ function MyAdvancedComponent() {
764
986
  }
765
987
 
766
988
  // Example: Accessing action history
767
- console.log("Action executions:", actionTracker.getExecutions());
989
+ if (actionTracker) { // actionTracker is only available if enableMetrics is true
990
+ console.log("Action executions:", actionTracker.getExecutions());
991
+ }
992
+
993
+ // Example: Watching a specific action's loading state
994
+ const isLoadingSomeAction = watch('checkout'); // Assuming 'checkout' is an action
995
+ console.log("Is 'checkout' action loading?", isLoadingSomeAction);
996
+
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
+ // }
768
1002
 
769
1003
  return (
770
1004
  <div>
771
1005
  {/* ... your component content ... */}
1006
+ <p>Store Ready: {isReady ? 'Yes' : 'No'}</p>
772
1007
  </div>
773
1008
  );
774
1009
  }
@@ -776,65 +1011,60 @@ function MyAdvancedComponent() {
776
1011
 
777
1012
  ## Project Architecture
778
1013
 
779
- `@asaidimu/react-store` is structured to provide a modular yet integrated state management solution.
1014
+ `@asaidimu/react-store` is structured to provide a modular yet integrated state management solution. It separates core state logic into reusable utilities while offering a streamlined React-specific API.
1015
+
1016
+ ### Internal Structure
1017
+
1018
+ 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.
780
1019
 
781
1020
  ```
782
1021
  .
783
1022
  ├── 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
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.
807
1027
  ├── package.json
808
1028
  └── tsconfig.json
809
1029
  ```
810
1030
 
1031
+ ### Key External Dependencies
1032
+
1033
+ This library leverages the following `@asaidimu` packages for its core functionalities:
1034
+
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.
1036
+ * **`@asaidimu/utils-persistence`**: Offers various persistence adapters like `WebStoragePersistence` and `IndexedDBPersistence` for saving and loading state, including cross-tab synchronization.
1037
+
811
1038
  ### Core Components
812
1039
 
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.
1040
+ * **`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.
1042
+ * **`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.
818
1045
 
819
1046
  ### Data Flow
820
1047
 
821
- 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.
1048
+ 1. **Action Dispatch**: A React component calls a bound action (e.g., `actions.addItem()`).
1049
+ 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`.
1051
+ 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.
1053
+ 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.
1056
+ 9. **State Merging**: The final, possibly transformed, update is immutably merged into the current state using `ReactiveDataStore`'s internal utility.
1057
+ 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.
832
1062
 
833
1063
  ### Extension Points
834
1064
 
835
- * **Custom Middleware**: Easily add your own `Middleware` or `BlockingMiddleware` functions for custom logic.
836
- * **Custom Persistence Adapters**: Implement the `DataStorePersistence<T>` interface to integrate with any storage solution (e.g., a backend API, WebSockets, or a custom in-memory store).
837
- * **Remote Observability Destinations**: Create new `RemoteDestination` implementations to send metrics and traces to any external observability platform not already supported.
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).
1067
+ * **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.
838
1068
 
839
1069
  ## Development & Contributing
840
1070
 
@@ -844,7 +1074,7 @@ We welcome contributions! Please follow the guidelines below.
844
1074
 
845
1075
  1. **Clone the repository:**
846
1076
  ```bash
847
- git clone https://github.com/asaidimu/react-store.git
1077
+ git clone https://github.com/asaidimu/node-react.git
848
1078
  cd react-store
849
1079
  ```
850
1080
  2. **Install dependencies:**
@@ -855,18 +1085,18 @@ We welcome contributions! Please follow the guidelines below.
855
1085
 
856
1086
  ### Scripts
857
1087
 
858
- * `bun ci`: Installs dependencies (for CI/CD environments).
859
- * `bun test`: Runs all unit tests using `Vitest`.
860
- * `bun test:ci`: Runs tests in CI mode (single run).
861
- * `bun clean`: Removes the `dist` directory.
862
- * `bun prebuild`: Cleans `dist` and runs a sync script (internal).
863
- * `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).
865
- * `bun postbuild`: Copies `README.md`, `LICENSE.md`, and `dist.package.json` into the `dist` folder.
1088
+ * `bun ci`: Installs dependencies, typically used in CI/CD environments to ensure a clean install.
1089
+ * `bun test`: Runs all unit tests using `Vitest` in interactive watch mode.
1090
+ * `bun test:ci`: Runs all unit tests once, suitable for CI/CD pipelines.
1091
+ * `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.
1093
+ * `bun build`: Compiles the TypeScript source into `dist/` for CJS and ESM formats, generates type definitions, and minifies the code using `Terser`.
1094
+ * `bun dev`: Starts the e-commerce dashboard demonstration application using `Vite`.
1095
+ * `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.
866
1096
 
867
1097
  ### Testing
868
1098
 
869
- Tests are written using `Vitest` and `React Testing Library`.
1099
+ Tests are written using `Vitest` and `React Testing Library` for component and hook testing.
870
1100
 
871
1101
  To run tests:
872
1102
 
@@ -880,116 +1110,103 @@ bun test --watch
880
1110
 
881
1111
  1. **Fork** the repository and create your branch from `main`.
882
1112
  2. **Code Standards**: Ensure your code adheres to existing coding styles (TypeScript, ESLint, Prettier are configured).
883
- 3. **Tests**: Add unit and integration tests for new features or bug fixes. Ensure all tests pass.
884
- 4. **Commits**: Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages.
885
- 5. **Pull Requests**: Submit a pull request to the `main` branch. Provide a clear description of your changes.
1113
+ 3. **Tests**: Add unit and integration tests for new features or bug fixes. Ensure all tests pass (`bun test`).
1114
+ 4. **Commits**: Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages. This project uses `semantic-release` for automated versioning and changelog generation.
1115
+ 5. **Pull Requests**: Submit a pull request to the `main` branch. Provide a clear description of your changes, referencing any relevant issues.
886
1116
 
887
1117
  ### Issue Reporting
888
1118
 
889
- For bugs, feature requests, or questions, please open an issue on the [GitHub Issues page](https://github.com/asaidimu/react-store/issues).
1119
+ For bugs, feature requests, or questions, please open an issue on the [GitHub Issues page](https://github.com/asaidimu/node-react/issues).
890
1120
 
891
1121
  ## Additional Information
892
1122
 
893
1123
  ### Best Practices
894
1124
 
895
- 1. **Granular Selectors**: Always use `select((state) => state.path.to.value)` instead of `select((state) => state)` to prevent unnecessary re-renders of components.
896
- 2. **Action Design**: Keep actions focused on a single responsibility. Use `async` actions for asynchronous operations and return partial updates upon completion.
1125
+ 1. **Granular Selectors**: Always use `select((state) => state.path.to.value)` instead of `select((state) => state)` to prevent unnecessary re-renders of components. The more specific your selector, the more optimized your component updates will be.
1126
+ 2. **Action Design**: Keep actions focused on a single responsibility. Use `async` actions for asynchronous operations (e.g., API calls) and return partial updates or promises resolving to partial updates upon completion. Actions should describe *what* happened, not *how*.
897
1127
  3. **Persistence**:
898
1128
  * Use unique `storeId` or `storageKey` for each distinct store to avoid data conflicts.
899
- * Always check the `isReady` flag for UI elements that depend on the initial state loaded from persistence.
900
- 4. **Middleware**: Leverage middleware for cross-cutting concerns like logging, analytics, or complex validation logic.
901
- 5. **`Symbol.for("delete")`**: Use this explicit symbol for property removal to maintain clarity and avoid accidental data mutations.
1129
+ * 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.
1131
+ 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
+ 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.
902
1133
 
903
1134
  ### API Reference
904
1135
 
905
1136
  #### `createStore(definition, options)`
906
1137
 
907
- The main entry point for creating a store.
1138
+ The main entry point for creating a store hook.
908
1139
 
909
1140
  ```typescript
910
- type StoreDefinition<T, R extends Actions<T>> = {
911
- state: T; // Initial state object
912
- actions: R; // Object mapping action names to action functions
913
- middleware?: Record<string, Middleware<T>>; // Optional transforming middleware
914
- blockingMiddleware?: Record<string, BlockingMiddleware<T>>; // Optional blocking middleware
915
- };
1141
+ // From src/types.ts
1142
+ export interface StoreDefinition<
1143
+ TState extends object,
1144
+ TArtifactsMap extends ArtifactsMap<TState>, // Artifacts can be defined but not shown in this example
1145
+ TActions extends ActionMap<TState, TArtifactsMap>,
1146
+ > {
1147
+ state: TState;
1148
+ actions: TActions;
1149
+ artifacts?: TArtifactsMap; // Optional artifact definitions
1150
+ blockingMiddleware?: Record<string, BlockingMiddleware<TState>>; // Optional blocking middleware
1151
+ middleware?: Record<string, Middleware<TState>>; // Optional transforming middleware
1152
+ }
916
1153
 
917
- interface StoreOptions<T> {
918
- enableMetrics?: boolean; // Enable StoreObservability features (default: false)
919
- enableConsoleLogging?: boolean; // Log store events to console (default: false)
920
- maxEvents?: number; // Maximum number of events to keep in history (default: 500)
921
- maxStateHistory?: number; // Maximum number of state snapshots for time travel (default: 20)
922
- logEvents?: { // Which event categories to log (defaults to all true if enableConsoleLogging is true)
923
- updates?: boolean;
924
- middleware?: boolean;
925
- transactions?: boolean;
926
- };
927
- performanceThresholds?: { // Thresholds for logging slow operations (in ms)
928
- updateTime?: number; // default: 50ms
929
- middlewareTime?: number; // default: 20ms
930
- };
931
- persistence?: DataStorePersistence<T>; // Optional persistence adapter instance
932
- debounceTime?: number; // Time in milliseconds to debounce actions (default: 250ms)
1154
+ interface StoreOptions<T> extends ObserverOptions { // ObserverOptions from @asaidimu/utils-store
1155
+ enableMetrics?: boolean; // Enable StoreObservability and ActionTracker features (default: false)
1156
+ persistence?: SimplePersistence<T>; // Optional persistence adapter instance (from @asaidimu/utils-persistence)
1157
+ debounceTime?: number; // Time in milliseconds to debounce actions (default: 0ms)
1158
+ // Other ObserverOptions for logging, performanceThresholds, maxEvents, maxStateHistory are inherited
933
1159
  }
934
1160
 
935
- const useStore = createStore(definition, options);
1161
+ const useStoreHook = createStore(definition, options);
936
1162
  ```
937
1163
 
938
- **Returns**: A `useStore` hook which, when called in a component, returns an object with:
939
- * `store`: Direct access to the `ReactiveDataStore` instance.
940
- * `observer`: The `StoreObservability` instance (available if `enableMetrics` is `true`). Provides debug and monitoring utilities.
941
- * `select`: A memoized selector function to extract specific state slices. Re-renders components only when selected data changes.
942
- * `actions`: An object containing your defined actions. These actions are debounced and tracked.
943
- * `actionTracker`: An instance of `ActionTracker` for monitoring the execution history of your actions.
944
- * `state`: A hook `() => T` that returns the entire current state object. Use sparingly as it will cause re-renders on *any* state change.
1164
+ **Returns**: A React hook (`useStoreHook`) which, when called in a component, returns an object with the following properties:
1165
+
1166
+ * `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.
1168
+ * `select`: A memoized selector function `(<S>(selector: (state: TState) => S) => S)`. Extracts specific state slices. Re-renders components only when selected data changes.
1169
+ * `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
+ * `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
+ * `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.
945
1172
  * `isReady`: A boolean indicating whether the store's persistence layer (if configured) has finished loading its initial state.
1173
+ * `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.
946
1175
 
947
- #### `ReactiveDataStore` (accessed via `useStore().store`)
1176
+ #### `ReactiveDataStore` (accessed via `useStoreHook().store` from `@asaidimu/utils-store`)
948
1177
 
949
- * `get(clone?: boolean): T`: Retrieves the current state. Pass `true` to get a deep clone (recommended for mutations outside of actions).
950
- * `set(update: StateUpdater<T>): Promise<void>`: Updates the state with a partial object or a function returning a partial object.
951
- * `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.
953
- * `use(middleware: Middleware<T>, name?: string): string`: Adds a transforming middleware. Returns its ID.
954
- * `useBlockingMiddleware(middleware: BlockingMiddleware<T>, name?: string): string`: Adds a blocking middleware. Returns its ID.
1178
+ * `get(clone?: boolean): TState`: Retrieves the current state. Pass `true` to get a deep clone (recommended for mutations outside of actions).
1179
+ * `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.
1181
+ * `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.
955
1184
  * `removeMiddleware(id: string): boolean`: Removes a middleware by its ID.
956
1185
  * `isReady(): boolean`: Checks if the persistence layer has loaded its initial state.
957
- * `onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void`: Subscribes to internal store events (e.g., `'update:complete'`, `'middleware:error'`).
1186
+ * `onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void`: Subscribes to internal store events (e.g., `'update:complete'`, `'middleware:error'`, `'transaction:start'`).
1187
+
1188
+ #### `StoreObservability` (accessed via `useStoreHook().observer` from `@asaidimu/utils-store`)
958
1189
 
959
- #### `StoreObservability` (accessed via `useStore().observer`)
1190
+ Available only if `enableMetrics` is `true` in `createStore` options.
960
1191
 
961
1192
  * `getEventHistory(): DebugEvent[]`: Retrieves a history of all captured store events.
962
- * `getStateHistory(): T[]`: Returns a history of state snapshots, enabling time-travel.
963
- * `getRecentChanges(limit?: number): Array<{ timestamp: number; changedPaths: string[]; from: Partial<T>; to: Partial<T>; }>`: Provides a simplified view of recent state changes.
1193
+ * `getStateHistory(): TState[]`: Returns a history of state snapshots, enabling time-travel debugging (if `maxStateHistory` > 0).
1194
+ * `getRecentChanges(limit?: number): Array<{ timestamp: number; changedPaths: string[]; from: DeepPartial<TState>; to: DeepPartial<TState>; }>`: Provides a simplified view of recent state changes.
964
1195
  * `getPerformanceMetrics(): StoreMetrics`: Returns an object containing performance statistics (e.g., `updateCount`, `averageUpdateTime`).
965
1196
  * `createTimeTravel(): { canUndo: () => boolean; canRedo: () => boolean; undo: () => Promise<void>; redo: () => Promise<void>; getHistoryLength: () => number; clear: () => void; }`: Returns controls for time-travel debugging.
966
- * `createLoggingMiddleware(options?: object): Middleware<T>`: A factory for a simple logging middleware.
967
- * `createValidationMiddleware(validator: (state: T, update: DeepPartial<T>) => boolean | { valid: boolean; reason?: string }): BlockingMiddleware<T>`: A factory for a schema validation middleware.
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.
968
1199
  * `clearHistory(): void`: Clears the event and state history.
969
1200
  * `disconnect(): void`: Cleans up all listeners and resources.
970
1201
 
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.
1202
+ #### Persistence Adapters (from `@asaidimu/utils-persistence`)
984
1203
 
985
- #### Persistence Adapters
986
-
987
- All adapters implement `DataStorePersistence<T>`:
1204
+ All adapters implement `SimplePersistence<T>`:
988
1205
 
989
1206
  * `set(id:string, state: T): boolean | Promise<boolean>`: Persists data.
990
- * `get(): T | null | Promise<T | null>`: Retrieves data.
991
- * `subscribe(id:string, callback: (state:T) => void): () => void`: Subscribes to external changes.
992
- * `clear(): boolean | Promise<boolean>`: Clears persisted data.
1207
+ * `get(id:string): T | null | Promise<T | null>`: Retrieves data.
1208
+ * `subscribe(id:string, callback: (state:T) => void): () => void`: Subscribes to external changes (e.g., from other tabs).
1209
+ * `clear(id:string): boolean | Promise<boolean>`: Clears persisted data.
993
1210
 
994
1211
  ##### `IndexedDBPersistence(storeId: string)`
995
1212
 
@@ -1000,13 +1217,9 @@ All adapters implement `DataStorePersistence<T>`:
1000
1217
  * **`storageKey`**: The key under which data is stored (e.g., `'app-config'`).
1001
1218
  * **`session`**: Optional. If `true`, uses `sessionStorage`; otherwise, uses `localStorage` (default: `false`).
1002
1219
 
1003
- ##### `LocalStoragePersistence(storageKey: string)` (Deprecated)
1004
-
1005
- * This is an alias for `WebStoragePersistence`. Use `WebStoragePersistence` instead.
1006
-
1007
1220
  ### Comparison with Other State Management Solutions
1008
1221
 
1009
- `@asaidimu/react-store` aims to provide a comprehensive, all-in-one solution for React state management. Here's a comparison to popular alternatives:
1222
+ `@asaidimu/react-store` aims to be a comprehensive, all-in-one solution for React state management, integrating features that often require multiple libraries in other ecosystems. Here's a comparison to popular alternatives:
1010
1223
 
1011
1224
  | **Feature** | **@asaidimu/react-store** | **Redux** | **Zustand** | **MobX** | **Recoil** |
1012
1225
  | :--------------------- | :------------------------ | :----------------- | :----------------- | :----------------- | :----------------- |
@@ -1015,20 +1228,59 @@ All adapters implement `DataStorePersistence<T>`:
1015
1228
  | **API Complexity** | Medium (rich feature set balanced with simplicity). | High (many concepts: actions, reducers, etc.). | Low (straightforward). | Medium (proxies, decorators). | Medium (atom/selectors). |
1016
1229
  | **Scalability** | High (transactions, persistence, remote metrics). | High (structured but verbose). | High (small but flexible). | High (reactive scaling). | High (granular atoms). |
1017
1230
  | **Extensibility** | Excellent (middleware, custom persistence, observability). | Good (middleware, enhancers). | Good (middleware-like). | Moderate (custom reactions). | Moderate (custom selectors). |
1018
- | **Performance** | Optimized (selectors, reactive updates). | Good (predictable but manual optimization). | Excellent (minimal overhead). | Good (reactive overhead). | Good (granular updates). |
1019
- | **Bundle Size** | Moderate (includes observability, persistence, remote observability). | Large (core + toolkit). | Tiny (~1KB). | Moderate (~20KB). | Moderate (~10KB). |
1231
+ | **Performance** | Optimized (selectors, reactive updates via `useSyncExternalStore`). | Good (predictable but manual optimization). | Excellent (minimal overhead). | Good (reactive overhead). | Good (granular updates). |
1232
+ | **Bundle Size** | Moderate (includes observability, persistence, remote observability framework). | Large (core + toolkit). | Tiny (~1KB). | Moderate (~20KB). | Moderate (~10KB). |
1020
1233
  | **Persistence** | Built-in (IndexedDB, WebStorage, cross-tab). | Manual (via middleware). | Manual (via middleware). | Manual (custom). | Manual (custom). |
1021
- | **Observability** | Excellent (metrics, time-travel, remote). | Good (dev tools). | Basic (via plugins). | Good (reactive logs). | Basic (via plugins). |
1022
- | **React Integration** | Native (hooks, `useSyncExternalStore`) | Manual (React-Redux). | Native (hooks). | Native (observers). | Native (atoms). |
1234
+ | **Observability** | Excellent (metrics, time-travel, event logging, remote). | Good (dev tools). | Basic (via plugins). | Good (reactive logs). | Basic (via plugins). |
1235
+ | **React Integration** | Native (hooks, `useSyncExternalStore`). | Manual (React-Redux). | Native (hooks). | Native (observers). | Native (atoms). |
1023
1236
 
1024
1237
  #### Where `@asaidimu/react-store` Shines
1025
- * **All-in-One**: It aims to be a single solution for state management, persistence, and observability, reducing the need for multiple external dependencies.
1026
- * **Flexibility**: The robust middleware system and transaction support make it highly adaptable to complex business logic and data flows.
1027
- * **Modern React**: It leverages `useSyncExternalStore` for direct integration with React's concurrency model, ensuring efficient and up-to-date component renders.
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.
1239
+ * **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
+ * **Modern React**: It leverages `useSyncExternalStore` for direct integration with React's concurrency model, ensuring efficient and up-to-date component renders with minimal overhead.
1028
1241
 
1029
1242
  #### Trade-Offs
1030
- * **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.
1031
- * **Learning Curve**: The rich feature set might present a slightly steeper learning curve for developers new to advanced state management concepts, though the API strives for simplicity.
1243
+ * **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.
1245
+
1246
+ ### Troubleshooting
1247
+
1248
+ * **Components not re-rendering:**
1249
+ * Ensure you are using `select` with a specific path (e.g., `select(s => s.user.name)`) instead of the entire state object.
1250
+ * Verify that the data at the selected path is actually changing (reference equality matters for objects/arrays).
1251
+ * **Persistence not loading/saving:**
1252
+ * Check if `isReady` is `true` before interacting with state dependent on persistence.
1253
+ * Ensure your `persistence` instance is correctly passed to `createStore`.
1254
+ * Check browser developer tools for `localStorage`, `sessionStorage`, or `IndexedDB` to see if data is being stored/retrieved.
1255
+ * Look for console errors related to persistence.
1256
+ * **Actions not executing or seem delayed:**
1257
+ * Check the `debounceTime` option in your `createStore` configuration. If set, actions will be delayed.
1258
+ * If actions are `async`, ensure you `await` them where necessary in your components.
1259
+ * 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`.
1262
+ * Check console logs (if `enableConsoleLogging` is `true`) for `middleware:start`, `middleware:complete`, or `middleware:error` events.
1263
+ * **TypeScript errors:**
1264
+ * Verify your state interfaces match the `initialState` structure.
1265
+ * Ensure action return types are `DeepPartial<TState>` as expected.
1266
+ * Update `@asaidimu/react-store` and `@types/react` to their latest compatible versions.
1267
+
1268
+ ### FAQ
1269
+
1270
+ **Q: Does it support React Server Components (RSC)?**
1271
+ 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
+
1273
+ **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.
1275
+
1276
+ **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.
1278
+
1279
+ **Q: What about immutability?**
1280
+ 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
+
1282
+ **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.
1032
1284
 
1033
1285
  ### Changelog
1034
1286
 
@@ -1041,3 +1293,4 @@ This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.m
1041
1293
  ### Acknowledgments
1042
1294
 
1043
1295
  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.