@zajno/common 2.8.9 → 2.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cjs/lazy/promise.js +20 -4
- package/cjs/lazy/promise.js.map +1 -1
- package/cjs/structures/promiseCache/cache.js +112 -26
- package/cjs/structures/promiseCache/cache.js.map +1 -1
- package/cjs/structures/promiseCache/core.js +50 -13
- package/cjs/structures/promiseCache/core.js.map +1 -1
- package/esm/lazy/promise.js +20 -4
- package/esm/lazy/promise.js.map +1 -1
- package/esm/structures/promiseCache/cache.js +112 -26
- package/esm/structures/promiseCache/cache.js.map +1 -1
- package/esm/structures/promiseCache/core.js +50 -13
- package/esm/structures/promiseCache/core.js.map +1 -1
- package/package.json +1 -1
- package/types/lazy/promise.d.ts +2 -2
- package/types/lazy/types.d.ts +10 -4
- package/types/structures/promiseCache/cache.d.ts +54 -14
- package/types/structures/promiseCache/core.d.ts +50 -13
- package/types/structures/promiseCache/types.d.ts +17 -1
- package/types/structures/tempoCache.d.ts +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PromiseCacheCore } from './core.js';
|
|
2
|
-
import type { ErrorCallback, InvalidationConfig } from './types.js';
|
|
2
|
+
import type { ErrorCallback, InvalidationConfig, PromiseCacheFetcher, PromiseCacheKeyAdapter, PromiseCacheKeyParser } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Caches items by a key (string or another type) which are resolved by an async fetcher (`Promise`).
|
|
5
5
|
*
|
|
@@ -10,18 +10,19 @@ import type { ErrorCallback, InvalidationConfig } from './types.js';
|
|
|
10
10
|
* - auto-invalidation of cached items (time-based, callback-based, max items).
|
|
11
11
|
* - error tracking per key.
|
|
12
12
|
*/
|
|
13
|
-
export declare class PromiseCache<T, K = string> extends PromiseCacheCore<T, K> {
|
|
13
|
+
export declare class PromiseCache<T, K = string, TInitial extends T | undefined = undefined> extends PromiseCacheCore<T, K, TInitial> {
|
|
14
14
|
private readonly fetcher;
|
|
15
15
|
private _batch;
|
|
16
16
|
private _invalidationConfig;
|
|
17
17
|
private _onError;
|
|
18
|
+
private _initialValueFactory;
|
|
18
19
|
/**
|
|
19
20
|
* Creates an instance of PromiseCache.
|
|
20
21
|
* @param fetcher Function to fetch data by key.
|
|
21
22
|
* @param keyAdapter Optional function to adapt non-string keys to strings.
|
|
22
23
|
* @param keyParser Optional function to parse string keys back to their original type.
|
|
23
24
|
*/
|
|
24
|
-
constructor(fetcher:
|
|
25
|
+
constructor(fetcher: PromiseCacheFetcher<T, K>, keyAdapter?: PromiseCacheKeyAdapter<K>, keyParser?: PromiseCacheKeyParser<K>);
|
|
25
26
|
/**
|
|
26
27
|
* Provide a fetcher function that takes multiple ids and returns multiple results at once. Will be called with a slight delay to allow multiple ids to be collected.
|
|
27
28
|
*
|
|
@@ -36,9 +37,11 @@ export declare class PromiseCache<T, K = string> extends PromiseCacheCore<T, K>
|
|
|
36
37
|
* This is a convenience wrapper around {@link useInvalidation}.
|
|
37
38
|
*
|
|
38
39
|
* @param ms Time in milliseconds after which the item will be considered invalid. If null, auto-invalidation is disabled.
|
|
39
|
-
*
|
|
40
|
+
*
|
|
41
|
+
* @deprecated The `keepInstance` parameter is deprecated and ignored — stale values are now always kept during invalidation.
|
|
42
|
+
* Use `invalidate()` followed by `get()` if you need to clear the stale value before re-fetching.
|
|
40
43
|
*/
|
|
41
|
-
useInvalidationTime(ms: number | null,
|
|
44
|
+
useInvalidationTime(ms: number | null, _keepInstance?: boolean): this;
|
|
42
45
|
/**
|
|
43
46
|
* Configures advanced invalidation policy.
|
|
44
47
|
*
|
|
@@ -54,6 +57,19 @@ export declare class PromiseCache<T, K = string> extends PromiseCacheCore<T, K>
|
|
|
54
57
|
* @param callback The callback to call on error. Receives the original key and the raw error.
|
|
55
58
|
*/
|
|
56
59
|
useOnError(callback: ErrorCallback<K> | null): this;
|
|
60
|
+
/**
|
|
61
|
+
* Sets a default/initial value returned before the fetch completes or on error when no stale value exists.
|
|
62
|
+
*
|
|
63
|
+
* Accepts either a static value or a per-key factory function `(key: K) => TInitial`.
|
|
64
|
+
* The value is **not** stored in the cache — it's a synthetic default (same as `LazyPromise`'s initial value).
|
|
65
|
+
*
|
|
66
|
+
* **Note:** Functions are always interpreted as factories. If `T` is a function type,
|
|
67
|
+
* wrap it: `useInitialValue((key) => myFallbackFn)`.
|
|
68
|
+
*
|
|
69
|
+
* @param initial A value (non-function) or `(key: K) => TInitial` factory.
|
|
70
|
+
* @returns `this` for chaining.
|
|
71
|
+
*/
|
|
72
|
+
useInitialValue<TNewInitial extends T | undefined>(initial: TNewInitial | ((key: K) => TNewInitial)): PromiseCache<T, K, TNewInitial>;
|
|
57
73
|
/**
|
|
58
74
|
* Returns a promise that resolves to the cached value of the item if loaded already, otherwise starts fetching and the promise will be resolved to the final value.
|
|
59
75
|
*
|
|
@@ -62,9 +78,25 @@ export declare class PromiseCache<T, K = string> extends PromiseCacheCore<T, K>
|
|
|
62
78
|
* @param id The id of the item.
|
|
63
79
|
* @returns A promise that resolves to the result, whether it's cached or freshly fetched.
|
|
64
80
|
*/
|
|
65
|
-
get(id: K): Promise<T |
|
|
81
|
+
get(id: K): Promise<T | TInitial>;
|
|
82
|
+
/**
|
|
83
|
+
* Re-fetches the value for the specified key while keeping the stale cached value available.
|
|
84
|
+
*
|
|
85
|
+
* Does not change the loading status — consumers reading `getCurrent()` / `getLazy().value`
|
|
86
|
+
* continue to see the stale value as if nothing happened.
|
|
87
|
+
*
|
|
88
|
+
* Implements "latest wins" concurrency: if multiple refreshes are called concurrently,
|
|
89
|
+
* all promises resolve to the value from the latest refresh.
|
|
90
|
+
*
|
|
91
|
+
* On error, the stale value is preserved and the error is stored.
|
|
92
|
+
*
|
|
93
|
+
* @param id The key of the item to refresh.
|
|
94
|
+
* @returns A promise resolving to the refreshed value, or the stale value on error.
|
|
95
|
+
*/
|
|
96
|
+
refresh(id: K): Promise<T | TInitial>;
|
|
66
97
|
/** Clears the cache and resets the loading state. */
|
|
67
98
|
clear(): void;
|
|
99
|
+
protected _getInitialValue(id: K): TInitial;
|
|
68
100
|
protected _getCurrent(id: K): {
|
|
69
101
|
item: T | undefined;
|
|
70
102
|
key: string;
|
|
@@ -74,21 +106,29 @@ export declare class PromiseCache<T, K = string> extends PromiseCacheCore<T, K>
|
|
|
74
106
|
/** @override Stores the result for the specified key, enforcing max items. */
|
|
75
107
|
protected storeResult(key: string, res: T): void;
|
|
76
108
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
109
|
+
* Unified fetch method with "latest wins" semantics.
|
|
110
|
+
*
|
|
111
|
+
* - Tracks the active factory promise per key via `_activeFetchPromises`.
|
|
112
|
+
* - If superseded by a newer fetch, delegates to the newer promise.
|
|
113
|
+
* - On error, preserves the stale cached value.
|
|
114
|
+
*
|
|
115
|
+
* @param id The original key.
|
|
116
|
+
* @param key The string cache key.
|
|
117
|
+
* @returns A promise resolving to the fetched/refreshed value, or the stale value on error.
|
|
81
118
|
*/
|
|
82
|
-
protected _doFetchAsync(id: K, key: string): Promise<T |
|
|
119
|
+
protected _doFetchAsync(id: K, key: string, refreshing: boolean): Promise<T | TInitial>;
|
|
83
120
|
/** Performs a fetch operation in batch mode if available, otherwise uses the regular fetch. Throws on error. */
|
|
84
|
-
protected tryFetchInBatch(id: K): Promise<T>;
|
|
121
|
+
protected tryFetchInBatch(id: K, refreshing?: boolean): Promise<T>;
|
|
85
122
|
/** Handles a fetch error: stores it, logs it, and calls the onError callback. */
|
|
86
|
-
|
|
123
|
+
protected _handleError(id: K, err: unknown): void;
|
|
87
124
|
/**
|
|
88
125
|
* Enforces the max items limit by removing items to make room.
|
|
89
|
-
* Strategy: first removes invalid items, then oldest valid items.
|
|
126
|
+
* Strategy: first removes invalid items, then oldest valid items by timestamp.
|
|
90
127
|
* Items currently being fetched (in-flight) are not evicted.
|
|
91
128
|
*
|
|
129
|
+
* Note: Phase 2 scans all timestamps linearly (O(n) per eviction).
|
|
130
|
+
* This is acceptable for typical `maxItems` values (up to ~1000).
|
|
131
|
+
*
|
|
92
132
|
* @param incomingKey The key of the item about to be stored (excluded from eviction).
|
|
93
133
|
*/
|
|
94
134
|
private _enforceMaxItems;
|
|
@@ -11,12 +11,12 @@ import type { DeferredGetter } from './types.js';
|
|
|
11
11
|
* - promise caching
|
|
12
12
|
* - error storage
|
|
13
13
|
* - timestamps for cached items
|
|
14
|
-
* - direct cache manipulation (invalidate,
|
|
14
|
+
* - direct cache manipulation (invalidate, set, clear)
|
|
15
15
|
* - keys iteration
|
|
16
16
|
*
|
|
17
17
|
* Subclasses are expected to implement fetching logic, invalidation policies, etc.
|
|
18
18
|
*/
|
|
19
|
-
export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
19
|
+
export declare abstract class PromiseCacheCore<T, K = string, TInitial extends T | undefined = undefined> extends Loggable {
|
|
20
20
|
protected readonly keyAdapter?: ((k: K) => string) | null | undefined;
|
|
21
21
|
protected readonly keyParser?: ((id: string) => K) | null | undefined;
|
|
22
22
|
/** Stores resolved items in map by id. */
|
|
@@ -26,14 +26,26 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
26
26
|
/** Stores items loading count. */
|
|
27
27
|
protected readonly _loadingCount: IValueModel<number>;
|
|
28
28
|
/** Stores items Promises state (if still loading) in map by id. */
|
|
29
|
-
protected readonly _fetchCache: IMapModel<string, Promise<T |
|
|
29
|
+
protected readonly _fetchCache: IMapModel<string, Promise<T | TInitial>>;
|
|
30
30
|
/** Stores last errors by key. Observable-friendly via IMapModel. */
|
|
31
31
|
protected readonly _errorsMap: IMapModel<string, unknown>;
|
|
32
32
|
/** Stores items resolve timestamps (for expiration) in map by id. */
|
|
33
33
|
protected readonly _timestamps: Map<string, number>;
|
|
34
|
+
/**
|
|
35
|
+
* Tracks the latest in-flight factory promise per key for "latest wins" refresh semantics.
|
|
36
|
+
* Separate from `_fetchCache` (which stores the public-facing promise returned to callers).
|
|
37
|
+
*/
|
|
38
|
+
protected readonly _activeFetchPromises: Map<string, Promise<T | TInitial>>;
|
|
34
39
|
protected _version: number;
|
|
35
40
|
constructor(keyAdapter?: ((k: K) => string) | null | undefined, keyParser?: ((id: string) => K) | null | undefined);
|
|
36
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Returns the number of items currently being fetched (includes background refreshes).
|
|
43
|
+
*
|
|
44
|
+
* Note: `loadingCount` includes background refreshes started via `refresh()`,
|
|
45
|
+
* but `getIsLoading(key)` does **not** reflect background refreshes — it only
|
|
46
|
+
* tracks the per-key status set by `get()`. Use `loadingCount` for global
|
|
47
|
+
* "something is loading" indicators.
|
|
48
|
+
*/
|
|
37
49
|
get loadingCount(): number;
|
|
38
50
|
/** Returns the number of cached items (resolved values). */
|
|
39
51
|
get cachedCount(): number;
|
|
@@ -68,7 +80,7 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
68
80
|
*
|
|
69
81
|
* Warning: as name indicates, this should be "pure"/"const" function, i.e. should not reference `this`/`super`.
|
|
70
82
|
*/
|
|
71
|
-
protected pure_createFetchCache(): IMapModel<string, Promise<T |
|
|
83
|
+
protected pure_createFetchCache(): IMapModel<string, Promise<T | TInitial>>;
|
|
72
84
|
/**
|
|
73
85
|
* @pure @const
|
|
74
86
|
* Creates a map for storing last errors by key. Override to inject own instance, e.g. for observability.
|
|
@@ -87,9 +99,9 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
87
99
|
*
|
|
88
100
|
* - `value` / `promise` trigger a fetch if not started.
|
|
89
101
|
* - `currentValue` reads without triggering.
|
|
90
|
-
* - `refresh()`
|
|
102
|
+
* - `refresh()` re-fetches while keeping the stale value available.
|
|
91
103
|
*/
|
|
92
|
-
getLazy(key: K): ILazyPromise<T>;
|
|
104
|
+
getLazy(key: K): ILazyPromise<T, TInitial>;
|
|
93
105
|
/**
|
|
94
106
|
* Returns a {@link DeferredGetter} object for a specified key.
|
|
95
107
|
*
|
|
@@ -102,7 +114,11 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
102
114
|
/**
|
|
103
115
|
* Returns the loading state of an item.
|
|
104
116
|
*
|
|
105
|
-
*
|
|
117
|
+
* Note: background refreshes via `refresh()` do **not** update per-key loading status.
|
|
118
|
+
* This method only reflects fetches initiated by `get()`. Use `loadingCount` for
|
|
119
|
+
* a global indicator that includes background refreshes.
|
|
120
|
+
*
|
|
121
|
+
* @returns true if loading, false if loading completed, undefined if loading was not started yet (or invalidated).
|
|
106
122
|
*/
|
|
107
123
|
getIsLoading(id: K): boolean | undefined;
|
|
108
124
|
/**
|
|
@@ -117,10 +133,23 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
117
133
|
* @returns The raw error, or null if no error.
|
|
118
134
|
*/
|
|
119
135
|
getLastError(id: K): unknown;
|
|
120
|
-
/** Returns the current cached value, optionally triggering a fetch. */
|
|
121
|
-
getCurrent(id: K, initiateFetch?: boolean): T |
|
|
136
|
+
/** Returns the current cached value, optionally triggering a fetch. Falls back to the initial value if configured. */
|
|
137
|
+
getCurrent(id: K, initiateFetch?: boolean): T | TInitial;
|
|
122
138
|
/** Returns a promise that resolves to the cached or freshly fetched value. */
|
|
123
|
-
abstract get(id: K): Promise<T |
|
|
139
|
+
abstract get(id: K): Promise<T | TInitial>;
|
|
140
|
+
/**
|
|
141
|
+
* Re-fetches the value for the specified key while keeping the stale cached value available.
|
|
142
|
+
*
|
|
143
|
+
* Implements stale-while-revalidate semantics:
|
|
144
|
+
* - The current cached value remains accessible via `getCurrent()` / `getLazy().value` during the refresh.
|
|
145
|
+
* - On success, the cached value is updated.
|
|
146
|
+
* - On error, the stale value is preserved and the error is stored.
|
|
147
|
+
* - Multiple concurrent refreshes use "latest wins" semantics.
|
|
148
|
+
*
|
|
149
|
+
* @param id The key of the item to refresh.
|
|
150
|
+
* @returns A promise resolving to the refreshed value, or the stale value on error.
|
|
151
|
+
*/
|
|
152
|
+
abstract refresh(id: K): Promise<T | TInitial>;
|
|
124
153
|
/** Returns true if the item is cached or fetching was initiated. Does not initiate fetching. */
|
|
125
154
|
hasKey(id: K): boolean;
|
|
126
155
|
/** Returns an iterator over the keys of the cached items. */
|
|
@@ -133,7 +162,11 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
133
162
|
keysParsed(): K[] | null;
|
|
134
163
|
/** Instantly invalidates the cached item for the specified id, like it was never fetched/accessed. */
|
|
135
164
|
invalidate(id: K): void;
|
|
136
|
-
/**
|
|
165
|
+
/** Injects a value into the cache for the specified key, as if it had been fetched. Sets the timestamp and clears any previous error. Cancels any in-flight fetch for this key. */
|
|
166
|
+
set(id: K, value: T): void;
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated Use {@link set} instead.
|
|
169
|
+
*/
|
|
137
170
|
updateValueDirectly(id: K, value: T): void;
|
|
138
171
|
/**
|
|
139
172
|
* Iterates over all cached items and removes those that are invalid (expired).
|
|
@@ -154,18 +187,22 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
|
|
|
154
187
|
* Override to implement custom invalidation logic.
|
|
155
188
|
*/
|
|
156
189
|
protected abstract getIsInvalidated(key: string): boolean;
|
|
190
|
+
/** Returns the initial/default value for a key. Used as fallback when no cached value exists. */
|
|
191
|
+
protected abstract _getInitialValue(id: K): TInitial;
|
|
157
192
|
/** @internal updates all caches states at once. */
|
|
158
193
|
protected _set(key: string, item: T | undefined, promise: Promise<T> | undefined, isLoading: boolean | undefined): void;
|
|
159
194
|
/** Updates the loading status for the specified key. Override to add a hook. */
|
|
160
195
|
protected setStatus(key: string, status: boolean): void;
|
|
161
196
|
/** Updates the promise for the specified key. Override to add a hook. */
|
|
162
|
-
protected setPromise(key: string, promise: Promise<T |
|
|
197
|
+
protected setPromise(key: string, promise: Promise<T | TInitial>): void;
|
|
163
198
|
/** Stores the result for the specified key. Override to add a hook. */
|
|
164
199
|
protected storeResult(key: string, res: T): void;
|
|
165
200
|
/** Hooks into the fetch process before it starts. */
|
|
166
201
|
protected onBeforeFetch(_key: string): void;
|
|
167
202
|
/** Hooks into the fetch process after it completes. */
|
|
168
203
|
protected onFetchComplete(key: string): void;
|
|
204
|
+
/** Hooks into the superseded fetch cleanup. Only decrements loading count — does not touch fetch cache or status. */
|
|
205
|
+
protected onFetchSuperseded(_key: string): void;
|
|
169
206
|
/** Hooks into the result preparation process, before it's stored into the cache. */
|
|
170
207
|
protected prepareResult(res: T): T;
|
|
171
208
|
/** @internal Helper to set or delete a value in a map. */
|
|
@@ -32,6 +32,17 @@ export declare namespace DeferredGetter {
|
|
|
32
32
|
export type InvalidationCallback<T> = (key: string, value: T | undefined, cachedAt: number) => boolean;
|
|
33
33
|
/** Callback for handling errors during fetching. */
|
|
34
34
|
export type ErrorCallback<K> = (key: K, error: unknown) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Fetcher function signature for PromiseCache.
|
|
37
|
+
*
|
|
38
|
+
* @param id The key of the item to fetch.
|
|
39
|
+
* @param refreshing `true` when called via `refresh()`, `false` on initial `get()`.
|
|
40
|
+
*/
|
|
41
|
+
export type PromiseCacheFetcher<T, K = string> = (id: K, refreshing?: boolean) => Promise<T>;
|
|
42
|
+
/** Converts a non-string key to a string for internal cache storage. Resolves to `undefined` when `K` is `string`. */
|
|
43
|
+
export type PromiseCacheKeyAdapter<K> = K extends string ? undefined : (k: K) => string;
|
|
44
|
+
/** Parses a string key back to the original key type. Resolves to `undefined` when `K` is `string`. */
|
|
45
|
+
export type PromiseCacheKeyParser<K> = K extends string ? undefined : (id: string) => K;
|
|
35
46
|
/**
|
|
36
47
|
* Configuration for cache invalidation policy.
|
|
37
48
|
*
|
|
@@ -51,8 +62,13 @@ export interface InvalidationConfig<T> {
|
|
|
51
62
|
* then oldest valid items are removed to make room.
|
|
52
63
|
*
|
|
53
64
|
* Note: items currently being fetched (in-flight) are not evicted.
|
|
65
|
+
*
|
|
66
|
+
* Performance: eviction scans all cached timestamps linearly. Suitable for caches up to ~1000 items.
|
|
54
67
|
*/
|
|
55
68
|
readonly maxItems?: number | null;
|
|
56
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* @deprecated This option is now ignored — stale values are always kept during invalidation (stale-while-revalidate).
|
|
71
|
+
* Use `invalidate()` followed by `get()` if you need to clear the stale value before re-fetching.
|
|
72
|
+
*/
|
|
57
73
|
readonly keepInstance?: boolean;
|
|
58
74
|
}
|
|
@@ -26,5 +26,5 @@ export declare namespace TempoCache {
|
|
|
26
26
|
*
|
|
27
27
|
* Note a limitation: calling `reset` (or changing the stored value directly in other way) on `lazy` will not affect the value cached by `TempoCache` instance.
|
|
28
28
|
*/
|
|
29
|
-
function createFromLazyPromise<T>(lazy: ILazyPromise<T> & IResettableModel, lifetimeMs: number): TempoCache<Promise<T>>;
|
|
29
|
+
function createFromLazyPromise<T>(lazy: ILazyPromise<T> & IResettableModel, lifetimeMs: number): TempoCache<Promise<T | undefined>>;
|
|
30
30
|
}
|