@asaidimu/utils-store 10.2.3 → 10.2.5

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.ts CHANGED
@@ -1,78 +1,9 @@
1
- /**
2
- * Interface defining the shape of the EventBus.
3
- * @template TEventMap - A record mapping event names to their respective payload types.
4
- */
5
- interface EventBus<TEventMap extends Record<string, any>> {
6
- /**
7
- * Subscribes to a specific event by name.
8
- * @param eventName - The name of the event to subscribe to.
9
- * @param callback - The function to call when the event is emitted.
10
- * @param options - Extra options to determine the behaviour of the
11
- * subscription
12
- * @returns A function to unsubscribe from the event.
13
- */
14
- subscribe<TEventName extends keyof TEventMap | "*">(eventName: TEventName, callback: TEventName extends "*" ? (payload: TEventMap[keyof TEventMap] & {
15
- __event__: keyof TEventMap;
16
- }) => void : (payload: TEventMap[TEventName]) => void, options?: SubscribeOptions): () => void;
17
- /**
18
- * Subscribes to an event and automatically unsubscribes after it fires once.
19
- * @param eventName - The name of the event to subscribe to.
20
- * @param callback - The function to call when the event is emitted.
21
- * @returns A function to cancel the one-shot subscription before it fires.
22
- */
23
- once<TEventName extends keyof TEventMap | "*">(eventName: TEventName, callback: TEventName extends "*" ? (payload: TEventMap[keyof TEventMap] & {
24
- __event__: keyof TEventMap;
25
- }) => void : (payload: TEventMap[TEventName]) => void, options?: SubscribeOptions): () => void;
26
- /**
27
- * Emits an event with a payload to all subscribed listeners.
28
- * @param event - An object containing the event name and payload.
29
- */
30
- emit: <TEventName extends keyof TEventMap>(event: {
31
- name: TEventName;
32
- payload: TEventMap[TEventName];
33
- }) => void;
34
- /**
35
- * Retrieves metrics about event bus usage.
36
- * @returns An object containing various metrics.
37
- */
38
- metrics: () => EventMetrics;
39
- /**
40
- * Clears all subscriptions and resets metrics.
41
- *
42
- * After calling `clear()`, the bus is fully reset and can be reused
43
- * cross-tab communication is re-established if it was previously enabled.
44
- *
45
- * @param options - Optional configuration object.
46
- * @param options.permanent - If `true`, the bus becomes permanently unusable after clearing.
47
- * Defaults to `false`.
48
- * @returns {void}
49
- */
50
- clear: (options?: {
51
- permanent?: boolean;
52
- }) => void;
53
- }
54
- /**
55
- * Interface defining the metrics tracked by the EventBus.
56
- */
57
- interface EventMetrics {
58
- /** Total number of events emitted (both sync and deferred paths). */
59
- totalEvents: number;
60
- /** Number of active subscriptions across all event names. */
61
- activeSubscriptions: number;
62
- /** Map of event names to their emission counts. */
63
- eventCounts: Map<string, number>;
64
- /** Average duration of event dispatch in milliseconds. */
65
- averageEmitDuration: number;
66
- }
67
- interface SubscribeOptions {
68
- /**
69
- * Debounce delay in milliseconds. When multiple events arrive in quick
70
- * succession, the callback runs only after the quiet period ends, using the
71
- * latest payload. Default = no debouncing.
72
- */
73
- debounce?: number;
74
- }
1
+ import { EventBus, SubscribeOptions, SubscribeOptions as SubscribeOptions$1 } from "@asaidimu/utils-events";
2
+ import { SystemLogger } from "@asaidimu/utils-logger";
3
+ import { SimplePersistence } from "@asaidimu/utils-persistence";
4
+ import { SimplePersistence as SimplePersistence$1 } from "@asaidimu/utils-persistence/types.ts";
75
5
 
6
+ //#region src/store/types.d.ts
76
7
  /**
77
8
  * Utility type for representing partial updates to the state, allowing deep nesting.
78
9
  * It makes all properties optional and applies the same transformation recursively
@@ -80,64 +11,62 @@ interface SubscribeOptions {
80
11
  * preserving the original structure. It also includes the original type T and
81
12
  * undefined as possibilities for the top level and nested values.
82
13
  */
83
- 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 : {
84
- [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined;
85
- } | undefined | T : T | undefined | symbol;
14
+ 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 : { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> | undefined : T[K] | undefined } | undefined | T : T | undefined | symbol;
86
15
  /**
87
16
  * Interface for performance and execution metrics of the state store.
88
17
  */
89
18
  interface StoreMetrics {
90
- /** The number of times the state has been successfully updated. */
91
- updateCount: number;
92
- /** The total number of listener functions executed in response to state changes. */
93
- listenerExecutions: number;
94
- /** The average time taken for a state update process to complete (in milliseconds). */
95
- averageUpdateTime: number;
96
- /** The size (e.g., number of paths changed) of the largest single state update. */
97
- largestUpdateSize: number;
98
- /** List of state paths that trigger the most listener executions. */
99
- mostActiveListenerPaths: string[];
100
- /** The total number of update attempts (including blocked ones). */
101
- totalUpdates: number;
102
- /** The number of updates that were blocked by blocking middleware. */
103
- blockedUpdates: number;
104
- /** The average duration of a state update cycle (in milliseconds). */
105
- averageUpdateDuration: number;
106
- /** The total number of middleware functions executed. */
107
- middlewareExecutions: number;
108
- /** The total number of transactions initiated. */
109
- transactionCount: number;
110
- /** The total number of store events fired. */
111
- totalEventsFired: number;
112
- /** The total number of actions dispatched. */
113
- totalActionsDispatched: number;
114
- /** The total number of actions that completed successfully. */
115
- totalActionsSucceeded: number;
116
- /** The total number of actions that failed with an error. */
117
- totalActionsFailed: number;
118
- /** The average duration of an action execution (in milliseconds). */
119
- averageActionDuration: number;
19
+ /** The number of times the state has been successfully updated. */
20
+ updateCount: number;
21
+ /** The total number of listener functions executed in response to state changes. */
22
+ listenerExecutions: number;
23
+ /** The average time taken for a state update process to complete (in milliseconds). */
24
+ averageUpdateTime: number;
25
+ /** The size (e.g., number of paths changed) of the largest single state update. */
26
+ largestUpdateSize: number;
27
+ /** List of state paths that trigger the most listener executions. */
28
+ mostActiveListenerPaths: string[];
29
+ /** The total number of update attempts (including blocked ones). */
30
+ totalUpdates: number;
31
+ /** The number of updates that were blocked by blocking middleware. */
32
+ blockedUpdates: number;
33
+ /** The average duration of a state update cycle (in milliseconds). */
34
+ averageUpdateDuration: number;
35
+ /** The total number of middleware functions executed. */
36
+ middlewareExecutions: number;
37
+ /** The total number of transactions initiated. */
38
+ transactionCount: number;
39
+ /** The total number of store events fired. */
40
+ totalEventsFired: number;
41
+ /** The total number of actions dispatched. */
42
+ totalActionsDispatched: number;
43
+ /** The total number of actions that completed successfully. */
44
+ totalActionsSucceeded: number;
45
+ /** The total number of actions that failed with an error. */
46
+ totalActionsFailed: number;
47
+ /** The average duration of an action execution (in milliseconds). */
48
+ averageActionDuration: number;
120
49
  }
121
50
  /**
122
51
  * Extended store state for monitoring the current execution status (e.g., if an update is in progress).
123
52
  */
124
53
  interface StoreExecutionState<T> {
125
- /** Indicates if a state update process is currently executing. */
126
- executing: boolean;
127
- /** The changes (DeepPartial) currently being processed in the execution cycle. Null if none. */
128
- changes: DeepPartial<T> | null;
129
- /** A queue of pending state update functions/objects to be applied sequentially. */
130
- pendingChanges: Array<StateUpdater<T>>;
131
- /** Names of all currently registered middlewares. */
132
- middlewares: string[];
133
- /** Details of the middleware currently running. Null if none. */
134
- runningMiddleware: {
135
- id: string;
136
- name: string;
137
- startTime: number;
138
- } | null;
139
- /** Indicates if the store is currently within an active transaction block. */
140
- transactionActive: boolean;
54
+ /** Indicates if a state update process is currently executing. */
55
+ executing: boolean;
56
+ /** The changes (DeepPartial) currently being processed in the execution cycle. Null if none. */
57
+ changes: DeepPartial<T> | null;
58
+ /** A queue of pending state update functions/objects to be applied sequentially. */
59
+ pendingChanges: Array<StateUpdater<T>>;
60
+ /** Names of all currently registered middlewares. */
61
+ middlewares: string[];
62
+ /** Details of the middleware currently running. Null if none. */
63
+ runningMiddleware: {
64
+ id: string;
65
+ name: string;
66
+ startTime: number;
67
+ } | null;
68
+ /** Indicates if the store is currently within an active transaction block. */
69
+ transactionActive: boolean;
141
70
  }
142
71
  /**
143
72
  * Event types emitted by the state store for observability and debugging.
@@ -147,101 +76,92 @@ type StoreEvent = "update:start" | "update:complete" | "middleware:start" | "mid
147
76
  * Payload for the 'selector:changed' event.
148
77
  */
149
78
  interface SelectorChangedPayload<S> {
150
- /** Unique identifier of the selector. */
151
- selectorId: string;
152
- /** The new computed result of the selector. */
153
- newResult: S;
154
- /** Timestamp of when the change occurred. */
155
- timestamp: number;
79
+ /** Unique identifier of the selector. */
80
+ selectorId: string;
81
+ /** The new computed result of the selector. */
82
+ newResult: S;
83
+ /** Timestamp of when the change occurred. */
84
+ timestamp: number;
156
85
  }
157
86
  /**
158
87
  * Maps each `StoreEvent` type to its corresponding event payload interface.
159
88
  * Uses conditional types to ensure type safety for event listeners.
160
89
  */
161
- type StoreEvents = {
162
- [K in StoreEvent]: K extends "update:complete" ? {
163
- /** List of state changes (deltas) applied in the update. */
164
- deltas: StateDelta[];
165
- /** Total duration of the update process (in milliseconds). */
166
- duration: number;
167
- /** Timestamp of the update completion. */
168
- timestamp: number;
169
- /** Optional ID of the action that triggered the update. */
170
- actionId?: string;
171
- /** The resulting new state after the update (may be a partial/transformed state). */
172
- newState: any;
173
- /** True if the update was blocked by a middleware. */
174
- blocked?: boolean;
175
- /** Any error that occurred during the update. */
176
- error?: any;
177
- } : 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" ? {
178
- transactionId: string;
179
- timestamp: number;
180
- } : 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;
181
- };
90
+ type StoreEvents = { [K in StoreEvent]: K extends "update:complete" ? {
91
+ /** List of state changes (deltas) applied in the update. */deltas: StateDelta[]; /** Total duration of the update process (in milliseconds). */
92
+ duration: number; /** Timestamp of the update completion. */
93
+ timestamp: number; /** Optional ID of the action that triggered the update. */
94
+ actionId?: string; /** The resulting new state after the update (may be a partial/transformed state). */
95
+ newState: any; /** True if the update was blocked by a middleware. */
96
+ blocked?: boolean; /** Any error that occurred during the update. */
97
+ error?: any;
98
+ } : 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" ? {
99
+ transactionId: string;
100
+ timestamp: number;
101
+ } : 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 };
182
102
  /**
183
103
  * Payload for the 'selector:accessed' event.
184
104
  */
