@zajno/common 2.8.9 → 2.8.11

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.
@@ -1,7 +1,7 @@
1
1
  import { type IDisposable } from '../functions/disposer.js';
2
2
  import type { IResettableModel } from '../models/types.js';
3
3
  import type { IExpireTracker } from '../structures/expire.js';
4
- import type { IControllableLazyPromise, ILazyPromiseExtension, LazyFactory } from './types.js';
4
+ import type { IControllableLazyPromise, ILazyPromiseExtension, IResolvedLazyPromise, LazyFactory } from './types.js';
5
5
  /**
6
6
  * Asynchronous lazy-loading container that initializes via a promise-based factory.
7
7
  * Handles concurrent operations with "latest wins" semantics: multiple refreshes are automatically
@@ -22,11 +22,14 @@ export declare class LazyPromise<T, TInitial extends T | undefined = undefined>
22
22
  constructor(factory: LazyFactory<T>, initial?: TInitial);
23
23
  /** Current loading state: true = loading, false = loaded, null = not started */
24
24
  get isLoading(): boolean | null;
25
+ /** Returns true if a value of type `T` has been successfully loaded (no error). */
25
26
  get hasValue(): boolean;
26
27
  get error(): unknown;
28
+ /** @inheritdoc */
29
+ hasResolvedValue(): this is LazyPromise<T, TInitial> & IResolvedLazyPromise<T, TInitial>;
27
30
  /** @deprecated Use {@link error} instead. */
28
31
  get errorMessage(): string | null;
29
- get promise(): Promise<T>;
32
+ get promise(): Promise<T | TInitial>;
30
33
  get value(): T | TInitial;
31
34
  /** Returns current value without triggering loading. */
32
35
  get currentValue(): T | TInitial;
@@ -79,7 +82,7 @@ export declare class LazyPromise<T, TInitial extends T | undefined = undefined>
79
82
  *
80
83
  * @returns Promise resolving to the refreshed value
81
84
  */
82
- refresh(): Promise<T>;
85
+ refresh(): Promise<T | TInitial>;
83
86
  reset(): void;
84
87
  dispose(): void;
85
88
  private ensureInstanceLoading;
@@ -3,7 +3,14 @@ import type { IResettableModel } from '../models/types.js';
3
3
  export interface ILazy<T> {
4
4
  /** Returns current value, triggering loading if not yet loaded. */
5
5
  readonly value: T;
6
- /** Returns true if value has been loaded. Does not trigger loading. */
6
+ /**
7
+ * Returns true if a value of type `T` has been successfully loaded (no error).
8
+ *
9
+ * When `true`, `value` is guaranteed to be `T` (not `TInitial` or an error fallback).
10
+ * When `false`, `value` may be `TInitial`, `undefined`, or a stale value from a previous successful load.
11
+ *
12
+ * Does not trigger loading.
13
+ */
7
14
  readonly hasValue: boolean;
8
15
  /** Returns current value or undefined if not loaded. Does not trigger loading. */
9
16
  readonly currentValue: T | undefined;
@@ -23,12 +30,18 @@ export interface ILazyPromise<T, TInitial extends T | undefined = undefined> ext
23
30
  * Does not trigger loading.
24
31
  */
25
32
  readonly isLoading: boolean | null | undefined;
26
- /** Returns the promise for the value, triggering loading if not started. */
27
- readonly promise: Promise<T>;
33
+ /**
34
+ * Returns the promise for the value, triggering loading if not started.
35
+ *
36
+ * On error, resolves to the current value (stale or initial) instead of rejecting.
37
+ */
38
+ readonly promise: Promise<T | TInitial>;
28
39
  /**
29
40
  * Re-executes the factory to get fresh data. If concurrent refreshes occur, the latest wins.
30
41
  * All awaiting promises will resolve to the final refreshed value.
31
42
  *
43
+ * On error, resolves to the current value (stale or initial) instead of rejecting.
44
+ *
32
45
  * **⚠️ Use sparingly:** Only refresh when explicitly needed for fresh data.
33
46
  * Over-use defeats lazy loading and caching benefits.
34
47
  *
@@ -43,9 +56,32 @@ export interface ILazyPromise<T, TInitial extends T | undefined = undefined> ext
43
56
  * - Using instead of cache expiration (use `withExpire`)
44
57
  * - Calling in loops or high-frequency events without debouncing
45
58
  *
46
- * @returns Promise resolving to the refreshed value
59
+ * @returns Promise resolving to the refreshed value, or the current value on error
47
60
  */
48
- refresh(): Promise<T>;
61
+ refresh(): Promise<T | TInitial>;
62
+ /**
63
+ * Type-narrowing check: returns `true` if the value has been successfully resolved to `T`.
64
+ *
65
+ * When this returns `true`, `value` and `currentValue` are narrowed to `T` (not `TInitial`).
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * const lazy: ILazyPromise<User> = cache.getLazy('user-1');
70
+ * if (lazy.hasResolvedValue()) {
71
+ * // lazy.value is `User` here, not `User | undefined`
72
+ * console.log(lazy.value.name);
73
+ * }
74
+ * ```
75
+ */
76
+ hasResolvedValue(): this is IResolvedLazyPromise<T, TInitial>;
77
+ }
78
+ /** Narrowed state of ILazyPromise after successful resolution. */
79
+ export interface IResolvedLazyPromise<T, TInitial extends T | undefined = undefined> extends ILazyPromise<T, TInitial> {
80
+ readonly value: T;
81
+ readonly currentValue: T;
82
+ readonly hasValue: true;
83
+ readonly isLoading: false;
84
+ readonly error: null;
49
85
  }
