🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

lru-cache

Package Overview
Dependencies
Maintainers
1
Versions
163
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lru-cache - npm Package Compare versions

Comparing version
11.3.1
to
11.3.2
+1
dist/esm/node/diagnostics-channel-node.d.mts.map
{"version":3,"file":"diagnostics-channel-node.d.mts","sourceRoot":"","sources":["../../../src/diagnostics-channel-node.mts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAA;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AACvE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,CAAA;AACvC,eAAO,MAAM,OAAO,EAAE,OAAO,CAAC,OAAO,CAAgC,CAAA;AACrE,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,OAAO,CAA+B,CAAA"}
{"version":3,"file":"diagnostics-channel-node.mjs","sourceRoot":"","sources":["../../../src/diagnostics-channel-node.mts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,6DAA6D;AAC7D,4DAA4D;AAC5D,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAA;AAGlC,MAAM,CAAC,MAAM,OAAO,GAAqB,OAAO,CAAC,mBAAmB,CAAC,CAAA;AACrE,MAAM,CAAC,MAAM,OAAO,GAA4B,cAAc,CAAC,WAAW,CAAC,CAAA","sourcesContent":["// simple node version that imports from node builtin\n// this gets compiled to a require() commonjs-style override,\n// not using top level await on a conditional dynamic import\nimport { tracingChannel, channel } from 'node:diagnostics_channel'\nexport { tracingChannel, channel }\nimport type { TracingChannel, Channel } from 'node:diagnostics_channel'\nexport type { TracingChannel, Channel }\nexport const metrics: Channel<unknown> = channel('lru-cache:metrics')\nexport const tracing: TracingChannel<unknown> = tracingChannel('lru-cache')\n"]}
import { tracingChannel, channel } from 'node:diagnostics_channel';
export { tracingChannel, channel };
import type { TracingChannel, Channel } from 'node:diagnostics_channel';
export type { TracingChannel, Channel };
export declare const metrics: Channel<unknown>;
export declare const tracing: TracingChannel<unknown>;
//# sourceMappingURL=diagnostics-channel-node.d.mts.map
// simple node version that imports from node builtin
// this gets compiled to a require() commonjs-style override,
// not using top level await on a conditional dynamic import
import { tracingChannel, channel } from 'node:diagnostics_channel';
export { tracingChannel, channel };
export const metrics = channel('lru-cache:metrics');
export const tracing = tracingChannel('lru-cache');
//# sourceMappingURL=diagnostics-channel-node.mjs.map
/**
* @module LRUCache
*/
export type Perf = {
now: () => number;
};
declare const TYPE: unique symbol;
export type PosInt = number & {
[TYPE]: 'Positive Integer';
};
export type Index = number & {
[TYPE]: 'LRUCache Index';
};
export type UintArray = Uint8Array | Uint16Array | Uint32Array;
export type NumberArray = UintArray | number[];
declare class ZeroArray extends Array<number> {
constructor(size: number);
}
export type { ZeroArray };
export type { Stack };
export type StackLike = Stack | Index[];
declare class Stack {
#private;
heap: NumberArray;
length: number;
static create(max: number): StackLike;
constructor(max: number, HeapCls: {
new (n: number): NumberArray;
});
push(n: Index): void;
pop(): Index;
}
/**
* Promise representing an in-progress {@link LRUCache#fetch} call
*/
export type BackgroundFetch<V> = Promise<V | undefined> & {
__returned: BackgroundFetch<V> | undefined;
__abortController: AbortController;
__staleWhileFetching: V | undefined;
};
export type DisposeTask<K, V> = [
value: V,
key: K,
reason: LRUCache.DisposeReason
];
export declare namespace LRUCache {
/**
* An integer greater than 0, reflecting the calculated size of items
*/
type Size = number;
/**
* Integer greater than 0, representing some number of milliseconds, or the
* time at which a TTL started counting from.
*/
type Milliseconds = number;
/**
* An integer greater than 0, reflecting a number of items
*/
type Count = number;
/**
* The reason why an item was removed from the cache, passed
* to the {@link Disposer} methods.
*
* - `evict`: The item was evicted because it is the least recently used,
* and the cache is full.
* - `set`: A new value was set, overwriting the old value being disposed.
* - `delete`: The item was explicitly deleted, either by calling
* {@link LRUCache#delete}, {@link LRUCache#clear}, or
* {@link LRUCache#set} with an undefined value.
* - `expire`: The item was removed due to exceeding its TTL.
* - `fetch`: A {@link OptionsBase#fetchMethod} operation returned
* `undefined` or was aborted, causing the item to be deleted.
*/
type DisposeReason = 'evict' | 'set' | 'delete' | 'expire' | 'fetch';
/**
* A method called upon item removal, passed as the
* {@link OptionsBase.dispose} and/or
* {@link OptionsBase.disposeAfter} options.
*/
type Disposer<K, V> = (value: V, key: K, reason: DisposeReason) => void;
/**
* The reason why an item was added to the cache, passed
* to the {@link Inserter} methods.
*
* - `add`: the item was not found in the cache, and was added
* - `update`: the item was in the cache, with the same value provided
* - `replace`: the item was in the cache, and replaced
*/
type InsertReason = 'add' | 'update' | 'replace';
/**
* A method called upon item insertion, passed as the
* {@link OptionsBase.insert}
*/
type Inserter<K, V> = (value: V, key: K, reason: InsertReason) => void;
/**
* A function that returns the effective calculated size
* of an entry in the cache.
*/
type SizeCalculator<K, V> = (value: V, key: K) => Size;
/**
* Options provided to the
* {@link OptionsBase.fetchMethod} function.
*/
interface FetcherOptions<K, V, FC = unknown> {
signal: AbortSignal;
options: FetcherFetchOptions<K, V, FC>;
/**
* Object provided in the {@link FetchOptions.context} option to
* {@link LRUCache#fetch}
*/
context: FC;
}
/**
* Occasionally, it may be useful to track the internal behavior of the
* cache, particularly for logging, debugging, or for behavior within the
* `fetchMethod`. To do this, you can pass a `status` object to the
* {@link LRUCache#fetch}, {@link LRUCache#get}, {@link LRUCache#set},
* {@link LRUCache#memo}, and {@link LRUCache#has} methods.
*
* The `status` option should be a plain JavaScript object. The following
* fields will be set on it appropriately, depending on the situation.
*
* These objects are also the context objects passed to listeners on the
* `lru-cache:metrics` diagnostic channel, and the `lru-cache` tracing
* channels, in platforms that support them.
*/
interface Status<K, V> {
/**
* The operation being performed
*/
op?: 'get' | 'set' | 'memo' | 'fetch' | 'delete' | 'has' | 'peek';
/**
* The status of a set() operation.
*
* - add: the item was not found in the cache, and was added
* - update: the item was in the cache, with the same value provided
* - replace: the item was in the cache, and replaced
* - miss: the item was not added to the cache for some reason
*/
set?: 'add' | 'update' | 'replace' | 'miss' | 'deleted';
/**
* The status of a delete() operation.
*/
delete?: LRUCache.DisposeReason;
/**
* The result of a peek() operation
*
* - hit: the item was found and returned
* - stale: the item is in the cache, but past its ttl and not returned
* - miss: item not in the cache
*/
peek?: 'hit' | 'miss' | 'stale';
/**
* The status of a memo() operation.
*
* - 'hit': the item was found in the cache and returned
* - 'miss': the `memoMethod` function was called
*/
memo?: 'hit' | 'miss';
/**
* The `context` option provided to a memo or fetch operation
*
* In practice, of course, this will be the same type as the `FC`
* fetch context param used to instantiate the LRUCache, but the
* convolutions of threading that through would get quite complicated,
* and preclude forcing/forbidding the passing of a `context` param
* where it is/isn't expected, which is more valuable for error
* prevention.
*/
context?: unknown;
/**
* the ttl stored for the item, or undefined if ttls are not used.
*/
ttl?: Milliseconds;
/**
* the start time for the item, or undefined if ttls are not used.
*/
start?: Milliseconds;
/**
* The timestamp used for TTL calculation
*/
now?: Milliseconds;
/**
* the remaining ttl for the item, or undefined if ttls are not used.
*/
remainingTTL?: Milliseconds;
/**
* The calculated size for the item, if sizes are used.
*/
entrySize?: Size;
/**
* The total calculated size of the cache, if sizes are used.
*/
totalCalculatedSize?: Size;
/**
* A flag indicating that the item was not stored, due to exceeding the
* {@link OptionsBase.maxEntrySize}
*/
maxEntrySizeExceeded?: true;
/**
* The key that was set or retrieved
*/
key?: K;
/**
* The value that was set
*/
value?: V;
/**
* The old value, specified in the case of `set:'replace'`
*/
oldValue?: V;
/**
* The results of a {@link LRUCache#has} operation
*
* - hit: the item was found in the cache
* - stale: the item was found in the cache, but is stale
* - miss: the item was not found in the cache
*/
has?: 'hit' | 'stale' | 'miss';
/**
* The status of a {@link LRUCache#fetch} operation.
* Note that this can change as the underlying fetch() moves through
* various states.
*
* - inflight: there is another fetch() for this key which is in process
* - get: there is no {@link OptionsBase.fetchMethod}, so
* {@link LRUCache#get} was called.
* - miss: the item is not in cache, and will be fetched.
* - hit: the item is in the cache, and was resolved immediately.
* - stale: the item is in the cache, but stale.
* - refresh: the item is in the cache, and not stale, but
* {@link FetchOptions.forceRefresh} was specified.
*/
fetch?: 'get' | 'inflight' | 'miss' | 'hit' | 'stale' | 'refresh';
/**
* `forceRefresh` option was used for either a fetch or memo operation
*/
forceRefresh?: boolean;
/**
* The {@link OptionsBase.fetchMethod} was called
*/
fetchDispatched?: true;
/**
* The cached value was updated after a successful call to
* {@link OptionsBase.fetchMethod}
*/
fetchUpdated?: true;
/**
* The reason for a fetch() rejection. Either the error raised by the
* {@link OptionsBase.fetchMethod}, or the reason for an
* AbortSignal.
*/
fetchError?: Error;
/**
* The fetch received an abort signal
*/
fetchAborted?: true;
/**
* The abort signal received was ignored, and the fetch was allowed to
* continue in the background.
*/
fetchAbortIgnored?: true;
/**
* The fetchMethod promise resolved successfully
*/
fetchResolved?: true;
/**
* The fetchMethod promise was rejected
*/
fetchRejected?: true;
/**
* The status of a {@link LRUCache#get} operation.
*
* - fetching: The item is currently being fetched. If a previous value
* is present and allowed, that will be returned.
* - stale: The item is in the cache, and is stale. If it was returned,
* then the `returnedStale` flag will be set.
* - stale-fetching: The value is being fetched in the background, but is
* currently stale. If the stale value was returned, then the
* `returnedStale` flag will be set.
* - hit: the item is in the cache
* - miss: the item is not in the cache
*/
get?: 'stale' | 'hit' | 'miss' | 'fetching' | 'stale-fetching';
/**
* A fetch or get operation returned a stale value.
*/
returnedStale?: true;
/**
* A tracingChannel trace was started for this operation
*/
trace?: boolean;
}
/**
* options which override the options set in the LRUCache constructor
* when calling {@link LRUCache#fetch}.
*
* This is the union of {@link GetOptions} and {@link SetOptions}, plus
* {@link OptionsBase.noDeleteOnFetchRejection},
* {@link OptionsBase.allowStaleOnFetchRejection},
* {@link FetchOptions.forceRefresh}, and
* {@link FetcherOptions.context}
*
* Any of these may be modified in the {@link OptionsBase.fetchMethod}
* function, but the {@link GetOptions} fields will of course have no
* effect, as the {@link LRUCache#get} call already happened by the time
* the fetchMethod is called.
*/
interface FetcherFetchOptions<K, V, FC = unknown> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' | 'noDeleteOnFetchRejection' | 'allowStaleOnFetchRejection' | 'ignoreFetchAbort' | 'allowStaleOnFetchAbort'> {
status?: Status<K, V>;
size?: Size;
}
/**
* Options that may be passed to the {@link LRUCache#fetch} method.
*/
interface FetchOptions<K, V, FC> extends FetcherFetchOptions<K, V, FC> {
/**
* Set to true to force a re-load of the existing data, even if it
* is not yet stale.
*/
forceRefresh?: boolean;
/**
* Context provided to the {@link OptionsBase.fetchMethod} as
* the {@link FetcherOptions.context} param.
*
* If the FC type is specified as unknown (the default),
* undefined or void, then this is optional. Otherwise, it will
* be required.
*/
context?: FC;
signal?: AbortSignal;
status?: Status<K, V>;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is something
* other than `unknown`, `undefined`, or `void`
*/
interface FetchOptionsWithContext<K, V, FC> extends FetchOptions<K, V, FC> {
context: FC;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is
* `undefined` or `void`
*/
interface FetchOptionsNoContext<K, V> extends FetchOptions<K, V, undefined> {
context?: undefined;
}
interface MemoOptions<K, V, FC = unknown> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' | 'noDeleteOnFetchRejection' | 'allowStaleOnFetchRejection' | 'ignoreFetchAbort' | 'allowStaleOnFetchAbort'> {
/**
* Set to true to force a re-load of the existing data, even if it
* is not yet stale.
*/
forceRefresh?: boolean;
/**
* Context provided to the {@link OptionsBase.memoMethod} as
* the {@link MemoizerOptions.context} param.
*
* If the FC type is specified as unknown (the default),
* undefined or void, then this is optional. Otherwise, it will
* be required.
*/
context?: FC;
status?: Status<K, V>;
}
/**
* Options provided to {@link LRUCache#memo} when the FC type is something
* other than `unknown`, `undefined`, or `void`
*/
interface MemoOptionsWithContext<K, V, FC> extends MemoOptions<K, V, FC> {
context: FC;
}
/**
* Options provided to {@link LRUCache#memo} when the FC type is
* `undefined` or `void`
*/
interface MemoOptionsNoContext<K, V> extends MemoOptions<K, V, undefined> {
context?: undefined;
}
/**
* Options provided to the
* {@link OptionsBase.memoMethod} function.
*/
interface MemoizerOptions<K, V, FC = unknown> {
options: MemoizerMemoOptions<K, V, FC>;
/**
* Object provided in the {@link MemoOptions.context} option to
* {@link LRUCache#memo}
*/
context: FC;
}
/**
* options which override the options set in the LRUCache constructor
* when calling {@link LRUCache#memo}.
*
* This is the union of {@link GetOptions} and {@link SetOptions}, plus
* {@link MemoOptions.forceRefresh}, and
* {@link MemoOptions.context}
*
* Any of these may be modified in the {@link OptionsBase.memoMethod}
* function, but the {@link GetOptions} fields will of course have no
* effect, as the {@link LRUCache#get} call already happened by the time
* the memoMethod is called.
*/
interface MemoizerMemoOptions<K, V, FC = unknown> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL'> {
status?: Status<K, V>;
size?: Size;
start?: Milliseconds;
}
/**
* Options that may be passed to the {@link LRUCache#has} method.
*/
interface HasOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'updateAgeOnHas'> {
status?: Status<K, V>;
}
/**
* Options that may be passed to the {@link LRUCache#get} method.
*/
interface GetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet'> {
status?: Status<K, V>;
}
/**
* Options that may be passed to the {@link LRUCache#peek} method.
*/
interface PeekOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale'> {
status?: Status<K, V>;
}
/**
* Options that may be passed to the {@link LRUCache#set} method.
*/
interface SetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL'> {
/**
* If size tracking is enabled, then setting an explicit size
* in the {@link LRUCache#set} call will prevent calling the
* {@link OptionsBase.sizeCalculation} function.
*/
size?: Size;
/**
* If TTL tracking is enabled, then setting an explicit start
* time in the {@link LRUCache#set} call will override the
* default time from `performance.now()` or `Date.now()`.
*
* Note that it must be a valid value for whichever time-tracking
* method is in use.
*/
start?: Milliseconds;
status?: Status<K, V>;
}
/**
* The type signature for the {@link OptionsBase.fetchMethod} option.
*/
type Fetcher<K, V, FC = unknown> = (key: K, staleValue: V | undefined, options: FetcherOptions<K, V, FC>) => Promise<V | undefined | void> | V | undefined | void;
/**
* the type signature for the {@link OptionsBase.memoMethod} option.
*/
type Memoizer<K, V, FC = unknown> = (key: K, staleValue: V | undefined, options: MemoizerOptions<K, V, FC>) => V;
/**
* Options which may be passed to the {@link LRUCache} constructor.
*
* Most of these may be overridden in the various options that use
* them.
*
* Despite all being technically optional, the constructor requires that
* a cache is at minimum limited by one or more of {@link OptionsBase.max},
* {@link OptionsBase.ttl}, or {@link OptionsBase.maxSize}.
*
* If {@link OptionsBase.ttl} is used alone, then it is strongly advised
* (and in fact required by the type definitions here) that the cache
* also set {@link OptionsBase.ttlAutopurge}, to prevent potentially
* unbounded storage.
*
* All options are also available on the {@link LRUCache} instance, making
* it safe to pass an LRUCache instance as the options argumemnt to
* make another empty cache of the same type.
*
* Some options are marked as read-only, because changing them after
* instantiation is not safe. Changing any of the other options will of
* course only have an effect on subsequent method calls.
*/
interface OptionsBase<K, V, FC> {
/**
* The maximum number of items to store in the cache before evicting
* old entries. This is read-only on the {@link LRUCache} instance,
* and may not be overridden.
*
* If set, then storage space will be pre-allocated at construction
* time, and the cache will perform significantly faster.
*
* Note that significantly fewer items may be stored, if
* {@link OptionsBase.maxSize} and/or {@link OptionsBase.ttl} are also
* set.
*
* **It is strongly recommended to set a `max` to prevent unbounded growth
* of the cache.**
*/
max?: Count;
/**
* Max time in milliseconds for items to live in cache before they are
* considered stale. Note that stale items are NOT preemptively removed by
* default, and MAY live in the cache, contributing to its LRU max, long
* after they have expired, unless {@link OptionsBase.ttlAutopurge} is
* set.
*
* If set to `0` (the default value), then that means "do not track
* TTL", not "expire immediately".
*
* Also, as this cache is optimized for LRU/MRU operations, some of
* the staleness/TTL checks will reduce performance, as they will incur
* overhead by deleting items.
*
* This is not primarily a TTL cache, and does not make strong TTL
* guarantees. There is no pre-emptive pruning of expired items, but you
* _may_ set a TTL on the cache, and it will treat expired items as missing
* when they are fetched, and delete them.
*
* Optional, but must be a non-negative integer in ms if specified.
*
* This may be overridden by passing an options object to `cache.set()`.
*
* At least one of `max`, `maxSize`, or `TTL` is required. This must be a
* positive integer if set.
*
* Even if ttl tracking is enabled, **it is strongly recommended to set a
* `max` to prevent unbounded growth of the cache.**
*
* If ttl tracking is enabled, and `max` and `maxSize` are not set,
* and `ttlAutopurge` is not set, then a warning will be emitted
* cautioning about the potential for unbounded memory consumption.
* (The TypeScript definitions will also discourage this.)
*/
ttl?: Milliseconds;
/**
* Minimum amount of time in ms in which to check for staleness.
* Defaults to 1, which means that the current time is checked
* at most once per millisecond.
*
* Set to 0 to check the current time every time staleness is tested.
* (This reduces performance, and is theoretically unnecessary.)
*
* Setting this to a higher value will improve performance somewhat
* while using ttl tracking, albeit at the expense of keeping stale
* items around a bit longer than their TTLs would indicate.
*
* @default 1
*/
ttlResolution?: Milliseconds;
/**
* Preemptively remove stale items from the cache.
*
* Note that this may *significantly* degrade performance, especially if
* the cache is storing a large number of items. It is almost always best
* to just leave the stale items in the cache, and let them fall out as new
* items are added.
*
* Note that this means that {@link OptionsBase.allowStale} is a bit
* pointless, as stale items will be deleted almost as soon as they
* expire.
*
* Use with caution!
*/
ttlAutopurge?: boolean;
/**
* When using time-expiring entries with `ttl`, setting this to `true` will
* make each item's age reset to 0 whenever it is retrieved from cache with
* {@link LRUCache#get}, causing it to not expire. (It can still fall out
* of cache based on recency of use, of course.)
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*
* This may be overridden by passing an options object to `cache.get()`.
*/
updateAgeOnGet?: boolean;
/**
* When using time-expiring entries with `ttl`, setting this to `true` will
* make each item's age reset to 0 whenever its presence in the cache is
* checked with {@link LRUCache#has}, causing it to not expire. (It can
* still fall out of cache based on recency of use, of course.)
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*/
updateAgeOnHas?: boolean;
/**
* Allow {@link LRUCache#get} and {@link LRUCache#fetch} calls to return
* stale data, if available.
*
* By default, if you set `ttl`, stale items will only be deleted from the
* cache when you `get(key)`. That is, it's not preemptively pruning items,
* unless {@link OptionsBase.ttlAutopurge} is set.
*
* If you set `allowStale:true`, it'll return the stale value *as well as*
* deleting it. If you don't set this, then it'll return `undefined` when
* you try to get a stale entry.
*
* Note that when a stale entry is fetched, _even if it is returned due to
* `allowStale` being set_, it is removed from the cache immediately. You
* can suppress this behavior by setting
* {@link OptionsBase.noDeleteOnStaleGet}, either in the constructor, or in
* the options provided to {@link LRUCache#get}.
*
* This may be overridden by passing an options object to `cache.get()`.
* The `cache.has()` method will always return `false` for stale items.
*
* Only relevant if a ttl is set.
*/
allowStale?: boolean;
/**
* Function that is called on items when they are dropped from the
* cache, as `dispose(value, key, reason)`.
*
* This can be handy if you want to close file descriptors or do
* other cleanup tasks when items are no longer stored in the cache.
*
* **NOTE**: It is called _before_ the item has been fully removed
* from the cache, so if you want to put it right back in, you need
* to wait until the next tick. If you try to add it back in during
* the `dispose()` function call, it will break things in subtle and
* weird ways.
*
* Unlike several other options, this may _not_ be overridden by
* passing an option to `set()`, for performance reasons.
*
* The `reason` will be one of the following strings, corresponding
* to the reason for the item's deletion:
*
* - `evict` Item was evicted to make space for a new addition
* - `set` Item was overwritten by a new value
* - `expire` Item expired its TTL
* - `fetch` Item was deleted due to a failed or aborted fetch, or a
* fetchMethod returning `undefined.
* - `delete` Item was removed by explicit `cache.delete(key)`,
* `cache.clear()`, or `cache.set(key, undefined)`.
*/
dispose?: Disposer<K, V>;
/**
* Function that is called when new items are inserted into the cache,
* as `onInsert(value, key, reason)`.
*
* This can be useful if you need to perform actions when an item is
* added, such as logging or tracking insertions.
*
* Unlike some other options, this may _not_ be overridden by passing
* an option to `set()`, for performance and consistency reasons.
*/
onInsert?: Inserter<K, V>;
/**
* The same as {@link OptionsBase.dispose}, but called *after* the entry
* is completely removed and the cache is once again in a clean state.
*
* It is safe to add an item right back into the cache at this point.
* However, note that it is *very* easy to inadvertently create infinite
* recursion this way.
*/
disposeAfter?: Disposer<K, V>;
/**
* Set to true to suppress calling the
* {@link OptionsBase.dispose} function if the entry key is
* still accessible within the cache.
*
* This may be overridden by passing an options object to
* {@link LRUCache#set}.
*
* Only relevant if `dispose` or `disposeAfter` are set.
*/
noDisposeOnSet?: boolean;
/**
* Boolean flag to tell the cache to not update the TTL when setting a new
* value for an existing key (ie, when updating a value rather than
* inserting a new value). Note that the TTL value is _always_ set (if
* provided) when adding a new entry into the cache.
*
* Has no effect if a {@link OptionsBase.ttl} is not set.
*
* May be passed as an option to {@link LRUCache#set}.
*/
noUpdateTTL?: boolean;
/**
* Set to a positive integer to track the sizes of items added to the
* cache, and automatically evict items in order to stay below this size.
* Note that this may result in fewer than `max` items being stored.
*
* Attempting to add an item to the cache whose calculated size is greater
* that this amount will be a no-op. The item will not be cached, and no
* other items will be evicted.
*
* Optional, must be a positive integer if provided.
*
* Sets `maxEntrySize` to the same value, unless a different value is
* provided for `maxEntrySize`.
*
* At least one of `max`, `maxSize`, or `TTL` is required. This must be a
* positive integer if set.
*
* Even if size tracking is enabled, **it is strongly recommended to set a
* `max` to prevent unbounded growth of the cache.**
*
* Note also that size tracking can negatively impact performance,
* though for most cases, only minimally.
*/
maxSize?: Size;
/**
* The maximum allowed size for any single item in the cache.
*
* If a larger item is passed to {@link LRUCache#set} or returned by a
* {@link OptionsBase.fetchMethod} or {@link OptionsBase.memoMethod}, then
* it will not be stored in the cache.
*
* Attempting to add an item whose calculated size is greater than
* this amount will not cache the item or evict any old items, but
* WILL delete an existing value if one is already present.
*
* Optional, must be a positive integer if provided. Defaults to
* the value of `maxSize` if provided.
*/
maxEntrySize?: Size;
/**
* A function that returns a number indicating the item's size.
*
* Requires {@link OptionsBase.maxSize} to be set.
*
* If not provided, and {@link OptionsBase.maxSize} or
* {@link OptionsBase.maxEntrySize} are set, then all
* {@link LRUCache#set} calls **must** provide an explicit
* {@link SetOptions.size} or sizeCalculation param.
*/
sizeCalculation?: SizeCalculator<K, V>;
/**
* Method that provides the implementation for {@link LRUCache#fetch}
*
* ```ts
* fetchMethod(key, staleValue, { signal, options, context })
* ```
*
* If `fetchMethod` is not provided, then `cache.fetch(key)` is equivalent
* to `Promise.resolve(cache.get(key))`.
*
* If at any time, `signal.aborted` is set to `true`, or if the
* `signal.onabort` method is called, or if it emits an `'abort'` event
* which you can listen to with `addEventListener`, then that means that
* the fetch should be abandoned. This may be passed along to async
* functions aware of AbortController/AbortSignal behavior.
*
* The `fetchMethod` should **only** return `undefined` or a Promise
* resolving to `undefined` if the AbortController signaled an `abort`
* event. In all other cases, it should return or resolve to a value
* suitable for adding to the cache.
*
* The `options` object is a union of the options that may be provided to
* `set()` and `get()`. If they are modified, then that will result in
* modifying the settings to `cache.set()` when the value is resolved, and
* in the case of
* {@link OptionsBase.noDeleteOnFetchRejection} and
* {@link OptionsBase.allowStaleOnFetchRejection}, the handling of
* `fetchMethod` failures.
*
* For example, a DNS cache may update the TTL based on the value returned
* from a remote DNS server by changing `options.ttl` in the `fetchMethod`.
*/
fetchMethod?: Fetcher<K, V, FC>;
/**
* Method that provides the implementation for {@link LRUCache#memo}
*/
memoMethod?: Memoizer<K, V, FC>;
/**
* Set to true to suppress the deletion of stale data when a
* {@link OptionsBase.fetchMethod} returns a rejected promise.
*/
noDeleteOnFetchRejection?: boolean;
/**
* Do not delete stale items when they are retrieved with
* {@link LRUCache#get}.
*
* Note that the `get` return value will still be `undefined`
* unless {@link OptionsBase.allowStale} is true.
*
* When using time-expiring entries with `ttl`, by default stale
* items will be removed from the cache when the key is accessed
* with `cache.get()`.
*
* Setting this option will cause stale items to remain in the cache, until
* they are explicitly deleted with `cache.delete(key)`, or retrieved with
* `noDeleteOnStaleGet` set to `false`.
*
* This may be overridden by passing an options object to `cache.get()`.
*
* Only relevant if a ttl is used.
*/
noDeleteOnStaleGet?: boolean;
/**
* Set to true to allow returning stale data when a
* {@link OptionsBase.fetchMethod} throws an error or returns a rejected
* promise.
*
* This differs from using {@link OptionsBase.allowStale} in that stale
* data will ONLY be returned in the case that the {@link LRUCache#fetch}
* fails, not any other times.
*
* If a `fetchMethod` fails, and there is no stale value available, the
* `fetch()` will resolve to `undefined`. Ie, all `fetchMethod` errors are
* suppressed.
*
* Implies `noDeleteOnFetchRejection`.
*
* This may be set in calls to `fetch()`, or defaulted on the constructor,
* or overridden by modifying the options object in the `fetchMethod`.
*/
allowStaleOnFetchRejection?: boolean;
/**
* Set to true to return a stale value from the cache when the
* `AbortSignal` passed to the {@link OptionsBase.fetchMethod} dispatches
* an `'abort'` event, whether user-triggered, or due to internal cache
* behavior.
*
* Unless {@link OptionsBase.ignoreFetchAbort} is also set, the underlying
* {@link OptionsBase.fetchMethod} will still be considered canceled, and
* any value it returns will be ignored and not cached.
*
* Caveat: since fetches are aborted when a new value is explicitly
* set in the cache, this can lead to fetch returning a stale value,
* since that was the fallback value _at the moment the `fetch()` was
* initiated_, even though the new updated value is now present in
* the cache.
*
* For example:
*
* ```ts
* const cache = new LRUCache<string, any>({
* ttl: 100,
* fetchMethod: async (url, oldValue, { signal }) => {
* const res = await fetch(url, { signal })
* return await res.json()
* }
* })
* cache.set('https://example.com/', { some: 'data' })
* // 100ms go by...
* const result = cache.fetch('https://example.com/')
* cache.set('https://example.com/', { other: 'thing' })
* console.log(await result) // { some: 'data' }
* console.log(cache.get('https://example.com/')) // { other: 'thing' }
* ```
*/
allowStaleOnFetchAbort?: boolean;
/**
* Set to true to ignore the `abort` event emitted by the `AbortSignal`
* object passed to {@link OptionsBase.fetchMethod}, and still cache the
* resulting resolution value, as long as it is not `undefined`.
*
* When used on its own, this means aborted {@link LRUCache#fetch} calls
* are not immediately resolved or rejected when they are aborted, and
* instead take the full time to await.
*
* When used with {@link OptionsBase.allowStaleOnFetchAbort}, aborted
* {@link LRUCache#fetch} calls will resolve immediately to their stale
* cached value or `undefined`, and will continue to process and eventually
* update the cache when they resolve, as long as the resulting value is
* not `undefined`, thus supporting a "return stale on timeout while
* refreshing" mechanism by passing `AbortSignal.timeout(n)` as the signal.
*
* For example:
*
* ```ts
* const c = new LRUCache({
* ttl: 100,
* ignoreFetchAbort: true,
* allowStaleOnFetchAbort: true,
* fetchMethod: async (key, oldValue, { signal }) => {
* // note: do NOT pass the signal to fetch()!
* // let's say this fetch can take a long time.
* const res = await fetch(`https://slow-backend-server/${key}`)
* return await res.json()
* },
* })
*
* // this will return the stale value after 100ms, while still
* // updating in the background for next time.
* const val = await c.fetch('key', { signal: AbortSignal.timeout(100) })
* ```
*
* **Note**: regardless of this setting, an `abort` event _is still
* emitted on the `AbortSignal` object_, so may result in invalid results
* when passed to other underlying APIs that use AbortSignals.
*
* This may be overridden in the {@link OptionsBase.fetchMethod} or the
* call to {@link LRUCache#fetch}.
*/
ignoreFetchAbort?: boolean;
/**
* In some cases, you may want to swap out the performance/Date object
* used for TTL tracking. This should almost certainly NOT be done in
* production environments!
*
* This value defaults to `global.performance` if it has a `now()` method,
* or the `global.Date` object otherwise.
*/
perf?: Perf;
}
interface OptionsMaxLimit<K, V, FC> extends OptionsBase<K, V, FC> {
max: Count;
}
interface OptionsTTLLimit<K, V, FC> extends OptionsBase<K, V, FC> {
ttl: Milliseconds;
ttlAutopurge: boolean;
}
interface OptionsSizeLimit<K, V, FC> extends OptionsBase<K, V, FC> {
maxSize: Size;
}
/**
* The valid safe options for the {@link LRUCache} constructor
*/
type Options<K, V, FC> = OptionsMaxLimit<K, V, FC> | OptionsSizeLimit<K, V, FC> | OptionsTTLLimit<K, V, FC>;
/**
* Entry objects used by {@link LRUCache#load} and {@link LRUCache#dump},
* and returned by {@link LRUCache#info}.
*/
interface Entry<V> {
value: V;
ttl?: Milliseconds;
size?: Size;
start?: Milliseconds;
}
}
/**
* Default export, the thing you're using this module to get.
*
* The `K` and `V` types define the key and value types, respectively. The
* optional `FC` type defines the type of the `context` object passed to
* `cache.fetch()` and `cache.memo()`.
*
* Keys and values **must not** be `null` or `undefined`.
*
* All properties from the options object (with the exception of `max`,
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
* added as normal public members. (The listed options are read-only getters.)
*
* Changing any of these will alter the defaults for subsequent method calls.
*/
export declare class LRUCache<K extends {}, V extends {}, FC = unknown> {
#private;
/**
* {@link LRUCache.OptionsBase.perf}
*/
get perf(): Perf;
/**
* {@link LRUCache.OptionsBase.ttl}
*/
ttl: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlResolution}
*/
ttlResolution: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlAutopurge}
*/
ttlAutopurge: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnGet}
*/
updateAgeOnGet: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnHas}
*/
updateAgeOnHas: boolean;
/**
* {@link LRUCache.OptionsBase.allowStale}
*/
allowStale: boolean;
/**
* {@link LRUCache.OptionsBase.noDisposeOnSet}
*/
noDisposeOnSet: boolean;
/**
* {@link LRUCache.OptionsBase.noUpdateTTL}
*/
noUpdateTTL: boolean;
/**
* {@link LRUCache.OptionsBase.maxEntrySize}
*/
maxEntrySize: LRUCache.Size;
/**
* {@link LRUCache.OptionsBase.sizeCalculation}
*/
sizeCalculation?: LRUCache.SizeCalculator<K, V>;
/**
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
*/
noDeleteOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
*/
noDeleteOnStaleGet: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
*/
allowStaleOnFetchAbort: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
*/
allowStaleOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
*/
ignoreFetchAbort: boolean;
/**
* Do not call this method unless you need to inspect the
* inner workings of the cache. If anything returned by this
* object is modified in any way, strange breakage may occur.
*
* These fields are private for a reason!
*
* @internal
*/
static unsafeExposeInternals<K extends {}, V extends {}, FC extends unknown = unknown>(c: LRUCache<K, V, FC>): {
starts: ZeroArray | undefined;
ttls: ZeroArray | undefined;
autopurgeTimers: (NodeJS.Timeout | undefined)[] | undefined;
sizes: ZeroArray | undefined;
keyMap: Map<K, number>;
keyList: (K | undefined)[];
valList: (V | BackgroundFetch<V> | undefined)[];
next: NumberArray;
prev: NumberArray;
readonly head: Index;
readonly tail: Index;
free: StackLike;
isBackgroundFetch: (p: unknown) => p is BackgroundFetch<V>;
backgroundFetch: (k: K, index: number | undefined, options: LRUCache.FetchOptions<K, V, FC>, context: unknown) => BackgroundFetch<V>;
moveToTail: (index: number) => void;
indexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
rindexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
isStale: (index: number | undefined) => boolean;
};
/**
* {@link LRUCache.OptionsBase.max} (read-only)
*/
get max(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.maxSize} (read-only)
*/
get maxSize(): LRUCache.Count;
/**
* The total computed size of items in the cache (read-only)
*/
get calculatedSize(): LRUCache.Size;
/**
* The number of items stored in the cache (read-only)
*/
get size(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
*/
get fetchMethod(): LRUCache.Fetcher<K, V, FC> | undefined;
get memoMethod(): LRUCache.Memoizer<K, V, FC> | undefined;
/**
* {@link LRUCache.OptionsBase.dispose} (read-only)
*/
get dispose(): LRUCache.Disposer<K, V> | undefined;
/**
* {@link LRUCache.OptionsBase.onInsert} (read-only)
*/
get onInsert(): LRUCache.Inserter<K, V> | undefined;
/**
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
*/
get disposeAfter(): LRUCache.Disposer<K, V> | undefined;
constructor(options: LRUCache.Options<K, V, FC> | LRUCache<K, V, FC>);
/**
* Return the number of ms left in the item's TTL. If item is not in cache,
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
*/
getRemainingTTL(key: K): number;
/**
* Return a generator yielding `[key, value]` pairs,
* in order from most recently used to least recently used.
*/
entries(): Generator<[K, V], void, unknown>;
/**
* Inverse order version of {@link LRUCache.entries}
*
* Return a generator yielding `[key, value]` pairs,
* in order from least recently used to most recently used.
*/
rentries(): Generator<(K | V)[], void, unknown>;
/**
* Return a generator yielding the keys in the cache,
* in order from most recently used to least recently used.
*/
keys(): Generator<K, void, unknown>;
/**
* Inverse order version of {@link LRUCache.keys}
*
* Return a generator yielding the keys in the cache,
* in order from least recently used to most recently used.
*/
rkeys(): Generator<K, void, unknown>;
/**
* Return a generator yielding the values in the cache,
* in order from most recently used to least recently used.
*/
values(): Generator<V, void, unknown>;
/**
* Inverse order version of {@link LRUCache.values}
*
* Return a generator yielding the values in the cache,
* in order from least recently used to most recently used.
*/
rvalues(): Generator<V | undefined, void, unknown>;
/**
* Iterating over the cache itself yields the same results as
* {@link LRUCache.entries}
*/
[Symbol.iterator](): Generator<[K, V], void, unknown>;
/**
* A String value that is used in the creation of the default string
* description of an object. Called by the built-in method
* `Object.prototype.toString`.
*/
[Symbol.toStringTag]: string;
/**
* Find a value for which the supplied fn method returns a truthy value,
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
*/
find(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => boolean, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Call the supplied function on each item in the cache, in order from most
* recently used to least recently used.
*
* `fn` is called as `fn(value, key, cache)`.
*
* If `thisp` is provided, function will be called in the `this`-context of
* the provided object, or the cache if no `thisp` object is provided.
*
* Does not update age or recenty of use, or iterate over stale values.
*/
forEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => unknown, thisp?: unknown): void;
/**
* The same as {@link LRUCache.forEach} but items are iterated over in
* reverse order. (ie, less recently used items are iterated over first.)
*/
rforEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => unknown, thisp?: unknown): void;
/**
* Delete any stale entries. Returns true if anything was removed,
* false otherwise.
*/
purgeStale(): boolean;
/**
* Get the extended info about a given entry, to get its value, size, and
* TTL info simultaneously. Returns `undefined` if the key is not present.
*
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
* serialization, the `start` value is always the current timestamp, and the
* `ttl` is a calculated remaining time to live (negative if expired).
*
* Always returns stale values, if their info is found in the cache, so be
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
* if relevant.
*/
info(key: K): LRUCache.Entry<V> | undefined;
/**
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
* passed to {@link LRUCache#load}.
*
* The `start` fields are calculated relative to a portable `Date.now()`
* timestamp, even if `performance.now()` is available.
*
* Stale entries are always included in the `dump`, even if
* {@link LRUCache.OptionsBase.allowStale} is false.
*
* Note: this returns an actual array, not a generator, so it can be more
* easily passed around.
*/
dump(): [K, LRUCache.Entry<V>][];
/**
* Reset the cache and load in the items in entries in the order listed.
*
* The shape of the resulting cache may be different if the same options are
* not used in both caches.
*
* The `start` fields are assumed to be calculated relative to a portable
* `Date.now()` timestamp, even if `performance.now()` is available.
*/
load(arr: [K, LRUCache.Entry<V>][]): void;
/**
* Add a value to the cache.
*
* Note: if `undefined` is specified as a value, this is an alias for
* {@link LRUCache#delete}
*
* Fields on the {@link LRUCache.SetOptions} options param will override
* their corresponding values in the constructor options for the scope
* of this single `set()` operation.
*
* If `start` is provided, then that will set the effective start
* time for the TTL calculation. Note that this must be a previous
* value of `performance.now()` if supported, or a previous value of
* `Date.now()` if not.
*
* Options object may also include `size`, which will prevent
* calling the `sizeCalculation` function and just use the specified
* number if it is a positive integer, and `noDisposeOnSet` which
* will prevent calling a `dispose` function in the case of
* overwrites.
*
* If the `size` (or return value of `sizeCalculation`) for a given
* entry is greater than `maxEntrySize`, then the item will not be
* added to the cache.
*
* Will update the recency of the entry.
*
* If the value is `undefined`, then this is an alias for
* `cache.delete(key)`. `undefined` is never stored in the cache.
*/
set(k: K, v: V | undefined, setOptions?: LRUCache.SetOptions<K, V, FC>): this;
/**
* Evict the least recently used item, returning its value or
* `undefined` if cache is empty.
*/
pop(): V | undefined;
/**
* Check if a key is in the cache, without updating the recency of use.
* Will return false if the item is stale, even though it is technically
* in the cache.
*
* Check if a key is in the cache, without updating the recency of
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
* to `true` in either the options or the constructor.
*
* Will return `false` if the item is stale, even though it is technically in
* the cache. The difference can be determined (if it matters) by using a
* `status` argument, and inspecting the `has` field.
*
* Will not update item age unless
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
*/
has(k: K, hasOptions?: LRUCache.HasOptions<K, V, FC>): boolean;
/**
* Like {@link LRUCache#get} but doesn't update recency or delete stale
* items.
*
* Returns `undefined` if the item is stale, unless
* {@link LRUCache.OptionsBase.allowStale} is set.
*/
peek(k: K, peekOptions?: LRUCache.PeekOptions<K, V, FC>): V | undefined;
/**
* Make an asynchronous cached fetch using the
* {@link LRUCache.OptionsBase.fetchMethod} function.
*
* If the value is in the cache and not stale, then the returned
* Promise resolves to the value.
*
* If not in the cache, or beyond its TTL staleness, then
* `fetchMethod(key, staleValue, { options, signal, context })` is
* called, and the value returned will be added to the cache once
* resolved.
*
* If called with `allowStale`, and an asynchronous fetch is
* currently in progress to reload a stale value, then the former
* stale value will be returned.
*
* If called with `forceRefresh`, then the cached item will be
* re-fetched, even if it is not stale. However, if `allowStale` is also
* set, then the old value will still be returned. This is useful
* in cases where you want to force a reload of a cached value. If
* a background fetch is already in progress, then `forceRefresh`
* has no effect.
*
* If multiple fetches for the same key are issued, then they will all be
* coalesced into a single call to fetchMethod.
*
* Note that this means that handling options such as
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort},
* {@link LRUCache.FetchOptions.signal},
* and {@link LRUCache.OptionsBase.allowStaleOnFetchRejection} will be
* determined by the FIRST fetch() call for a given key.
*
* This is a known (fixable) shortcoming which will be addresed on when
* someone complains about it, as the fix would involve added complexity and
* may not be worth the costs for this edge case.
*
* If {@link LRUCache.OptionsBase.fetchMethod} is not specified, then this is
* effectively an alias for `Promise.resolve(cache.get(key))`.
*
* When the fetch method resolves to a value, if the fetch has not
* been aborted due to deletion, eviction, or being overwritten,
* then it is added to the cache using the options provided.
*
* If the key is evicted or deleted before the `fetchMethod`
* resolves, then the AbortSignal passed to the `fetchMethod` will
* receive an `abort` event, and the promise returned by `fetch()`
* will reject with the reason for the abort.
*
* If a `signal` is passed to the `fetch()` call, then aborting the
* signal will abort the fetch and cause the `fetch()` promise to
* reject with the reason provided.
*
* **Setting `context`**
*
* If an `FC` type is set to a type other than `unknown`, `void`, or
* `undefined` in the {@link LRUCache} constructor, then all
* calls to `cache.fetch()` _must_ provide a `context` option. If
* set to `undefined` or `void`, then calls to fetch _must not_
* provide a `context` option.
*
* The `context` param allows you to provide arbitrary data that
* might be relevant in the course of fetching the data. It is only
* relevant for the course of a single `fetch()` operation, and
* discarded afterwards.
*
* **Note: `fetch()` calls are inflight-unique**
*
* If you call `fetch()` multiple times with the same key value,
* then every call after the first will resolve on the same
* promise<sup>1</sup>,
* _even if they have different settings that would otherwise change
* the behavior of the fetch_, such as `noDeleteOnFetchRejection`
* or `ignoreFetchAbort`.
*
* In most cases, this is not a problem (in fact, only fetching
* something once is what you probably want, if you're caching in
* the first place). If you are changing the fetch() options
* dramatically between runs, there's a good chance that you might
* be trying to fit divergent semantics into a single object, and
* would be better off with multiple cache instances.
*
* **1**: Ie, they're not the "same Promise", but they resolve at
* the same time, because they're both waiting on the same
* underlying fetchMethod response.
*/
fetch(k: K, fetchOptions: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : LRUCache.FetchOptionsWithContext<K, V, FC>): Promise<undefined | V>;
fetch(k: unknown extends FC ? K : FC extends undefined | void ? K : never, fetchOptions?: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : never): Promise<undefined | V>;
/**
* In some cases, `cache.fetch()` may resolve to `undefined`, either because
* a {@link LRUCache.OptionsBase#fetchMethod} was not provided (turning
* `cache.fetch(k)` into just an async wrapper around `cache.get(k)`) or
* because `ignoreFetchAbort` was specified (either to the constructor or
* in the {@link LRUCache.FetchOptions}). Also, the
* {@link LRUCache.OptionsBase.fetchMethod} may return `undefined` or `void`, making
* the test even more complicated.
*
* Because inferring the cases where `undefined` might be returned are so
* cumbersome, but testing for `undefined` can also be annoying, this method
* can be used, which will reject if `this.fetch()` resolves to undefined.
*/
forceFetch(k: K, fetchOptions: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : LRUCache.FetchOptionsWithContext<K, V, FC>): Promise<V>;
forceFetch(k: unknown extends FC ? K : FC extends undefined | void ? K : never, fetchOptions?: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : never): Promise<V>;
/**
* If the key is found in the cache, then this is equivalent to
* {@link LRUCache#get}. If not, in the cache, then calculate the value using
* the {@link LRUCache.OptionsBase.memoMethod}, and add it to the cache.
*
* If an `FC` type is set to a type other than `unknown`, `void`, or
* `undefined` in the LRUCache constructor, then all calls to `cache.memo()`
* _must_ provide a `context` option. If set to `undefined` or `void`, then
* calls to memo _must not_ provide a `context` option.
*
* The `context` param allows you to provide arbitrary data that might be
* relevant in the course of fetching the data. It is only relevant for the
* course of a single `memo()` operation, and discarded afterwards.
*/
memo(k: K, memoOptions: unknown extends FC ? LRUCache.MemoOptions<K, V, FC> : FC extends undefined | void ? LRUCache.MemoOptionsNoContext<K, V> : LRUCache.MemoOptionsWithContext<K, V, FC>): V;
memo(k: unknown extends FC ? K : FC extends undefined | void ? K : never, memoOptions?: unknown extends FC ? LRUCache.MemoOptions<K, V, FC> : FC extends undefined | void ? LRUCache.MemoOptionsNoContext<K, V> : never): V;
/**
* Return a value from the cache. Will update the recency of the cache
* entry found.
*
* If the key is not found, get() will return `undefined`.
*/
get(k: K, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Deletes a key out of the cache.
*
* Returns true if the key was deleted, false otherwise.
*/
delete(k: K): boolean;
/**
* Clear the cache entirely, throwing away all values.
*/
clear(): void;
}
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
/**
* @module LRUCache
*/
import { metrics, tracing } from './diagnostics-channel.js';
const hasSubscribers = () => metrics.hasSubscribers || tracing.hasSubscribers;
const defaultPerf = (typeof performance === 'object' &&
performance &&
typeof performance.now === 'function') ?
performance
: Date;
const warned = new Set();
/* c8 ignore start */
const PROCESS = (typeof process === 'object' && !!process ?
process
: {});
/* c8 ignore stop */
const emitWarning = (msg, type, code, fn) => {
if (typeof PROCESS.emitWarning === 'function') {
PROCESS.emitWarning(msg, type, code, fn);
}
else {
//oxlint-disable-next-line no-console
console.error(`[${code}] ${type}: ${msg}`);
}
};
const shouldWarn = (code) => !warned.has(code);
const TYPE = Symbol('type');
const isPosInt = (n) => !!n && n === Math.floor(n) && n > 0 && isFinite(n);
// This is a little bit ridiculous, tbh.
// The maximum array length is 2^32-1 or thereabouts on most JS impls.
// And well before that point, you're caching the entire world, I mean,
// that's ~32GB of just integers for the next/prev links, plus whatever
// else to hold that many keys and values. Just filling the memory with
// zeroes at init time is brutal when you get that big.
// But why not be complete?
// Maybe in the future, these limits will have expanded.
/* c8 ignore start */
const getUintArray = (max) => !isPosInt(max) ? null
: max <= Math.pow(2, 8) ? Uint8Array
: max <= Math.pow(2, 16) ? Uint16Array
: max <= Math.pow(2, 32) ? Uint32Array
: max <= Number.MAX_SAFE_INTEGER ? ZeroArray
: null;
/* c8 ignore stop */
class ZeroArray extends Array {
constructor(size) {
super(size);
this.fill(0);
}
}
class Stack {
heap;
length;
// private constructor
static #constructing = false;
static create(max) {
const HeapCls = getUintArray(max);
if (!HeapCls)
return [];
Stack.#constructing = true;
const s = new Stack(max, HeapCls);
Stack.#constructing = false;
return s;
}
constructor(max, HeapCls) {
/* c8 ignore start */
if (!Stack.#constructing) {
throw new TypeError('instantiate Stack using Stack.create(n)');
}
/* c8 ignore stop */
this.heap = new HeapCls(max);
this.length = 0;
}
push(n) {
this.heap[this.length++] = n;
}
pop() {
return this.heap[--this.length];
}
}
/**
* Default export, the thing you're using this module to get.
*
* The `K` and `V` types define the key and value types, respectively. The
* optional `FC` type defines the type of the `context` object passed to
* `cache.fetch()` and `cache.memo()`.
*
* Keys and values **must not** be `null` or `undefined`.
*
* All properties from the options object (with the exception of `max`,
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
* added as normal public members. (The listed options are read-only getters.)
*
* Changing any of these will alter the defaults for subsequent method calls.
*/
export class LRUCache {
// options that cannot be changed without disaster
#max;
#maxSize;
#dispose;
#onInsert;
#disposeAfter;
#fetchMethod;
#memoMethod;
#perf;
/**
* {@link LRUCache.OptionsBase.perf}
*/
get perf() {
return this.#perf;
}
/**
* {@link LRUCache.OptionsBase.ttl}
*/
ttl;
/**
* {@link LRUCache.OptionsBase.ttlResolution}
*/
ttlResolution;
/**
* {@link LRUCache.OptionsBase.ttlAutopurge}
*/
ttlAutopurge;
/**
* {@link LRUCache.OptionsBase.updateAgeOnGet}
*/
updateAgeOnGet;
/**
* {@link LRUCache.OptionsBase.updateAgeOnHas}
*/
updateAgeOnHas;
/**
* {@link LRUCache.OptionsBase.allowStale}
*/
allowStale;
/**
* {@link LRUCache.OptionsBase.noDisposeOnSet}
*/
noDisposeOnSet;
/**
* {@link LRUCache.OptionsBase.noUpdateTTL}
*/
noUpdateTTL;
/**
* {@link LRUCache.OptionsBase.maxEntrySize}
*/
maxEntrySize;
/**
* {@link LRUCache.OptionsBase.sizeCalculation}
*/
sizeCalculation;
/**
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
*/
noDeleteOnFetchRejection;
/**
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
*/
noDeleteOnStaleGet;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
*/
allowStaleOnFetchAbort;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
*/
allowStaleOnFetchRejection;
/**
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
*/
ignoreFetchAbort;
// computed properties
#size;
#calculatedSize;
#keyMap;
#keyList;
#valList;
#next;
#prev;
#head;
#tail;
#free;
#disposed;
#sizes;
#starts;
#ttls;
#autopurgeTimers;
#hasDispose;
#hasFetchMethod;
#hasDisposeAfter;
#hasOnInsert;
/**
* Do not call this method unless you need to inspect the
* inner workings of the cache. If anything returned by this
* object is modified in any way, strange breakage may occur.
*
* These fields are private for a reason!
*
* @internal
*/
static unsafeExposeInternals(c) {
return {
// properties
starts: c.#starts,
ttls: c.#ttls,
autopurgeTimers: c.#autopurgeTimers,
sizes: c.#sizes,
keyMap: c.#keyMap,
keyList: c.#keyList,
valList: c.#valList,
next: c.#next,
prev: c.#prev,
get head() {
return c.#head;
},
get tail() {
return c.#tail;
},
free: c.#free,
// methods
isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
moveToTail: (index) => c.#moveToTail(index),
indexes: (options) => c.#indexes(options),
rindexes: (options) => c.#rindexes(options),
isStale: (index) => c.#isStale(index),
};
}
// Protected read-only members
/**
* {@link LRUCache.OptionsBase.max} (read-only)
*/
get max() {
return this.#max;
}
/**
* {@link LRUCache.OptionsBase.maxSize} (read-only)
*/
get maxSize() {
return this.#maxSize;
}
/**
* The total computed size of items in the cache (read-only)
*/
get calculatedSize() {
return this.#calculatedSize;
}
/**
* The number of items stored in the cache (read-only)
*/
get size() {
return this.#size;
}
/**
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
*/
get fetchMethod() {
return this.#fetchMethod;
}
get memoMethod() {
return this.#memoMethod;
}
/**
* {@link LRUCache.OptionsBase.dispose} (read-only)
*/
get dispose() {
return this.#dispose;
}
/**
* {@link LRUCache.OptionsBase.onInsert} (read-only)
*/
get onInsert() {
return this.#onInsert;
}
/**
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
*/
get disposeAfter() {
return this.#disposeAfter;
}
constructor(options) {
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, onInsert, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, perf, } = options;
if (perf !== undefined) {
if (typeof perf?.now !== 'function') {
throw new TypeError('perf option must have a now() method if specified');
}
}
this.#perf = perf ?? defaultPerf;
if (max !== 0 && !isPosInt(max)) {
throw new TypeError('max option must be a nonnegative integer');
}
const UintArray = max ? getUintArray(max) : Array;
if (!UintArray) {
throw new Error('invalid max value: ' + max);
}
this.#max = max;
this.#maxSize = maxSize;
this.maxEntrySize = maxEntrySize || this.#maxSize;
this.sizeCalculation = sizeCalculation;
if (this.sizeCalculation) {
if (!this.#maxSize && !this.maxEntrySize) {
throw new TypeError('cannot set sizeCalculation without setting maxSize or maxEntrySize');
}
if (typeof this.sizeCalculation !== 'function') {
throw new TypeError('sizeCalculation set to non-function');
}
}
if (memoMethod !== undefined && typeof memoMethod !== 'function') {
throw new TypeError('memoMethod must be a function if defined');
}
this.#memoMethod = memoMethod;
if (fetchMethod !== undefined && typeof fetchMethod !== 'function') {
throw new TypeError('fetchMethod must be a function if specified');
}
this.#fetchMethod = fetchMethod;
this.#hasFetchMethod = !!fetchMethod;
this.#keyMap = new Map();
this.#keyList = Array.from({ length: max }).fill(undefined);
this.#valList = Array.from({ length: max }).fill(undefined);
this.#next = new UintArray(max);
this.#prev = new UintArray(max);
this.#head = 0;
this.#tail = 0;
this.#free = Stack.create(max);
this.#size = 0;
this.#calculatedSize = 0;
if (typeof dispose === 'function') {
this.#dispose = dispose;
}
if (typeof onInsert === 'function') {
this.#onInsert = onInsert;
}
if (typeof disposeAfter === 'function') {
this.#disposeAfter = disposeAfter;
this.#disposed = [];
}
else {
this.#disposeAfter = undefined;
this.#disposed = undefined;
}
this.#hasDispose = !!this.#dispose;
this.#hasOnInsert = !!this.#onInsert;
this.#hasDisposeAfter = !!this.#disposeAfter;
this.noDisposeOnSet = !!noDisposeOnSet;
this.noUpdateTTL = !!noUpdateTTL;
this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
this.ignoreFetchAbort = !!ignoreFetchAbort;
// NB: maxEntrySize is set to maxSize if it's set
if (this.maxEntrySize !== 0) {
if (this.#maxSize !== 0) {
if (!isPosInt(this.#maxSize)) {
throw new TypeError('maxSize must be a positive integer if specified');
}
}
if (!isPosInt(this.maxEntrySize)) {
throw new TypeError('maxEntrySize must be a positive integer if specified');
}
this.#initializeSizeTracking();
}
this.allowStale = !!allowStale;
this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
this.updateAgeOnGet = !!updateAgeOnGet;
this.updateAgeOnHas = !!updateAgeOnHas;
this.ttlResolution =
isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
this.ttlAutopurge = !!ttlAutopurge;
this.ttl = ttl || 0;
if (this.ttl) {
if (!isPosInt(this.ttl)) {
throw new TypeError('ttl must be a positive integer if specified');
}
this.#initializeTTLTracking();
}
// do not allow completely unbounded caches
if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) {
throw new TypeError('At least one of max, maxSize, or ttl is required');
}
if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
const code = 'LRU_CACHE_UNBOUNDED';
if (shouldWarn(code)) {
warned.add(code);
const msg = 'TTL caching without ttlAutopurge, max, or maxSize can ' +
'result in unbounded memory consumption.';
emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache);
}
}
}
/**
* Return the number of ms left in the item's TTL. If item is not in cache,
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
*/
getRemainingTTL(key) {
return this.#keyMap.has(key) ? Infinity : 0;
}
#initializeTTLTracking() {
const ttls = new ZeroArray(this.#max);
const starts = new ZeroArray(this.#max);
this.#ttls = ttls;
this.#starts = starts;
const purgeTimers = this.ttlAutopurge ?
Array.from({
length: this.#max,
})
: undefined;
this.#autopurgeTimers = purgeTimers;
this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
starts[index] = ttl !== 0 ? start : 0;
ttls[index] = ttl;
setPurgetTimer(index, ttl);
};
this.#updateItemAge = index => {
starts[index] = ttls[index] !== 0 ? this.#perf.now() : 0;
setPurgetTimer(index, ttls[index]);
};
// clear out the purge timer if we're setting TTL to 0, and
// previously had a ttl purge timer running, so it doesn't
// fire unnecessarily. Don't need to do this if we're not doing
// autopurge.
const setPurgetTimer = !this.ttlAutopurge ?
() => { }
: (index, ttl) => {
if (purgeTimers?.[index]) {
clearTimeout(purgeTimers[index]);
purgeTimers[index] = undefined;
}
if (ttl && ttl !== 0 && purgeTimers) {
const t = setTimeout(() => {
if (this.#isStale(index)) {
this.#delete(this.#keyList[index], 'expire');
}
}, ttl + 1);
// unref() not supported on all platforms
/* c8 ignore start */
if (t.unref) {
t.unref();
}
/* c8 ignore stop */
purgeTimers[index] = t;
}
};
this.#statusTTL = (status, index) => {
if (ttls[index]) {
const ttl = ttls[index];
const start = starts[index];
/* c8 ignore start */
if (!ttl || !start) {
return;
}
/* c8 ignore stop */
status.ttl = ttl;
status.start = start;
status.now = cachedNow || getNow();
const age = status.now - start;
status.remainingTTL = ttl - age;
}
};
// debounce calls to perf.now() to 1s so we're not hitting
// that costly call repeatedly.
let cachedNow = 0;
const getNow = () => {
const n = this.#perf.now();
if (this.ttlResolution > 0) {
cachedNow = n;
const t = setTimeout(() => (cachedNow = 0), this.ttlResolution);
// not available on all platforms
/* c8 ignore start */
if (t.unref) {
t.unref();
}
/* c8 ignore stop */
}
return n;
};
this.getRemainingTTL = key => {
const index = this.#keyMap.get(key);
if (index === undefined) {
return 0;
}
const ttl = ttls[index];
const start = starts[index];
if (!ttl || !start) {
return Infinity;
}
const age = (cachedNow || getNow()) - start;
return ttl - age;
};
this.#isStale = index => {
const s = starts[index];
const t = ttls[index];
return !!t && !!s && (cachedNow || getNow()) - s > t;
};
}
// conditionally set private methods related to TTL
#updateItemAge = () => { };
#statusTTL = () => { };
#setItemTTL = () => { };
/* c8 ignore stop */
#isStale = () => false;
#initializeSizeTracking() {
const sizes = new ZeroArray(this.#max);
this.#calculatedSize = 0;
this.#sizes = sizes;
this.#removeItemSize = index => {
this.#calculatedSize -= sizes[index];
sizes[index] = 0;
};
this.#requireSize = (k, v, size, sizeCalculation) => {
// provisionally accept background fetches.
// actual value size will be checked when they return.
if (this.#isBackgroundFetch(v)) {
return 0;
}
if (!isPosInt(size)) {
if (sizeCalculation) {
if (typeof sizeCalculation !== 'function') {
throw new TypeError('sizeCalculation must be a function');
}
size = sizeCalculation(v, k);
if (!isPosInt(size)) {
throw new TypeError('sizeCalculation return invalid (expect positive integer)');
}
}
else {
throw new TypeError('invalid size value (must be positive integer). ' +
'When maxSize or maxEntrySize is used, sizeCalculation ' +
'or size must be set.');
}
}
return size;
};
this.#addItemSize = (index, size, status) => {
sizes[index] = size;
if (this.#maxSize) {
const maxSize = this.#maxSize - sizes[index];
while (this.#calculatedSize > maxSize) {
this.#evict(true);
}
}
this.#calculatedSize += sizes[index];
if (status) {
status.entrySize = size;
status.totalCalculatedSize = this.#calculatedSize;
}
};
}
#removeItemSize = _i => { };
#addItemSize = (_i, _s, _st) => { };
#requireSize = (_k, _v, size, sizeCalculation) => {
if (size || sizeCalculation) {
throw new TypeError('cannot set size without setting maxSize or maxEntrySize on cache');
}
return 0;
};
*#indexes({ allowStale = this.allowStale } = {}) {
if (this.#size) {
for (let i = this.#tail; this.#isValidIndex(i);) {
if (allowStale || !this.#isStale(i)) {
yield i;
}
if (i === this.#head) {
break;
}
else {
i = this.#prev[i];
}
}
}
}
*#rindexes({ allowStale = this.allowStale } = {}) {
if (this.#size) {
for (let i = this.#head; this.#isValidIndex(i);) {
if (allowStale || !this.#isStale(i)) {
yield i;
}
if (i === this.#tail) {
break;
}
else {
i = this.#next[i];
}
}
}
}
#isValidIndex(index) {
return (index !== undefined &&
this.#keyMap.get(this.#keyList[index]) === index);
}
/**
* Return a generator yielding `[key, value]` pairs,
* in order from most recently used to least recently used.
*/
*entries() {
for (const i of this.#indexes()) {
if (this.#valList[i] !== undefined &&
this.#keyList[i] !== undefined &&
!this.#isBackgroundFetch(this.#valList[i])) {
yield [this.#keyList[i], this.#valList[i]];
}
}
}
/**
* Inverse order version of {@link LRUCache.entries}
*
* Return a generator yielding `[key, value]` pairs,
* in order from least recently used to most recently used.
*/
*rentries() {
for (const i of this.#rindexes()) {
if (this.#valList[i] !== undefined &&
this.#keyList[i] !== undefined &&
!this.#isBackgroundFetch(this.#valList[i])) {
yield [this.#keyList[i], this.#valList[i]];
}
}
}
/**
* Return a generator yielding the keys in the cache,
* in order from most recently used to least recently used.
*/
*keys() {
for (const i of this.#indexes()) {
const k = this.#keyList[i];
if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
yield k;
}
}
}
/**
* Inverse order version of {@link LRUCache.keys}
*
* Return a generator yielding the keys in the cache,
* in order from least recently used to most recently used.
*/
*rkeys() {
for (const i of this.#rindexes()) {
const k = this.#keyList[i];
if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
yield k;
}
}
}
/**
* Return a generator yielding the values in the cache,
* in order from most recently used to least recently used.
*/
*values() {
for (const i of this.#indexes()) {
const v = this.#valList[i];
if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
yield this.#valList[i];
}
}
}
/**
* Inverse order version of {@link LRUCache.values}
*
* Return a generator yielding the values in the cache,
* in order from least recently used to most recently used.
*/
*rvalues() {
for (const i of this.#rindexes()) {
const v = this.#valList[i];
if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
yield this.#valList[i];
}
}
}
/**
* Iterating over the cache itself yields the same results as
* {@link LRUCache.entries}
*/
[Symbol.iterator]() {
return this.entries();
}
/**
* A String value that is used in the creation of the default string
* description of an object. Called by the built-in method
* `Object.prototype.toString`.
*/
[Symbol.toStringTag] = 'LRUCache';
/**
* Find a value for which the supplied fn method returns a truthy value,
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
*/
find(fn, getOptions = {}) {
for (const i of this.#indexes()) {
const v = this.#valList[i];
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (value === undefined)
continue;
if (fn(value, this.#keyList[i], this)) {
return this.#get(this.#keyList[i], getOptions);
}
}
}
/**
* Call the supplied function on each item in the cache, in order from most
* recently used to least recently used.
*
* `fn` is called as `fn(value, key, cache)`.
*
* If `thisp` is provided, function will be called in the `this`-context of
* the provided object, or the cache if no `thisp` object is provided.
*
* Does not update age or recenty of use, or iterate over stale values.
*/
forEach(fn, thisp = this) {
for (const i of this.#indexes()) {
const v = this.#valList[i];
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (value === undefined)
continue;
fn.call(thisp, value, this.#keyList[i], this);
}
}
/**
* The same as {@link LRUCache.forEach} but items are iterated over in
* reverse order. (ie, less recently used items are iterated over first.)
*/
rforEach(fn, thisp = this) {
for (const i of this.#rindexes()) {
const v = this.#valList[i];
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (value === undefined)
continue;
fn.call(thisp, value, this.#keyList[i], this);
}
}
/**
* Delete any stale entries. Returns true if anything was removed,
* false otherwise.
*/
purgeStale() {
let deleted = false;
for (const i of this.#rindexes({ allowStale: true })) {
if (this.#isStale(i)) {
this.#delete(this.#keyList[i], 'expire');
deleted = true;
}
}
return deleted;
}
/**
* Get the extended info about a given entry, to get its value, size, and
* TTL info simultaneously. Returns `undefined` if the key is not present.
*
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
* serialization, the `start` value is always the current timestamp, and the
* `ttl` is a calculated remaining time to live (negative if expired).
*
* Always returns stale values, if their info is found in the cache, so be
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
* if relevant.
*/
info(key) {
const i = this.#keyMap.get(key);
if (i === undefined)
return undefined;
const v = this.#valList[i];
/* c8 ignore start - this isn't tested for the info function,
* but it's the same logic as found in other places. */
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (value === undefined)
return undefined;
/* c8 ignore stop */
const entry = { value };
if (this.#ttls && this.#starts) {
const ttl = this.#ttls[i];
const start = this.#starts[i];
if (ttl && start) {
const remain = ttl - (this.#perf.now() - start);
entry.ttl = remain;
entry.start = Date.now();
}
}
if (this.#sizes) {
entry.size = this.#sizes[i];
}
return entry;
}
/**
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
* passed to {@link LRUCache#load}.
*
* The `start` fields are calculated relative to a portable `Date.now()`
* timestamp, even if `performance.now()` is available.
*
* Stale entries are always included in the `dump`, even if
* {@link LRUCache.OptionsBase.allowStale} is false.
*
* Note: this returns an actual array, not a generator, so it can be more
* easily passed around.
*/
dump() {
const arr = [];
for (const i of this.#indexes({ allowStale: true })) {
const key = this.#keyList[i];
const v = this.#valList[i];
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (value === undefined || key === undefined)
continue;
const entry = { value };
if (this.#ttls && this.#starts) {
entry.ttl = this.#ttls[i];
// always dump the start relative to a portable timestamp
// it's ok for this to be a bit slow, it's a rare operation.
const age = this.#perf.now() - this.#starts[i];
entry.start = Math.floor(Date.now() - age);
}
if (this.#sizes) {
entry.size = this.#sizes[i];
}
arr.unshift([key, entry]);
}
return arr;
}
/**
* Reset the cache and load in the items in entries in the order listed.
*
* The shape of the resulting cache may be different if the same options are
* not used in both caches.
*
* The `start` fields are assumed to be calculated relative to a portable
* `Date.now()` timestamp, even if `performance.now()` is available.
*/
load(arr) {
this.clear();
for (const [key, entry] of arr) {
if (entry.start) {
// entry.start is a portable timestamp, but we may be using
// node's performance.now(), so calculate the offset, so that
// we get the intended remaining TTL, no matter how long it's
// been on ice.
//
// it's ok for this to be a bit slow, it's a rare operation.
const age = Date.now() - entry.start;
entry.start = this.#perf.now() - age;
}
this.#set(key, entry.value, entry);
}
}
/**
* Add a value to the cache.
*
* Note: if `undefined` is specified as a value, this is an alias for
* {@link LRUCache#delete}
*
* Fields on the {@link LRUCache.SetOptions} options param will override
* their corresponding values in the constructor options for the scope
* of this single `set()` operation.
*
* If `start` is provided, then that will set the effective start
* time for the TTL calculation. Note that this must be a previous
* value of `performance.now()` if supported, or a previous value of
* `Date.now()` if not.
*
* Options object may also include `size`, which will prevent
* calling the `sizeCalculation` function and just use the specified
* number if it is a positive integer, and `noDisposeOnSet` which
* will prevent calling a `dispose` function in the case of
* overwrites.
*
* If the `size` (or return value of `sizeCalculation`) for a given
* entry is greater than `maxEntrySize`, then the item will not be
* added to the cache.
*
* Will update the recency of the entry.
*
* If the value is `undefined`, then this is an alias for
* `cache.delete(key)`. `undefined` is never stored in the cache.
*/
set(k, v, setOptions = {}) {
const { status = metrics.hasSubscribers ? {} : undefined } = setOptions;
setOptions.status = status;
if (status) {
status.op = 'set';
status.key = k;
if (v !== undefined)
status.value = v;
}
const result = this.#set(k, v, setOptions);
if (status && metrics.hasSubscribers) {
metrics.publish(status);
}
return result;
}
#set(k, v, setOptions = {}) {
const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status, } = setOptions;
if (v === undefined) {
if (status)
status.set = 'deleted';
this.delete(k);
return this;
}
let { noUpdateTTL = this.noUpdateTTL } = setOptions;
if (status && !this.#isBackgroundFetch(v))
status.value = v;
const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation, status);
// if the item doesn't fit, don't do anything
// NB: maxEntrySize set to maxSize by default
if (this.maxEntrySize && size > this.maxEntrySize) {
// have to delete, in case something is there already.
this.#delete(k, 'set');
if (status) {
status.set = 'miss';
status.maxEntrySizeExceeded = true;
}
return this;
}
let index = this.#size === 0 ? undefined : this.#keyMap.get(k);
if (index === undefined) {
// addition
index = (this.#size === 0 ? this.#tail
: this.#free.length !== 0 ? this.#free.pop()
: this.#size === this.#max ? this.#evict(false)
: this.#size);
this.#keyList[index] = k;
this.#valList[index] = v;
this.#keyMap.set(k, index);
this.#next[this.#tail] = index;
this.#prev[index] = this.#tail;
this.#tail = index;
this.#size++;
this.#addItemSize(index, size, status);
if (status)
status.set = 'add';
noUpdateTTL = false;
if (this.#hasOnInsert) {
this.#onInsert?.(v, k, 'add');
}
}
else {
// update
this.#moveToTail(index);
const oldVal = this.#valList[index];
if (v !== oldVal) {
if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
oldVal.__abortController.abort(new Error('replaced'));
const { __staleWhileFetching: s } = oldVal;
if (s !== undefined && !noDisposeOnSet) {
if (this.#hasDispose) {
this.#dispose?.(s, k, 'set');
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([s, k, 'set']);
}
}
}
else if (!noDisposeOnSet) {
if (this.#hasDispose) {
this.#dispose?.(oldVal, k, 'set');
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([oldVal, k, 'set']);
}
}
this.#removeItemSize(index);
this.#addItemSize(index, size, status);
this.#valList[index] = v;
if (status) {
status.set = 'replace';
const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ?
oldVal.__staleWhileFetching
: oldVal;
if (oldValue !== undefined)
status.oldValue = oldValue;
}
}
else if (status) {
status.set = 'update';
}
if (this.#hasOnInsert) {
this.onInsert?.(v, k, v === oldVal ? 'update' : 'replace');
}
}
if (ttl !== 0 && !this.#ttls) {
this.#initializeTTLTracking();
}
if (this.#ttls) {
if (!noUpdateTTL) {
this.#setItemTTL(index, ttl, start);
}
if (status)
this.#statusTTL(status, index);
}
if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
const dt = this.#disposed;
let task;
while ((task = dt?.shift())) {
this.#disposeAfter?.(...task);
}
}
return this;
}
/**
* Evict the least recently used item, returning its value or
* `undefined` if cache is empty.
*/
pop() {
try {
while (this.#size) {
const val = this.#valList[this.#head];
this.#evict(true);
if (this.#isBackgroundFetch(val)) {
if (val.__staleWhileFetching) {
return val.__staleWhileFetching;
}
}
else if (val !== undefined) {
return val;
}
}
}
finally {
if (this.#hasDisposeAfter && this.#disposed) {
const dt = this.#disposed;
let task;
while ((task = dt?.shift())) {
this.#disposeAfter?.(...task);
}
}
}
}
#evict(free) {
const head = this.#head;
const k = this.#keyList[head];
const v = this.#valList[head];
if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) {
v.__abortController.abort(new Error('evicted'));
}
else if (this.#hasDispose || this.#hasDisposeAfter) {
if (this.#hasDispose) {
this.#dispose?.(v, k, 'evict');
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([v, k, 'evict']);
}
}
this.#removeItemSize(head);
if (this.#autopurgeTimers?.[head]) {
clearTimeout(this.#autopurgeTimers[head]);
this.#autopurgeTimers[head] = undefined;
}
// if we aren't about to use the index, then null these out
if (free) {
this.#keyList[head] = undefined;
this.#valList[head] = undefined;
this.#free.push(head);
}
if (this.#size === 1) {
this.#head = this.#tail = 0;
this.#free.length = 0;
}
else {
this.#head = this.#next[head];
}
this.#keyMap.delete(k);
this.#size--;
return head;
}
/**
* Check if a key is in the cache, without updating the recency of use.
* Will return false if the item is stale, even though it is technically
* in the cache.
*
* Check if a key is in the cache, without updating the recency of
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
* to `true` in either the options or the constructor.
*
* Will return `false` if the item is stale, even though it is technically in
* the cache. The difference can be determined (if it matters) by using a
* `status` argument, and inspecting the `has` field.
*
* Will not update item age unless
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
*/
has(k, hasOptions = {}) {
const { status = metrics.hasSubscribers ? {} : undefined } = hasOptions;
hasOptions.status = status;
if (status) {
status.op = 'has';
status.key = k;
}
const result = this.#has(k, hasOptions);
if (metrics.hasSubscribers)
metrics.publish(status);
return result;
}
#has(k, hasOptions = {}) {
const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
const index = this.#keyMap.get(k);
if (index !== undefined) {
const v = this.#valList[index];
if (this.#isBackgroundFetch(v) &&
v.__staleWhileFetching === undefined) {
return false;
}
if (!this.#isStale(index)) {
if (updateAgeOnHas) {
this.#updateItemAge(index);
}
if (status) {
status.has = 'hit';
this.#statusTTL(status, index);
}
return true;
}
else if (status) {
status.has = 'stale';
this.#statusTTL(status, index);
}
}
else if (status) {
status.has = 'miss';
}
return false;
}
/**
* Like {@link LRUCache#get} but doesn't update recency or delete stale
* items.
*
* Returns `undefined` if the item is stale, unless
* {@link LRUCache.OptionsBase.allowStale} is set.
*/
peek(k, peekOptions = {}) {
const { status = hasSubscribers() ? {} : undefined } = peekOptions;
if (status) {
status.op = 'peek';
status.key = k;
}
peekOptions.status = status;
const result = this.#peek(k, peekOptions);
if (metrics.hasSubscribers) {
metrics.publish(status);
}
return result;
}
#peek(k, peekOptions) {
const { status, allowStale = this.allowStale } = peekOptions;
const index = this.#keyMap.get(k);
if (index === undefined || (!allowStale && this.#isStale(index))) {
if (status)
status.peek = index === undefined ? 'miss' : 'stale';
return undefined;
}
const v = this.#valList[index];
const val = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
if (status) {
if (val !== undefined) {
status.peek = 'hit';
status.value = val;
}
else {
status.peek = 'miss';
}
}
return val;
}
#backgroundFetch(k, index, options, context) {
const v = index === undefined ? undefined : this.#valList[index];
if (this.#isBackgroundFetch(v)) {
return v;
}
const ac = new AbortController();
const { signal } = options;
// when/if our AC signals, then stop listening to theirs.
signal?.addEventListener('abort', () => ac.abort(signal.reason), {
signal: ac.signal,
});
const fetchOpts = {
signal: ac.signal,
options,
context,
};
const cb = (v, updateCache = false) => {
const { aborted } = ac.signal;
const ignoreAbort = options.ignoreFetchAbort && v !== undefined;
const proceed = options.ignoreFetchAbort ||
!!(options.allowStaleOnFetchAbort && v !== undefined);
if (options.status) {
if (aborted && !updateCache) {
options.status.fetchAborted = true;
options.status.fetchError = ac.signal.reason;
if (ignoreAbort)
options.status.fetchAbortIgnored = true;
}
else {
options.status.fetchResolved = true;
}
}
if (aborted && !ignoreAbort && !updateCache) {
return fetchFail(ac.signal.reason, proceed);
}
// either we didn't abort, and are still here, or we did, and ignored
const bf = p;
// if nothing else has been written there but we're set to update the
// cache and ignore the abort, or if it's still pending on this specific
// background request, then write it to the cache.
const vl = this.#valList[index];
if (vl === p || (vl === undefined && ignoreAbort && updateCache)) {
if (v === undefined) {
if (bf.__staleWhileFetching !== undefined) {
this.#valList[index] = bf.__staleWhileFetching;
}
else {
this.#delete(k, 'fetch');
}
}
else {
if (options.status)
options.status.fetchUpdated = true;
this.#set(k, v, fetchOpts.options);
}
}
return v;
};
const eb = (er) => {
if (options.status) {
options.status.fetchRejected = true;
options.status.fetchError = er;
}
// do not pass go, do not collect $200
return fetchFail(er, false);
};
const fetchFail = (er, proceed) => {
const { aborted } = ac.signal;
const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
const noDelete = allowStale || options.noDeleteOnFetchRejection;
const bf = p;
if (this.#valList[index] === p) {
// if we allow stale on fetch rejections, then we need to ensure that
// the stale value is not removed from the cache when the fetch fails.
const del = !noDelete || (!proceed && bf.__staleWhileFetching === undefined);
if (del) {
this.#delete(k, 'fetch');
}
else if (!allowStaleAborted) {
// still replace the *promise* with the stale value,
// since we are done with the promise at this point.
// leave it untouched if we're still waiting for an
// aborted background fetch that hasn't yet returned.
this.#valList[index] = bf.__staleWhileFetching;
}
}
if (allowStale) {
if (options.status && bf.__staleWhileFetching !== undefined) {
options.status.returnedStale = true;
}
return bf.__staleWhileFetching;
}
else if (bf.__returned === bf) {
throw er;
}
};
const pcall = (res, rej) => {
const fmp = this.#fetchMethod?.(k, v, fetchOpts);
if (fmp && fmp instanceof Promise) {
fmp.then(v => res(v === undefined ? undefined : v), rej);
}
// ignored, we go until we finish, regardless.
// defer check until we are actually aborting,
// so fetchMethod can override.
ac.signal.addEventListener('abort', () => {
if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
res(undefined);
// when it eventually resolves, update the cache.
if (options.allowStaleOnFetchAbort) {
res = v => cb(v, true);
}
}
});
};
if (options.status)
options.status.fetchDispatched = true;
const p = new Promise(pcall).then(cb, eb);
const bf = Object.assign(p, {
__abortController: ac,
__staleWhileFetching: v,
__returned: undefined,
});
if (index === undefined) {
// internal, don't expose status.
this.#set(k, bf, { ...fetchOpts.options, status: undefined });
index = this.#keyMap.get(k);
}
else {
this.#valList[index] = bf;
}
return bf;
}
#isBackgroundFetch(p) {
if (!this.#hasFetchMethod)
return false;
const b = p;
return (!!b &&
b instanceof Promise &&
b.hasOwnProperty('__staleWhileFetching') &&
b.__abortController instanceof AbortController);
}
fetch(k, fetchOptions = {}) {
const ths = tracing.hasSubscribers;
const { status = hasSubscribers() ? {} : undefined } = fetchOptions;
fetchOptions.status = status;
if (status && fetchOptions.context) {
status.context = fetchOptions.context;
}
const p = this.#fetch(k, fetchOptions);
if (status && hasSubscribers()) {
if (ths) {
status.trace = true;
tracing.tracePromise(() => p, status).catch(() => { });
}
}
return p;
}
async #fetch(k, fetchOptions = {}) {
const {
// get options
allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet,
// set options
ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL,
// fetch exclusive options
noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal, } = fetchOptions;
if (status) {
status.op = 'fetch';
status.key = k;
if (forceRefresh)
status.forceRefresh = true;
}
if (!this.#hasFetchMethod) {
if (status)
status.fetch = 'get';
return this.#get(k, {
allowStale,
updateAgeOnGet,
noDeleteOnStaleGet,
status,
});
}
const options = {
allowStale,
updateAgeOnGet,
noDeleteOnStaleGet,
ttl,
noDisposeOnSet,
size,
sizeCalculation,
noUpdateTTL,
noDeleteOnFetchRejection,
allowStaleOnFetchRejection,
allowStaleOnFetchAbort,
ignoreFetchAbort,
status,
signal,
};
let index = this.#keyMap.get(k);
if (index === undefined) {
if (status)
status.fetch = 'miss';
const p = this.#backgroundFetch(k, index, options, context);
return (p.__returned = p);
}
else {
// in cache, maybe already fetching
const v = this.#valList[index];
if (this.#isBackgroundFetch(v)) {
const stale = allowStale && v.__staleWhileFetching !== undefined;
if (status) {
status.fetch = 'inflight';
if (stale)
status.returnedStale = true;
}
return stale ? v.__staleWhileFetching : (v.__returned = v);
}
// if we force a refresh, that means do NOT serve the cached value,
// unless we are already in the process of refreshing the cache.
const isStale = this.#isStale(index);
if (!forceRefresh && !isStale) {
if (status)
status.fetch = 'hit';
this.#moveToTail(index);
if (updateAgeOnGet) {
this.#updateItemAge(index);
}
if (status)
this.#statusTTL(status, index);
return v;
}
// ok, it is stale or a forced refresh, and not already fetching.
// refresh the cache.
const p = this.#backgroundFetch(k, index, options, context);
const hasStale = p.__staleWhileFetching !== undefined;
const staleVal = hasStale && allowStale;
if (status) {
status.fetch = isStale ? 'stale' : 'refresh';
if (staleVal && isStale)
status.returnedStale = true;
}
return staleVal ? p.__staleWhileFetching : (p.__returned = p);
}
}
forceFetch(k, fetchOptions = {}) {
const ths = tracing.hasSubscribers;
const { status = hasSubscribers() ? {} : undefined } = fetchOptions;
fetchOptions.status = status;
if (status && fetchOptions.context) {
status.context = fetchOptions.context;
}
const p = this.#forceFetch(k, fetchOptions);
if (status && hasSubscribers()) {
if (ths) {
status.trace = true;
tracing.tracePromise(() => p, status).catch(() => { });
}
}
return p;
}
async #forceFetch(k, fetchOptions = {}) {
const v = await this.#fetch(k, fetchOptions);
if (v === undefined)
throw new Error('fetch() returned undefined');
return v;
}
memo(k, memoOptions = {}) {
const { status = metrics.hasSubscribers ? {} : undefined } = memoOptions;
memoOptions.status = status;
if (status) {
status.op = 'memo';
status.key = k;
if (memoOptions.context) {
status.context = memoOptions.context;
}
}
const result = this.#memo(k, memoOptions);
if (status)
status.value = result;
if (metrics.hasSubscribers)
metrics.publish(status);
return result;
}
#memo(k, memoOptions = {}) {
const memoMethod = this.#memoMethod;
if (!memoMethod) {
throw new Error('no memoMethod provided to constructor');
}
const { context, status, forceRefresh, ...options } = memoOptions;
if (status && forceRefresh)
status.forceRefresh = true;
const v = this.#get(k, options);
const refresh = forceRefresh || v === undefined;
if (status) {
status.memo = refresh ? 'miss' : 'hit';
if (!refresh)
status.value = v;
}
if (!refresh)
return v;
const vv = memoMethod(k, v, {
options,
context,
});
if (status)
status.value = vv;
this.#set(k, vv, options);
return vv;
}
/**
* Return a value from the cache. Will update the recency of the cache
* entry found.
*
* If the key is not found, get() will return `undefined`.
*/
get(k, getOptions = {}) {
const { status = metrics.hasSubscribers ? {} : undefined } = getOptions;
getOptions.status = status;
if (status) {
status.op = 'get';
status.key = k;
}
const result = this.#get(k, getOptions);
if (status) {
if (result !== undefined)
status.value = result;
if (metrics.hasSubscribers)
metrics.publish(status);
}
return result;
}
#get(k, getOptions = {}) {
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status, } = getOptions;
const index = this.#keyMap.get(k);
if (index === undefined) {
if (status)
status.get = 'miss';
return undefined;
}
const value = this.#valList[index];
const fetching = this.#isBackgroundFetch(value);
if (status)
this.#statusTTL(status, index);
if (this.#isStale(index)) {
// delete only if not an in-flight background fetch
if (!fetching) {
if (!noDeleteOnStaleGet) {
this.#delete(k, 'expire');
}
if (status)
status.get = 'stale';
if (allowStale) {
if (status)
status.returnedStale = true;
return value;
}
return undefined;
}
if (status)
status.get = 'stale-fetching';
if (allowStale && value.__staleWhileFetching !== undefined) {
if (status)
status.returnedStale = true;
return value.__staleWhileFetching;
}
return undefined;
}
// not stale
if (status)
status.get = fetching ? 'fetching' : 'hit';
// if we're currently fetching it, we don't actually have it yet
// it's not stale, which means this isn't a staleWhileRefetching.
// If it's not stale, and fetching, AND has a __staleWhileFetching
// value, then that means the user fetched with {forceRefresh:true},
// so it's safe to return that value.
this.#moveToTail(index);
if (updateAgeOnGet) {
this.#updateItemAge(index);
}
return fetching ? value.__staleWhileFetching : value;
}
#connect(p, n) {
this.#prev[n] = p;
this.#next[p] = n;
}
#moveToTail(index) {
// if tail already, nothing to do
// if head, move head to next[index]
// else
// move next[prev[index]] to next[index] (head has no prev)
// move prev[next[index]] to prev[index]
// prev[index] = tail
// next[tail] = index
// tail = index
if (index !== this.#tail) {
if (index === this.#head) {
this.#head = this.#next[index];
}
else {
this.#connect(this.#prev[index], this.#next[index]);
}
this.#connect(this.#tail, index);
this.#tail = index;
}
}
/**
* Deletes a key out of the cache.
*
* Returns true if the key was deleted, false otherwise.
*/
delete(k) {
return this.#delete(k, 'delete');
}
#delete(k, reason) {
if (metrics.hasSubscribers) {
metrics.publish({
op: 'delete',
delete: reason,
key: k,
});
}
let deleted = false;
if (this.#size !== 0) {
const index = this.#keyMap.get(k);
if (index !== undefined) {
if (this.#autopurgeTimers?.[index]) {
clearTimeout(this.#autopurgeTimers?.[index]);
this.#autopurgeTimers[index] = undefined;
}
deleted = true;
if (this.#size === 1) {
this.#clear(reason);
}
else {
this.#removeItemSize(index);
const v = this.#valList[index];
if (this.#isBackgroundFetch(v)) {
v.__abortController.abort(new Error('deleted'));
}
else if (this.#hasDispose || this.#hasDisposeAfter) {
if (this.#hasDispose) {
this.#dispose?.(v, k, reason);
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([v, k, reason]);
}
}
this.#keyMap.delete(k);
this.#keyList[index] = undefined;
this.#valList[index] = undefined;
if (index === this.#tail) {
this.#tail = this.#prev[index];
}
else if (index === this.#head) {
this.#head = this.#next[index];
}
else {
const pi = this.#prev[index];
this.#next[pi] = this.#next[index];
const ni = this.#next[index];
this.#prev[ni] = this.#prev[index];
}
this.#size--;
this.#free.push(index);
}
}
}
if (this.#hasDisposeAfter && this.#disposed?.length) {
const dt = this.#disposed;
let task;
while ((task = dt?.shift())) {
this.#disposeAfter?.(...task);
}
}
return deleted;
}
/**
* Clear the cache entirely, throwing away all values.
*/
clear() {
return this.#clear('delete');
}
#clear(reason) {
for (const index of this.#rindexes({ allowStale: true })) {
const v = this.#valList[index];
if (this.#isBackgroundFetch(v)) {
v.__abortController.abort(new Error('deleted'));
}
else {
const k = this.#keyList[index];
if (this.#hasDispose) {
this.#dispose?.(v, k, reason);
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([v, k, reason]);
}
}
}
this.#keyMap.clear();
this.#valList.fill(undefined);
this.#keyList.fill(undefined);
if (this.#ttls && this.#starts) {
this.#ttls.fill(0);
this.#starts.fill(0);
for (const t of this.#autopurgeTimers ?? []) {
if (t !== undefined)
clearTimeout(t);
}
this.#autopurgeTimers?.fill(undefined);
}
if (this.#sizes) {
this.#sizes.fill(0);
}
this.#head = 0;
this.#tail = 0;
this.#free.length = 0;
this.#calculatedSize = 0;
this.#size = 0;
if (this.#hasDisposeAfter && this.#disposed) {
const dt = this.#disposed;
let task;
while ((task = dt?.shift())) {
this.#disposeAfter?.(...task);
}
}
}
}
//# sourceMappingURL=index.js.map

