@asaidimu/utils-remote-store 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.mts +231 -265
- package/index.d.ts +231 -265
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +2 -2
package/index.d.mts
CHANGED
|
@@ -1,5 +1,198 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface SimplePersistence<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Persists data to storage.
|
|
4
|
+
*
|
|
5
|
+
* @param id The **unique identifier of the *consumer instance*** making the change. This is NOT the ID of the data (`T`) itself.
|
|
6
|
+
* Think of it as the ID of the specific browser tab, component, or module that's currently interacting with the persistence layer.
|
|
7
|
+
* It should typically be a **UUID** generated once at the consumer instance's instantiation.
|
|
8
|
+
* 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.
|
|
9
|
+
* @param state The state (of type T) to persist. This state is generally considered the **global or shared state** that all instances interact with.
|
|
10
|
+
* @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations (like `IndexedDBPersistence`), this returns a `Promise<boolean>`.
|
|
11
|
+
*/
|
|
12
|
+
set(id: string, state: T): boolean | Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves the global persisted data from storage.
|
|
15
|
+
*
|
|
16
|
+
* @returns The retrieved state of type `T`, or `null` if no data is found or if an error occurs during retrieval/parsing.
|
|
17
|
+
* For asynchronous implementations, this returns a `Promise<T | null>`.
|
|
18
|
+
*/
|
|
19
|
+
get(): (T | null) | (Promise<T | null>);
|
|
20
|
+
/**
|
|
21
|
+
* 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).
|
|
22
|
+
*
|
|
23
|
+
* @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.
|
|
24
|
+
* @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.
|
|
25
|
+
* @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.
|
|
26
|
+
*/
|
|
27
|
+
subscribe(id: string, callback: (state: T) => void): () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Clears (removes) the entire global persisted data from storage.
|
|
30
|
+
*
|
|
31
|
+
* @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations, this returns a `Promise<boolean>`.
|
|
32
|
+
*/
|
|
33
|
+
clear(): boolean | Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Returns metadata about the persistence layer.
|
|
36
|
+
*
|
|
37
|
+
* This is useful for distinguishing between multiple apps running on the same host
|
|
38
|
+
* (e.g., several apps served at `localhost:3000` that share the same storage key).
|
|
39
|
+
*
|
|
40
|
+
* @returns An object containing:
|
|
41
|
+
* - `version`: The semantic version string of the persistence schema or application.
|
|
42
|
+
* - `id`: A unique identifier for the application using this persistence instance.
|
|
43
|
+
*/
|
|
44
|
+
stats(): {
|
|
45
|
+
version: string;
|
|
46
|
+
id: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface CacheOptions {
|
|
51
|
+
staleTime?: number;
|
|
52
|
+
cacheTime?: number;
|
|
53
|
+
retryAttempts?: number;
|
|
54
|
+
retryDelay?: number;
|
|
55
|
+
maxSize?: number;
|
|
56
|
+
enableMetrics?: boolean;
|
|
57
|
+
persistence?: SimplePersistence<SerializableCacheState>;
|
|
58
|
+
persistenceId?: string;
|
|
59
|
+
serializeValue?: (value: any) => any;
|
|
60
|
+
deserializeValue?: (value: any) => any;
|
|
61
|
+
persistenceDebounceTime?: number;
|
|
62
|
+
}
|
|
63
|
+
interface CacheMetrics {
|
|
64
|
+
hits: number;
|
|
65
|
+
misses: number;
|
|
66
|
+
fetches: number;
|
|
67
|
+
errors: number;
|
|
68
|
+
evictions: number;
|
|
69
|
+
staleHits: number;
|
|
70
|
+
}
|
|
71
|
+
interface SerializableCacheEntry {
|
|
72
|
+
data: any;
|
|
73
|
+
lastUpdated: number;
|
|
74
|
+
lastAccessed: number;
|
|
75
|
+
accessCount: number;
|
|
76
|
+
error?: {
|
|
77
|
+
name: string;
|
|
78
|
+
message: string;
|
|
79
|
+
stack?: string;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
type SerializableCacheState = Array<[string, SerializableCacheEntry]>;
|
|
83
|
+
type CacheEventBase<Type extends string, Payload = {}> = {
|
|
84
|
+
type: Type;
|
|
85
|
+
key: string;
|
|
86
|
+
timestamp: number;
|
|
87
|
+
} & Payload;
|
|
88
|
+
type CacheReadHitEvent<T = any> = CacheEventBase<'cache:read:hit', {
|
|
89
|
+
data: T;
|
|
90
|
+
isStale: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
type CacheReadMissEvent = CacheEventBase<'cache:read:miss'>;
|
|
93
|
+
type CacheFetchStartEvent = CacheEventBase<'cache:fetch:start', {
|
|
94
|
+
attempt: number;
|
|
95
|
+
}>;
|
|
96
|
+
type CacheFetchSuccessEvent<T = any> = CacheEventBase<'cache:fetch:success', {
|
|
97
|
+
data: T;
|
|
98
|
+
}>;
|
|
99
|
+
type CacheFetchErrorEvent = CacheEventBase<'cache:fetch:error', {
|
|
100
|
+
error: Error;
|
|
101
|
+
attempt: number;
|
|
102
|
+
}>;
|
|
103
|
+
type CacheDataEvictEvent = CacheEventBase<'cache:data:evict', {
|
|
104
|
+
reason?: string;
|
|
105
|
+
}>;
|
|
106
|
+
type CacheDataInvalidateEvent = CacheEventBase<'cache:data:invalidate'>;
|
|
107
|
+
type CacheDataSetEvent<T = any> = CacheEventBase<'cache:data:set', {
|
|
108
|
+
newData: T;
|
|
109
|
+
oldData?: T;
|
|
110
|
+
}>;
|
|
111
|
+
type CachePersistenceLoadSuccessEvent = CacheEventBase<'cache:persistence:load:success', {
|
|
112
|
+
message?: string;
|
|
113
|
+
}>;
|
|
114
|
+
type CachePersistenceLoadErrorEvent = CacheEventBase<'cache:persistence:load:error', {
|
|
115
|
+
message?: string;
|
|
116
|
+
error?: any;
|
|
117
|
+
}>;
|
|
118
|
+
type CachePersistenceSaveSuccessEvent = CacheEventBase<'cache:persistence:save:success'>;
|
|
119
|
+
type CachePersistenceSaveErrorEvent = CacheEventBase<'cache:persistence:save:error', {
|
|
120
|
+
message?: string;
|
|
121
|
+
error?: any;
|
|
122
|
+
}>;
|
|
123
|
+
type CachePersistenceClearSuccessEvent = CacheEventBase<'cache:persistence:clear:success'>;
|
|
124
|
+
type CachePersistenceClearErrorEvent = CacheEventBase<'cache:persistence:clear:error', {
|
|
125
|
+
message?: string;
|
|
126
|
+
error?: any;
|
|
127
|
+
}>;
|
|
128
|
+
type CachePersistenceSyncEvent = CacheEventBase<'cache:persistence:sync', {
|
|
129
|
+
message?: string;
|
|
130
|
+
}>;
|
|
131
|
+
type CacheEvent = CacheReadHitEvent | CacheReadMissEvent | CacheFetchStartEvent | CacheFetchSuccessEvent | CacheFetchErrorEvent | CacheDataEvictEvent | CacheDataInvalidateEvent | CacheDataSetEvent | CachePersistenceLoadSuccessEvent | CachePersistenceLoadErrorEvent | CachePersistenceSaveSuccessEvent | CachePersistenceSaveErrorEvent | CachePersistenceClearSuccessEvent | CachePersistenceClearErrorEvent | CachePersistenceSyncEvent;
|
|
132
|
+
type CacheEventType = CacheEvent['type'];
|
|
133
|
+
|
|
134
|
+
declare class QueryCache {
|
|
135
|
+
private cache;
|
|
136
|
+
private queries;
|
|
137
|
+
private fetching;
|
|
138
|
+
private readonly defaultOptions;
|
|
139
|
+
private metrics;
|
|
140
|
+
private eventBus;
|
|
141
|
+
private gcTimer?;
|
|
142
|
+
private readonly persistenceId;
|
|
143
|
+
private persistenceUnsubscribe?;
|
|
144
|
+
private persistenceDebounceTimer?;
|
|
145
|
+
private isHandlingRemoteUpdate;
|
|
146
|
+
constructor(defaultOptions?: CacheOptions);
|
|
147
|
+
private initializePersistence;
|
|
148
|
+
private serializeCache;
|
|
149
|
+
private deserializeAndLoadCache;
|
|
150
|
+
private schedulePersistState;
|
|
151
|
+
private handleRemoteStateChange;
|
|
152
|
+
registerQuery<T>(key: string, fetchFunction: () => Promise<T>, options?: CacheOptions): void;
|
|
153
|
+
get<T>(key: string, options?: {
|
|
154
|
+
waitForFresh?: boolean;
|
|
155
|
+
throwOnError?: boolean;
|
|
156
|
+
}): Promise<T | undefined>;
|
|
157
|
+
peek<T>(key: string): T | undefined;
|
|
158
|
+
has(key: string): boolean;
|
|
159
|
+
private fetch;
|
|
160
|
+
private fetchAndWait;
|
|
161
|
+
private performFetchWithRetry;
|
|
162
|
+
private isStale;
|
|
163
|
+
invalidate(key: string, refetch?: boolean): Promise<void>;
|
|
164
|
+
invalidatePattern(pattern: RegExp, refetch?: boolean): Promise<void>;
|
|
165
|
+
prefetch(key: string): Promise<void>;
|
|
166
|
+
refresh<T>(key: string): Promise<T | undefined>;
|
|
167
|
+
setData<T>(key: string, data: T): void;
|
|
168
|
+
remove(key: string): boolean;
|
|
169
|
+
private enforceSizeLimit;
|
|
170
|
+
private startGarbageCollection;
|
|
171
|
+
garbageCollect(): number;
|
|
172
|
+
getStats(): {
|
|
173
|
+
size: number;
|
|
174
|
+
metrics: CacheMetrics;
|
|
175
|
+
hitRate: number;
|
|
176
|
+
staleHitRate: number;
|
|
177
|
+
entries: Array<{
|
|
178
|
+
key: string;
|
|
179
|
+
lastAccessed: number;
|
|
180
|
+
lastUpdated: number;
|
|
181
|
+
accessCount: number;
|
|
182
|
+
isStale: boolean;
|
|
183
|
+
isLoading?: boolean;
|
|
184
|
+
error?: boolean;
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
187
|
+
on<EType extends CacheEventType>(event: EType, listener: (ev: Extract<CacheEvent, {
|
|
188
|
+
type: EType;
|
|
189
|
+
}>) => void): () => void;
|
|
190
|
+
private emitEvent;
|
|
191
|
+
private updateMetrics;
|
|
192
|
+
private delay;
|
|
193
|
+
clear(): Promise<void>;
|
|
194
|
+
destroy(): void;
|
|
195
|
+
}
|
|
3
196
|
|
|
4
197
|
interface StoreErrorDetails {
|
|
5
198
|
code: string;
|
|
@@ -205,7 +398,9 @@ interface PagedQueryResult<T> {
|
|
|
205
398
|
/** Function to fetch a specific page of data.
|
|
206
399
|
* @param page The page number to fetch.
|
|
207
400
|
*/
|
|
208
|
-
|
|
401
|
+
navigate: (page: number) => Promise<void>;
|
|
402
|
+
refresh: (delay?: number) => Promise<void>;
|
|
403
|
+
changeParams: (setter: (params: any) => any) => Promise<void>;
|
|
209
404
|
}
|
|
210
405
|
/**
|
|
211
406
|
* Represents a basic record in the remote store.
|
|
@@ -230,26 +425,6 @@ type PaginationInfo = {
|
|
|
230
425
|
* Represents the name of a resource in the store, e.g., 'todos', 'users'.
|
|
231
426
|
*/
|
|
232
427
|
type ResourceName = string;
|
|
233
|
-
/**
|
|
234
|
-
* Represents the reactive result of a single record query.
|
|
235
|
-
* @template T The type of the data being queried.
|
|
236
|
-
*/
|
|
237
|
-
interface ReactiveQueryResult<T> {
|
|
238
|
-
/** The current query result, including data, loading state, and errors. */
|
|
239
|
-
value: () => QueryResult<T>;
|
|
240
|
-
/** A function to subscribe to changes in the query result. Returns an unsubscribe function. */
|
|
241
|
-
onValueChange: (callback: () => void) => () => void;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Represents the reactive result of a paginated query (list or find).
|
|
245
|
-
* @template T The type of the records in the page.
|
|
246
|
-
*/
|
|
247
|
-
interface ReactivePagedQueryResult<T> {
|
|
248
|
-
/** The current paginated query result, including page data, loading state, and errors. */
|
|
249
|
-
value: () => PagedQueryResult<T>;
|
|
250
|
-
/** A function to subscribe to changes in the query result. Returns an unsubscribe function. */
|
|
251
|
-
onValueChange: (callback: () => void) => () => void;
|
|
252
|
-
}
|
|
253
428
|
/**
|
|
254
429
|
* Internal interface representing an active subscription to a query.
|
|
255
430
|
* @template T The type of the data being queried.
|
|
@@ -271,283 +446,80 @@ interface QuerySubscription<T> {
|
|
|
271
446
|
result: QueryResult<T> | PagedQueryResult<T>;
|
|
272
447
|
}
|
|
273
448
|
|
|
449
|
+
/**
|
|
450
|
+
* Represents the result of a store query with stable React integration.
|
|
451
|
+
* @template T The type of the result data.
|
|
452
|
+
*/
|
|
453
|
+
interface StoreResult<T extends Record<string, any> = Record<string, any>, V = QueryResult<T> | PagedQueryResult<T>> {
|
|
454
|
+
/** Function that returns the current query state */
|
|
455
|
+
value: () => V;
|
|
456
|
+
/** Function to subscribe to state changes */
|
|
457
|
+
onValueChange: (callback: () => void) => () => void;
|
|
458
|
+
}
|
|
274
459
|
/**
|
|
275
460
|
* A reactive remote store that provides cached and observable access to data
|
|
276
461
|
* from a `BaseStore`. It handles caching, invalidation, and real-time updates
|
|
277
462
|
* via server-sent events (SSE).
|
|
278
|
-
*
|
|
279
|
-
* @template T The type of the records managed by the store, extending Record.
|
|
280
|
-
* @template TFindOptions Options for the find operation.
|
|
281
|
-
* @template TReadOptions Options for the read operation.
|
|
282
|
-
* @template TListOptions Options for the list operation.
|
|
283
|
-
* @template TDeleteOptions Options for the delete operation.
|
|
284
|
-
* @template TUpdateOptions Options for the update operation.
|
|
285
|
-
* @template TCreateOptions Options for the create operation.
|
|
286
|
-
* @template TUploadOptions Options for the upload operation.
|
|
287
|
-
* @template TStreamOptions Options for the stream operation.
|
|
288
463
|
*/
|
|
289
464
|
declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<string, unknown>, TReadOptions = Record<string, unknown>, TListOptions = Record<string, unknown>, TDeleteOptions = Record<string, unknown>, TUpdateOptions = Record<string, unknown>, TCreateOptions = Record<string, unknown>, TUploadOptions = Record<string, unknown>, TStreamOptions = Record<string, unknown>> {
|
|
290
465
|
private cache;
|
|
291
466
|
private baseStore;
|
|
292
467
|
private correlator?;
|
|
293
468
|
private storeEventCorrelator?;
|
|
294
|
-
private
|
|
469
|
+
private queryStates;
|
|
470
|
+
private stableResults;
|
|
471
|
+
private stablePaginationMethods;
|
|
472
|
+
private errorCache;
|
|
295
473
|
private keyCache;
|
|
296
474
|
private unsubscribeFromBaseStore;
|
|
297
|
-
|
|
298
|
-
* Creates an instance of ReactiveRemoteStore.
|
|
299
|
-
* @param cache The QueryCache instance to use for caching data.
|
|
300
|
-
* @param baseStore The underlying BaseStore for actual data fetching and mutations.
|
|
301
|
-
* @param correlator Optional function to determine which queries to invalidate after a mutation.
|
|
302
|
-
* @param storeEventCorrelator Optional function to determine which queries to invalidate after a store event.
|
|
303
|
-
*/
|
|
475
|
+
private cacheEventCleanups;
|
|
304
476
|
constructor(cache: QueryCache, baseStore: BaseStore<T, TFindOptions, TReadOptions, TListOptions, TDeleteOptions, TUpdateOptions, TCreateOptions, TUploadOptions, TStreamOptions>, correlator?: Correlator | undefined, storeEventCorrelator?: StoreEventCorrelator | undefined);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* @template T The type of the data for the subscription.
|
|
308
|
-
* @param queryKey The unique key for the query.
|
|
309
|
-
* @param operation The operation type (e.g., 'read', 'list').
|
|
310
|
-
* @param params The parameters for the query.
|
|
311
|
-
* @param selector A function that returns the current query result.
|
|
312
|
-
* @param notificationCondition A function to determine if a cache event should trigger a notification.
|
|
313
|
-
* @returns The created QuerySubscription.
|
|
314
|
-
*/
|
|
315
|
-
private createSubscription;
|
|
316
|
-
/**
|
|
317
|
-
* Retrieves an existing subscription or creates a new one if it doesn't exist.
|
|
318
|
-
* @template T The type of the data for the subscription.
|
|
319
|
-
* @param queryKey The unique key for the query.
|
|
320
|
-
* @param operation The operation type (e.g., 'read', 'list').
|
|
321
|
-
* @param params The parameters for the query.
|
|
322
|
-
* @param selector A function that returns the current query result.
|
|
323
|
-
* @param notificationCondition A function to determine if a cache event should trigger a notification.
|
|
324
|
-
* @returns The existing or newly created QuerySubscription.
|
|
325
|
-
*/
|
|
326
|
-
private getOrCreateSubscription;
|
|
327
|
-
/**
|
|
328
|
-
* Builds a unique cache key for a given operation and its parameters.
|
|
329
|
-
* Uses a WeakMap for caching keys of object parameters to avoid re-hashing.
|
|
330
|
-
* @param operation The name of the operation (e.g., 'read', 'list').
|
|
331
|
-
* @param params The parameters for the operation.
|
|
332
|
-
* @returns A unique string key for the operation and parameters.
|
|
333
|
-
*/
|
|
477
|
+
private setupCacheEventListeners;
|
|
478
|
+
private handleCacheEvent;
|
|
334
479
|
private buildKey;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
private
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Retrieves a single record reactively.
|
|
349
|
-
*
|
|
350
|
-
* This method provides a reactive query result for a single record. The data is fetched from the cache if available,
|
|
351
|
-
* otherwise it's fetched from the underlying `baseStore`. The method returns an object containing the current
|
|
352
|
-
* query result and a function to subscribe to future updates.
|
|
353
|
-
*
|
|
354
|
-
* @param params The options for the read operation, used to identify the record.
|
|
355
|
-
* @returns A `ReactiveQueryResult` object containing the reactive value and an `onValueChange` subscription function.
|
|
356
|
-
*/
|
|
357
|
-
read(params: TReadOptions): ReactiveQueryResult<T>;
|
|
358
|
-
/**
|
|
359
|
-
* Creates a selector function for a paginated query (list or find).
|
|
360
|
-
* @template TParams The type of the parameters for the query.
|
|
361
|
-
* @param baseQueryKey The base unique key for the query.
|
|
362
|
-
* @param baseParams The base parameters for the query.
|
|
363
|
-
* @param fetchFn The function to call to fetch a page of data.
|
|
364
|
-
* @returns A function that returns the current PagedQueryResult.
|
|
365
|
-
*/
|
|
366
|
-
private createPagedSelector;
|
|
367
|
-
/**
|
|
368
|
-
* Sets up a paginated query (list or find) with caching and reactivity.
|
|
369
|
-
* @template TParams The type of the parameters for the query.
|
|
370
|
-
* @param type The type of the paginated query ('list' or 'find').
|
|
371
|
-
* @param params The parameters for the query.
|
|
372
|
-
* @param fetchFn The function to call to fetch a page of data.
|
|
373
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
374
|
-
*/
|
|
480
|
+
private getOrCreateError;
|
|
481
|
+
private getOrCreateStoreError;
|
|
482
|
+
private computeResult;
|
|
483
|
+
private scheduleBackgroundFetch;
|
|
484
|
+
private getCurrentPageForQuery;
|
|
485
|
+
private getOrCreatePaginationMethods;
|
|
486
|
+
private computeResultForParams;
|
|
487
|
+
hasActiveQuery(operation: string, params: any): boolean;
|
|
488
|
+
getActiveQuery<TResult extends Record<string, unknown> = T>(operation: string, params: any): StoreResult<TResult> | undefined;
|
|
489
|
+
read(params: TReadOptions): StoreResult<T, QueryResult<T>>;
|
|
490
|
+
list(params: TListOptions): StoreResult<T, PagedQueryResult<T>>;
|
|
491
|
+
find(params: TFindOptions): StoreResult<T, PagedQueryResult<T>>;
|
|
375
492
|
private setupPagedQuery;
|
|
376
|
-
/**
|
|
377
|
-
* Lists records from the store with pagination and reactivity.
|
|
378
|
-
* @param params The list options.
|
|
379
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
380
|
-
*/
|
|
381
|
-
/**
|
|
382
|
-
* Retrieves a paginated list of records reactively.
|
|
383
|
-
*
|
|
384
|
-
* This method provides a reactive query result for a list of records. It supports pagination and automatically
|
|
385
|
-
* fetches data from the cache or the `baseStore`. The result includes methods for navigating to the next,
|
|
386
|
-
* previous, or a specific page.
|
|
387
|
-
*
|
|
388
|
-
* @param params The options for the list operation, including pagination details.
|
|
389
|
-
* @returns A `ReactivePagedQueryResult` object containing the reactive paged value and an `onValueChange` subscription function.
|
|
390
|
-
*/
|
|
391
|
-
list(params: TListOptions): ReactivePagedQueryResult<T>;
|
|
392
|
-
/**
|
|
393
|
-
* Finds records from the store with pagination and reactivity.
|
|
394
|
-
* @param params The find options.
|
|
395
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
396
|
-
*/
|
|
397
|
-
/**
|
|
398
|
-
* Finds and retrieves a paginated list of records reactively based on a query.
|
|
399
|
-
*
|
|
400
|
-
* Similar to `list`, this method provides a reactive query result for a set of records that match the given
|
|
401
|
-
* find options. It supports pagination and provides methods for navigating through the pages.
|
|
402
|
-
*
|
|
403
|
-
* @param params The options for the find operation, used to query for specific records.
|
|
404
|
-
* @returns A `ReactivePagedQueryResult` object containing the reactive paged value and an `onValueChange` subscription function.
|
|
405
|
-
*/
|
|
406
|
-
find(params: TFindOptions): ReactivePagedQueryResult<T>;
|
|
407
|
-
/**
|
|
408
|
-
* Invalidates relevant queries in the cache based on a mutation operation.
|
|
409
|
-
* If a correlator is provided, it will be used to determine which queries to invalidate.
|
|
410
|
-
* Otherwise, it invalidates all 'list' and 'find' queries.
|
|
411
|
-
* @param mutation An object describing the mutation operation and its parameters.
|
|
412
|
-
*/
|
|
413
493
|
private invalidateQueries;
|
|
414
|
-
/**
|
|
415
|
-
* Handles incoming store events, invalidating relevant queries if a `storeEventCorrelator` is provided.
|
|
416
|
-
* @param event The StoreEvent received.
|
|
417
|
-
*/
|
|
418
494
|
private handleStoreEvent;
|
|
419
|
-
/**
|
|
420
|
-
* Creates a new record.
|
|
421
|
-
*
|
|
422
|
-
* This method sends a request to the `baseStore` to create a new record. Upon successful creation,
|
|
423
|
-
* it updates the cache with the new record and invalidates relevant queries to ensure data consistency.
|
|
424
|
-
*
|
|
425
|
-
* @param params An object containing the data for the new record and optional create options.
|
|
426
|
-
* @returns A promise that resolves to the newly created record, or `undefined` if the creation fails.
|
|
427
|
-
* @throws An error if the create operation fails.
|
|
428
|
-
*/
|
|
429
495
|
create(params: {
|
|
430
496
|
data: Partial<T>;
|
|
431
497
|
options?: TCreateOptions;
|
|
432
498
|
}): Promise<T | undefined>;
|
|
433
|
-
/**
|
|
434
|
-
* Updates an existing record.
|
|
435
|
-
*
|
|
436
|
-
* This method sends a request to the `baseStore` to update a record. If the update is successful,
|
|
437
|
-
* it updates the cache with the modified record and invalidates relevant queries.
|
|
438
|
-
*
|
|
439
|
-
* @param params An object containing the ID of the record to update, the partial data, and optional update options.
|
|
440
|
-
* @returns A promise that resolves to the updated record, or `undefined` if the update fails.
|
|
441
|
-
* @throws An error if the update operation fails.
|
|
442
|
-
*/
|
|
443
499
|
update(params: {
|
|
444
500
|
data: Partial<T>;
|
|
445
501
|
options?: TUpdateOptions;
|
|
446
502
|
}): Promise<T | undefined>;
|
|
447
|
-
/**
|
|
448
|
-
* Deletes a record.
|
|
449
|
-
*
|
|
450
|
-
* This method sends a request to the `baseStore` to delete a record. Upon successful deletion,
|
|
451
|
-
* it removes the record from the cache and invalidates relevant queries.
|
|
452
|
-
*
|
|
453
|
-
* @param params The options for the delete operation, used to identify the record to be deleted.
|
|
454
|
-
* @returns A promise that resolves when the deletion is complete.
|
|
455
|
-
* @throws An error if the delete operation fails.
|
|
456
|
-
*/
|
|
457
503
|
delete(params: TDeleteOptions): Promise<void>;
|
|
458
|
-
/**
|
|
459
|
-
* Sends a notification event to the base store.
|
|
460
|
-
*
|
|
461
|
-
* This can be used to trigger server-side events or other custom actions in the `baseStore`.
|
|
462
|
-
*
|
|
463
|
-
* @param event The `StoreEvent` to be sent.
|
|
464
|
-
* @returns A promise that resolves when the notification has been processed.
|
|
465
|
-
*/
|
|
466
504
|
notify(event: StoreEvent): Promise<void>;
|
|
467
|
-
|
|
468
|
-
* Establishes a real-time data stream.
|
|
469
|
-
*
|
|
470
|
-
* This method delegates to the `baseStore`'s `stream` method to create a persistent connection for
|
|
471
|
-
* receiving real-time updates. The provided callback will be invoked when new data is available.
|
|
472
|
-
*
|
|
473
|
-
* @param options The options for the stream operation.
|
|
474
|
-
* @param onStreamChange A callback function that is executed when the stream's data changes.
|
|
475
|
-
* @returns A promise that resolves with a function to close the stream.
|
|
476
|
-
*/
|
|
477
|
-
stream(options: TStreamOptions, onStreamChange: () => void): Promise<{
|
|
505
|
+
stream(options: TStreamOptions, onStreamChange: () => void): {
|
|
478
506
|
stream: () => AsyncIterable<T>;
|
|
479
507
|
cancel: () => void;
|
|
480
508
|
status: () => "active" | "cancelled" | "completed";
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
* Uploads a file and creates a new record associated with it.
|
|
484
|
-
*
|
|
485
|
-
* This method handles file uploads through the `baseStore`. After a successful upload, it updates the cache
|
|
486
|
-
* with the new record and invalidates relevant queries.
|
|
487
|
-
*
|
|
488
|
-
* @param params An object containing the file to upload and optional upload options.
|
|
489
|
-
* @returns A promise that resolves to the newly created record, or `undefined` if the upload fails.
|
|
490
|
-
* @throws An error if the upload operation fails.
|
|
491
|
-
*/
|
|
509
|
+
};
|
|
510
|
+
subscribe(scope: string, callback: (event: StoreEvent) => void): Promise<() => void>;
|
|
492
511
|
upload(params: {
|
|
493
512
|
file: File;
|
|
494
513
|
options?: TUploadOptions;
|
|
495
514
|
}): Promise<T | undefined>;
|
|
496
|
-
/**
|
|
497
|
-
* Forces a refresh of a specific query.
|
|
498
|
-
*
|
|
499
|
-
* This method bypasses the cache's staleness checks and forces a refetch of the data from the `baseStore`.
|
|
500
|
-
* The method is overloaded to support `read`, `list`, and `find` operations.
|
|
501
|
-
*
|
|
502
|
-
* @param operation The type of operation to refresh ('read', 'list', or 'find').
|
|
503
|
-
* @param params The parameters for the operation.
|
|
504
|
-
* @returns A promise that resolves to the refreshed data.
|
|
505
|
-
*/
|
|
506
515
|
refresh(operation: 'read', params: TReadOptions): Promise<T | undefined>;
|
|
507
516
|
refresh(operation: 'list', params: TListOptions): Promise<Page<T> | undefined>;
|
|
508
517
|
refresh(operation: 'find', query: TFindOptions): Promise<Page<T> | undefined>;
|
|
509
|
-
/**
|
|
510
|
-
* Pre-fetches data for a query and caches it.
|
|
511
|
-
*
|
|
512
|
-
* This method is used to proactively fetch data that is likely to be needed soon. It fetches the data
|
|
513
|
-
* and stores it in the cache, so that subsequent requests for the same data can be served instantly.
|
|
514
|
-
* The method is overloaded for `read`, `list`, and `find` operations.
|
|
515
|
-
*
|
|
516
|
-
* @param operation The type of operation to prefetch ('read', 'list', or 'find').
|
|
517
|
-
* @param params The parameters for the operation.
|
|
518
|
-
*/
|
|
519
518
|
prefetch(operation: 'read', params: TReadOptions): void;
|
|
520
519
|
prefetch(operation: 'list', params: TListOptions): void;
|
|
521
520
|
prefetch(operation: 'find', params: TFindOptions): void;
|
|
522
|
-
/**
|
|
523
|
-
* Invalidates the cached data for a specific query.
|
|
524
|
-
*
|
|
525
|
-
* This marks the query's data as stale, forcing a refetch the next time it's accessed. This is useful
|
|
526
|
-
* when you know the data has changed on the server, but the change was not triggered by a mutation
|
|
527
|
-
* through this store.
|
|
528
|
-
*
|
|
529
|
-
* @param operation The type of operation to invalidate ('read', 'list', or 'find').
|
|
530
|
-
* @param params The parameters for the operation.
|
|
531
|
-
* @returns A promise that resolves when the invalidation is complete.
|
|
532
|
-
*/
|
|
533
521
|
invalidate(operation: string, params: any): Promise<void>;
|
|
534
|
-
/**
|
|
535
|
-
* Invalidates all active queries in the store.
|
|
536
|
-
*
|
|
537
|
-
* This method marks all currently active queries as stale, forcing them to be refetched the next time
|
|
538
|
-
* they are accessed. This is a more aggressive approach to cache invalidation.
|
|
539
|
-
*
|
|
540
|
-
* @returns A promise that resolves when all invalidations are complete.
|
|
541
|
-
*/
|
|
542
522
|
invalidateAll(): Promise<void>;
|
|
543
|
-
/**
|
|
544
|
-
* Retrieves statistics about the store and its cache.
|
|
545
|
-
*
|
|
546
|
-
* This method returns an object containing statistics from the underlying cache, plus the number of
|
|
547
|
-
* active subscriptions in the reactive store.
|
|
548
|
-
*
|
|
549
|
-
* @returns An object with cache statistics and the number of active subscriptions.
|
|
550
|
-
*/
|
|
551
523
|
getStats(): {
|
|
552
524
|
activeSubscriptions: number;
|
|
553
525
|
size: number;
|
|
@@ -564,12 +536,6 @@ declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<s
|
|
|
564
536
|
error?: boolean;
|
|
565
537
|
}>;
|
|
566
538
|
};
|
|
567
|
-
/**
|
|
568
|
-
* Cleans up all resources used by the store.
|
|
569
|
-
*
|
|
570
|
-
* This method should be called when the store is no longer needed. It unsubscribes from all cache events,
|
|
571
|
-
* clears all query subscriptions, and unsubscribes from the base store's events.
|
|
572
|
-
*/
|
|
573
539
|
destroy(): void;
|
|
574
540
|
}
|
|
575
541
|
|
|
@@ -580,4 +546,4 @@ declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<s
|
|
|
580
546
|
*/
|
|
581
547
|
declare function hash(data: any): string;
|
|
582
548
|
|
|
583
|
-
export { type ActiveQuery, type BaseStore, type Correlator, type MutationOperation, type Page, type PagedQueryResult, type PaginationInfo, type QueryResult, type QuerySubscription,
|
|
549
|
+
export { type ActiveQuery, type BaseStore, type Correlator, type MutationOperation, type Page, type PagedQueryResult, type PaginationInfo, type QueryResult, type QuerySubscription, ReactiveRemoteStore, type ResourceName, StoreError, type StoreErrorDetails, type StoreEvent, type StoreEventCorrelator, type StoreRecord, type StoreResult, hash };
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,198 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface SimplePersistence<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Persists data to storage.
|
|
4
|
+
*
|
|
5
|
+
* @param id The **unique identifier of the *consumer instance*** making the change. This is NOT the ID of the data (`T`) itself.
|
|
6
|
+
* Think of it as the ID of the specific browser tab, component, or module that's currently interacting with the persistence layer.
|
|
7
|
+
* It should typically be a **UUID** generated once at the consumer instance's instantiation.
|
|
8
|
+
* 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.
|
|
9
|
+
* @param state The state (of type T) to persist. This state is generally considered the **global or shared state** that all instances interact with.
|
|
10
|
+
* @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations (like `IndexedDBPersistence`), this returns a `Promise<boolean>`.
|
|
11
|
+
*/
|
|
12
|
+
set(id: string, state: T): boolean | Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves the global persisted data from storage.
|
|
15
|
+
*
|
|
16
|
+
* @returns The retrieved state of type `T`, or `null` if no data is found or if an error occurs during retrieval/parsing.
|
|
17
|
+
* For asynchronous implementations, this returns a `Promise<T | null>`.
|
|
18
|
+
*/
|
|
19
|
+
get(): (T | null) | (Promise<T | null>);
|
|
20
|
+
/**
|
|
21
|
+
* 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).
|
|
22
|
+
*
|
|
23
|
+
* @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.
|
|
24
|
+
* @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.
|
|
25
|
+
* @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.
|
|
26
|
+
*/
|
|
27
|
+
subscribe(id: string, callback: (state: T) => void): () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Clears (removes) the entire global persisted data from storage.
|
|
30
|
+
*
|
|
31
|
+
* @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations, this returns a `Promise<boolean>`.
|
|
32
|
+
*/
|
|
33
|
+
clear(): boolean | Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Returns metadata about the persistence layer.
|
|
36
|
+
*
|
|
37
|
+
* This is useful for distinguishing between multiple apps running on the same host
|
|
38
|
+
* (e.g., several apps served at `localhost:3000` that share the same storage key).
|
|
39
|
+
*
|
|
40
|
+
* @returns An object containing:
|
|
41
|
+
* - `version`: The semantic version string of the persistence schema or application.
|
|
42
|
+
* - `id`: A unique identifier for the application using this persistence instance.
|
|
43
|
+
*/
|
|
44
|
+
stats(): {
|
|
45
|
+
version: string;
|
|
46
|
+
id: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface CacheOptions {
|
|
51
|
+
staleTime?: number;
|
|
52
|
+
cacheTime?: number;
|
|
53
|
+
retryAttempts?: number;
|
|
54
|
+
retryDelay?: number;
|
|
55
|
+
maxSize?: number;
|
|
56
|
+
enableMetrics?: boolean;
|
|
57
|
+
persistence?: SimplePersistence<SerializableCacheState>;
|
|
58
|
+
persistenceId?: string;
|
|
59
|
+
serializeValue?: (value: any) => any;
|
|
60
|
+
deserializeValue?: (value: any) => any;
|
|
61
|
+
persistenceDebounceTime?: number;
|
|
62
|
+
}
|
|
63
|
+
interface CacheMetrics {
|
|
64
|
+
hits: number;
|
|
65
|
+
misses: number;
|
|
66
|
+
fetches: number;
|
|
67
|
+
errors: number;
|
|
68
|
+
evictions: number;
|
|
69
|
+
staleHits: number;
|
|
70
|
+
}
|
|
71
|
+
interface SerializableCacheEntry {
|
|
72
|
+
data: any;
|
|
73
|
+
lastUpdated: number;
|
|
74
|
+
lastAccessed: number;
|
|
75
|
+
accessCount: number;
|
|
76
|
+
error?: {
|
|
77
|
+
name: string;
|
|
78
|
+
message: string;
|
|
79
|
+
stack?: string;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
type SerializableCacheState = Array<[string, SerializableCacheEntry]>;
|
|
83
|
+
type CacheEventBase<Type extends string, Payload = {}> = {
|
|
84
|
+
type: Type;
|
|
85
|
+
key: string;
|
|
86
|
+
timestamp: number;
|
|
87
|
+
} & Payload;
|
|
88
|
+
type CacheReadHitEvent<T = any> = CacheEventBase<'cache:read:hit', {
|
|
89
|
+
data: T;
|
|
90
|
+
isStale: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
type CacheReadMissEvent = CacheEventBase<'cache:read:miss'>;
|
|
93
|
+
type CacheFetchStartEvent = CacheEventBase<'cache:fetch:start', {
|
|
94
|
+
attempt: number;
|
|
95
|
+
}>;
|
|
96
|
+
type CacheFetchSuccessEvent<T = any> = CacheEventBase<'cache:fetch:success', {
|
|
97
|
+
data: T;
|
|
98
|
+
}>;
|
|
99
|
+
type CacheFetchErrorEvent = CacheEventBase<'cache:fetch:error', {
|
|
100
|
+
error: Error;
|
|
101
|
+
attempt: number;
|
|
102
|
+
}>;
|
|
103
|
+
type CacheDataEvictEvent = CacheEventBase<'cache:data:evict', {
|
|
104
|
+
reason?: string;
|
|
105
|
+
}>;
|
|
106
|
+
type CacheDataInvalidateEvent = CacheEventBase<'cache:data:invalidate'>;
|
|
107
|
+
type CacheDataSetEvent<T = any> = CacheEventBase<'cache:data:set', {
|
|
108
|
+
newData: T;
|
|
109
|
+
oldData?: T;
|
|
110
|
+
}>;
|
|
111
|
+
type CachePersistenceLoadSuccessEvent = CacheEventBase<'cache:persistence:load:success', {
|
|
112
|
+
message?: string;
|
|
113
|
+
}>;
|
|
114
|
+
type CachePersistenceLoadErrorEvent = CacheEventBase<'cache:persistence:load:error', {
|
|
115
|
+
message?: string;
|
|
116
|
+
error?: any;
|
|
117
|
+
}>;
|
|
118
|
+
type CachePersistenceSaveSuccessEvent = CacheEventBase<'cache:persistence:save:success'>;
|
|
119
|
+
type CachePersistenceSaveErrorEvent = CacheEventBase<'cache:persistence:save:error', {
|
|
120
|
+
message?: string;
|
|
121
|
+
error?: any;
|
|
122
|
+
}>;
|
|
123
|
+
type CachePersistenceClearSuccessEvent = CacheEventBase<'cache:persistence:clear:success'>;
|
|
124
|
+
type CachePersistenceClearErrorEvent = CacheEventBase<'cache:persistence:clear:error', {
|
|
125
|
+
message?: string;
|
|
126
|
+
error?: any;
|
|
127
|
+
}>;
|
|
128
|
+
type CachePersistenceSyncEvent = CacheEventBase<'cache:persistence:sync', {
|
|
129
|
+
message?: string;
|
|
130
|
+
}>;
|
|
131
|
+
type CacheEvent = CacheReadHitEvent | CacheReadMissEvent | CacheFetchStartEvent | CacheFetchSuccessEvent | CacheFetchErrorEvent | CacheDataEvictEvent | CacheDataInvalidateEvent | CacheDataSetEvent | CachePersistenceLoadSuccessEvent | CachePersistenceLoadErrorEvent | CachePersistenceSaveSuccessEvent | CachePersistenceSaveErrorEvent | CachePersistenceClearSuccessEvent | CachePersistenceClearErrorEvent | CachePersistenceSyncEvent;
|
|
132
|
+
type CacheEventType = CacheEvent['type'];
|
|
133
|
+
|
|
134
|
+
declare class QueryCache {
|
|
135
|
+
private cache;
|
|
136
|
+
private queries;
|
|
137
|
+
private fetching;
|
|
138
|
+
private readonly defaultOptions;
|
|
139
|
+
private metrics;
|
|
140
|
+
private eventBus;
|
|
141
|
+
private gcTimer?;
|
|
142
|
+
private readonly persistenceId;
|
|
143
|
+
private persistenceUnsubscribe?;
|
|
144
|
+
private persistenceDebounceTimer?;
|
|
145
|
+
private isHandlingRemoteUpdate;
|
|
146
|
+
constructor(defaultOptions?: CacheOptions);
|
|
147
|
+
private initializePersistence;
|
|
148
|
+
private serializeCache;
|
|
149
|
+
private deserializeAndLoadCache;
|
|
150
|
+
private schedulePersistState;
|
|
151
|
+
private handleRemoteStateChange;
|
|
152
|
+
registerQuery<T>(key: string, fetchFunction: () => Promise<T>, options?: CacheOptions): void;
|
|
153
|
+
get<T>(key: string, options?: {
|
|
154
|
+
waitForFresh?: boolean;
|
|
155
|
+
throwOnError?: boolean;
|
|
156
|
+
}): Promise<T | undefined>;
|
|
157
|
+
peek<T>(key: string): T | undefined;
|
|
158
|
+
has(key: string): boolean;
|
|
159
|
+
private fetch;
|
|
160
|
+
private fetchAndWait;
|
|
161
|
+
private performFetchWithRetry;
|
|
162
|
+
private isStale;
|
|
163
|
+
invalidate(key: string, refetch?: boolean): Promise<void>;
|
|
164
|
+
invalidatePattern(pattern: RegExp, refetch?: boolean): Promise<void>;
|
|
165
|
+
prefetch(key: string): Promise<void>;
|
|
166
|
+
refresh<T>(key: string): Promise<T | undefined>;
|
|
167
|
+
setData<T>(key: string, data: T): void;
|
|
168
|
+
remove(key: string): boolean;
|
|
169
|
+
private enforceSizeLimit;
|
|
170
|
+
private startGarbageCollection;
|
|
171
|
+
garbageCollect(): number;
|
|
172
|
+
getStats(): {
|
|
173
|
+
size: number;
|
|
174
|
+
metrics: CacheMetrics;
|
|
175
|
+
hitRate: number;
|
|
176
|
+
staleHitRate: number;
|
|
177
|
+
entries: Array<{
|
|
178
|
+
key: string;
|
|
179
|
+
lastAccessed: number;
|
|
180
|
+
lastUpdated: number;
|
|
181
|
+
accessCount: number;
|
|
182
|
+
isStale: boolean;
|
|
183
|
+
isLoading?: boolean;
|
|
184
|
+
error?: boolean;
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
187
|
+
on<EType extends CacheEventType>(event: EType, listener: (ev: Extract<CacheEvent, {
|
|
188
|
+
type: EType;
|
|
189
|
+
}>) => void): () => void;
|
|
190
|
+
private emitEvent;
|
|
191
|
+
private updateMetrics;
|
|
192
|
+
private delay;
|
|
193
|
+
clear(): Promise<void>;
|
|
194
|
+
destroy(): void;
|
|
195
|
+
}
|
|
3
196
|
|
|
4
197
|
interface StoreErrorDetails {
|
|
5
198
|
code: string;
|
|
@@ -205,7 +398,9 @@ interface PagedQueryResult<T> {
|
|
|
205
398
|
/** Function to fetch a specific page of data.
|
|
206
399
|
* @param page The page number to fetch.
|
|
207
400
|
*/
|
|
208
|
-
|
|
401
|
+
navigate: (page: number) => Promise<void>;
|
|
402
|
+
refresh: (delay?: number) => Promise<void>;
|
|
403
|
+
changeParams: (setter: (params: any) => any) => Promise<void>;
|
|
209
404
|
}
|
|
210
405
|
/**
|
|
211
406
|
* Represents a basic record in the remote store.
|
|
@@ -230,26 +425,6 @@ type PaginationInfo = {
|
|
|
230
425
|
* Represents the name of a resource in the store, e.g., 'todos', 'users'.
|
|
231
426
|
*/
|
|
232
427
|
type ResourceName = string;
|
|
233
|
-
/**
|
|
234
|
-
* Represents the reactive result of a single record query.
|
|
235
|
-
* @template T The type of the data being queried.
|
|
236
|
-
*/
|
|
237
|
-
interface ReactiveQueryResult<T> {
|
|
238
|
-
/** The current query result, including data, loading state, and errors. */
|
|
239
|
-
value: () => QueryResult<T>;
|
|
240
|
-
/** A function to subscribe to changes in the query result. Returns an unsubscribe function. */
|
|
241
|
-
onValueChange: (callback: () => void) => () => void;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Represents the reactive result of a paginated query (list or find).
|
|
245
|
-
* @template T The type of the records in the page.
|
|
246
|
-
*/
|
|
247
|
-
interface ReactivePagedQueryResult<T> {
|
|
248
|
-
/** The current paginated query result, including page data, loading state, and errors. */
|
|
249
|
-
value: () => PagedQueryResult<T>;
|
|
250
|
-
/** A function to subscribe to changes in the query result. Returns an unsubscribe function. */
|
|
251
|
-
onValueChange: (callback: () => void) => () => void;
|
|
252
|
-
}
|
|
253
428
|
/**
|
|
254
429
|
* Internal interface representing an active subscription to a query.
|
|
255
430
|
* @template T The type of the data being queried.
|
|
@@ -271,283 +446,80 @@ interface QuerySubscription<T> {
|
|
|
271
446
|
result: QueryResult<T> | PagedQueryResult<T>;
|
|
272
447
|
}
|
|
273
448
|
|
|
449
|
+
/**
|
|
450
|
+
* Represents the result of a store query with stable React integration.
|
|
451
|
+
* @template T The type of the result data.
|
|
452
|
+
*/
|
|
453
|
+
interface StoreResult<T extends Record<string, any> = Record<string, any>, V = QueryResult<T> | PagedQueryResult<T>> {
|
|
454
|
+
/** Function that returns the current query state */
|
|
455
|
+
value: () => V;
|
|
456
|
+
/** Function to subscribe to state changes */
|
|
457
|
+
onValueChange: (callback: () => void) => () => void;
|
|
458
|
+
}
|
|
274
459
|
/**
|
|
275
460
|
* A reactive remote store that provides cached and observable access to data
|
|
276
461
|
* from a `BaseStore`. It handles caching, invalidation, and real-time updates
|
|
277
462
|
* via server-sent events (SSE).
|
|
278
|
-
*
|
|
279
|
-
* @template T The type of the records managed by the store, extending Record.
|
|
280
|
-
* @template TFindOptions Options for the find operation.
|
|
281
|
-
* @template TReadOptions Options for the read operation.
|
|
282
|
-
* @template TListOptions Options for the list operation.
|
|
283
|
-
* @template TDeleteOptions Options for the delete operation.
|
|
284
|
-
* @template TUpdateOptions Options for the update operation.
|
|
285
|
-
* @template TCreateOptions Options for the create operation.
|
|
286
|
-
* @template TUploadOptions Options for the upload operation.
|
|
287
|
-
* @template TStreamOptions Options for the stream operation.
|
|
288
463
|
*/
|
|
289
464
|
declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<string, unknown>, TReadOptions = Record<string, unknown>, TListOptions = Record<string, unknown>, TDeleteOptions = Record<string, unknown>, TUpdateOptions = Record<string, unknown>, TCreateOptions = Record<string, unknown>, TUploadOptions = Record<string, unknown>, TStreamOptions = Record<string, unknown>> {
|
|
290
465
|
private cache;
|
|
291
466
|
private baseStore;
|
|
292
467
|
private correlator?;
|
|
293
468
|
private storeEventCorrelator?;
|
|
294
|
-
private
|
|
469
|
+
private queryStates;
|
|
470
|
+
private stableResults;
|
|
471
|
+
private stablePaginationMethods;
|
|
472
|
+
private errorCache;
|
|
295
473
|
private keyCache;
|
|
296
474
|
private unsubscribeFromBaseStore;
|
|
297
|
-
|
|
298
|
-
* Creates an instance of ReactiveRemoteStore.
|
|
299
|
-
* @param cache The QueryCache instance to use for caching data.
|
|
300
|
-
* @param baseStore The underlying BaseStore for actual data fetching and mutations.
|
|
301
|
-
* @param correlator Optional function to determine which queries to invalidate after a mutation.
|
|
302
|
-
* @param storeEventCorrelator Optional function to determine which queries to invalidate after a store event.
|
|
303
|
-
*/
|
|
475
|
+
private cacheEventCleanups;
|
|
304
476
|
constructor(cache: QueryCache, baseStore: BaseStore<T, TFindOptions, TReadOptions, TListOptions, TDeleteOptions, TUpdateOptions, TCreateOptions, TUploadOptions, TStreamOptions>, correlator?: Correlator | undefined, storeEventCorrelator?: StoreEventCorrelator | undefined);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* @template T The type of the data for the subscription.
|
|
308
|
-
* @param queryKey The unique key for the query.
|
|
309
|
-
* @param operation The operation type (e.g., 'read', 'list').
|
|
310
|
-
* @param params The parameters for the query.
|
|
311
|
-
* @param selector A function that returns the current query result.
|
|
312
|
-
* @param notificationCondition A function to determine if a cache event should trigger a notification.
|
|
313
|
-
* @returns The created QuerySubscription.
|
|
314
|
-
*/
|
|
315
|
-
private createSubscription;
|
|
316
|
-
/**
|
|
317
|
-
* Retrieves an existing subscription or creates a new one if it doesn't exist.
|
|
318
|
-
* @template T The type of the data for the subscription.
|
|
319
|
-
* @param queryKey The unique key for the query.
|
|
320
|
-
* @param operation The operation type (e.g., 'read', 'list').
|
|
321
|
-
* @param params The parameters for the query.
|
|
322
|
-
* @param selector A function that returns the current query result.
|
|
323
|
-
* @param notificationCondition A function to determine if a cache event should trigger a notification.
|
|
324
|
-
* @returns The existing or newly created QuerySubscription.
|
|
325
|
-
*/
|
|
326
|
-
private getOrCreateSubscription;
|
|
327
|
-
/**
|
|
328
|
-
* Builds a unique cache key for a given operation and its parameters.
|
|
329
|
-
* Uses a WeakMap for caching keys of object parameters to avoid re-hashing.
|
|
330
|
-
* @param operation The name of the operation (e.g., 'read', 'list').
|
|
331
|
-
* @param params The parameters for the operation.
|
|
332
|
-
* @returns A unique string key for the operation and parameters.
|
|
333
|
-
*/
|
|
477
|
+
private setupCacheEventListeners;
|
|
478
|
+
private handleCacheEvent;
|
|
334
479
|
private buildKey;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
private
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Retrieves a single record reactively.
|
|
349
|
-
*
|
|
350
|
-
* This method provides a reactive query result for a single record. The data is fetched from the cache if available,
|
|
351
|
-
* otherwise it's fetched from the underlying `baseStore`. The method returns an object containing the current
|
|
352
|
-
* query result and a function to subscribe to future updates.
|
|
353
|
-
*
|
|
354
|
-
* @param params The options for the read operation, used to identify the record.
|
|
355
|
-
* @returns A `ReactiveQueryResult` object containing the reactive value and an `onValueChange` subscription function.
|
|
356
|
-
*/
|
|
357
|
-
read(params: TReadOptions): ReactiveQueryResult<T>;
|
|
358
|
-
/**
|
|
359
|
-
* Creates a selector function for a paginated query (list or find).
|
|
360
|
-
* @template TParams The type of the parameters for the query.
|
|
361
|
-
* @param baseQueryKey The base unique key for the query.
|
|
362
|
-
* @param baseParams The base parameters for the query.
|
|
363
|
-
* @param fetchFn The function to call to fetch a page of data.
|
|
364
|
-
* @returns A function that returns the current PagedQueryResult.
|
|
365
|
-
*/
|
|
366
|
-
private createPagedSelector;
|
|
367
|
-
/**
|
|
368
|
-
* Sets up a paginated query (list or find) with caching and reactivity.
|
|
369
|
-
* @template TParams The type of the parameters for the query.
|
|
370
|
-
* @param type The type of the paginated query ('list' or 'find').
|
|
371
|
-
* @param params The parameters for the query.
|
|
372
|
-
* @param fetchFn The function to call to fetch a page of data.
|
|
373
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
374
|
-
*/
|
|
480
|
+
private getOrCreateError;
|
|
481
|
+
private getOrCreateStoreError;
|
|
482
|
+
private computeResult;
|
|
483
|
+
private scheduleBackgroundFetch;
|
|
484
|
+
private getCurrentPageForQuery;
|
|
485
|
+
private getOrCreatePaginationMethods;
|
|
486
|
+
private computeResultForParams;
|
|
487
|
+
hasActiveQuery(operation: string, params: any): boolean;
|
|
488
|
+
getActiveQuery<TResult extends Record<string, unknown> = T>(operation: string, params: any): StoreResult<TResult> | undefined;
|
|
489
|
+
read(params: TReadOptions): StoreResult<T, QueryResult<T>>;
|
|
490
|
+
list(params: TListOptions): StoreResult<T, PagedQueryResult<T>>;
|
|
491
|
+
find(params: TFindOptions): StoreResult<T, PagedQueryResult<T>>;
|
|
375
492
|
private setupPagedQuery;
|
|
376
|
-
/**
|
|
377
|
-
* Lists records from the store with pagination and reactivity.
|
|
378
|
-
* @param params The list options.
|
|
379
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
380
|
-
*/
|
|
381
|
-
/**
|
|
382
|
-
* Retrieves a paginated list of records reactively.
|
|
383
|
-
*
|
|
384
|
-
* This method provides a reactive query result for a list of records. It supports pagination and automatically
|
|
385
|
-
* fetches data from the cache or the `baseStore`. The result includes methods for navigating to the next,
|
|
386
|
-
* previous, or a specific page.
|
|
387
|
-
*
|
|
388
|
-
* @param params The options for the list operation, including pagination details.
|
|
389
|
-
* @returns A `ReactivePagedQueryResult` object containing the reactive paged value and an `onValueChange` subscription function.
|
|
390
|
-
*/
|
|
391
|
-
list(params: TListOptions): ReactivePagedQueryResult<T>;
|
|
392
|
-
/**
|
|
393
|
-
* Finds records from the store with pagination and reactivity.
|
|
394
|
-
* @param params The find options.
|
|
395
|
-
* @returns An object containing the current PagedQueryResult and a function to subscribe to changes.
|
|
396
|
-
*/
|
|
397
|
-
/**
|
|
398
|
-
* Finds and retrieves a paginated list of records reactively based on a query.
|
|
399
|
-
*
|
|
400
|
-
* Similar to `list`, this method provides a reactive query result for a set of records that match the given
|
|
401
|
-
* find options. It supports pagination and provides methods for navigating through the pages.
|
|
402
|
-
*
|
|
403
|
-
* @param params The options for the find operation, used to query for specific records.
|
|
404
|
-
* @returns A `ReactivePagedQueryResult` object containing the reactive paged value and an `onValueChange` subscription function.
|
|
405
|
-
*/
|
|
406
|
-
find(params: TFindOptions): ReactivePagedQueryResult<T>;
|
|
407
|
-
/**
|
|
408
|
-
* Invalidates relevant queries in the cache based on a mutation operation.
|
|
409
|
-
* If a correlator is provided, it will be used to determine which queries to invalidate.
|
|
410
|
-
* Otherwise, it invalidates all 'list' and 'find' queries.
|
|
411
|
-
* @param mutation An object describing the mutation operation and its parameters.
|
|
412
|
-
*/
|
|
413
493
|
private invalidateQueries;
|
|
414
|
-
/**
|
|
415
|
-
* Handles incoming store events, invalidating relevant queries if a `storeEventCorrelator` is provided.
|
|
416
|
-
* @param event The StoreEvent received.
|
|
417
|
-
*/
|
|
418
494
|
private handleStoreEvent;
|
|
419
|
-
/**
|
|
420
|
-
* Creates a new record.
|
|
421
|
-
*
|
|
422
|
-
* This method sends a request to the `baseStore` to create a new record. Upon successful creation,
|
|
423
|
-
* it updates the cache with the new record and invalidates relevant queries to ensure data consistency.
|
|
424
|
-
*
|
|
425
|
-
* @param params An object containing the data for the new record and optional create options.
|
|
426
|
-
* @returns A promise that resolves to the newly created record, or `undefined` if the creation fails.
|
|
427
|
-
* @throws An error if the create operation fails.
|
|
428
|
-
*/
|
|
429
495
|
create(params: {
|
|
430
496
|
data: Partial<T>;
|
|
431
497
|
options?: TCreateOptions;
|
|
432
498
|
}): Promise<T | undefined>;
|
|
433
|
-
/**
|
|
434
|
-
* Updates an existing record.
|
|
435
|
-
*
|
|
436
|
-
* This method sends a request to the `baseStore` to update a record. If the update is successful,
|
|
437
|
-
* it updates the cache with the modified record and invalidates relevant queries.
|
|
438
|
-
*
|
|
439
|
-
* @param params An object containing the ID of the record to update, the partial data, and optional update options.
|
|
440
|
-
* @returns A promise that resolves to the updated record, or `undefined` if the update fails.
|
|
441
|
-
* @throws An error if the update operation fails.
|
|
442
|
-
*/
|
|
443
499
|
update(params: {
|
|
444
500
|
data: Partial<T>;
|
|
445
501
|
options?: TUpdateOptions;
|
|
446
502
|
}): Promise<T | undefined>;
|
|
447
|
-
/**
|
|
448
|
-
* Deletes a record.
|
|
449
|
-
*
|
|
450
|
-
* This method sends a request to the `baseStore` to delete a record. Upon successful deletion,
|
|
451
|
-
* it removes the record from the cache and invalidates relevant queries.
|
|
452
|
-
*
|
|
453
|
-
* @param params The options for the delete operation, used to identify the record to be deleted.
|
|
454
|
-
* @returns A promise that resolves when the deletion is complete.
|
|
455
|
-
* @throws An error if the delete operation fails.
|
|
456
|
-
*/
|
|
457
503
|
delete(params: TDeleteOptions): Promise<void>;
|
|
458
|
-
/**
|
|
459
|
-
* Sends a notification event to the base store.
|
|
460
|
-
*
|
|
461
|
-
* This can be used to trigger server-side events or other custom actions in the `baseStore`.
|
|
462
|
-
*
|
|
463
|
-
* @param event The `StoreEvent` to be sent.
|
|
464
|
-
* @returns A promise that resolves when the notification has been processed.
|
|
465
|
-
*/
|
|
466
504
|
notify(event: StoreEvent): Promise<void>;
|
|
467
|
-
|
|
468
|
-
* Establishes a real-time data stream.
|
|
469
|
-
*
|
|
470
|
-
* This method delegates to the `baseStore`'s `stream` method to create a persistent connection for
|
|
471
|
-
* receiving real-time updates. The provided callback will be invoked when new data is available.
|
|
472
|
-
*
|
|
473
|
-
* @param options The options for the stream operation.
|
|
474
|
-
* @param onStreamChange A callback function that is executed when the stream's data changes.
|
|
475
|
-
* @returns A promise that resolves with a function to close the stream.
|
|
476
|
-
*/
|
|
477
|
-
stream(options: TStreamOptions, onStreamChange: () => void): Promise<{
|
|
505
|
+
stream(options: TStreamOptions, onStreamChange: () => void): {
|
|
478
506
|
stream: () => AsyncIterable<T>;
|
|
479
507
|
cancel: () => void;
|
|
480
508
|
status: () => "active" | "cancelled" | "completed";
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
* Uploads a file and creates a new record associated with it.
|
|
484
|
-
*
|
|
485
|
-
* This method handles file uploads through the `baseStore`. After a successful upload, it updates the cache
|
|
486
|
-
* with the new record and invalidates relevant queries.
|
|
487
|
-
*
|
|
488
|
-
* @param params An object containing the file to upload and optional upload options.
|
|
489
|
-
* @returns A promise that resolves to the newly created record, or `undefined` if the upload fails.
|
|
490
|
-
* @throws An error if the upload operation fails.
|
|
491
|
-
*/
|
|
509
|
+
};
|
|
510
|
+
subscribe(scope: string, callback: (event: StoreEvent) => void): Promise<() => void>;
|
|
492
511
|
upload(params: {
|
|
493
512
|
file: File;
|
|
494
513
|
options?: TUploadOptions;
|
|
495
514
|
}): Promise<T | undefined>;
|
|
496
|
-
/**
|
|
497
|
-
* Forces a refresh of a specific query.
|
|
498
|
-
*
|
|
499
|
-
* This method bypasses the cache's staleness checks and forces a refetch of the data from the `baseStore`.
|
|
500
|
-
* The method is overloaded to support `read`, `list`, and `find` operations.
|
|
501
|
-
*
|
|
502
|
-
* @param operation The type of operation to refresh ('read', 'list', or 'find').
|
|
503
|
-
* @param params The parameters for the operation.
|
|
504
|
-
* @returns A promise that resolves to the refreshed data.
|
|
505
|
-
*/
|
|
506
515
|
refresh(operation: 'read', params: TReadOptions): Promise<T | undefined>;
|
|
507
516
|
refresh(operation: 'list', params: TListOptions): Promise<Page<T> | undefined>;
|
|
508
517
|
refresh(operation: 'find', query: TFindOptions): Promise<Page<T> | undefined>;
|
|
509
|
-
/**
|
|
510
|
-
* Pre-fetches data for a query and caches it.
|
|
511
|
-
*
|
|
512
|
-
* This method is used to proactively fetch data that is likely to be needed soon. It fetches the data
|
|
513
|
-
* and stores it in the cache, so that subsequent requests for the same data can be served instantly.
|
|
514
|
-
* The method is overloaded for `read`, `list`, and `find` operations.
|
|
515
|
-
*
|
|
516
|
-
* @param operation The type of operation to prefetch ('read', 'list', or 'find').
|
|
517
|
-
* @param params The parameters for the operation.
|
|
518
|
-
*/
|
|
519
518
|
prefetch(operation: 'read', params: TReadOptions): void;
|
|
520
519
|
prefetch(operation: 'list', params: TListOptions): void;
|
|
521
520
|
prefetch(operation: 'find', params: TFindOptions): void;
|
|
522
|
-
/**
|
|
523
|
-
* Invalidates the cached data for a specific query.
|
|
524
|
-
*
|
|
525
|
-
* This marks the query's data as stale, forcing a refetch the next time it's accessed. This is useful
|
|
526
|
-
* when you know the data has changed on the server, but the change was not triggered by a mutation
|
|
527
|
-
* through this store.
|
|
528
|
-
*
|
|
529
|
-
* @param operation The type of operation to invalidate ('read', 'list', or 'find').
|
|
530
|
-
* @param params The parameters for the operation.
|
|
531
|
-
* @returns A promise that resolves when the invalidation is complete.
|
|
532
|
-
*/
|
|
533
521
|
invalidate(operation: string, params: any): Promise<void>;
|
|
534
|
-
/**
|
|
535
|
-
* Invalidates all active queries in the store.
|
|
536
|
-
*
|
|
537
|
-
* This method marks all currently active queries as stale, forcing them to be refetched the next time
|
|
538
|
-
* they are accessed. This is a more aggressive approach to cache invalidation.
|
|
539
|
-
*
|
|
540
|
-
* @returns A promise that resolves when all invalidations are complete.
|
|
541
|
-
*/
|
|
542
522
|
invalidateAll(): Promise<void>;
|
|
543
|
-
/**
|
|
544
|
-
* Retrieves statistics about the store and its cache.
|
|
545
|
-
*
|
|
546
|
-
* This method returns an object containing statistics from the underlying cache, plus the number of
|
|
547
|
-
* active subscriptions in the reactive store.
|
|
548
|
-
*
|
|
549
|
-
* @returns An object with cache statistics and the number of active subscriptions.
|
|
550
|
-
*/
|
|
551
523
|
getStats(): {
|
|
552
524
|
activeSubscriptions: number;
|
|
553
525
|
size: number;
|
|
@@ -564,12 +536,6 @@ declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<s
|
|
|
564
536
|
error?: boolean;
|
|
565
537
|
}>;
|
|
566
538
|
};
|
|
567
|
-
/**
|
|
568
|
-
* Cleans up all resources used by the store.
|
|
569
|
-
*
|
|
570
|
-
* This method should be called when the store is no longer needed. It unsubscribes from all cache events,
|
|
571
|
-
* clears all query subscriptions, and unsubscribes from the base store's events.
|
|
572
|
-
*/
|
|
573
539
|
destroy(): void;
|
|
574
540
|
}
|
|
575
541
|
|
|
@@ -580,4 +546,4 @@ declare class ReactiveRemoteStore<T extends StoreRecord, TFindOptions = Record<s
|
|
|
580
546
|
*/
|
|
581
547
|
declare function hash(data: any): string;
|
|
582
548
|
|
|
583
|
-
export { type ActiveQuery, type BaseStore, type Correlator, type MutationOperation, type Page, type PagedQueryResult, type PaginationInfo, type QueryResult, type QuerySubscription,
|
|
549
|
+
export { type ActiveQuery, type BaseStore, type Correlator, type MutationOperation, type Page, type PagedQueryResult, type PaginationInfo, type QueryResult, type QuerySubscription, ReactiveRemoteStore, type ResourceName, StoreError, type StoreErrorDetails, type StoreEvent, type StoreEventCorrelator, type StoreRecord, type StoreResult, hash };
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=
|
|
1
|
+
"use strict";var e=require("./store"),t=require("./hash"),r=require("./error"),o=require("./types");Object.keys(e).forEach((function(t){"default"===t||Object.prototype.hasOwnProperty.call(exports,t)||Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})})),Object.keys(t).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return t[e]}})})),Object.keys(r).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return r[e]}})})),Object.keys(o).forEach((function(e){"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:function(){return o[e]}})}));
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export*from"./store";export*from"./hash";export*from"./error";export*from"./types";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asaidimu/utils-remote-store",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "A reactive store for remote data, built on top of @asaidimu/utils-cache",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"./*"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@asaidimu/utils-cache": "2.1.
|
|
12
|
+
"@asaidimu/utils-cache": "2.1.1",
|
|
13
13
|
"eventsource": "^4.0.0"
|
|
14
14
|
},
|
|
15
15
|
"exports": {
|