50
86
  /**
51
87
  * Controllable lazy promise with manual state management.
@@ -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: (id: K) => Promise<T>, keyAdapter?: K extends string ? null : (k: K) => string, keyParser?: K extends string ? null : (id: string) => K);
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
- * @param keepInstance If true, the cached item will not be removed during invalidation, but the old instance is kept. Defaults to false.
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, keepInstance?: boolean): this;
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,33 +78,52 @@ 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 | undefined>;
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;
68
- protected _getCurrent(id: K): {
69
- item: T | undefined;
70
- key: string;
71
- isInvalid: boolean;
72
- };
99
+ protected _getInitialValue(id: K): TInitial;
73
100
  protected getIsInvalidated(key: string): boolean;
74
101
  /** @override Stores the result for the specified key, enforcing max items. */
75
102
  protected storeResult(key: string, res: T): void;
76
103
  /**
77
- * Fetches the item asynchronously.
78
- * @param id The id of the item.
79
- * @param key The cache key.
80
- * @returns A promise that resolves to the fetched item.
104
+ * Unified fetch method with "latest wins" semantics.
105
+ *
106
+ * - Tracks the active factory promise per key via `_activeFetchPromises`.
107
+ * - If superseded by a newer fetch, delegates to the newer promise.
108
+ * - On error, preserves the stale cached value.
109
+ *
110
+ * @param id The original key.
111
+ * @param key The string cache key.
112
+ * @returns A promise resolving to the fetched/refreshed value, or the stale value on error.
81
113
  */
82
- protected _doFetchAsync(id: K, key: string): Promise<T | undefined>;
114
+ protected _doFetchAsync(id: K, key: string, refreshing: boolean): Promise<T | TInitial>;
83
115
  /** Performs a fetch operation in batch mode if available, otherwise uses the regular fetch. Throws on error. */
84
- protected tryFetchInBatch(id: K): Promise<T>;
116
+ protected tryFetchInBatch(id: K, refreshing?: boolean): Promise<T>;
85
117
  /** Handles a fetch error: stores it, logs it, and calls the onError callback. */
86
- private _handleError;
118
+ protected _handleError(id: K, err: unknown): void;
87
119
  /**
88
120
  * Enforces the max items limit by removing items to make room.
89
- * Strategy: first removes invalid items, then oldest valid items.
121
+ * Strategy: first removes invalid items, then oldest valid items by timestamp.
90
122
  * Items currently being fetched (in-flight) are not evicted.
91
123
  *
124
+ * Note: Phase 2 scans all timestamps linearly (O(n) per eviction).
125
+ * This is acceptable for typical `maxItems` values (up to ~1000).
126
+ *
92
127
  * @param incomingKey The key of the item about to be stored (excluded from eviction).
93
128
  */