185
105
  interface SelectorAccessedPayload {
186
- /** Unique identifier of the selector. */
187
- selectorId: string;
188
- /** List of state paths accessed during the selector computation. */
189
- accessedPaths: string[];
190
- /** Duration of the selector computation (in milliseconds). */
191
- duration: number;
192
- /** Timestamp of the access. */
193
- timestamp: number;
106
+ /** Unique identifier of the selector. */
107
+ selectorId: string;
108
+ /** List of state paths accessed during the selector computation. */
109
+ accessedPaths: string[];
110
+ /** Duration of the selector computation (in milliseconds). */
111
+ duration: number;
112
+ /** Timestamp of the access. */
113
+ timestamp: number;
194
114
  }
195
115
  /**
196
116
  * Payload for the 'action:start' event.
197
117
  */
198
118
  interface ActionStartPayload {
199
- /** Unique identifier for the action execution. */
200
- actionId: string;
201
- /** Name of the action function. */
202
- name: string;
203
- /** The parameters passed to the action function. */
204
- params: any[];
205
- /** Timestamp of when the action execution started. */
206
- timestamp: number;
119
+ /** Unique identifier for the action execution. */
120
+ actionId: string;
121
+ /** Name of the action function. */
122
+ name: string;
123
+ /** The parameters passed to the action function. */
124
+ params: any[];
125
+ /** Timestamp of when the action execution started. */
126
+ timestamp: number;
207
127
  }
208
128
  /**
209
129
  * Payload for the 'action:complete' event (successful action execution).
210
130
  */
211
131
  interface ActionCompletePayload {
212
- /** Unique identifier for the action execution. */
213
- actionId: string;
214
- /** Name of the action function. */
215
- name: string;
216
- /** The parameters passed to the action function. */
217
- params: any[];
218
- /** Timestamp of when the action execution started. */
219
- startTime: number;
220
- /** Timestamp of when the action execution completed. */
221
- endTime: number;
222
- /** Total duration of the action execution (in milliseconds). */
223
- duration: number;
224
- /** The result returned by the action function. */
225
- result: any;
132
+ /** Unique identifier for the action execution. */
133
+ actionId: string;
134
+ /** Name of the action function. */
135
+ name: string;
136
+ /** The parameters passed to the action function. */
137
+ params: any[];
138
+ /** Timestamp of when the action execution started. */
139
+ startTime: number;
140
+ /** Timestamp of when the action execution completed. */
141
+ endTime: number;
142
+ /** Total duration of the action execution (in milliseconds). */
143
+ duration: number;
144
+ /** The result returned by the action function. */
145
+ result: any;
226
146
  }
227
147
  /**
228
148
  * Payload for the 'action:error' event (failed action execution).
229
149
  */
230
150
  interface ActionErrorPayload {
231
- /** Unique identifier for the action execution. */
232
- actionId: string;
233
- /** Name of the action function. */
234
- name: string;
235
- /** The parameters passed to the action function. */
236
- params: any[];
237
- /** Timestamp of when the action execution started. */
238
- startTime: number;
239
- /** Timestamp of when the action execution ended (with error). */
240
- endTime: number;
241
- /** Total duration of the action execution (in milliseconds). */
242
- duration: number;
243
- /** The error object. */
244
- error: any;
151
+ /** Unique identifier for the action execution. */
152
+ actionId: string;
153
+ /** Name of the action function. */
154
+ name: string;
155
+ /** The parameters passed to the action function. */
156
+ params: any[];
157
+ /** Timestamp of when the action execution started. */
158
+ startTime: number;
159
+ /** Timestamp of when the action execution ended (with error). */
160
+ endTime: number;
161
+ /** Total duration of the action execution (in milliseconds). */
162
+ duration: number;
163
+ /** The error object. */
164
+ error: any;
245
165
  }
246
166
  /**
247
167
  * Type for a generic middleware function.
@@ -253,33 +173,33 @@ type Middleware<T> = (state: T, update: DeepPartial<T>) => Promise<DeepPartial<T
253
173
  * Middleware execution information for event emissions and tracking.
254
174
  */
255
175
  interface MiddlewareExecution {
256
- /** Unique identifier for the middleware instance. */
257
- id: string;
258
- /** Name of the middleware. */
259
- name: string;
260
- /** Timestamp of when the middleware execution started. */
261
- startTime: number;
262
- /** Timestamp of when the middleware execution completed. */
263
- endTime: number;
264
- /** Total duration of the middleware execution (in milliseconds). */
265
- duration: number;
266
- /** True if the middleware blocked the update. */
267
- blocked: boolean;
268
- /** Error object if the middleware failed. */
269
- error?: Error;
270
- /** List of state changes (deltas) that resulted from this middleware's transformation. */
271
- deltas: StateDelta[];
176
+ /** Unique identifier for the middleware instance. */
177
+ id: string;
178
+ /** Name of the middleware. */
179
+ name: string;
180
+ /** Timestamp of when the middleware execution started. */
181
+ startTime: number;
182
+ /** Timestamp of when the middleware execution completed. */
183
+ endTime: number;
184
+ /** Total duration of the middleware execution (in milliseconds). */
185
+ duration: number;
186
+ /** True if the middleware blocked the update. */
187
+ blocked: boolean;
188
+ /** Error object if the middleware failed. */
189
+ error?: Error;
190
+ /** List of state changes (deltas) that resulted from this middleware's transformation. */
191
+ deltas: StateDelta[];
272
192
  }
273
193
  /**
274
194
  * Represents a single change to the state, detailing the path, old value, and new value.
275
195
  */
276
196
  interface StateDelta {
277
- /** Dot-separated path to the changed property (e.g., "user.profile.name"). */
278
- path: string;
279
- /** The value of the property *before* the update. */
280
- oldValue: any;
281
- /** The value of the property *after* the update. */
282
- newValue: any;
197
+ /** Dot-separated path to the changed property (e.g., "user.profile.name"). */
198
+ path: string;
199
+ /** The value of the property *before* the update. */
200
+ oldValue: any;
201
+ /** The value of the property *after* the update. */
202
+ newValue: any;
283
203
  }
284
204
  /**
285
205
  * Represents a state update, which can be:
@@ -307,333 +227,281 @@ type TransformMiddleware<T> = (state: T, changes: DeepPartial<T>) => Promise<Dee
307
227
  * It returns a boolean or an object containing a `block` boolean and an optional `error`.
308
228
  */
309
229
  type BlockingMiddleware<T> = (state: T, changes: DeepPartial<T>) => Promise<boolean | {
310
- block: boolean;
311
- error?: Error;
230
+ block: boolean;
231
+ error?: Error;
312
232
  }> | boolean | {
313
- block: boolean;
314
- error?: Error;
233
+ block: boolean;
234
+ error?: Error;
315
235
  };
316
236
  /**
317
237
  * Type representing the configuration object passed to the `use` method to register a middleware.
318
238
  */
319
239
  interface MiddlewareConfig<T> {
320
- /** The middleware function (can be a transform or blocking middleware). */
321
- action: TransformMiddleware<T> | BlockingMiddleware<T>;
322
- /** An optional, human-readable name for the middleware. */
323
- name?: string;
324
- /** If true, the middleware is treated as a blocking middleware (must return a boolean or `{ block: boolean }`). */
325
- block?: boolean;
240
+ /** The middleware function (can be a transform or blocking middleware). */
241
+ action: TransformMiddleware<T> | BlockingMiddleware<T>;
242
+ /** An optional, human-readable name for the middleware. */
243
+ name?: string;
244
+ /** If true, the middleware is treated as a blocking middleware (must return a boolean or `{ block: boolean }`). */
245
+ block?: boolean;
326
246
  }
327
247
  /**
328
248
  * Interface for a reactive selector result, providing access to the value and subscription capabilities.
329
249
  */
330
250
  interface ReactiveSelector<S> {
331
- /** Unique identifier for the selector. */
332
- id: string;
333
- /** Function to get the current computed value of the selector. */
334
- get: () => S;
335
- /**
336
- * Subscribes a callback function to run whenever the selector's result changes.
337
- * Returns an unsubscribe function.
338
- */
339
- subscribe: (callback: (state: S) => void) => () => void;
251
+ /** Unique identifier for the selector. */
252
+ id: string;
253
+ /** Function to get the current computed value of the selector. */
254
+ get: () => S;
255
+ /**
256
+ * Subscribes a callback function to run whenever the selector's result changes.
257
+ * Returns an unsubscribe function.
258
+ */
259
+ subscribe: (callback: (state: S) => void) => () => void;
340
260
  }
341
261
  interface ActionWatcher {
342
- /** Unique identifier for the action */
343
- name: string;
344
- /** Function to get the current computed value of the action. */
345
- status: () => boolean;
346
- /**
347
- * Subscribes a callback function to run whenever the action's status changes.
348
- * Returns an unsubscribe function.
349
- */
350
- subscribe: (callback: () => void) => () => void;
262
+ /** Unique identifier for the action */
263
+ name: string;
264
+ /** Function to get the current computed value of the action. */
265
+ status: () => boolean;
266
+ /**
267
+ * Subscribes a callback function to run whenever the action's status changes.
268
+ * Returns an unsubscribe function.
269
+ */
270
+ subscribe: (callback: () => void) => () => void;
351
271
  }
352
272
  interface TransactionOptions {
353
- /** If true, blocks resolution until changes are fully committed to the database row */
354
- flush?: boolean;
273
+ /** If true, blocks resolution until changes are fully committed to the database row */
274
+ flush?: boolean;
355
275
  }
356
276
  /**
357
277
  * Interface defining the contract for the core data state store.
358
278
  * T must be an object type.
359
279
  */
