@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.cts +1269 -0
- package/index.d.ts +856 -972
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +2 -1
- package/index.d.mts +0 -1217
package/index.d.ts
CHANGED
|
@@ -1,78 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
311
|
-
|
|
230
|
+
block: boolean;
|
|
231
|
+
error?: Error;
|
|
312
232
|
}> | boolean | {
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
354
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
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
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
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
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1062
|
+
constructor();
|
|
1185
1063
|
}
|
|
1186
1064
|
declare class UnknownActionError extends Error {
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1065
|
+
constructor({
|
|
1066
|
+
action
|
|
1067
|
+
}: {
|
|
1068
|
+
action: string;
|
|
1069
|
+
});
|
|
1190
1070
|
}
|
|
1191
1071
|
declare class ActionManager<T extends object> {
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
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,
|
|
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 };
|