Sorry, the diff of this file is too big to display

import{tracingChannel as j,channel as I}from"node:diagnostics_channel";var S=I("lru-cache:metrics"),W=j("lru-cache");var x=()=>S.hasSubscribers||W.hasSubscribers,G=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,M=new Set,C=typeof process=="object"&&process?process:{},P=(u,e,t,i)=>{typeof C.emitWarning=="function"?C.emitWarning(u,e,t,i):console.error(`[${t}] ${e}: ${u}`)},H=u=>!M.has(u),$=Symbol("type"),F=u=>!!u&&u===Math.floor(u)&&u>0&&isFinite(u),U=u=>F(u)?u<=Math.pow(2,8)?Uint8Array:u<=Math.pow(2,16)?Uint16Array:u<=Math.pow(2,32)?Uint32Array:u<=Number.MAX_SAFE_INTEGER?O:null:null,O=class extends Array{constructor(e){super(e),this.fill(0)}},R=class u{heap;length;static#o=!1;static create(e){let t=U(e);if(!t)return[];u.#o=!0;let i=new u(e,t);return u.#o=!1,i}constructor(e,t){if(!u.#o)throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new t(e),this.length=0}push(e){this.heap[this.length++]=e}pop(){return this.heap[--this.length]}},L=class u{#o;#u;#w;#x;#S;#M;#U;#m;get perf(){return this.#m}ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#n;#b;#s;#i;#t;#a;#c;#l;#h;#y;#r;#_;#F;#d;#g;#T;#W;#f;#j;static unsafeExposeInternals(e){return{starts:e.#F,ttls:e.#d,autopurgeTimers:e.#g,sizes:e.#_,keyMap:e.#s,keyList:e.#i,valList:e.#t,next:e.#a,prev:e.#c,get head(){return e.#l},get tail(){return e.#h},free:e.#y,isBackgroundFetch:t=>e.#e(t),backgroundFetch:(t,i,s,n)=>e.#P(t,i,s,n),moveToTail:t=>e.#L(t),indexes:t=>e.#A(t),rindexes:t=>e.#z(t),isStale:t=>e.#p(t)}}get max(){return this.#o}get maxSize(){return this.#u}get calculatedSize(){return this.#b}get size(){return this.#n}get fetchMethod(){return this.#M}get memoMethod(){return this.#U}get dispose(){return this.#w}get onInsert(){return this.#x}get disposeAfter(){return this.#S}constructor(e){let{max:t=0,ttl:i,ttlResolution:s=1,ttlAutopurge:n,updateAgeOnGet:o,updateAgeOnHas:r,allowStale:h,dispose:l,onInsert:c,disposeAfter:f,noDisposeOnSet:g,noUpdateTTL:p,maxSize:T=0,maxEntrySize:w=0,sizeCalculation:y,fetchMethod:a,memoMethod:m,noDeleteOnFetchRejection:_,noDeleteOnStaleGet:b,allowStaleOnFetchRejection:d,allowStaleOnFetchAbort:A,ignoreFetchAbort:z,perf:D}=e;if(D!==void 0&&typeof D?.now!="function")throw new TypeError("perf option must have a now() method if specified");if(this.#m=D??G,t!==0&&!F(t))throw new TypeError("max option must be a nonnegative integer");let v=t?U(t):Array;if(!v)throw new Error("invalid max value: "+t);if(this.#o=t,this.#u=T,this.maxEntrySize=w||this.#u,this.sizeCalculation=y,this.sizeCalculation){if(!this.#u&&!this.maxEntrySize)throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");if(typeof this.sizeCalculation!="function")throw new TypeError("sizeCalculation set to non-function")}if(m!==void 0&&typeof m!="function")throw new TypeError("memoMethod must be a function if defined");if(this.#U=m,a!==void 0&&typeof a!="function")throw new TypeError("fetchMethod must be a function if specified");if(this.#M=a,this.#W=!!a,this.#s=new Map,this.#i=Array.from({length:t}).fill(void 0),this.#t=Array.from({length:t}).fill(void 0),this.#a=new v(t),this.#c=new v(t),this.#l=0,this.#h=0,this.#y=R.create(t),this.#n=0,this.#b=0,typeof l=="function"&&(this.#w=l),typeof c=="function"&&(this.#x=c),typeof f=="function"?(this.#S=f,this.#r=[]):(this.#S=void 0,this.#r=void 0),this.#T=!!this.#w,this.#j=!!this.#x,this.#f=!!this.#S,this.noDisposeOnSet=!!g,this.noUpdateTTL=!!p,this.noDeleteOnFetchRejection=!!_,this.allowStaleOnFetchRejection=!!d,this.allowStaleOnFetchAbort=!!A,this.ignoreFetchAbort=!!z,this.maxEntrySize!==0){if(this.#u!==0&&!F(this.#u))throw new TypeError("maxSize must be a positive integer if specified");if(!F(this.maxEntrySize))throw new TypeError("maxEntrySize must be a positive integer if specified");this.#X()}if(this.allowStale=!!h,this.noDeleteOnStaleGet=!!b,this.updateAgeOnGet=!!o,this.updateAgeOnHas=!!r,this.ttlResolution=F(s)||s===0?s:1,this.ttlAutopurge=!!n,this.ttl=i||0,this.ttl){if(!F(this.ttl))throw new TypeError("ttl must be a positive integer if specified");this.#H()}if(this.#o===0&&this.ttl===0&&this.#u===0)throw new TypeError("At least one of max, maxSize, or ttl is required");if(!this.ttlAutopurge&&!this.#o&&!this.#u){let E="LRU_CACHE_UNBOUNDED";H(E)&&(M.add(E),P("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.","UnboundedCacheWarning",E,u))}}getRemainingTTL(e){return this.#s.has(e)?1/0:0}#H(){let e=new O(this.#o),t=new O(this.#o);this.#d=e,this.#F=t;let i=this.ttlAutopurge?Array.from({length:this.#o}):void 0;this.#g=i,this.#N=(r,h,l=this.#m.now())=>{t[r]=h!==0?l:0,e[r]=h,s(r,h)},this.#D=r=>{t[r]=e[r]!==0?this.#m.now():0,s(r,e[r])};let s=this.ttlAutopurge?(r,h)=>{if(i?.[r]&&(clearTimeout(i[r]),i[r]=void 0),h&&h!==0&&i){let l=setTimeout(()=>{this.#p(r)&&this.#v(this.#i[r],"expire")},h+1);l.unref&&l.unref(),i[r]=l}}:()=>{};this.#E=(r,h)=>{if(e[h]){let l=e[h],c=t[h];if(!l||!c)return;r.ttl=l,r.start=c,r.now=n||o();let f=r.now-c;r.remainingTTL=l-f}};let n=0,o=()=>{let r=this.#m.now();if(this.ttlResolution>0){n=r;let h=setTimeout(()=>n=0,this.ttlResolution);h.unref&&h.unref()}return r};this.getRemainingTTL=r=>{let h=this.#s.get(r);if(h===void 0)return 0;let l=e[h],c=t[h];if(!l||!c)return 1/0;let f=(n||o())-c;return l-f},this.#p=r=>{let h=t[r],l=e[r];return!!l&&!!h&&(n||o())-h>l}}#D=()=>{};#E=()=>{};#N=()=>{};#p=()=>!1;#X(){let e=new O(this.#o);this.#b=0,this.#_=e,this.#R=t=>{this.#b-=e[t],e[t]=0},this.#k=(t,i,s,n)=>{if(this.#e(i))return 0;if(!F(s))if(n){if(typeof n!="function")throw new TypeError("sizeCalculation must be a function");if(s=n(i,t),!F(s))throw new TypeError("sizeCalculation return invalid (expect positive integer)")}else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");return s},this.#I=(t,i,s)=>{if(e[t]=i,this.#u){let n=this.#u-e[t];for(;this.#b>n;)this.#G(!0)}this.#b+=e[t],s&&(s.entrySize=i,s.totalCalculatedSize=this.#b)}}#R=e=>{};#I=(e,t,i)=>{};#k=(e,t,i,s)=>{if(i||s)throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");return 0};*#A({allowStale:e=this.allowStale}={}){if(this.#n)for(let t=this.#h;this.#V(t)&&((e||!this.#p(t))&&(yield t),t!==this.#l);)t=this.#c[t]}*#z({allowStale:e=this.allowStale}={}){if(this.#n)for(let t=this.#l;this.#V(t)&&((e||!this.#p(t))&&(yield t),t!==this.#h);)t=this.#a[t]}#V(e){return e!==void 0&&this.#s.get(this.#i[e])===e}*entries(){for(let e of this.#A())this.#t[e]!==void 0&&this.#i[e]!==void 0&&!this.#e(this.#t[e])&&(yield[this.#i[e],this.#t[e]])}*rentries(){for(let e of this.#z())this.#t[e]!==void 0&&this.#i[e]!==void 0&&!this.#e(this.#t[e])&&(yield[this.#i[e],this.#t[e]])}*keys(){for(let e of this.#A()){let t=this.#i[e];t!==void 0&&!this.#e(this.#t[e])&&(yield t)}}*rkeys(){for(let e of this.#z()){let t=this.#i[e];t!==void 0&&!this.#e(this.#t[e])&&(yield t)}}*values(){for(let e of this.#A())this.#t[e]!==void 0&&!this.#e(this.#t[e])&&(yield this.#t[e])}*rvalues(){for(let e of this.#z())this.#t[e]!==void 0&&!this.#e(this.#t[e])&&(yield this.#t[e])}[Symbol.iterator](){return this.entries()}[Symbol.toStringTag]="LRUCache";find(e,t={}){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;if(n!==void 0&&e(n,this.#i[i],this))return this.#C(this.#i[i],t)}}forEach(e,t=this){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&e.call(t,n,this.#i[i],this)}}rforEach(e,t=this){for(let i of this.#z()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&e.call(t,n,this.#i[i],this)}}purgeStale(){let e=!1;for(let t of this.#z({allowStale:!0}))this.#p(t)&&(this.#v(this.#i[t],"expire"),e=!0);return e}info(e){let t=this.#s.get(e);if(t===void 0)return;let i=this.#t[t],s=this.#e(i)?i.__staleWhileFetching:i;if(s===void 0)return;let n={value:s};if(this.#d&&this.#F){let o=this.#d[t],r=this.#F[t];if(o&&r){let h=o-(this.#m.now()-r);n.ttl=h,n.start=Date.now()}}return this.#_&&(n.size=this.#_[t]),n}dump(){let e=[];for(let t of this.#A({allowStale:!0})){let i=this.#i[t],s=this.#t[t],n=this.#e(s)?s.__staleWhileFetching:s;if(n===void 0||i===void 0)continue;let o={value:n};if(this.#d&&this.#F){o.ttl=this.#d[t];let r=this.#m.now()-this.#F[t];o.start=Math.floor(Date.now()-r)}this.#_&&(o.size=this.#_[t]),e.unshift([i,o])}return e}load(e){this.clear();for(let[t,i]of e){if(i.start){let s=Date.now()-i.start;i.start=this.#m.now()-s}this.#O(t,i.value,i)}}set(e,t,i={}){let{status:s=S.hasSubscribers?{}:void 0}=i;i.status=s,s&&(s.op="set",s.key=e,t!==void 0&&(s.value=t));let n=this.#O(e,t,i);return s&&S.hasSubscribers&&S.publish(s),n}#O(e,t,i={}){let{ttl:s=this.ttl,start:n,noDisposeOnSet:o=this.noDisposeOnSet,sizeCalculation:r=this.sizeCalculation,status:h}=i;if(t===void 0)return h&&(h.set="deleted"),this.delete(e),this;let{noUpdateTTL:l=this.noUpdateTTL}=i;h&&!this.#e(t)&&(h.value=t);let c=this.#k(e,t,i.size||0,r,h);if(this.maxEntrySize&&c>this.maxEntrySize)return this.#v(e,"set"),h&&(h.set="miss",h.maxEntrySizeExceeded=!0),this;let f=this.#n===0?void 0:this.#s.get(e);if(f===void 0)f=this.#n===0?this.#h:this.#y.length!==0?this.#y.pop():this.#n===this.#o?this.#G(!1):this.#n,this.#i[f]=e,this.#t[f]=t,this.#s.set(e,f),this.#a[this.#h]=f,this.#c[f]=this.#h,this.#h=f,this.#n++,this.#I(f,c,h),h&&(h.set="add"),l=!1,this.#j&&this.#x?.(t,e,"add");else{this.#L(f);let g=this.#t[f];if(t!==g){if(this.#W&&this.#e(g)){g.__abortController.abort(new Error("replaced"));let{__staleWhileFetching:p}=g;p!==void 0&&!o&&(this.#T&&this.#w?.(p,e,"set"),this.#f&&this.#r?.push([p,e,"set"]))}else o||(this.#T&&this.#w?.(g,e,"set"),this.#f&&this.#r?.push([g,e,"set"]));if(this.#R(f),this.#I(f,c,h),this.#t[f]=t,h){h.set="replace";let p=g&&this.#e(g)?g.__staleWhileFetching:g;p!==void 0&&(h.oldValue=p)}}else h&&(h.set="update");this.#j&&this.onInsert?.(t,e,t===g?"update":"replace")}if(s!==0&&!this.#d&&this.#H(),this.#d&&(l||this.#N(f,s,n),h&&this.#E(h,f)),!o&&this.#f&&this.#r){let g=this.#r,p;for(;p=g?.shift();)this.#S?.(...p)}return this}pop(){try{for(;this.#n;){let e=this.#t[this.#l];if(this.#G(!0),this.#e(e)){if(e.__staleWhileFetching)return e.__staleWhileFetching}else if(e!==void 0)return e}}finally{if(this.#f&&this.#r){let e=this.#r,t;for(;t=e?.shift();)this.#S?.(...t)}}}#G(e){let t=this.#l,i=this.#i[t],s=this.#t[t];return this.#W&&this.#e(s)?s.__abortController.abort(new Error("evicted")):(this.#T||this.#f)&&(this.#T&&this.#w?.(s,i,"evict"),this.#f&&this.#r?.push([s,i,"evict"])),this.#R(t),this.#g?.[t]&&(clearTimeout(this.#g[t]),this.#g[t]=void 0),e&&(this.#i[t]=void 0,this.#t[t]=void 0,this.#y.push(t)),this.#n===1?(this.#l=this.#h=0,this.#y.length=0):this.#l=this.#a[t],this.#s.delete(i),this.#n--,t}has(e,t={}){let{status:i=S.hasSubscribers?{}:void 0}=t;t.status=i,i&&(i.op="has",i.key=e);let s=this.#Y(e,t);return S.hasSubscribers&&S.publish(i),s}#Y(e,t={}){let{updateAgeOnHas:i=this.updateAgeOnHas,status:s}=t,n=this.#s.get(e);if(n!==void 0){let o=this.#t[n];if(this.#e(o)&&o.__staleWhileFetching===void 0)return!1;if(this.#p(n))s&&(s.has="stale",this.#E(s,n));else return i&&this.#D(n),s&&(s.has="hit",this.#E(s,n)),!0}else s&&(s.has="miss");return!1}peek(e,t={}){let{status:i=x()?{}:void 0}=t;i&&(i.op="peek",i.key=e),t.status=i;let s=this.#J(e,t);return S.hasSubscribers&&S.publish(i),s}#J(e,t){let{status:i,allowStale:s=this.allowStale}=t,n=this.#s.get(e);if(n===void 0||!s&&this.#p(n)){i&&(i.peek=n===void 0?"miss":"stale");return}let o=this.#t[n],r=this.#e(o)?o.__staleWhileFetching:o;return i&&(r!==void 0?(i.peek="hit",i.value=r):i.peek="miss"),r}#P(e,t,i,s){let n=t===void 0?void 0:this.#t[t];if(this.#e(n))return n;let o=new AbortController,{signal:r}=i;r?.addEventListener("abort",()=>o.abort(r.reason),{signal:o.signal});let h={signal:o.signal,options:i,context:s},l=(w,y=!1)=>{let{aborted:a}=o.signal,m=i.ignoreFetchAbort&&w!==void 0,_=i.ignoreFetchAbort||!!(i.allowStaleOnFetchAbort&&w!==void 0);if(i.status&&(a&&!y?(i.status.fetchAborted=!0,i.status.fetchError=o.signal.reason,m&&(i.status.fetchAbortIgnored=!0)):i.status.fetchResolved=!0),a&&!m&&!y)return f(o.signal.reason,_);let b=p,d=this.#t[t];return(d===p||d===void 0&&m&&y)&&(w===void 0?b.__staleWhileFetching!==void 0?this.#t[t]=b.__staleWhileFetching:this.#v(e,"fetch"):(i.status&&(i.status.fetchUpdated=!0),this.#O(e,w,h.options))),w},c=w=>(i.status&&(i.status.fetchRejected=!0,i.status.fetchError=w),f(w,!1)),f=(w,y)=>{let{aborted:a}=o.signal,m=a&&i.allowStaleOnFetchAbort,_=m||i.allowStaleOnFetchRejection,b=_||i.noDeleteOnFetchRejection,d=p;if(this.#t[t]===p&&(!b||!y&&d.__staleWhileFetching===void 0?this.#v(e,"fetch"):m||(this.#t[t]=d.__staleWhileFetching)),_)return i.status&&d.__staleWhileFetching!==void 0&&(i.status.returnedStale=!0),d.__staleWhileFetching;if(d.__returned===d)throw w},g=(w,y)=>{let a=this.#M?.(e,n,h);a&&a instanceof Promise&&a.then(m=>w(m===void 0?void 0:m),y),o.signal.addEventListener("abort",()=>{(!i.ignoreFetchAbort||i.allowStaleOnFetchAbort)&&(w(void 0),i.allowStaleOnFetchAbort&&(w=m=>l(m,!0)))})};i.status&&(i.status.fetchDispatched=!0);let p=new Promise(g).then(l,c),T=Object.assign(p,{__abortController:o,__staleWhileFetching:n,__returned:void 0});return t===void 0?(this.#O(e,T,{...h.options,status:void 0}),t=this.#s.get(e)):this.#t[t]=T,T}#e(e){if(!this.#W)return!1;let t=e;return!!t&&t instanceof Promise&&t.hasOwnProperty("__staleWhileFetching")&&t.__abortController instanceof AbortController}fetch(e,t={}){let i=W.hasSubscribers,{status:s=x()?{}:void 0}=t;t.status=s,s&&t.context&&(s.context=t.context);let n=this.#B(e,t);return s&&x()&&i&&(s.trace=!0,W.tracePromise(()=>n,s).catch(()=>{})),n}async#B(e,t={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,ttl:o=this.ttl,noDisposeOnSet:r=this.noDisposeOnSet,size:h=0,sizeCalculation:l=this.sizeCalculation,noUpdateTTL:c=this.noUpdateTTL,noDeleteOnFetchRejection:f=this.noDeleteOnFetchRejection,allowStaleOnFetchRejection:g=this.allowStaleOnFetchRejection,ignoreFetchAbort:p=this.ignoreFetchAbort,allowStaleOnFetchAbort:T=this.allowStaleOnFetchAbort,context:w,forceRefresh:y=!1,status:a,signal:m}=t;if(a&&(a.op="fetch",a.key=e,y&&(a.forceRefresh=!0)),!this.#W)return a&&(a.fetch="get"),this.#C(e,{allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,status:a});let _={allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,ttl:o,noDisposeOnSet:r,size:h,sizeCalculation:l,noUpdateTTL:c,noDeleteOnFetchRejection:f,allowStaleOnFetchRejection:g,allowStaleOnFetchAbort:T,ignoreFetchAbort:p,status:a,signal:m},b=this.#s.get(e);if(b===void 0){a&&(a.fetch="miss");let d=this.#P(e,b,_,w);return d.__returned=d}else{let d=this.#t[b];if(this.#e(d)){let E=i&&d.__staleWhileFetching!==void 0;return a&&(a.fetch="inflight",E&&(a.returnedStale=!0)),E?d.__staleWhileFetching:d.__returned=d}let A=this.#p(b);if(!y&&!A)return a&&(a.fetch="hit"),this.#L(b),s&&this.#D(b),a&&this.#E(a,b),d;let z=this.#P(e,b,_,w),v=z.__staleWhileFetching!==void 0&&i;return a&&(a.fetch=A?"stale":"refresh",v&&A&&(a.returnedStale=!0)),v?z.__staleWhileFetching:z.__returned=z}}forceFetch(e,t={}){let i=W.hasSubscribers,{status:s=x()?{}:void 0}=t;t.status=s,s&&t.context&&(s.context=t.context);let n=this.#K(e,t);return s&&x()&&i&&(s.trace=!0,W.tracePromise(()=>n,s).catch(()=>{})),n}async#K(e,t={}){let i=await this.#B(e,t);if(i===void 0)throw new Error("fetch() returned undefined");return i}memo(e,t={}){let{status:i=S.hasSubscribers?{}:void 0}=t;t.status=i,i&&(i.op="memo",i.key=e,t.context&&(i.context=t.context));let s=this.#Q(e,t);return i&&(i.value=s),S.hasSubscribers&&S.publish(i),s}#Q(e,t={}){let i=this.#U;if(!i)throw new Error("no memoMethod provided to constructor");let{context:s,status:n,forceRefresh:o,...r}=t;n&&o&&(n.forceRefresh=!0);let h=this.#C(e,r),l=o||h===void 0;if(n&&(n.memo=l?"miss":"hit",l||(n.value=h)),!l)return h;let c=i(e,h,{options:r,context:s});return n&&(n.value=c),this.#O(e,c,r),c}get(e,t={}){let{status:i=S.hasSubscribers?{}:void 0}=t;t.status=i,i&&(i.op="get",i.key=e);let s=this.#C(e,t);return i&&(s!==void 0&&(i.value=s),S.hasSubscribers&&S.publish(i)),s}#C(e,t={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,status:o}=t,r=this.#s.get(e);if(r===void 0){o&&(o.get="miss");return}let h=this.#t[r],l=this.#e(h);return o&&this.#E(o,r),this.#p(r)?l?(o&&(o.get="stale-fetching"),i&&h.__staleWhileFetching!==void 0?(o&&(o.returnedStale=!0),h.__staleWhileFetching):void 0):(n||this.#v(e,"expire"),o&&(o.get="stale"),i?(o&&(o.returnedStale=!0),h):void 0):(o&&(o.get=l?"fetching":"hit"),this.#L(r),s&&this.#D(r),l?h.__staleWhileFetching:h)}#$(e,t){this.#c[t]=e,this.#a[e]=t}#L(e){e!==this.#h&&(e===this.#l?this.#l=this.#a[e]:this.#$(this.#c[e],this.#a[e]),this.#$(this.#h,e),this.#h=e)}delete(e){return this.#v(e,"delete")}#v(e,t){S.hasSubscribers&&S.publish({op:"delete",delete:t,key:e});let i=!1;if(this.#n!==0){let s=this.#s.get(e);if(s!==void 0)if(this.#g?.[s]&&(clearTimeout(this.#g?.[s]),this.#g[s]=void 0),i=!0,this.#n===1)this.#q(t);else{this.#R(s);let n=this.#t[s];if(this.#e(n)?n.__abortController.abort(new Error("deleted")):(this.#T||this.#f)&&(this.#T&&this.#w?.(n,e,t),this.#f&&this.#r?.push([n,e,t])),this.#s.delete(e),this.#i[s]=void 0,this.#t[s]=void 0,s===this.#h)this.#h=this.#c[s];else if(s===this.#l)this.#l=this.#a[s];else{let o=this.#c[s];this.#a[o]=this.#a[s];let r=this.#a[s];this.#c[r]=this.#c[s]}this.#n--,this.#y.push(s)}}if(this.#f&&this.#r?.length){let s=this.#r,n;for(;n=s?.shift();)this.#S?.(...n)}return i}clear(){return this.#q("delete")}#q(e){for(let t of this.#z({allowStale:!0})){let i=this.#t[t];if(this.#e(i))i.__abortController.abort(new Error("deleted"));else{let s=this.#i[t];this.#T&&this.#w?.(i,s,e),this.#f&&this.#r?.push([i,s,e])}}if(this.#s.clear(),this.#t.fill(void 0),this.#i.fill(void 0),this.#d&&this.#F){this.#d.fill(0),this.#F.fill(0);for(let t of this.#g??[])t!==void 0&&clearTimeout(t);this.#g?.fill(void 0)}if(this.#_&&this.#_.fill(0),this.#l=0,this.#h=0,this.#y.length=0,this.#b=0,this.#n=0,this.#f&&this.#r){let t=this.#r,i;for(;i=t?.shift();)this.#S?.(...i)}}};export{L as LRUCache};
//# sourceMappingURL=index.min.js.map

Sorry, the diff of this file is too big to display

+16
-1
{
"name": "lru-cache",
"description": "A cache object that deletes the least-recently-used items.",
"version": "11.3.1",
"version": "11.3.2",
"author": "Isaac Z. Schlueter <i@izs.me>",

@@ -36,2 +36,5 @@ "keywords": [

"tshy": {
"esmDialects": [
"node"
],
"exports": {

@@ -41,2 +44,6 @@ "./raw": "./src/index.ts",

"import": {
"node": {
"types": "./dist/esm/node/index.d.ts",
"default": "./dist/esm/node/index.min.js"
},
"types": "./dist/esm/index.d.ts",

@@ -79,2 +86,6 @@ "default": "./dist/esm/index.min.js"

"import": {
"node": {
"types": "./dist/esm/node/index.d.ts",
"default": "./dist/esm/node/index.js"
},
"types": "./dist/esm/index.d.ts",

@@ -90,2 +101,6 @@ "default": "./dist/esm/index.js"

"import": {
"node": {
"types": "./dist/esm/node/index.d.ts",
"default": "./dist/esm/node/index.min.js"
},
"types": "./dist/esm/index.d.ts",

@@ -92,0 +107,0 @@ "default": "./dist/esm/index.min.js"