360
280
  interface DataStore<T extends object> {
361
- /**
362
- * Gets the current state of the store.
363
- * @param clone If true, returns a deep clone of the state; otherwise, returns the internal state reference.
364
- * @returns The current state T.
365
- */
366
- get(clone?: boolean): T;
367
- /**
368
- * Gets a subset of the store.
369
- * @param paths The paths which to include in the returned object.
370
- * @param separator Optional separator for paths. Defaults to `.` .
371
- * @returns An object of the shape K mapping paths to their current values.
372
- */
373
- subset<K extends Record<string, any> = Record<string, any>>(paths: Array<string>, separator?: string): K;
374
- /**
375
- * Registers a named action function that can modify the state.
376
- * @param action The action configuration object.
377
- * @returns A function to unregister the action.
378
- */
379
- register<R extends any[]>(action: {
380
- name: string;
381
- fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
382
- debounce?: {
383
- delay: number;
384
- condition?: (previous: R, current: R) => boolean;
385
- };
386
- }): () => void;
387
- /**
388
- * Executes (dispatches) a previously registered action by its name.
389
- * @param name The name of the action.
390
- * @param args The parameters to pass to the action function.
391
- * @returns A promise that resolves to the final state after the action and subsequent updates are complete.
392
- */
393
- dispatch<R extends any[]>(name: string, ...args: R): Promise<T>;
394
- /**
395
- * Sets or updates the state using a StateUpdater.
396
- * @param update The new state, partial state, or a function returning a partial state.
397
- * @param options Configuration options for the set operation.
398
- * @returns A promise that resolves to the current state when the update is complete.
399
- */
400
- set(update: StateUpdater<T>, options?: {
401
- force?: boolean;
402
- actionId?: string;
403
- }): Promise<T>;
404
- /**
405
- * Creates a reactive selector that computes a derived value and tracks dependencies.
406
- * @param selector A function to compute the derived state value S from the full state T.
407
- * @returns A `ReactiveSelector<S>` object.
408
- */
409
- select<S>(selector: (state: T) => S): ReactiveSelector<S>;
410
- /**
411
- * Subscribes a callback to run when the data at the specified path(s) changes.
412
- * @param path A single path string or an array of path strings to watch.
413
- * @param callback The function to execute when a change occurs in the watched path(s).
414
- * @param options Extra options to pass to the event bus
415
- * @returns An unsubscribe function.
416
- */
417
- watch(path: string | Array<string>, callback: (state: T) => void, options?: SubscribeOptions): () => void;
418
- /**
419
- * Subscribes to execution‑status changes of a registered action.
420
- *
421
- * The provided callback is called **every time** the action transitions
422
- * between idle and running (i.e. on `action:start`, `action:complete`, or
423
- * `action:error` for the given name). The current status can also be read
424
- * synchronously with `isActionRunning(name)`.
425
- *
426
- * **Deferred listener teardown**
427
- * To avoid unnecessary churn when subscriptions are rapidly created and
428
- * destroyed, the underlying event listeners are not removed immediately
429
- * on unsubscribe. Instead, a *pending reset* is queued via `queueMicrotask`.
430
- * If a new subscription for the same action arrives before that microtask
431
- * executes, the reset is silently cancelled and the already‑established
432
- * listeners are reused. This keeps the subscription infrastructure stable
433
- * and prevents cascading notifications that could otherwise arise from
434
- * repeated subscribe‑unsubscribe‑subscribe cycles.
435
- *
436
- * @param name - The name of the action to watch.
437
- * @returns An ActionWatcher
438
- */
439
- watchAction(name: string): ActionWatcher;
440
- /**
441
- * Executes an operation function within a transaction block.
442
- * All state updates (`set` or actions) within the transaction are batched and applied atomically (all or nothing).
443
- * @param operation The function containing the state updates.
444
- * @returns A promise that resolves to the return value of the operation function.
445
- */
446
- transaction<R>(operation: () => R | Promise<R>, options?: TransactionOptions): Promise<R>;
447
- /**
448
- * Registers a middleware function to intercept state updates.
449
- * @param props The middleware configuration.
450
- * @returns A function to unregister the middleware.
451
- */
452
- use(props: MiddlewareConfig<T>): () => boolean;
453
- /**
454
- * Subscribes a listener to a specific store event type.
455
- * @param event The type of store event to listen for.
456
- * @param listener The callback function to execute when the event fires.
457
- * @returns An unsubscribe function.
458
- */
459
- on(event: StoreEvent, listener: (data: any) => void): () => void;
460
- /**
461
- * Returns the unique identifier of the store instance.
462
- */
463
- id(): string;
464
- /**
465
- * Checks whether the store is fully initialized and ready for use.
466
- */
467
- isReady(): boolean;
468
- /**
469
- * Returns a promise that resolves once the store is fully initialised.
470
- * Safe to call multiple times — all callers share the same latch.
471
- *
472
- * @param timeout - Optional maximum wait time in milliseconds.
473
- * @throws {TimeoutError} If the store does not become ready within the timeout.
474
- *
475
- * @example
476
- * await store.ready();
477
- * const state = store.get();
478
- */
479
- ready(timeout?: number): Promise<void>;
480
- /**
481
- * Returns a readonly snapshot of the current execution state of the store.
482
- */
483
- state(): Readonly<StoreExecutionState<T>>;
484
- /**
485
- * Releases all resources held by the store and renders it unusable
486
- */
487
- dispose(): Promise<void>;
281
+ /**
282
+ * Gets the current state of the store.
283
+ * @param clone If true, returns a deep clone of the state; otherwise, returns the internal state reference.
284
+ * @returns The current state T.
285
+ */
286
+ get(clone?: boolean): T;
287
+ /**
288
+ * Gets a subset of the store.
289
+ * @param paths The paths which to include in the returned object.
290
+ * @param separator Optional separator for paths. Defaults to `.` .
291
+ * @returns An object of the shape K mapping paths to their current values.
292
+ */
293
+ subset<K extends Record<string, any> = Record<string, any>>(paths: Array<string>, separator?: string): K;
294
+ /**
295
+ * Registers a named action function that can modify the state.
296
+ * @param action The action configuration object.
297
+ * @returns A function to unregister the action.
298
+ */
299
+ register<R extends any[]>(action: {
300
+ name: string;
301
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
302
+ debounce?: {
303
+ delay: number;
304
+ condition?: (previous: R, current: R) => boolean;
305
+ };
306
+ }): () => void;
307
+ /**
308
+ * Executes (dispatches) a previously registered action by its name.
309
+ * @param name The name of the action.
310
+ * @param args The parameters to pass to the action function.
311
+ * @returns A promise that resolves to the final state after the action and subsequent updates are complete.
312
+ */
313
+ dispatch<R extends any[]>(name: string, ...args: R): Promise<T>;
314
+ /**
315
+ * Sets or updates the state using a StateUpdater.
316
+ * @param update The new state, partial state, or a function returning a partial state.
317
+ * @param options Configuration options for the set operation.
318
+ * @returns A promise that resolves to the current state when the update is complete.
319
+ */
320
+ set(update: StateUpdater<T>, options?: {
321
+ force?: boolean;
322
+ actionId?: string;
323
+ }): Promise<T>;
324
+ /**
325
+ * Creates a reactive selector that computes a derived value and tracks dependencies.
326
+ * @param selector A function to compute the derived state value S from the full state T.
327
+ * @returns A `ReactiveSelector<S>` object.
328
+ */
329
+ select<S>(selector: (state: T) => S): ReactiveSelector<S>;
330
+ /**
331
+ * Subscribes a callback to run when the data at the specified path(s) changes.
332
+ * @param path A single path string or an array of path strings to watch.
333
+ * @param callback The function to execute when a change occurs in the watched path(s).
334
+ * @param options Extra options to pass to the event bus
335
+ * @returns An unsubscribe function.
336
+ */
337
+ watch(path: string | Array<string>, callback: (state: T) => void, options?: SubscribeOptions$1): () => void;
338
+ /**
339
+ * Subscribes to execution‑status changes of a registered action.
340
+ *
341
+ * The provided callback is called **every time** the action transitions
342
+ * between idle and running (i.e. on `action:start`, `action:complete`, or
343
+ * `action:error` for the given name). The current status can also be read
344
+ * synchronously with `isActionRunning(name)`.
345
+ *
346
+ * **Deferred listener teardown**
347
+ * To avoid unnecessary churn when subscriptions are rapidly created and
348
+ * destroyed, the underlying event listeners are not removed immediately
349
+ * on unsubscribe. Instead, a *pending reset* is queued via `queueMicrotask`.
350
+ * If a new subscription for the same action arrives before that microtask
351
+ * executes, the reset is silently cancelled and the already‑established
352
+ * listeners are reused. This keeps the subscription infrastructure stable
353
+ * and prevents cascading notifications that could otherwise arise from
354
+ * repeated subscribe‑unsubscribe‑subscribe cycles.
355
+ *
356
+ * @param name - The name of the action to watch.
357
+ * @returns An ActionWatcher
358
+ */
359
+ watchAction(name: string): ActionWatcher;
360
+ /**
361
+ * Executes an operation function within a transaction block.
362
+ * All state updates (`set` or actions) within the transaction are batched and applied atomically (all or nothing).
363
+ * @param operation The function containing the state updates.
364
+ * @returns A promise that resolves to the return value of the operation function.
365
+ */
366
+ transaction<R>(operation: () => R | Promise<R>, options?: TransactionOptions): Promise<R>;
367
+ /**
368
+ * Registers a middleware function to intercept state updates.
369
+ * @param props The middleware configuration.
370
+ * @returns A function to unregister the middleware.
371
+ */
372
+ use(props: MiddlewareConfig<T>): () => boolean;
373
+ /**
374
+ * Subscribes a listener to a specific store event type.
375
+ * @param event The type of store event to listen for.
376
+ * @param listener The callback function to execute when the event fires.
377
+ * @returns An unsubscribe function.
378
+ */
379
+ on(event: StoreEvent, listener: (data: any) => void): () => void;
380
+ /**
381
+ * Returns the unique identifier of the store instance.
382
+ */
383
+ id(): string;
384
+ /**
385
+ * Checks whether the store is fully initialized and ready for use.
386
+ */
387
+ isReady(): boolean;
388
+ /**
389
+ * Returns a promise that resolves once the store is fully initialised.
390
+ * Safe to call multiple times — all callers share the same latch.
391
+ *
392
+ * @param timeout - Optional maximum wait time in milliseconds.
393
+ * @throws {TimeoutError} If the store does not become ready within the timeout.
394
+ *
395
+ * @example
396
+ * await store.ready();
397
+ * const state = store.get();
398
+ */
399
+ ready(timeout?: number): Promise<void>;
400
+ /**
401
+ * Returns a readonly snapshot of the current execution state of the store.
402
+ */
403
+ state(): Readonly<StoreExecutionState<T>>;
404
+ /**
405
+ * Releases all resources held by the store and renders it unusable
406
+ */
407
+ dispose(): Promise<void>;
488
408
  }
489
409
  /** Payload for the 'persistence:queued' event. */
490
410
  interface PersistenceQueuedPayload {
491
- /** Unique ID for the persistence task. */
492
- taskId: string;
493
- /** Paths that were changed and triggered persistence. */
494
- changedPaths: string[];
495
- /** The current number of tasks waiting in the persistence queue. */
496
- queueSize: number;
497
- /** Timestamp of when the task was queued. */
498
- timestamp: number;
411
+ /** Unique ID for the persistence task. */
412
+ taskId: string;
413
+ /** Paths that were changed and triggered persistence. */
414
+ changedPaths: string[];
415
+ /** The current number of tasks waiting in the persistence queue. */
416
+ queueSize: number;
417
+ /** Timestamp of when the task was queued. */
418
+ timestamp: number;
499
419
  }