94
129
  private _enforceMaxItems;
@@ -11,29 +11,41 @@ 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, updateValueDirectly, clear)
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. */
23
- protected readonly _itemsCache: IMapModel<string, T | undefined>;
23
+ protected readonly _itemsCache: IMapModel<string, T>;
24
24
  /** Stores items loading state (loading or not) in map by id. */
25
25
  protected readonly _itemsStatus: IMapModel<string, boolean>;
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 | undefined>>;
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
- /** Returns the number of items currently being fetched. */
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;
@@ -54,7 +66,7 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
54
66
  *
55
67
  * Warning: as name indicates, this should be "pure"/"const" function, i.e. should not reference `this`/`super`.
56
68
  */
57
- protected pure_createItemsCache(): IMapModel<string, T | undefined>;
69
+ protected pure_createItemsCache(): IMapModel<string, T>;
58
70
  /**
59
71
  * @pure @const
60
72
  * Creates a map for tracking the loading state of items by id. Override to inject own instance, e.g. for observability.
@@ -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 | undefined>>;
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()` invalidates and re-fetches.
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
- * @returns true if loading, false if loading completed, undefined if loading was not started yet.
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 | undefined;
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 | undefined>;
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
- /** Updates the cached value for the specified id directly, like it was fetched already. */
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).
@@ -143,31 +176,29 @@ export declare abstract class PromiseCacheCore<T, K = string> extends Loggable {
143
176
  sanitize(): number;
144
177
  /** Clears the cache and resets the loading state. */
145
178
  clear(): void;
146
- /** Returns the current cached value for the specified key, without triggering a fetch. */
147
- protected abstract _getCurrent(id: K): {
148
- item: T | undefined;
149
- key: string;
150
- isInvalid: boolean;
151
- };
179
+ /** Returns the cached value if present, otherwise the initial value for the key. */
180
+ protected _getCachedOrInitial(key: string, id: K): T | TInitial;
152
181
  /**
153
182
  * Checks if the cached item for the specified key is invalidated (expired).
154
183
  * Override to implement custom invalidation logic.
155
184
  */
156
185
  protected abstract getIsInvalidated(key: string): boolean;
157
- /** @internal updates all caches states at once. */
158
- protected _set(key: string, item: T | undefined, promise: Promise<T> | undefined, isLoading: boolean | undefined): void;
186
+ /** Returns the initial/default value for a key. Used as fallback when no cached value exists. */
187
+ protected abstract _getInitialValue(id: K): TInitial;
188
+ /** @internal Deletes all cache entries for a key (item, promise, status). */
189
+ protected _deleteKey(key: string): void;
159
190
  /** Updates the loading status for the specified key. Override to add a hook. */
160
191
  protected setStatus(key: string, status: boolean): void;
161
192
  /** Updates the promise for the specified key. Override to add a hook. */
162
- protected setPromise(key: string, promise: Promise<T | undefined>): void;
193
+ protected setPromise(key: string, promise: Promise<T | TInitial>): void;
163
194
  /** Stores the result for the specified key. Override to add a hook. */
164
195
  protected storeResult(key: string, res: T): void;
165
196
  /** Hooks into the fetch process before it starts. */
166
197
  protected onBeforeFetch(_key: string): void;
167
198
  /** Hooks into the fetch process after it completes. */
168
199
  protected onFetchComplete(key: string): void;
200
+ /** Hooks into the superseded fetch cleanup. Only decrements loading count — does not touch fetch cache or status. */
201
+ protected onFetchSuperseded(_key: string): void;
169
202
  /** Hooks into the result preparation process, before it's stored into the cache. */
170
203
  protected prepareResult(res: T): T;
171
- /** @internal Helper to set or delete a value in a map. */
172
- protected static _setMapX<T>(key: string, map: IMapModel<string, T>, val: T): void;
173
204
  }
@@ -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
- /** If true, the cached item will not be removed during invalidation, but the old instance is kept. */
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
  }