@asaidimu/utils-store 2.3.3 → 5.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/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { EventBus } from '@asaidimu/events';
2
+
1
3
  interface SimplePersistence<T> {
2
4
  /**
3
5
  * Persists data to storage.
@@ -53,6 +55,26 @@ interface SimplePersistence<T> {
53
55
  type DeepPartial<T> = T extends object ? T extends readonly (infer U)[] ? readonly (DeepPartial<U> | undefined)[] | undefined | T : T extends (infer U)[] ? (DeepPartial<U> | undefined)[] | undefined | T : {
54
56
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
55
57
  } | undefined | T : T | undefined;
58
+ /**
59
+ * Interface for performance metrics of the state.
60
+ */
61
+ interface StoreMetrics {
62
+ updateCount: number;
63
+ listenerExecutions: number;
64
+ averageUpdateTime: number;
65
+ largestUpdateSize: number;
66
+ mostActiveListenerPaths: string[];
67
+ totalUpdates: number;
68
+ blockedUpdates: number;
69
+ averageUpdateDuration: number;
70
+ middlewareExecutions: number;
71
+ transactionCount: number;
72
+ totalEventsFired: number;
73
+ totalActionsDispatched: number;
74
+ totalActionsSucceeded: number;
75
+ totalActionsFailed: number;
76
+ averageActionDuration: number;
77
+ }
56
78
  /**
57
79
  * Extended store state for monitoring execution status
58
80
  */
@@ -71,7 +93,56 @@ interface StoreExecutionState<T> {
71
93
  /**
72
94
  * Event types emitted by the state for observability
73
95
  */
74
- type StoreEvent = "update:start" | "update:complete" | "middleware:start" | "middleware:complete" | "middleware:error" | "middleware:blocked" | "middleware:executed" | "transaction:start" | "transaction:complete" | "transaction:error" | "persistence:ready" | "persistence:queued" | "persistence:success" | "persistence:retry" | "persistence:failed" | "persistence:queue_cleared" | "persistence:init_error";
96
+ type StoreEvent = "update:start" | "update:complete" | "middleware:start" | "middleware:complete" | "middleware:error" | "middleware:blocked" | "middleware:executed" | "transaction:start" | "transaction:complete" | "transaction:error" | "persistence:ready" | "persistence:queued" | "persistence:success" | "persistence:retry" | "persistence:failed" | "persistence:queue_cleared" | "persistence:init_error" | "action:start" | "action:complete" | "action:error" | "selector:accessed" | "selector:changed";
97
+ interface SelectorChangedPayload<S> {
98
+ selectorId: string;
99
+ newResult: S;
100
+ timestamp: number;
101
+ }
102
+ type StoreEvents = {
103
+ [K in StoreEvent]: K extends "update:complete" ? {
104
+ deltas: StateDelta[];
105
+ duration: number;
106
+ timestamp: number;
107
+ actionId?: string;
108
+ newState: any;
109
+ blocked?: boolean;
110
+ error?: any;
111
+ } : K extends "selector:accessed" ? SelectorAccessedPayload : K extends "selector:changed" ? SelectorChangedPayload<any> : K extends "action:start" ? ActionStartPayload : K extends "action:complete" ? ActionCompletePayload : K extends "action:error" ? ActionErrorPayload : K extends "middleware:start" | "middleware:complete" | "middleware:error" | "middleware:blocked" | "middleware:executed" ? MiddlewareExecution : K extends "transaction:start" | "transaction:complete" | "transaction:error" ? {
112
+ transactionId: string;
113
+ timestamp: number;
114
+ } : K extends "persistence:queued" ? PersistenceQueuedPayload : K extends "persistence:success" ? PersistenceSuccessPayload : K extends "persistence:retry" ? PersistenceRetryPayload : K extends "persistence:failed" ? PersistenceFailedPayload : K extends "persistence:queue_cleared" ? PersistenceQueueClearedPayload : K extends "persistence:init_error" ? PersistenceInitErrorPayload : any;
115
+ };
116
+ interface SelectorAccessedPayload {
117
+ selectorId: string;
118
+ accessedPaths: string[];
119
+ duration: number;
120
+ timestamp: number;
121
+ }
122
+ interface ActionStartPayload {
123
+ actionId: string;
124
+ name: string;
125
+ params: any[];
126
+ timestamp: number;
127
+ }
128
+ interface ActionCompletePayload {
129
+ actionId: string;
130
+ name: string;
131
+ params: any[];
132
+ startTime: number;
133
+ endTime: number;
134
+ duration: number;
135
+ result: any;
136
+ }
137
+ interface ActionErrorPayload {
138
+ actionId: string;
139
+ name: string;
140
+ params: any[];
141
+ startTime: number;
142
+ endTime: number;
143
+ duration: number;
144
+ error: any;
145
+ }
75
146
  /**
76
147
  * Type for middleware functions. Return a partial state to transform the update.
77
148
  */
@@ -87,7 +158,12 @@ interface MiddlewareExecution {
87
158
  duration: number;
88
159
  blocked: boolean;
89
160
  error?: Error;
90
- changedPaths: string[];
161
+ deltas: StateDelta[];
162
+ }
163
+ interface StateDelta {
164
+ path: string;
165
+ oldValue: any;
166
+ newValue: any;
91
167
  }
92
168
  /**
93
169
  * Represents a state update, which can be either a partial state object or a function.
@@ -116,44 +192,42 @@ interface MiddlewareConfig<T> {
116
192
  name?: string;
117
193
  block?: boolean;
118
194
  }
119
- /**
120
- * Interface for performance metrics of the state.
121
- */
122
- interface StoreMetrics {
123
- updateCount: number;
124
- listenerExecutions: number;
125
- averageUpdateTime: number;
126
- largestUpdateSize: number;
127
- mostActiveListenerPaths: string[];
128
- }
129
- interface StoreMetrics {
130
- totalUpdates: number;
131
- blockedUpdates: number;
132
- listenerExecutions: number;
133
- averageUpdateDuration: number;
134
- middlewareExecutions: number;
135
- transactionCount: number;
136
- totalEventsFired: number;
137
- }
138
- interface DataStore<T extends object> {
139
- get(clone?: boolean): T;
140
- set(update: StateUpdater<T>): Promise<void>;
141
- subscribe(path: string, listener: (state: T) => void): () => void;
142
- transaction<R>(operation: () => R | Promise<R>): Promise<R>;
143
- metrics(): StoreMetrics;
144
- onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void;
195
+ interface ReactiveSelector<S> {
196
+ id: string;
197
+ get: () => S;
198
+ subscribe: (callback: (state: S) => void) => () => void;
145
199
  }
146
200
  /**
147
201
  * Interface defining the contract for the data state.
148
202
  */
149
203
  interface DataStore<T extends object> {
150
204
  get(clone?: boolean): T;
151
- set(update: StateUpdater<T>): Promise<void>;
205
+ register<R extends any[]>(action: {
206
+ name: string;
207
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
208
+ debounce?: {
209
+ delay: number;
210
+ condition?: (previous: R, current: R) => boolean;
211
+ };
212
+ }): () => void;
213
+ dispatch<R extends any[]>(name: string, ...args: R): Promise<T>;
214
+ set(update: StateUpdater<T>, options?: {
215
+ force?: boolean;
216
+ actionId?: string;
217
+ }): Promise<any>;
218
+ select<S>(selector: (state: T) => S): ReactiveSelector<S>;
219
+ /** @deprecated
220
+ * Use watch instead will be removed in next major version
221
+ * **/
152
222
  subscribe(path: string | Array<string>, callback: (state: T) => void): () => void;
223
+ watch(path: string | Array<string>, callback: (state: T) => void): () => void;
153
224
  transaction<R>(operation: () => R | Promise<R>): Promise<R>;
154
- use(props: MiddlewareConfig<T>): string;
155
- unuse(id: string): boolean;
225
+ use(props: MiddlewareConfig<T>): () => boolean;
226
+ /** @deprecated
227
+ * Use on instead will be removed in next majow version
228
+ * **/
156
229
  onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void;
230
+ on(event: StoreEvent, listener: (data: any) => void): () => void;
157
231
  id(): string;
158
232
  isReady(): boolean;
159
233
  state(): Readonly<StoreExecutionState<T>>;
@@ -193,18 +267,34 @@ interface PersistenceInitErrorPayload {
193
267
  error: any;
194
268
  timestamp: number;
195
269
  }
196
- declare const author = "https://github.com/asaidimu";
270
+ type StoreAction<T, R extends any[] = any[]> = {
271
+ id: string;
272
+ name: string;
273
+ action: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
274
+ debounce?: {
275
+ /** Active timer reference, if debouncing */
276
+ timer?: ReturnType<typeof setTimeout>;
277
+ /** Debounce delay in milliseconds */
278
+ delay: number;
279
+ /** Optional condition to decide whether to debounce based on previous vs current args */
280
+ condition?: (previous: R | undefined, current: R) => boolean;
281
+ /** Last call’s arguments, used for condition checks */
282
+ args?: R;
283
+ /** Internal promise resolvers to prevent memory leaks */
284
+ resolve?: (value: any) => void;
285
+ reject?: (reason?: any) => void;
286
+ };
287
+ };
197
288
 
198
289
  /**
199
- * Reactive Data Store Implementation
200
- * A type-safe reactive data state for managing complex application state.
201
- * Arrays are treated as primitive values (stored and updated as whole units).
290
+ * Reactive Data Store Implementation - Updated for Concurrency and Performance
291
+ * The public API is preserved for test compatibility.
202
292
  */
203
293
 
204
294
  /**
205
295
  * Main ReactiveDataStore - a robust, type-safe state management solution.
206
- * It features optimistic updates for a responsive user experience and
207
- * handles data persistence in the background.
296
+ * It features optimistic updates, a promise-based update queue for serial execution,
297
+ * and decoupled persistence.
208
298
  *
209
299
  * @template T The type of the data object managed by the store.
210
300
  */
@@ -219,278 +309,458 @@ declare class ReactiveDataStore<T extends object> implements DataStore<T> {
219
309
  private transactionManager;
220
310
  /** Collects and provides performance metrics for the store. */
221
311
  private metricsCollector;
222
- /** Queue for pending state updates when the store is busy. */
223
- private pendingUpdates;
224
- /** Flag to prevent concurrent updates. */
225
- private isUpdating;
226
- /** Event bus for notifying subscribers of state updates. */
312
+ private selectorManager;
313
+ private actionManager;
314
+ /**
315
+ * Promise chain to enforce serial, non-recursive execution
316
+ * of all state updates.
317
+ */
318
+ private updateQueue;
227
319
  private updateBus;
228
- /** General event bus for broadcasting internal store events. */
229
320
  private eventBus;
230
- /** Represents the current execution state of the store. */
231
321
  private executionState;
232
- /** A unique identifier for this store instance. */
233
322
  private instanceID;
234
- /** Function to deeply merge partial state updates. */
235
323
  private merge;
236
- /** Function to calculate the difference between two state objects. */
237
324
  private diff;
238
325
  /**
239
326
  * Creates a new ReactiveDataStore instance.
240
- *
241
- * @param initialData The initial state of the data store.
242
- * @param persistence An optional persistence handler for saving state.
243
- * @param deleteMarker A symbol used to mark properties for deletion.
244
- * @param options Configuration options for the store.
245
327
  */
246
328
  constructor(initialData: T, persistence?: SimplePersistence<T>, deleteMarker?: symbol, options?: {
247
329
  persistenceMaxRetries?: number;
248
330
  persistenceRetryDelay?: number;
249
331
  });
250
- /**
251
- * Checks if the persistence layer is ready to save data.
252
- *
253
- * @returns `true` if ready, otherwise `false`.
254
- */
255
332
  isReady(): boolean;
256
- /**
257
- * Returns the current read-only execution state of the store.
258
- */
259
333
  state(): Readonly<StoreExecutionState<T>>;
260
334
  /**
261
- * Gets the current state of the data store.
262
- *
263
- * @param clone If `true`, returns a deep clone of the state to prevent direct modification.
335
+ * Gets the current state. Optimized default to return reference (false) for performance.
336
+ * @param clone If `true`, returns a deep clone (use sparingly).
264
337
  * @returns The current state object.
265
338
  */
266
339
  get(clone?: boolean): T;
340
+ select<S>(selector: (state: T) => S): ReactiveSelector<S>;
341
+ register<R extends any[]>(action: {
342
+ name: string;
343
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
344
+ debounce?: {
345
+ delay: number;
346
+ condition?: (previous: R | undefined, current: R) => boolean;
347
+ };
348
+ }): () => void;
349
+ dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
350
+ /**
351
+ * Optimized method to update the state.
352
+ * Uses the Promise Queue to guarantee sequential execution.
353
+ * @returns A Promise that resolves with the new state T.
354
+ */
355
+ set(update: StateUpdater<T>, options?: {
356
+ force?: boolean;
357
+ actionId?: string;
358
+ }): Promise<any>;
359
+ /**
360
+ * Internal logic for performing a single, sequential state update.
361
+ */
362
+ private _performUpdate;
363
+ private setupPersistenceListener;
364
+ watch(path: string | Array<string>, callback: (state: T) => void): () => void;
365
+ /** @deprecated **/
366
+ subscribe(path: string | Array<string>, callback: (state: T) => void): () => void;
367
+ id(): string;
368
+ transaction<R>(operation: () => R | Promise<R>): Promise<R>;
369
+ use(props: MiddlewareConfig<T>): () => boolean;
370
+ metrics(): StoreMetrics;
371
+ on(event: StoreEvent, listener: (data: any) => void): () => void;
372
+ /** @deprecated */
373
+ onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void;
374
+ getPersistenceStatus(): {
375
+ queueSize: number;
376
+ isProcessing: boolean;
377
+ oldestTask?: number;
378
+ };
379
+ flushPersistence(): Promise<void>;
380
+ clearPersistenceQueue(): void;
381
+ dispose(): void;
382
+ private emit;
383
+ }
384
+
385
+ /**
386
+ * Defines the lifecycle scope of an artifact.
387
+ */
388
+ declare enum ArtifactScope {
389
+ /**
390
+ * Created once and cached.
391
+ * The container tracks its dependencies and rebuilds it if they change.
392
+ */
393
+ Singleton = "singleton",
267
394
  /**
268
- * Optimized method to update the state. It handles optimistic updates by
269
- * applying changes immediately and persisting them in the background.
270
- * Middleware is executed before and after the update.
395
+ * Created every time it is resolved.
396
+ * Dependencies are NOT tracked, and it is never cached.
397
+ */
398
+ Transient = "transient"
399
+ }
400
+ /**
401
+ * Dependency resolution context provided to the `use()` callback.
402
+ * Used to declare dependencies on other artifacts or state slices.
403
+ */
404
+ interface UseDependencyContext<TState extends object> {
405
+ /**
406
+ * Resolve another artifact.
407
+ * This records a dependency: if the target artifact is invalidated, the caller will be too.
271
408
  *
272
- * If another update is in progress, the new update is queued.
409
+ * @param key The key of the artifact to resolve.
410
+ */
411
+ resolve<TArtifact>(key: string): Promise<ResolvedArtifact<TArtifact>>;
412
+ /**
413
+ * Select a slice of state.
414
+ * This records a dependency: if the selected state changes, the artifact will be invalidated.
273
415
  *
274
- * @param update A partial state object or a function that returns a partial state object.
416
+ * @param selector A function that selects a part of the global state.
417
+ */
418
+ select<S>(selector: (state: TState) => S): S;
419
+ }
420
+ /**
421
+ * The context object provided to an artifact's factory function.
422
+ * Provides tools for state access, dependency injection, and lifecycle management.
423
+ */
424
+ interface ArtifactFactoryContext<TState extends object> {
425
+ /**
426
+ * Get the current state snapshot immediately.
427
+ * **Note:** Calling this does NOT create a subscription. Use `ctx.use(c => c.select(...))` for reactive behavior.
428
+ */
429
+ state(): TState;
430
+ /**
431
+ * The existing instance if the artifact is being re-evaluated/rebuilt.
432
+ * Useful for preserving internal state (like active connections) during hot-swaps.
275
433
  */
276
- set(update: StateUpdater<T>): Promise<void>;
434
+ current?: unknown;
277
435
  /**
278
- * Subscribes a callback function to state changes at a specific path.
279
- * The callback is triggered only when the specified path changes.
436
+ * Execute a callback to capture dependencies.
437
+ * All `resolve()` and `select()` calls inside this callback are recorded
438
+ * to build the reactive dependency graph.
280
439
  *
281
- * @param path The path or array of paths to subscribe to.
282
- * @param callback The function to call when the state at the path changes.
283
- * @returns A function to unsubscribe the callback.
440
+ * @param callback The function where dependencies are declared.
284
441
  */
285
- subscribe(path: string | Array<string>, callback: (state: T) => void): () => void;
442
+ use<K>(callback: (ctx: UseDependencyContext<TState>) => K | Promise<K>): Promise<K>;
286
443
  /**
287
- * Gets the unique identifier for this store instance.
444
+ * Register a cleanup function to be called when the artifact is disposed or rebuilt.
445
+ * Multiple cleanup functions can be registered; they will be called in reverse order (LIFO).
288
446
  *
289
- * @returns The instance ID as a string.
447
+ * @param cleanup A function to execute during teardown.
290
448
  */
291
- id(): string;
449
+ onCleanup(cleanup: ArtifactCleanup): void;
292
450
  /**
293
- * Executes a series of state updates atomically within a single transaction.
451
+ * Hot-swap the artifact instance without triggering a full teardown.
452
+ *
453
+ * **Behavior:**
454
+ * 1. Updates the internal instance **synchronously** (immediate consistency).
455
+ * 2. Invalidates downstream dependents **asynchronously** (graph consistency).
456
+ * 3. Notifies listeners (UI updates) only after the graph is consistent.
294
457
  *
295
- * @param operation A function containing the state updates to be performed.
296
- * @returns The result of the operation.
458
+ * @param value The new instance value to set.
459
+ *
460
+ * @example
461
+ * // Updating a WebSocket connection without losing the wrapping artifact
462
+ * factory: async (ctx) => {
463
+ * const ws = new WebSocket(url);
464
+ * ws.onmessage = (msg) => ctx.yield(JSON.parse(msg.data));
465
+ * return ws; // Initial value
466
+ * }
467
+ */
468
+ yield(value: unknown): void;
469
+ }
470
+ /**
471
+ * A function to clean up resources (close sockets, remove listeners, etc.).
472
+ */
473
+ type ArtifactCleanup = () => void | Promise<void>;
474
+ /**
475
+ * The result of resolving an artifact.
476
+ * Wraps the instance with metadata, error state, and control methods.
477
+ */
478
+ interface ResolvedArtifact<TArtifact> {
479
+ /** The resolved artifact instance. */
480
+ instance: TArtifact;
481
+ /** A function that runs all registered cleanups for this artifact. */
482
+ cleanup?: ArtifactCleanup;
483
+ /** Any error that occurred during creation. */
484
+ error?: any;
485
+ /**
486
+ * Manually invalidate this artifact.
487
+ * @param replace If `true`, forces an immediate rebuild (Eager). If `false`, marks as stale (Lazy).
488
+ */
489
+ invalidate(replace?: boolean): Promise<void>;
490
+ }
491
+ /**
492
+ * A factory function that creates an instance of an artifact.
493
+ */
494
+ type ArtifactFactory<TState extends object, TArtifact> = (context: ArtifactFactoryContext<TState>) => TArtifact | Promise<TArtifact>;
495
+ /**
496
+ * A reactive dependency injection container.
497
+ * Manages the lifecycle, caching, and dependency graph of application artifacts.
498
+ */
499
+ declare class ArtifactContainer<TState extends object> {
500
+ private readonly artifacts;
501
+ private readonly resolvingStack;
502
+ private readonly listeners;
503
+ private readonly getState;
504
+ private readonly subscribe;
505
+ /**
506
+ * @param props Interface to the external state store (e.g., Zustand, Redux).
297
507
  */
298
- transaction<R>(operation: () => R | Promise<R>): Promise<R>;
508
+ constructor(props: Pick<DataStore<TState>, "watch" | "get">);
299
509
  /**
300
- * Adds a middleware function to the store.
510
+ * Watch an artifact for changes and retrieve its current state.
301
511
  *
302
- * @param props The middleware configuration.
303
- * @returns A unique ID for the added middleware.
512
+ * @param id The artifact key to watch.
513
+ * @returns An object containing the ID, a getter, and a subscribe method.
514
+ *
515
+ * @example
516
+ * const watcher = container.watch("current-user");
517
+ * const unsub = watcher.subscribe(() => {
518
+ * const user = watcher.get()?.instance;
519
+ * console.log("User updated:", user);
520
+ * });
521
+ */
522
+ watch<TArtifact>(id: string): {
523
+ id: string;
524
+ get(): ResolvedArtifact<TArtifact> | null;
525
+ subscribe(callback: () => void): () => void;
526
+ };
527
+ /**
528
+ * Direct sync access to an artifact instance.
529
+ * Use this sparingly; prefer `resolve()` or `watch()`.
304
530
  */
305
- use(props: MiddlewareConfig<T>): string;
531
+ get(id: string): any | undefined;
306
532
  /**
307
- * Removes a middleware function by its unique ID.
533
+ * Registers a new artifact factory.
308
534
  *
309
- * @param id The ID of the middleware to remove.
310
- * @returns `true` if the middleware was successfully removed, `false` otherwise.
535
+ * @param options Configuration for the artifact.
536
+ * @returns A function to unregister the artifact.
311
537
  */
312
- unuse(id: string): boolean;
538
+ register<TArtifact>(options: {
539
+ key: string;
540
+ factory: ArtifactFactory<TState, TArtifact>;
541
+ scope?: ArtifactScope;
542
+ lazy?: boolean;
543
+ }): () => void;
313
544
  /**
314
- * Get the performance metrics for the store.
315
- * @deprecated WILL BE REMOVED in a future version.
545
+ * Unregisters an artifact and cleans up its resources.
316
546
  */
317
- metrics(): StoreMetrics;
547
+ unregister(key: string): Promise<void>;
318
548
  /**
319
- * Subscribes a listener to a specific store event.
549
+ * Resolves an artifact, creating it if necessary.
550
+ * Handles dependency tracking, caching, and error states.
320
551
  *
321
- * @param event The name of the event to listen for.
322
- * @param listener The callback function to execute when the event is emitted.
323
- * @returns A function to unsubscribe the listener.
552
+ * @param key The artifact identifier.
324
553
  */
325
- onStoreEvent(event: StoreEvent, listener: (data: any) => void): () => void;
554
+ resolve<TArtifact>(key: string): Promise<ResolvedArtifact<TArtifact>>;
326
555
  /**
327
- * Get the current status of the persistence queue.
328
- *
329
- * @returns An object containing the queue size, processing status, and the age of the oldest task.
556
+ * Helper to wrap a definition into the standard public return type.
330
557
  */
331
- getPersistenceStatus(): {
332
- queueSize: number;
333
- isProcessing: boolean;
334
- oldestTask?: number;
335
- };
558
+ private packageArtifact;
336
559
  /**
337
- * Forces immediate processing of any pending persistence operations.
560
+ * Executes the factory and captures dependencies.
561
+ * Contains the "Yield" implementation.
338
562
  */
339
- flushPersistence(): Promise<void>;
563
+ private createArtifactInstance;
340
564
  /**
341
- * Clears all pending persistence operations from the queue.
565
+ * Orchestrates the invalidation and notification sequence for a yield event.
566
+ * Ensures downstream dependents are invalidated BEFORE listeners are notified.
342
567
  */
343
- clearPersistenceQueue(): void;
568
+ private processYieldPropagation;
344
569
  /**
345
- * Cleans up resources, such as event listeners, to prevent memory leaks.
570
+ * Updates the dependency graph structure after a successful build.
346
571
  */
347
- dispose(): void;
572
+ private updateGraph;
348
573
  /**
349
- * A private utility method to emit an event on a given event bus.
350
- * Uses `queueMicrotask` to ensure events are emitted asynchronously after the current call stack clears.
574
+ * Cascading invalidation logic.
575
+ * Destroys the artifact, destroys dependents, then conditionally rebuilds.
351
576
  *
352
- * @param bus The event bus to emit the event on.
353
- * @param event The event object to emit.
577
+ * @param key The artifact key to invalidate
578
+ * @param replace If true, eagerly rebuild after invalidation. If false, respect lazy flag.
354
579
  */
355
- private emit;
580
+ private invalidate;
581
+ /**
582
+ * Cleans up a specific artifact definition's instance and subscriptions.
583
+ * Keeps the definition registered but clears the instance.
584
+ */
585
+ private disposeInstance;
586
+ /**
587
+ * Fully removes an artifact from the system.
588
+ */
589
+ private disposeArtifact;
590
+ private createCompositeCleanup;
591
+ private notifyListeners;
592
+ private detectCycles;
593
+ dispose(): void;
594
+ isLoading(key: string): boolean;
356
595
  }
357
596
 
358
597
  /**
359
- * Store Observability Module
360
- * A separate module to add debugging and observability capabilities to the ReactiveDataStore.
598
+ * @fileoverview Store Observer Module
599
+ * @description A comprehensive module to add advanced debugging, observability, and time-travel
600
+ * capabilities to a ReactiveDataStore. All console logging is centralized to respect a 'silent' flag,
601
+ * preventing test runner output pollution.
361
602
  */
362
603
 
363
604
  /**
364
- * Interface for debug event structure
605
+ * @interface DebugEvent
606
+ * @description Interface for the structure of a recorded debug event.
365
607
  */
366
608
  interface DebugEvent {
609
+ /** The type of store event (e.g., 'update:start', 'action:complete'). */
367
610
  type: string;
611
+ /** The timestamp when the event occurred. */
368
612
  timestamp: number;
613
+ /** The raw data payload associated with the event, including actionId where applicable. */
369
614
  data: any;
370
615
  }
371
616
  /**
372
- * Configuration options for the observability module
617
+ * @interface Snapshot
618
+ * @description Represents a rich snapshot of the state at a point in time for history tracking.
619
+ */
620
+ interface Snapshot<T> {
621
+ /** The complete state object at the time of the snapshot. */
622
+ state: T;
623
+ /** The timestamp of the state change. */
624
+ timestamp: number;
625
+ /** The list of changes (deltas) that resulted in this state. */
626
+ deltas: StateDelta[];
627
+ }
628
+ /**
629
+ * @interface ObserverSessionData
630
+ * @description Defines the data structure for a saved observer session.
631
+ */
632
+ interface ObserverSessionData<T extends object> {
633
+ /** The chronological history of debug events. */
634
+ eventHistory: DebugEvent[];
635
+ /** The chronological history of state snapshots. */
636
+ stateHistory: Snapshot<T>[];
637
+ }
638
+ /**
639
+ * @interface ObserverOptions
640
+ * @description Configuration options for the observer module.
373
641
  */
374
- interface ObservabilityOptions {
375
- /** Maximum number of events to keep in history */
642
+ interface ObserverOptions {
643
+ /** Maximum number of events to retain in memory. Defaults to 500. */
376
644
  maxEvents?: number;
377
- /** Whether to enable console logging */
645
+ /** Enables or disables console logging for all events (overridden by 'silent'). Defaults to false. */
378
646
  enableConsoleLogging?: boolean;
647
+ /** Maximum number of state snapshots to retain for time-travel. Defaults to 20. */
379
648
  maxStateHistory?: number;
380
- /** Options for specific event types to log */
649
+ /** Fine-grained control over which event types are logged to the console. */
381
650
  logEvents?: {
382
651
  updates?: boolean;
383
652
  middleware?: boolean;
384
653
  transactions?: boolean;
654
+ actions?: boolean;
655
+ selectors?: boolean;
385
656
  };
386
- /** Time threshold in ms to highlight slow operations */
657
+ /** Performance thresholds for triggering console warnings. Values are in milliseconds (ms). */
387
658
  performanceThresholds?: {
388
659
  updateTime?: number;
389
660
  middlewareTime?: number;
390
661
  };
662
+ /** If true, suppresses all console output and logging regardless of other options. Defaults to false. */
663
+ silent?: boolean;
391
664
  }
392
665
  /**
393
- * Class for observing and debugging a ReactiveDataStore instance
666
+ * @class StoreObserver
667
+ * @description Connects to a DataStore to capture state changes, events, and performance data.
668
+ * @template T The type of the store's state object.
394
669
  */
395
670
  declare class StoreObserver<T extends object> {
396
671
  protected store: DataStore<T>;
397
672
  private eventHistory;
673
+ private stateHistory;
674
+ private unsubscribers;
675
+ private isTimeTraveling;
676
+ private devTools;
677
+ private middlewareExecutions;
678
+ private activeTransactionCount;
679
+ private activeBatches;
398
680
  private maxEvents;
681
+ private maxStateHistory;
399
682
  private enableConsoleLogging;
683
+ private isSilent;
400
684
  private logEvents;
401
685
  private performanceThresholds;
402
- private unsubscribers;
403
- private stateHistory;
404
- private maxStateHistory;
405
- private activeTransactionCount;
406
- private activeBatches;
407
- private middlewareExecutions;
408
686
  /**
409
- * Creates a new StoreObservability instance
410
- * @param store The ReactiveDataStore to observe
411
- * @param options Configuration options
687
+ * @param store The DataStore instance to observe.
688
+ * @param options Configuration options for the observer.
412
689
  */
413
- constructor(store: DataStore<T>, options?: ObservabilityOptions);
690
+ constructor(store: DataStore<T>, options?: ObserverOptions);
414
691
  /**
415
- * Sets up all event listeners
692
+ * @private
693
+ * Centralized logging method. All console output must go through here to respect the `isSilent` flag.
694
+ * @param method The console method to call ('log', 'warn', 'error', 'group', 'groupEnd', 'table', 'debug').
695
+ * @param args Arguments to pass to the console method.
696
+ */
697
+ private _consoleLog;
698
+ /**
699
+ * @private
700
+ * Sets up listeners for all relevant store events.
416
701
  */
417
702
  private setupEventListeners;
418
703
  /**
419
- * Records a state snapshot
704
+ * @private
705
+ * Records a new state snapshot and manages the state history limit.
706
+ * @param deltas The state changes that led to this snapshot.
420
707
  */
421
708
  private recordStateSnapshot;
422
709
  /**
423
- * Records an event to the history
424
- * @param type Event type
425
- * @param data Event data
710
+ * @private
711
+ * Records a debug event and manages the event history limit.
712
+ * @param type The type of event.
713
+ * @param data The data payload of the event.
426
714
  */
427
715
  private recordEvent;
428
716
  /**
429
- * Logs an event to the console with appropriate formatting
430
- * @param type Event type
431
- * @param data Event data
432
- */
433
- private logEventToConsole;
434
- /**
435
- * Checks for performance issues in the events
436
- * @param type Event type
437
- * @param data Event data
438
- */
439
- private checkPerformance;
440
- /**
441
- * Returns the event history
442
- * @returns Array of debug events
717
+ * Returns a cloned copy of the recorded event history.
718
+ * @returns Array of debug events.
443
719
  */
444
720
  getEventHistory(): DebugEvent[];
445
721
  /**
446
- * Returns the state history
447
- * @returns Array of state snapshots
722
+ * Returns a cloned copy of the recorded state history (snapshots).
723
+ * @returns Array of state snapshots.
448
724
  */
449
- getStateHistory(): T[];
725
+ getStateHistory(): Snapshot<T>[];
450
726
  /**
451
- * Returns middleware execution history from the state
452
- * @returns Array of middleware executions
727
+ * Returns middleware execution history from the state.
728
+ * @returns Array of middleware executions.
453
729
  */
454
730
  getMiddlewareExecutions(): MiddlewareExecution[];
455
731
  /**
456
- * Returns state performance metrics
457
- * @returns Store metrics object
458
- */
459
- getPerformanceMetrics(): StoreMetrics;
460
- /**
461
- * Returns current transaction status
462
- * @returns Object with transaction status information
732
+ * Returns current transaction status.
733
+ * @returns Object with transaction status information.
463
734
  */
464
735
  getTransactionStatus(): {
465
736
  activeTransactions: number;
466
737
  activeBatches: string[];
467
738
  };
468
739
  /**
469
- * Creates a middleware that logs all updates
470
- * @param options Options for the logging middleware
471
- * @returns A middleware function
740
+ * Creates a standard middleware that logs all updates.
741
+ * NOTE: This is user-defined middleware and uses native console methods,
742
+ * so its output is independent of the observer's `silent` flag.
743
+ * @param options Options for the logging middleware.
744
+ * @returns A middleware function.
472
745
  */
473
746
  createLoggingMiddleware(options?: {
474
747
  logLevel?: "debug" | "info" | "warn";
475
748
  logUpdates?: boolean;
476
749
  }): (state: T, update: DeepPartial<T>) => DeepPartial<T>;
477
750
  /**
478
- * Creates a middleware that validates updates against a schema
479
- * @param validator Function that validates updates
480
- * @returns A blocking middleware function
751
+ * Creates a middleware that validates updates against a schema.
752
+ * Uses the internal `_consoleLog` for warnings.
753
+ * @param validator Function that validates updates.
754
+ * @returns A blocking middleware function.
481
755
  */
482
756
  createValidationMiddleware(validator: (state: T, update: DeepPartial<T>) => boolean | {
483
757
  valid: boolean;
484
758
  reason?: string;
485
759
  }): (state: T, update: DeepPartial<T>) => boolean;
486
760
  /**
487
- * Clears all event and state history
488
- */
489
- clearHistory(): void;
490
- /**
491
- * Returns a simplified view of recent state changes
492
- * @param limit Maximum number of state changes to compare
493
- * @returns Array of state difference objects
761
+ * Returns a simplified view of recent state changes.
762
+ * @param limit Maximum number of state changes to compare. Defaults to 5.
763
+ * @returns Array of state difference objects.
494
764
  */
495
765
  getRecentChanges(limit?: number): Array<{
496
766
  timestamp: number;
@@ -499,21 +769,157 @@ declare class StoreObserver<T extends object> {
499
769
  to: Partial<T>;
500
770
  }>;
501
771
  /**
502
- * Creates a time-travel debug middleware that lets you undo/redo state changes
503
- * @returns An object with undo/redo methods and state info
772
+ * Clears both the event and state history, preserving only the initial state snapshot.
773
+ */
774
+ clearHistory(): void;
775
+ /**
776
+ * Filters and returns events related to a specific action ID.
777
+ * @param actionId The ID of the action to filter by.
778
+ * @returns Array of debug events associated with the action.
779
+ */
780
+ getHistoryForAction(actionId: string): DebugEvent[];
781
+ /**
782
+ * Attempts to replay a state update from history using the recorded update payload.
783
+ * @param eventIndex The index of the replayable event (an "update:start" event) in the history array.
784
+ */
785
+ replay(eventIndex: number): Promise<void>;
786
+ /**
787
+ * Creates a time-travel utility object with undo/redo capabilities.
788
+ * @returns An object with methods for time-travel navigation.
504
789
  */
505
790
  createTimeTravel(): {
506
791
  canUndo: () => boolean;
507
792
  canRedo: () => boolean;
508
- undo: () => void;
509
- redo: () => void;
510
- getHistoryLength: () => number;
793
+ undo: () => Promise<void>;
794
+ redo: () => Promise<void>;
795
+ length: () => number;
511
796
  clear: () => void;
512
797
  };
513
798
  /**
514
- * Disconnects all event listeners and cleans up resources
799
+ * Saves the current observer session (events and state history) using a persistence mechanism.
800
+ * @param persistence An object implementing the SimplePersistence interface.
801
+ * @returns A promise that resolves to true if the session was saved successfully.
802
+ */
803
+ saveSession(persistence: SimplePersistence<ObserverSessionData<T>>): Promise<boolean>;
804
+ /**
805
+ * Loads a previously saved observer session and restores the state to the latest saved snapshot.
806
+ * @param persistence An object implementing the SimplePersistence interface.
807
+ * @returns A promise that resolves to true if a session was loaded.
808
+ */
809
+ loadSession(persistence: SimplePersistence<ObserverSessionData<T>>): Promise<boolean>;
810
+ /**
811
+ * Exports the current session data as a JSON file, initiating a browser download.
812
+ */
813
+ exportSession(): void;
814
+ /**
815
+ * Imports a session from a JSON file, restoring event history and state.
816
+ * @param file The file object (e.g., from an <input type="file"> event) to import.
817
+ * @returns A promise that resolves when the import is complete.
818
+ */
819
+ importSession(file: File): Promise<void>;
820
+ /**
821
+ * Cleans up the observer by unsubscribing all event listeners and clearing history.
515
822
  */
516
823
  disconnect(): void;
824
+ /**
825
+ * @private
826
+ * Logs an event to the console with appropriate formatting.
827
+ * Uses `this._consoleLog` for all output.
828
+ * @param type Event type.
829
+ * @param data Event data.
830
+ */
831
+ private _log;
832
+ /**
833
+ * @private
834
+ * Checks for performance issues in the events.
835
+ * Uses `this._consoleLog` for all output.
836
+ * @param type Event type.
837
+ * @param data Event data.
838
+ */
839
+ private _checkPerformance;
840
+ }
841
+
842
+ /**
843
+ * Creates a diff function with configurable options.
844
+ *
845
+ * @param {object} options - Configuration options for the diff function.
846
+ * @param {symbol} [options.deleteMarker] - A custom symbol to mark properties for deletion.
847
+ */
848
+ declare function createDiff(options?: {
849
+ deleteMarker?: symbol;
850
+ }): any;
851
+ /**
852
+ * Creates a derivePaths function with configurable options.
853
+ *
854
+ * @param {object} options - Configuration options for the derivePaths function.
855
+ * @param {symbol} [options.deleteMarker=Symbol.for("delete")] - A custom symbol to mark properties for deletion.
856
+ */
857
+ declare function createDerivePaths(options?: {
858
+ deleteMarker?: symbol;
859
+ }): <T>(changes: DeepPartial<T>) => string[];
860
+ /**
861
+ * @deprecated This function is deprecated. Use `createDiff()` to get a diff function,
862
+ * or `createDiff({ deleteMarker: yourSymbol })` for custom delete markers.
863
+ * Example: `import { createDiff } from 'your-module'; const diff = createDiff();`
864
+ *
865
+ * Identifies paths that differ between original and partial objects, using `Symbol.for("delete")` as the default delete marker.
866
+ * This is provided for backward compatibility.
867
+ */
868
+ declare const diff: any;
869
+ type DiffFunction = ReturnType<typeof createDiff>;
870
+ /**
871
+ * @deprecated This function is deprecated. Use `createDerivePaths()` to get a derivePaths function,
872
+ * or `createDerivePaths({ deleteMarker: yourSymbol })` for custom delete markers.
873
+ * Example: `import { createDerivePaths } from 'your-module'; const derivePaths = createDerivePaths();`
874
+ *
875
+ * Efficiently computes paths from changes, using `Symbol.for("delete")` as the default delete marker.
876
+ * This is provided for backward compatibility.
877
+ */
878
+ declare const derivePaths: <T>(changes: DeepPartial<T>) => string[];
879
+
880
+ /**
881
+ * Creates a shallow clone of an object or array.
882
+ */
883
+ declare const shallowClone: (obj: any) => any;
884
+ /**
885
+ * Creates a deep merge function with configurable options.
886
+ *
887
+ * @param {object} options - Configuration options for the merge function.
888
+ * @param {symbol} [options.deleteMarker=Symbol.for("delete")] - A custom symbol to mark properties for deletion during merge.
889
+ */
890
+ declare function createMerge(options?: {
891
+ deleteMarker?: symbol;
892
+ }): <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
893
+ /**
894
+ * @deprecated This function is deprecated. Use `createMerge()` to get a merge function,
895
+ * or `createMerge({ deleteMarker: yourSymbol })` for custom delete markers.
896
+ * Example: `import { createMerge } from 'your-module'; const merge = createMerge();`
897
+ *
898
+ * Deep merges changes into an original object immutably, using `Symbol.for("delete")` as the default delete marker.
899
+ * This is provided for backward compatibility.
900
+ */
901
+ declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
902
+ type MergeFunction = ReturnType<typeof createMerge>;
903
+
904
+ declare class ActionManager<T extends object> {
905
+ private eventBus;
906
+ private set;
907
+ private actions;
908
+ constructor(eventBus: EventBus<Record<StoreEvent, any>>, set: (update: StateUpdater<T>, options?: {
909
+ force?: boolean;
910
+ actionId?: string;
911
+ }) => Promise<any>);
912
+ register<R extends any[]>(action: {
913
+ name: string;
914
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
915
+ debounce?: {
916
+ delay: number;
917
+ condition?: (previous: R | undefined, current: R) => boolean;
918
+ };
919
+ }): () => void;
920
+ dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
921
+ private executeAction;
922
+ private emit;
517
923
  }
518
924
 
519
- export { type BlockingMiddleware, DELETE_SYMBOL, type DataStore, type DebugEvent, type DeepPartial, type Middleware, type MiddlewareConfig, type MiddlewareExecution, type ObservabilityOptions, type PersistenceFailedPayload, type PersistenceInitErrorPayload, type PersistenceQueueClearedPayload, type PersistenceQueuedPayload, type PersistenceRetryPayload, type PersistenceSuccessPayload, ReactiveDataStore, type StateUpdater, type StoreEvent, type StoreExecutionState, type StoreMetrics, StoreObserver, type TransformMiddleware, author };
925
+ export { type ActionCompletePayload, type ActionErrorPayload, ActionManager, type ActionStartPayload, type ArtifactCleanup, ArtifactContainer, type ArtifactFactory, type ArtifactFactoryContext, ArtifactScope, type BlockingMiddleware, DELETE_SYMBOL, type DataStore, type DeepPartial, type DiffFunction, type MergeFunction, type Middleware, type MiddlewareConfig, type MiddlewareExecution, type ObserverOptions, type PersistenceFailedPayload, type PersistenceInitErrorPayload, type PersistenceQueueClearedPayload, type PersistenceQueuedPayload, type PersistenceRetryPayload, type PersistenceSuccessPayload, ReactiveDataStore, type ReactiveSelector, type ResolvedArtifact, type SelectorAccessedPayload, type SelectorChangedPayload, type StateDelta, type StateUpdater, type StoreAction, type StoreEvent, type StoreEvents, type StoreExecutionState, type StoreMetrics, StoreObserver, type TransformMiddleware, type UseDependencyContext, createDerivePaths, createDiff, createMerge, derivePaths, diff, merge, shallowClone };