500
420
  /** Payload for the 'persistence:success' event. */
501
421
  interface PersistenceSuccessPayload {
502
- /** Unique ID for the persistence task. */
503
- taskId: string;
504
- /** Paths that were successfully persisted. */
505
- changedPaths: string[];
506
- /** Duration of the persistence operation (in milliseconds). */
507
- duration: number;
508
- /** Timestamp of the success. */
509
- timestamp: number;
422
+ /** Unique ID for the persistence task. */
423
+ taskId: string;
424
+ /** Paths that were successfully persisted. */
425
+ changedPaths: string[];
426
+ /** Duration of the persistence operation (in milliseconds). */
427
+ duration: number;
428
+ /** Timestamp of the success. */
429
+ timestamp: number;
510
430
  }
511
431
  /** Payload for the 'persistence:retry' event. */
512
432
  interface PersistenceRetryPayload {
513
- /** Unique ID for the persistence task. */
514
- taskId: string;
515
- /** Current retry attempt number. */
516
- attempt: number;
517
- /** Maximum allowed retries. */
518
- maxRetries: number;
519
- /** Time until the next retry attempt (in milliseconds). */
520
- nextRetryIn: number;
521
- /** The error that triggered the retry. */
522
- error: any;
523
- /** Timestamp of the retry event. */
524
- timestamp: number;
433
+ /** Unique ID for the persistence task. */
434
+ taskId: string;
435
+ /** Current retry attempt number. */
436
+ attempt: number;
437
+ /** Maximum allowed retries. */
438
+ maxRetries: number;
439
+ /** Time until the next retry attempt (in milliseconds). */
440
+ nextRetryIn: number;
441
+ /** The error that triggered the retry. */
442
+ error: any;
443
+ /** Timestamp of the retry event. */
444
+ timestamp: number;
525
445
  }
526
446
  /** Payload for the 'persistence:failed' event. */
527
447
  interface PersistenceFailedPayload {
528
- /** Unique ID for the persistence task. */
529
- taskId: string;
530
- /** Paths that failed to persist. */
531
- changedPaths: string[];
532
- /** Total number of attempts made. */
533
- attempts: number;
534
- /** The final error object. */
535
- error: any;
536
- /** Timestamp of the final failure. */
537
- timestamp: number;
448
+ /** Unique ID for the persistence task. */
449
+ taskId: string;
450
+ /** Paths that failed to persist. */
451
+ changedPaths: string[];
452
+ /** Total number of attempts made. */
453
+ attempts: number;
454
+ /** The final error object. */
455
+ error: any;
456
+ /** Timestamp of the final failure. */
457
+ timestamp: number;
538
458
  }
539
459
  /** Payload for the 'persistence:queue_cleared' event. */
540
460
  interface PersistenceQueueClearedPayload {
541
- /** The number of persistence tasks that were cleared from the queue. */
542
- clearedTasks: number;
543
- /** Timestamp of when the queue was cleared. */
544
- timestamp: number;
461
+ /** The number of persistence tasks that were cleared from the queue. */
462
+ clearedTasks: number;
463
+ /** Timestamp of when the queue was cleared. */
464
+ timestamp: number;
545
465
  }
546
466
  /** Payload for the 'persistence:init_error' event. */
547
467
  interface PersistenceInitErrorPayload {
548
- /** The error that occurred during persistence initialization. */
549
- error: any;
550
- /** Timestamp of the error. */
551
- timestamp: number;
468
+ /** The error that occurred during persistence initialization. */
469
+ error: any;
470
+ /** Timestamp of the error. */
471
+ timestamp: number;
552
472
  }
553
473
  /**
554
474
  * Interface describing a registered state action, including its metadata and debounce configuration.
555
475
  */
556
476
  type StoreAction<T, R extends any[] = any[]> = {
557
- /** Unique identifier for the action definition. */
558
- id: string;
559
- /** Name of the action, used for dispatching. */
560
- name: string;
561
- /** The actual function that takes state and arguments, and returns a state update. */
562
- action: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
563
- /** Optional configuration for debouncing action execution. */
564
- debounce?: {
565
- /** Active timer reference, if debouncing */
566
- timer?: ReturnType<typeof setTimeout>;
567
- /** Debounce delay in milliseconds */
568
- delay: number;
569
- /** Optional condition to decide whether to debounce based on previous vs current args */
570
- condition?: (previous: R | undefined, current: R) => boolean;
571
- /** Last call’s arguments, used for condition checks */
572
- args?: R;
573
- /** Internal promise resolvers to prevent memory leaks */
574
- resolve?: (value: any) => void;
575
- reject?: (reason?: any) => void;
576
- };
477
+ /** Unique identifier for the action definition. */id: string; /** Name of the action, used for dispatching. */
478
+ name: string; /** The actual function that takes state and arguments, and returns a state update. */
479
+ action: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>; /** Optional configuration for debouncing action execution. */
480
+ debounce?: {
481
+ /** Active timer reference, if debouncing */timer?: ReturnType<typeof setTimeout>; /** Debounce delay in milliseconds */
482
+ delay: number; /** Optional condition to decide whether to debounce based on previous vs current args */
483
+ condition?: (previous: R | undefined, current: R) => boolean; /** Last call’s arguments, used for condition checks */
484
+ args?: R; /** Internal promise resolvers to prevent memory leaks */
485
+ resolve?: (value: any) => void;
486
+ reject?: (reason?: any) => void;
487
+ };
577
488
  };
578
-
579
- interface SimplePersistence<T> {
580
- /**
581
- * Persists data to storage.
582
- *
583
- * @param id The **unique identifier of the *consumer instance*** making the change. This is NOT the ID of the data (`T`) itself.
584
- * Think of it as the ID of the specific browser tab, component, or module that's currently interacting with the persistence layer.
585
- * It should typically be a **UUID** generated once at the consumer instance's instantiation.
586
- * This `id` is crucial for the `subscribe` method, helping to differentiate updates originating from the current instance versus other instances/tabs, thereby preventing self-triggered notification loops.
587
- * @param state The state (of type T) to persist. This state is generally considered the **global or shared state** that all instances interact with.
588
- * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations (like `IndexedDBPersistence`), this returns a `Promise<boolean>`.
589
- */
590
- set(id: string, state: T): boolean | Promise<boolean>;
591
- /**
592
- * Retrieves the global persisted data from storage.
593
- *
594
- * @returns The retrieved state of type `T`, or `null` if no data is found or if an error occurs during retrieval/parsing.
595
- * For asynchronous implementations, this returns a `Promise<T | null>`.
596
- */
597
- get(): (T | null) | Promise<T | null>;
598
- /**
599
- * Subscribes to changes in the global persisted data that originate from *other* instances of your application (e.g., other tabs or independent components using the same persistence layer).
600
- *
601
- * @param id The **unique identifier of the *consumer instance* subscribing**. This allows the persistence implementation to filter out notifications that were initiated by the subscribing instance itself.
602
- * @param callback The function to call when the global persisted data changes from *another* source. The new state (`T`) is passed as an argument to this callback.
603
- * @returns A function that, when called, will unsubscribe the provided callback from future updates. Call this when your component or instance is no longer active to prevent memory leaks.
604
- */
605
- subscribe(id: string, callback: (state: T) => void): () => void;
606
- /**
607
- * Clears (removes) the entire global persisted data from storage.
608
- *
609
- * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations, this returns a `Promise<boolean>`.
610
- */
611
- clear(): boolean | Promise<boolean>;
612
- /**
613
- * Returns metadata about the persistence layer.
614
- *
615
- * This is useful for distinguishing between multiple apps running on the same host
616
- * (e.g., several apps served at `localhost:3000` that share the same storage key).
617
- *
618
- * @returns An object containing:
619
- * - `version`: The semantic version string of the persistence schema or application.
620
- * - `id`: A unique identifier for the application using this persistence instance.
621
- */
622
- stats(): {
623
- version: string;
624
- id: string;
625
- };
626
- }
627
-
489
+ //#endregion
490
+ //#region src/store/logger.d.ts
491
+ type StoreLogger = SystemLogger;
492
+ declare function createStoreLogger(logger?: StoreLogger): StoreLogger;
493
+ //#endregion
494
+ //#region src/store/store.d.ts
628
495
  type ReactiveDataStoreOptions<T> = {
629
- timeout?: number;
630
- state?: T;
631
- persistence?: SimplePersistence<T>;
632
- deleteMarker?: symbol;
633
- options?: {
634
- persistenceMaxRetries?: number;
635
- persistenceRetryDelay?: number;
636
- };
496
+ timeout?: number;
497
+ state?: T;
498
+ persistence?: SimplePersistence<T>;
499
+ deleteMarker?: symbol;
500
+ logger?: StoreLogger;
501
+ options?: {
502
+ persistenceMaxRetries?: number;
503
+ persistenceRetryDelay?: number;
504
+ };
637
505
  };
638
506
  /**
639
507
  * Main ReactiveDataStore - a robust, type-safe state management solution.
@@ -644,204 +512,213 @@ type ReactiveDataStoreOptions<T> = {
644
512
  * @template T The type of the data object managed by the store.
645
513
  */
646
514
  declare class ReactiveDataStore<T extends object> implements DataStore<T> {
647
- /** Manages the core application state. */
648
- private coreState;
649
- /** Orchestrates and executes middleware for state changes. */
650
- private middlewareEngine;
651
- /** Manages saving state changes to a persistence layer. */
652
- private persistenceHandler;
653
- /** Manages atomic state updates via transactions. */
654
- private transactionManager;
655
- /** Collects and provides performance metrics for the store. */
656
- private metricsCollector;
657
- private selectorManager;
658
- private actions;
659
- /**
660
- * Serializer enforces FIFO serial execution of all state updates.
661
- *
662
- * Replaces the bare `Promise<T | void>` chain. Benefits over the old pattern:
663
- * - Backpressure: rejects when the queue exceeds capacity rather than growing
664
- * unboundedly under write pressure.
665
- * - Clean shutdown: `close()` in dispose() immediately rejects any subsequent
666
- * `set()` calls with a clear error instead of silently enqueuing them.
667
- * - Observability: `updateSerializer.running()` and `updateSerializer.pending()`
668
- * replace the manually-managed `executionState.executing` flag.
669
- * - Error isolation: errors in one update do not corrupt the queue — the
670
- * Serializer's mutex is always released in its own `finally` block.
671
- */
672
- private updateSerializer;
673
- /**
674
- * Latch that opens once the store is fully initialised (persistence loaded).
675
- *
676
- * Replaces the poll-only `isReady(): boolean` pattern. Callers can now
677
- * `await store.ready()` with an optional timeout rather than polling or
678
- * subscribing to an internal event. `isReady()` is preserved as `latch.isOpen()`
679
- * for synchronous checks and backwards compatibility.
680
- */
681
- private readyLatch;
682
- private disposeOnce;
683
- private updateBus;
684
- private eventBus;
685
- private executionState;
686
- private instanceID;
687
- private merge;
688
- private diff;
689
- /**
690
- * Creates a new ReactiveDataStore instance.
691
- */
692
- constructor(initialData: T, persistence?: SimplePersistence<T>, deleteMarker?: symbol, options?: {
693
- persistenceMaxRetries?: number;
694
- persistenceRetryDelay?: number;
695
- broadcastChannel?: string;
696
- });
697
- /**
698
- * Returns true if the store has finished initialising (persistence loaded).
699
- * For async flows, prefer `await store.ready()` over polling this.
700
- */
701
- isReady(): boolean;
702
- /**
703
- * Returns a promise that resolves once the store is fully initialised.
704
- * Safe to call multiple times — all callers share the same latch.
705
- *
706
- * @param timeout - Optional maximum wait time in milliseconds.
707
- * @throws {TimeoutError} If the store does not become ready within the timeout.
708
- *
709
- * @example
710
- * await store.ready();
711
- * const state = store.get();
712
- */
713
- ready(timeout?: number): Promise<void>;
714
- state(): Readonly<StoreExecutionState<T>>;
715
- /**
716
- * Gets the current state. Optimized default to return reference (false) for performance.
717
- * @param clone If `true`, returns a deep clone (use sparingly).
718
- * @returns The current state object.
719
- */
720
- get(clone?: boolean): T;
721
- subset<K extends Record<string, any>>(paths: Array<string>, separator?: string): K;
722
- select<S>(selector: (state: T) => S): ReactiveSelector<S>;
723
- register<R extends any[]>(action: {
724
- name: string;
725
- fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
726
- debounce?: {
727
- delay: number;
728
- condition?: (previous: R | undefined, current: R) => boolean;
729
- };
730
- }): () => void;
731
- dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
732
- /**
733
- * Enqueues a state update for serial execution.
734
- *
735
- * Uses a `Serializer` internally, which guarantees:
736
- * - FIFO ordering of all updates.
737
- * - No concurrent execution — each update waits for the previous to complete.
738
- * - Backpressure: throws if the queue exceeds capacity.
739
- * - Clean rejection after `dispose()`.
740
- *
741
- * @returns A Promise that resolves with the new state T.
742
- */
743
- set(update: StateUpdater<T>, options?: {
744
- force?: boolean;
745
- actionId?: string;
746
- }): Promise<T>;
747
- /**
748
- * Internal logic for performing a single, sequential state update.
749
- * Always called inside the Serializer — never call directly.
750
- */
751
- private _performUpdate;
752
- /**
753
- * Opens the readyLatch once the persistence layer signals it is ready.
754
- * The latch can only open once — subsequent `persistence:ready` events are no-ops.
755
- */
756
- private setupReadyLatch;
757
- private setupPersistenceListener;
758
- watch(path: string | Array<string>, callback: (state: T) => void, options?: SubscribeOptions): () => void;
759
- /**
760
- * Subscribes to execution‑status changes of a registered action.
761
- *
762
- * The provided callback is called **every time** the action transitions
763
- * between idle and running (i.e. on `action:start`, `action:complete`, or
764
- * `action:error` for the given name). The current status can also be read
765
- * synchronously with `isActionRunning(name)`.
766
- *
767
- * **Deferred listener teardown**
768
- * To avoid unnecessary churn when subscriptions are rapidly created and
769
- * destroyed, the underlying event listeners are not removed immediately
770
- * on unsubscribe. Instead, a *pending reset* is queued via `queueMicrotask`.
771
- * If a new subscription for the same action arrives before that microtask
772
- * executes, the reset is silently cancelled and the already‑established
773
- * listeners are reused. This keeps the subscription infrastructure stable
774
- * and prevents cascading notifications that could otherwise arise from
775
- * repeated subscribe‑unsubscribe‑subscribe cycles.
776
- *
777
- * @param name - The name of the action to watch.
778
- * @returns ActionWatcher
779
- */
780
- watchAction(name: string): ActionWatcher;
781
- /**
782
- * Creates a debounced version of `set()` using a `Debouncer`.
783
- *
784
- * Useful for high-frequency write sources (e.g. text input, scroll position)
785
- * where you want to collapse rapid updates into a single state write after a
786
- * quiet period.
787
- *
788
- * @param delay - Quiet period in milliseconds before the update is applied.
789
- * @param leading - If true, also applies the first update immediately.
790
- * @returns A debounced setter function with the same signature as `set()`.
791
- *
792
- * @example
793
- * const debouncedSet = store.debouncedSetter({ delay: 200 });
794
- * inputEl.addEventListener("input", (e) => {
795
- * debouncedSet((s) => ({ ...s, query: e.target.value }));
796
- * });
797
- */
798
- debouncedSetter(options: {
799
- delay: number;
800
- leading?: boolean;
801
- }): (update: StateUpdater<T>, setOptions?: {
802
- force?: boolean;
803
- actionId?: string;
804
- }) => void;
805
- id(): string;
806
- transaction<R>(operation: () => R | Promise<R>, options?: TransactionOptions): Promise<R>;
807
- use(props: MiddlewareConfig<T>): () => boolean;
808
- metrics(): StoreMetrics;
809
- on(event: StoreEvent, listener: (data: any) => void): () => void;
810
- getPersistenceStatus(): {
811
- queueSize: number;
812
- isProcessing: boolean;
813
- pendingRetries: number;
814
- oldestTask?: number;
515
+ /** Manages the core application state. */
516
+ private coreState;
517
+ /** Orchestrates and executes middleware for state changes. */
518
+ private middlewareEngine;
519
+ /** Manages saving state changes to a persistence layer. */
520
+ private persistenceHandler;
521
+ /** Manages atomic state updates via transactions. */
522
+ private transactionManager;
523
+ /** Collects and provides performance metrics for the store. */
524
+ private metricsCollector;
525
+ private selectorManager;
526
+ private actions;
527
+ /**
528
+ * Serializer enforces FIFO serial execution of all state updates.
529
+ *
530
+ * Replaces the bare `Promise<T | void>` chain. Benefits over the old pattern:
531
+ * - Backpressure: rejects when the queue exceeds capacity rather than growing
532
+ * unboundedly under write pressure.
533
+ * - Clean shutdown: `close()` in dispose() immediately rejects any subsequent
534
+ * `set()` calls with a clear error instead of silently enqueuing them.
535
+ * - Observability: `updateSerializer.running()` and `updateSerializer.pending()`
536
+ * replace the manually-managed `executionState.executing` flag.
537
+ * - Error isolation: errors in one update do not corrupt the queue — the
538
+ * Serializer's mutex is always released in its own `finally` block.
539
+ */
540
+ private updateSerializer;
541
+ /**
542
+ * Latch that opens once the store is fully initialised (persistence loaded).
543
+ *
544
+ * Replaces the poll-only `isReady(): boolean` pattern. Callers can now
545
+ * `await store.ready()` with an optional timeout rather than polling or
546
+ * subscribing to an internal event. `isReady()` is preserved as `latch.isOpen()`
547
+ * for synchronous checks and backwards compatibility.
548
+ */
549
+ private readyLatch;
550
+ private disposeOnce;
551
+ private updateBus;
552
+ private eventBus;
553
+ private executionState;
554
+ private instanceID;
555
+ private merge;
556
+ private diff;
557
+ private logger;
558
+ /**
559
+ * Creates a new ReactiveDataStore instance.
560
+ */
561
+ constructor(initialData: T, persistence?: SimplePersistence<T>, deleteMarker?: symbol, options?: {
562
+ persistenceMaxRetries?: number;
563
+ persistenceRetryDelay?: number;
564
+ broadcastChannel?: string;
565
+ logger?: StoreLogger;
566
+ });
567
+ /**
568
+ * Returns true if the store has finished initialising (persistence loaded).
569
+ * For async flows, prefer `await store.ready()` over polling this.
570
+ */
571
+ isReady(): boolean;
572
+ /**
573
+ * Returns a promise that resolves once the store is fully initialised.
574
+ * Safe to call multiple times all callers share the same latch.
575
+ *
576
+ * @param timeout - Optional maximum wait time in milliseconds.
577
+ * @throws {TimeoutError} If the store does not become ready within the timeout.
578
+ *
579
+ * @example
580
+ * await store.ready();
581
+ * const state = store.get();
582
+ */
583
+ ready(timeout?: number): Promise<void>;
584
+ state(): Readonly<StoreExecutionState<T>>;
585
+ /**
586
+ * Gets the current state. Optimized default to return reference (false) for performance.
587
+ * @param clone If `true`, returns a deep clone (use sparingly).
588
+ * @returns The current state object.
589
+ */
590
+ get(clone?: boolean): T;
591
+ subset<K extends Record<string, any>>(paths: Array<string>, separator?: string): K;
592
+ select<S>(selector: (state: T) => S): ReactiveSelector<S>;
593
+ register<R extends any[]>(action: {
594
+ name: string;
595
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
596
+ debounce?: {
597
+ delay: number;
598
+ condition?: (previous: R | undefined, current: R) => boolean;
815
599
  };
816
- flush(): Promise<void>;
817
- /**
818
- * Discards all pending persistence tasks.
819
- * WARNING: Any queued writes not yet persisted will be lost.
820
- * Call flushPersistence() first if writes must not be lost.
821
- */
822
- discardPersistenceQueue(): void;
823
- /**
824
- * Disposes the store and all owned resources.
825
- *
826
- * Closes the update Serializer — any `set()` calls after dispose() will
827
- * reject immediately with `SerializerExecutionDone` rather than silently
828
- * enqueuing work against a dead store.
829
- */
830
- dispose(): Promise<void>;
831
- private checkDisposed;
832
- disposed(): boolean;
833
- private emit;
600
+ }): () => void;
601
+ dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
602
+ /**
603
+ * Enqueues a state update for serial execution.
604
+ *
605
+ * Uses a `Serializer` internally, which guarantees:
606
+ * - FIFO ordering of all updates.
607
+ * - No concurrent execution — each update waits for the previous to complete.
608
+ * - Backpressure: throws if the queue exceeds capacity.
609
+ * - Clean rejection after `dispose()`.
610
+ *
611
+ * @returns A Promise that resolves with the new state T.
612
+ */
613
+ set(update: StateUpdater<T>, options?: {
614
+ force?: boolean;
615
+ actionId?: string;
616
+ }): Promise<T>;
617
+ /**
618
+ * Internal logic for performing a single, sequential state update.
619
+ * Always called inside the Serializer — never call directly.
620
+ */
621
+ private _performUpdate;
622
+ /**
623
+ * Opens the readyLatch once the persistence layer signals it is ready.
624
+ * The latch can only open once — subsequent `persistence:ready` events are no-ops.
625
+ */
626
+ private setupReadyLatch;
627
+ private setupPersistenceListener;
628
+ watch(path: string | Array<string>, callback: (state: T) => void, options?: SubscribeOptions): () => void;
629
+ /**
630
+ * Subscribes to execution‑status changes of a registered action.
631
+ *
632
+ * The provided callback is called **every time** the action transitions
633
+ * between idle and running (i.e. on `action:start`, `action:complete`, or
634
+ * `action:error` for the given name). The current status can also be read
635
+ * synchronously with `isActionRunning(name)`.
636
+ *
637
+ * **Deferred listener teardown**
638
+ * To avoid unnecessary churn when subscriptions are rapidly created and
639
+ * destroyed, the underlying event listeners are not removed immediately
640
+ * on unsubscribe. Instead, a *pending reset* is queued via `queueMicrotask`.
641
+ * If a new subscription for the same action arrives before that microtask
642
+ * executes, the reset is silently cancelled and the already‑established
643
+ * listeners are reused. This keeps the subscription infrastructure stable
644
+ * and prevents cascading notifications that could otherwise arise from
645
+ * repeated subscribe‑unsubscribe‑subscribe cycles.
646
+ *
647
+ * @param name - The name of the action to watch.
648
+ * @returns ActionWatcher
649
+ */
650
+ watchAction(name: string): {
651
+ name: string;
652
+ status: () => boolean;
653
+ subscribe: (_: () => void) => () => void;
654
+ };
655
+ /**
656
+ * Creates a debounced version of `set()` using a `Debouncer`.
657
+ *
658
+ * Useful for high-frequency write sources (e.g. text input, scroll position)
659
+ * where you want to collapse rapid updates into a single state write after a
660
+ * quiet period.
661
+ *
662
+ * @param delay - Quiet period in milliseconds before the update is applied.
663
+ * @param leading - If true, also applies the first update immediately.
664
+ * @returns A debounced setter function with the same signature as `set()`.
665
+ *
666
+ * @example
667
+ * const debouncedSet = store.debouncedSetter({ delay: 200 });
668
+ * inputEl.addEventListener("input", (e) => {
669
+ * debouncedSet((s) => ({ ...s, query: e.target.value }));
670
+ * });
671
+ */
672
+ debouncedSetter(options: {
673
+ delay: number;
674
+ leading?: boolean;
675
+ }): (update: StateUpdater<T>, setOptions?: {
676
+ force?: boolean;
677
+ actionId?: string;
678
+ }) => void;
679
+ id(): string;
680
+ transaction<R>(operation: () => R | Promise<R>, options?: TransactionOptions): Promise<R>;
681
+ use(props: MiddlewareConfig<T>): () => boolean;
682
+ metrics(): StoreMetrics;
683
+ on(event: StoreEvent, listener: (data: any) => void): () => void;
684
+ getPersistenceStatus(): {
685
+ queueSize: number;
686
+ isProcessing: boolean;
687
+ pendingRetries: number;
688
+ oldestTask?: number;
689
+ };
690
+ flush(): Promise<void>;
691
+ /**
692
+ * Discards all pending persistence tasks.
693
+ * WARNING: Any queued writes not yet persisted will be lost.
694
+ * Call flushPersistence() first if writes must not be lost.
695
+ */
696
+ discardPersistenceQueue(): void;
697
+ /**
698
+ * Disposes the store and all owned resources.
699
+ *
700
+ * Closes the update Serializer — any `set()` calls after dispose() will
701
+ * reject immediately with `SerializerExecutionDone` rather than silently
702
+ * enqueuing work against a dead store.
703
+ */
704
+ dispose(): Promise<void>;
705
+ private checkDisposed;
706
+ disposed(): boolean;
707
+ private emit;
834
708
  }
835
-
709
+ //#endregion
710
+ //#region src/store/registry.d.ts
836
711
  /**
837
712
  * Configuration options for the StoreRegistry.
838
713
  */
839
714
  interface StoreRegistryOptions {
840
- /**
841
- * Optional callback fired when a store is actively garbage collected.
842
- * Highly recommended for production telemetry and memory leak debugging.
843
- */
844
- onEvict?: (storeId: string) => void;
715
+ /**
716
+ * Optional callback fired when a store is actively garbage collected.
717
+ * Highly recommended for production telemetry and memory leak debugging.
718
+ */
719
+ onEvict?: (storeId: string) => void;
720
+ /** Optional logger instance. Defaults to no-op. */
721
+ logger?: StoreLogger;
845
722
  }
846
723
  /**
847
724
  * A memory-safe, single-flight registry for ReactiveDataStores.
@@ -849,109 +726,106 @@ interface StoreRegistryOptions {
849
726
  * when no longer in use, automatically cleaning up internal references.
850
727
  */
851
728
  declare class StoreRegistry<S extends object> {
852
- private readonly stores;
853
- private readonly storeToOnce;
854
- private readonly finalizer;
855
- private readonly onEvict?;
856
- constructor(options?: StoreRegistryOptions);
857
- /**
858
- * Get an existing store for storeId, or create a new one via an always-cached Once primitive.
859
- * Ensures only one instantiation occurs even under concurrent calls.
860
- * * @param storeId - Unique identifier for the store.
861
- * @param initialState - The initial state to seed the store if it is created.
862
- * @param timeout - Optional timeout (ms) for store initialization.
863
- */
864
- get(storeId: string, options?: ReactiveDataStoreOptions<S>): Promise<ReactiveDataStore<S>>;
865
- getSync(storeId: string, options?: ReactiveDataStoreOptions<S>): ReactiveDataStore<S>;
866
- /**
867
- * Manually remove a store registry entry, unregistering its finalizer and disposing it.
868
- * @param storeId - Unique identifier for the store.
869
- * @returns True if a store was actively removed, false otherwise.
870
- */
871
- release(storeId: string): Promise<boolean>;
872
- /**
873
- * Clears all stores from the registry, disposes them, and unregisters all finalizers.
874
- */
875
- clear(): Promise<void>;
876
- /**
877
- * Get the store if it exists and has successfully finished initialization.
878
- * Does not trigger initialization if the store is missing or pending.
879
- */
880
- has(storeId: string): boolean;
881
- /**
882
- * Returns the current number of tracked stores.
883
- * Note: This includes entries that may have lost external references but haven't been GC'd yet.
884
- */
885
- get size(): number;
729
+ private readonly stores;
730
+ private readonly storeToOnce;
731
+ private readonly finalizer;
732
+ private readonly onEvict?;
733
+ private readonly logger;
734
+ constructor(options?: StoreRegistryOptions);
735
+ /**
736
+ * Get an existing store for storeId, or create a new one via an always-cached Once primitive.
737
+ * Ensures only one instantiation occurs even under concurrent calls.
738
+ * * @param storeId - Unique identifier for the store.
739
+ * @param initialState - The initial state to seed the store if it is created.
740
+ * @param timeout - Optional timeout (ms) for store initialization.
741
+ */
742
+ get(storeId: string, options?: ReactiveDataStoreOptions<S>): Promise<ReactiveDataStore<S>>;
743
+ getSync(storeId: string, options?: ReactiveDataStoreOptions<S>): ReactiveDataStore<S>;
744
+ /**
745
+ * Manually remove a store registry entry, unregistering its finalizer and disposing it.
746
+ * @param storeId - Unique identifier for the store.
747
+ * @returns True if a store was actively removed, false otherwise.
748
+ */
749
+ release(storeId: string): Promise<boolean>;
750
+ /**
751
+ * Clears all stores from the registry, disposes them, and unregisters all finalizers.
752
+ */
753
+ clear(): Promise<void>;
754
+ /**
755
+ * Get the store if it exists and has successfully finished initialization.
756
+ * Does not trigger initialization if the store is missing or pending.
757
+ */
758
+ has(storeId: string): boolean;
759
+ /**
760
+ * Returns the current number of tracked stores.
761
+ * Note: This includes entries that may have lost external references but haven't been GC'd yet.
762
+ */
763
+ get size(): number;
886
764
  }
887
-
888
- /**
889
- * @fileoverview Store Observer Module
890
- * @description A comprehensive module to add advanced debugging, observability, and time-travel
891
- * capabilities to a ReactiveDataStore. All console logging is centralized to respect a 'silent' flag,
892
- * preventing test runner output pollution.
893
- */
894
-
765
+ //#endregion
766
+ //#region src/store/observer.d.ts
895
767
  /**
896
768
  * @interface DebugEvent
897
769
  * @description Interface for the structure of a recorded debug event.
898
770
  */
899
771
  interface DebugEvent {
900
- /** The type of store event (e.g., 'update:start', 'action:complete'). */
901
- type: string;
902
- /** The timestamp when the event occurred. */
903
- timestamp: number;
904
- /** The raw data payload associated with the event, including actionId where applicable. */
905
- data: any;
772
+ /** The type of store event (e.g., 'update:start', 'action:complete'). */
773
+ type: string;
774
+ /** The timestamp when the event occurred. */
775
+ timestamp: number;
776
+ /** The raw data payload associated with the event, including actionId where applicable. */
777
+ data: any;
906
778
  }
907
779
  /**
908
780
  * @interface Snapshot
909
781
  * @description Represents a rich snapshot of the state at a point in time for history tracking.
910
782
  */
911
783
  interface Snapshot<T> {
912
- /** The complete state object at the time of the snapshot. */
913
- state: T;
914
- /** The timestamp of the state change. */
915
- timestamp: number;
916
- /** The list of changes (deltas) that resulted in this state. */
917
- deltas: StateDelta[];
784
+ /** The complete state object at the time of the snapshot. */
785
+ state: T;
786
+ /** The timestamp of the state change. */
787
+ timestamp: number;
788
+ /** The list of changes (deltas) that resulted in this state. */
789
+ deltas: StateDelta[];
918
790
  }
919
791
  /**
920
792
  * @interface ObserverSessionData
921
793
  * @description Defines the data structure for a saved observer session.
922
794
  */
923
795
  interface ObserverSessionData<T extends object> {
924
- /** The chronological history of debug events. */
925
- eventHistory: DebugEvent[];
926
- /** The chronological history of state snapshots. */
927
- stateHistory: Snapshot<T>[];
796
+ /** The chronological history of debug events. */
797
+ eventHistory: DebugEvent[];
798
+ /** The chronological history of state snapshots. */
799
+ stateHistory: Snapshot<T>[];
928
800
  }
929
801
  /**
930
802
  * @interface ObserverOptions
931
803
  * @description Configuration options for the observer module.
932
804
  */
933
805
  interface ObserverOptions {
934
- /** Maximum number of events to retain in memory. Defaults to 500. */
935
- maxEvents?: number;
936
- /** Enables or disables console logging for all events (overridden by 'silent'). Defaults to false. */
937
- enableConsoleLogging?: boolean;
938
- /** Maximum number of state snapshots to retain for time-travel. Defaults to 20. */
939
- maxStateHistory?: number;
940
- /** Fine-grained control over which event types are logged to the console. */
941
- logEvents?: {
942
- updates?: boolean;
943
- middleware?: boolean;
944
- transactions?: boolean;
945
- actions?: boolean;
946
- selectors?: boolean;
947
- };
948
- /** Performance thresholds for triggering console warnings. Values are in milliseconds (ms). */
949
- performanceThresholds?: {
950
- updateTime?: number;
951
- middlewareTime?: number;
952
- };
953
- /** If true, suppresses all console output and logging regardless of other options. Defaults to false. */
954
- silent?: boolean;
806
+ /** Maximum number of events to retain in memory. Defaults to 500. */
807
+ maxEvents?: number;
808
+ /** Enables or disables console logging for all events (overridden by 'silent'). Defaults to false. */
809
+ enableConsoleLogging?: boolean;
810
+ /** Maximum number of state snapshots to retain for time-travel. Defaults to 20. */
811
+ maxStateHistory?: number;
812
+ /** Fine-grained control over which event types are logged to the console. */
813
+ logEvents?: {
814
+ updates?: boolean;
815
+ middleware?: boolean;
816
+ transactions?: boolean;
817
+ actions?: boolean;
818
+ selectors?: boolean;
819
+ };
820
+ /** Performance thresholds for triggering console warnings. Values are in milliseconds (ms). */
821
+ performanceThresholds?: {
822
+ updateTime?: number;
823
+ middlewareTime?: number;
824
+ };
825
+ /** If true, suppresses all console output and logging regardless of other options. Defaults to false. */
826
+ silent?: boolean;
827
+ /** Optional logger instance. Defaults to no-op. */
828
+ logger?: StoreLogger;
955
829
  }
956
830
  /**
957
831
  * @class StoreObserver
@@ -959,177 +833,179 @@ interface ObserverOptions {
959
833
  * @template T The type of the store's state object.
960
834
  */
961
835
  declare class StoreObserver<T extends object> {
962
- protected store: DataStore<T>;
963
- private eventHistory;
964
- private stateHistory;
965
- private unsubscribers;
966
- private isTimeTraveling;
967
- private devTools;
968
- private middlewareExecutions;
969
- private activeTransactionCount;
970
- private activeBatches;
971
- private maxEvents;
972
- private maxStateHistory;
973
- private enableConsoleLogging;
974
- private isSilent;
975
- private logEvents;
976
- private performanceThresholds;
977
- /**
978
- * @param store The DataStore instance to observe.
979
- * @param options Configuration options for the observer.
980
- */
981
- constructor(store: DataStore<T>, options?: ObserverOptions);
982
- /**
983
- * @private
984
- * Centralized logging method. All console output must go through here to respect the `isSilent` flag.
985
- * @param method The console method to call ('log', 'warn', 'error', 'group', 'groupEnd', 'table', 'debug').
986
- * @param args Arguments to pass to the console method.
987
- */
988
- private _consoleLog;
989
- /**
990
- * @private
991
- * Sets up listeners for all relevant store events.
992
- */
993
- private setupEventListeners;
994
- /**
995
- * @private
996
- * Records a new state snapshot and manages the state history limit.
997
- * @param deltas The state changes that led to this snapshot.
998
- */
999
- private recordStateSnapshot;
1000
- /**
1001
- * @private
1002
- * Records a debug event and manages the event history limit.
1003
- * @param type The type of event.
1004
- * @param data The data payload of the event.
1005
- */
1006
- private recordEvent;
1007
- /**
1008
- * Returns a cloned copy of the recorded event history.
1009
- * @returns Array of debug events.
1010
- */
1011
- getEventHistory(): DebugEvent[];
1012
- /**
1013
- * Returns a cloned copy of the recorded state history (snapshots).
1014
- * @returns Array of state snapshots.
1015
- */
1016
- getStateHistory(): Snapshot<T>[];
1017
- /**
1018
- * Returns middleware execution history from the state.
1019
- * @returns Array of middleware executions.
1020
- */
1021
- getMiddlewareExecutions(): MiddlewareExecution[];
1022
- /**
1023
- * Returns current transaction status.
1024
- * @returns Object with transaction status information.
1025
- */
1026
- getTransactionStatus(): {
1027
- activeTransactions: number;
1028
- activeBatches: string[];
1029
- };
1030
- /**
1031
- * Creates a standard middleware that logs all updates.
1032
- * NOTE: This is user-defined middleware and uses native console methods,
1033
- * so its output is independent of the observer's `silent` flag.
1034
- * @param options Options for the logging middleware.
1035
- * @returns A middleware function.
1036
- */
1037
- createLoggingMiddleware(options?: {
1038
- logLevel?: "debug" | "info" | "warn";
1039
- logUpdates?: boolean;
1040
- }): (state: T, update: DeepPartial<T>) => DeepPartial<T>;
1041
- /**
1042
- * Creates a middleware that validates updates against a schema.
1043
- * Uses the internal `_consoleLog` for warnings.
1044
- * @param validator Function that validates updates.
1045
- * @returns A blocking middleware function.
1046
- */
1047
- createValidationMiddleware(validator: (state: T, update: DeepPartial<T>) => boolean | {
1048
- valid: boolean;
1049
- reason?: string;
1050
- }): (state: T, update: DeepPartial<T>) => boolean;
1051
- /**
1052
- * Returns a simplified view of recent state changes.
1053
- * @param limit Maximum number of state changes to compare. Defaults to 5.
1054
- * @returns Array of state difference objects.
1055
- */
1056
- getRecentChanges(limit?: number): Array<{
1057
- timestamp: number;
1058
- changedPaths: string[];
1059
- from: Partial<T>;
1060
- to: Partial<T>;
1061
- }>;
1062
- /**
1063
- * Clears both the event and state history, preserving only the initial state snapshot.
1064
- */
1065
- clearHistory(): void;
1066
- /**
1067
- * Filters and returns events related to a specific action ID.
1068
- * @param actionId The ID of the action to filter by.
1069
- * @returns Array of debug events associated with the action.
1070
- */
1071
- getHistoryForAction(actionId: string): DebugEvent[];
1072
- /**
1073
- * Attempts to replay a state update from history using the recorded update payload.
1074
- * @param eventIndex The index of the replayable event (an "update:start" event) in the history array.
1075
- */
1076
- replay(eventIndex: number): Promise<void>;
1077
- /**
1078
- * Creates a time-travel utility object with undo/redo capabilities.
1079
- * @returns An object with methods for time-travel navigation.
1080
- */
1081
- createTimeTravel(): {
1082
- canUndo: () => boolean;
1083
- canRedo: () => boolean;
1084
- undo: () => Promise<void>;
1085
- redo: () => Promise<void>;
1086
- length: () => number;
1087
- clear: () => void;
1088
- };
1089
- /**
1090
- * Saves the current observer session (events and state history) using a persistence mechanism.
1091
- * @param persistence An object implementing the SimplePersistence interface.
1092
- * @returns A promise that resolves to true if the session was saved successfully.
1093
- */
1094
- saveSession(persistence: SimplePersistence<ObserverSessionData<T>>): Promise<boolean>;
1095
- /**
1096
- * Loads a previously saved observer session and restores the state to the latest saved snapshot.
1097
- * @param persistence An object implementing the SimplePersistence interface.
1098
- * @returns A promise that resolves to true if a session was loaded.
1099
- */
1100
- loadSession(persistence: SimplePersistence<ObserverSessionData<T>>): Promise<boolean>;
1101
- /**
1102
- * Exports the current session data as a JSON file, initiating a browser download.
1103
- */
1104
- exportSession(): void;
1105
- /**
1106
- * Imports a session from a JSON file, restoring event history and state.
1107
- * @param file The file object (e.g., from an <input type="file"> event) to import.
1108
- * @returns A promise that resolves when the import is complete.
1109
- */
1110
- importSession(file: File): Promise<void>;
1111
- /**
1112
- * Cleans up the observer by unsubscribing all event listeners and clearing history.
1113
- */
1114
- disconnect(): void;
1115
- /**
1116
- * @private
1117
- * Logs an event to the console with appropriate formatting.
1118
- * Uses `this._consoleLog` for all output.
1119
- * @param type Event type.
1120
- * @param data Event data.
1121
- */
1122
- private _log;
1123
- /**
1124
- * @private
1125
- * Checks for performance issues in the events.
1126
- * Uses `this._consoleLog` for all output.
1127
- * @param type Event type.
1128
- * @param data Event data.
1129
- */
1130
- private _checkPerformance;
836
+ protected store: DataStore<T>;
837
+ private eventHistory;
838
+ private stateHistory;
839
+ private unsubscribers;
840
+ private isTimeTraveling;
841
+ private devTools;
842
+ private middlewareExecutions;
843
+ private activeTransactionCount;
844
+ private activeBatches;
845
+ private maxEvents;
846
+ private maxStateHistory;
847
+ private enableConsoleLogging;
848
+ private isSilent;
849
+ private logEvents;
850
+ private performanceThresholds;
851
+ private logger;
852
+ /**
853
+ * @param store The DataStore instance to observe.
854
+ * @param options Configuration options for the observer.
855
+ */
856
+ constructor(store: DataStore<T>, options?: ObserverOptions);
857
+ /**
858
+ * @private
859
+ * Centralized logging method. Routes to the structured logger for level-based calls
860
+ * (log, warn, error, debug) and to raw console for group/table calls which have no
861
+ * logger equivalent. Respects the `isSilent` flag.
862
+ * @param method The console method to call ('log', 'warn', 'error', 'group', 'groupEnd', 'table', 'debug').
863
+ * @param args Arguments to pass to the console/log method.
864
+ */
865
+ private _consoleLog;
866
+ /**
867
+ * @private
868
+ * Sets up listeners for all relevant store events.
869
+ */
870
+ private setupEventListeners;
871
+ /**
872
+ * @private
873
+ * Records a new state snapshot and manages the state history limit.
874
+ * @param deltas The state changes that led to this snapshot.
875
+ */
876
+ private recordStateSnapshot;
877
+ /**
878
+ * @private
879
+ * Records a debug event and manages the event history limit.
880
+ * @param type The type of event.
881
+ * @param data The data payload of the event.
882
+ */
883
+ private recordEvent;
884
+ /**
885
+ * Returns a cloned copy of the recorded event history.
886
+ * @returns Array of debug events.
887
+ */
888
+ getEventHistory(): DebugEvent[];
889
+ /**
890
+ * Returns a cloned copy of the recorded state history (snapshots).
891
+ * @returns Array of state snapshots.
892
+ */
893
+ getStateHistory(): Snapshot<T>[];
894
+ /**
895
+ * Returns middleware execution history from the state.
896
+ * @returns Array of middleware executions.
897
+ */
898
+ getMiddlewareExecutions(): MiddlewareExecution[];
899
+ /**
900
+ * Returns current transaction status.
901
+ * @returns Object with transaction status information.
902
+ */
903
+ getTransactionStatus(): {
904
+ activeTransactions: number;
905
+ activeBatches: string[];
906
+ };
907
+ /**
908
+ * Creates a standard middleware that logs all updates.
909
+ * @param options Options for the logging middleware.
910
+ * @returns A middleware function.
911
+ */
912
+ createLoggingMiddleware(options?: {
913
+ logLevel?: "debug" | "info" | "warn";
914
+ logUpdates?: boolean;
915
+ }): (state: T, update: DeepPartial<T>) => DeepPartial<T>;
916
+ /**
917
+ * Creates a middleware that validates updates against a schema.
918
+ * Uses the internal `_consoleLog` for warnings.
919
+ * @param validator Function that validates updates.
920
+ * @returns A blocking middleware function.
921
+ */
922
+ createValidationMiddleware(validator: (state: T, update: DeepPartial<T>) => boolean | {
923
+ valid: boolean;
924
+ reason?: string;
925
+ }): (state: T, update: DeepPartial<T>) => boolean;
926
+ /**
927
+ * Returns a simplified view of recent state changes.
928
+ * @param limit Maximum number of state changes to compare. Defaults to 5.
929
+ * @returns Array of state difference objects.
930
+ */
931
+ getRecentChanges(limit?: number): Array<{
932
+ timestamp: number;
933
+ changedPaths: string[];
934
+ from: Partial<T>;
935
+ to: Partial<T>;
936
+ }>;
937
+ /**
938
+ * Clears both the event and state history, preserving only the initial state snapshot.
939
+ */
940
+ clearHistory(): void;
941
+ /**
942
+ * Filters and returns events related to a specific action ID.
943
+ * @param actionId The ID of the action to filter by.
944
+ * @returns Array of debug events associated with the action.
945
+ */
946
+ getHistoryForAction(actionId: string): DebugEvent[];
947
+ /**
948
+ * Attempts to replay a state update from history using the recorded update payload.
949
+ * @param eventIndex The index of the replayable event (an "update:start" event) in the history array.
950
+ */
951
+ replay(eventIndex: number): Promise<void>;
952
+ /**
953
+ * Creates a time-travel utility object with undo/redo capabilities.
954
+ * @returns An object with methods for time-travel navigation.
955
+ */
956
+ createTimeTravel(): {
957
+ canUndo: () => boolean;
958
+ canRedo: () => boolean;
959
+ undo: () => Promise<void>;
960
+ redo: () => Promise<void>;
961
+ length: () => number;
962
+ clear: () => void;
963
+ };
964
+ /**
965
+ * Saves the current observer session (events and state history) using a persistence mechanism.
966
+ * @param persistence An object implementing the SimplePersistence interface.
967
+ * @returns A promise that resolves to true if the session was saved successfully.
968
+ */
969
+ saveSession(persistence: SimplePersistence$1<ObserverSessionData<T>>): Promise<boolean>;
970
+ /**
971
+ * Loads a previously saved observer session and restores the state to the latest saved snapshot.
972
+ * @param persistence An object implementing the SimplePersistence interface.
973
+ * @returns A promise that resolves to true if a session was loaded.
974
+ */
975
+ loadSession(persistence: SimplePersistence$1<ObserverSessionData<T>>): Promise<boolean>;
976
+ /**
977
+ * Exports the current session data as a JSON file, initiating a browser download.
978
+ */
979
+ exportSession(): void;
980
+ /**
981
+ * Imports a session from a JSON file, restoring event history and state.
982
+ * @param file The file object (e.g., from an <input type="file"> event) to import.
983
+ * @returns A promise that resolves when the import is complete.
984
+ */
985
+ importSession(file: File): Promise<void>;
986
+ /**
987
+ * Cleans up the observer by unsubscribing all event listeners and clearing history.
988
+ */
989
+ disconnect(): void;
990
+ /**
991
+ * @private
992
+ * Logs an event to the console with appropriate formatting.
993
+ * Uses `this._consoleLog` for all output.
994
+ * @param type Event type.
995
+ * @param data Event data.
996
+ */
997
+ private _log;
998
+ /**
999
+ * @private
1000
+ * Checks for performance issues in the events.
1001
+ * Uses `this._consoleLog` for all output.
1002
+ * @param type Event type.
1003
+ * @param data Event data.
1004
+ */
1005
+ private _checkPerformance;
1131
1006
  }
1132
-
1007
+ //#endregion
1008
+ //#region src/store/diff.d.ts
1133
1009
  /**
1134
1010
  * Creates a diff function with configurable options.
1135
1011
  *
@@ -1137,7 +1013,7 @@ declare class StoreObserver<T extends object> {
1137
1013
  * @param {symbol} [options.deleteMarker] - A custom symbol to mark properties for deletion.
1138
1014
  */
1139
1015
  declare function createDiff(options?: {
1140
- deleteMarker?: symbol;
1016
+ deleteMarker?: symbol;
1141
1017
  }): any;
1142
1018
  /**
1143
1019
  * Creates a derivePaths function with configurable options.
@@ -1146,7 +1022,7 @@ declare function createDiff(options?: {
1146
1022
  * @param {symbol} [options.deleteMarker=Symbol.for("delete")] - A custom symbol to mark properties for deletion.
1147
1023
  */
1148
1024
  declare function createDerivePaths(options?: {
1149
- deleteMarker?: symbol;
1025
+ deleteMarker?: symbol;
1150
1026
  }): <T>(changes: DeepPartial<T>) => string[];
1151
1027
  /**
1152
1028
  * @deprecated Use `createDiff()` instead.
@@ -1159,7 +1035,8 @@ type DiffFunction = ReturnType<typeof createDiff>;
1159
1035
  * Provided for backward compatibility with `Symbol.for("delete")` as the default delete marker.
1160
1036
  */
1161
1037
  declare const derivePaths: <T>(changes: DeepPartial<T>) => string[];
1162
-
1038
+ //#endregion
1039
+ //#region src/store/merge.d.ts
1163
1040
  /**
1164
1041
  * Creates a shallow clone of an object or array.
1165
1042
  */
@@ -1171,7 +1048,7 @@ declare const shallowClone: (obj: any) => any;
1171
1048
  * @param {symbol} [options.deleteMarker=Symbol.for("delete")] - A custom symbol to mark properties for deletion during merge.
1172
1049
  */
1173
1050
  declare function createMerge(options?: {
1174
- deleteMarker?: symbol;
1051
+ deleteMarker?: symbol;
1175
1052
  }): <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
1176
1053
  /**
1177
1054
  * @deprecated Use `createMerge()` instead.
@@ -1179,39 +1056,46 @@ declare function createMerge(options?: {
1179
1056
  */
1180
1057
  declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
1181
1058
  type MergeFunction = ReturnType<typeof createMerge>;
1182
-
1059
+ //#endregion
1060
+ //#region src/store/actions.d.ts
1183
1061
  declare class ActionCancelledError extends Error {
1184
- constructor();
1062
+ constructor();
1185
1063
  }
1186
1064
  declare class UnknownActionError extends Error {
1187
- constructor({ action }: {
1188
- action: string;
1189
- });
1065
+ constructor({
1066
+ action
1067
+ }: {
1068
+ action: string;
1069
+ });
1190
1070
  }
1191
1071
  declare class ActionManager<T extends object> {
1192
- private eventBus;
1193
- private set;
1194
- private registrations;
1195
- constructor(eventBus: EventBus<Record<StoreEvent, any>>, set: (update: StateUpdater<T>, options?: {
1196
- force?: boolean;
1197
- actionId?: string;
1198
- }) => Promise<any>);
1199
- register<R extends any[]>(action: {
1200
- name: string;
1201
- fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
1202
- debounce?: {
1203
- delay: number;
1204
- condition?: (previous: R | undefined, current: R) => boolean;
1205
- };
1206
- }): () => void;
1207
- dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
1208
- private executeAction;
1209
- running(name: string): boolean;
1210
- private subscribe;
1211
- watch(name: string): ActionWatcher;
1212
- private notifyStatusListeners;
1213
- private emit;
1214
- dispose(): void;
1072
+ private eventBus;
1073
+ private set;
1074
+ private registrations;
1075
+ constructor(eventBus: EventBus<Record<StoreEvent, any>>, set: (update: StateUpdater<T>, options?: {
1076
+ force?: boolean;
1077
+ actionId?: string;
1078
+ }) => Promise<any>);
1079
+ register<R extends any[]>(action: {
1080
+ name: string;
1081
+ fn: (state: T, ...args: R) => DeepPartial<T> | Promise<DeepPartial<T>>;
1082
+ debounce?: {
1083
+ delay: number;
1084
+ condition?: (previous: R | undefined, current: R) => boolean;
1085
+ };
1086
+ }): () => void;
1087
+ dispatch<R extends any[]>(name: string, ...params: R): Promise<T>;
1088
+ private executeAction;
1089
+ running(name: string): boolean;
1090
+ private subscribe;
1091
+ watch(name: string): {
1092
+ name: string;
1093
+ status: () => boolean;
1094
+ subscribe: (_: () => void) => () => void;
1095
+ };
1096
+ private notifyStatusListeners;
1097
+ private emit;
1098
+ dispose(): void;
1215
1099
  }
1216
-
1217
- export { ActionCancelledError, type ActionCompletePayload, type ActionErrorPayload, ActionManager, type ActionStartPayload, type ActionWatcher, 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 ReactiveDataStoreOptions, type ReactiveSelector, type SelectorAccessedPayload, type SelectorChangedPayload, type StateDelta, type StateUpdater, type StoreAction, type StoreEvent, type StoreEvents, type StoreExecutionState, type StoreMetrics, StoreObserver, StoreRegistry, type StoreRegistryOptions, type SubscribeOptions, type TransactionOptions, type TransformMiddleware, UnknownActionError, createDerivePaths, createDiff, createMerge, derivePaths, diff, merge, shallowClone };
1100
+ //#endregion
1101
+ export { ActionCancelledError, ActionCompletePayload, ActionErrorPayload, ActionManager, ActionStartPayload, ActionWatcher, BlockingMiddleware, DELETE_SYMBOL, DataStore, DeepPartial, DiffFunction, MergeFunction, Middleware, MiddlewareConfig, MiddlewareExecution, type ObserverOptions, PersistenceFailedPayload, PersistenceInitErrorPayload, PersistenceQueueClearedPayload, PersistenceQueuedPayload, PersistenceRetryPayload, PersistenceSuccessPayload, ReactiveDataStore, ReactiveDataStoreOptions, ReactiveSelector, SelectorAccessedPayload, SelectorChangedPayload, StateDelta, StateUpdater, StoreAction, StoreEvent, StoreEvents, StoreExecutionState, StoreLogger, StoreMetrics, StoreObserver, StoreRegistry, StoreRegistryOptions, type SubscribeOptions, TransactionOptions, TransformMiddleware, UnknownActionError, createDerivePaths, createDiff, createMerge, createStoreLogger, derivePaths, diff, merge, shallowClone };