@nocobase/plugin-workflow 2.1.0-beta.15 → 2.1.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/214.7e602cfe7a8251b8.js +10 -0
- package/dist/client/261.7722d7400942730e.js +10 -0
- package/dist/client/67.f904ef4520868b8a.js +10 -0
- package/dist/client/964.6251d37b35710747.js +10 -0
- package/dist/client/index.js +1 -1
- package/dist/client/nodes/create.d.ts +10 -0
- package/dist/client/nodes/destroy.d.ts +10 -0
- package/dist/client/nodes/index.d.ts +3 -0
- package/dist/client/nodes/query.d.ts +10 -0
- package/dist/client/nodes/update.d.ts +10 -0
- package/dist/client/triggers/collection.d.ts +14 -1
- package/dist/client/triggers/index.d.ts +4 -0
- package/dist/client/triggers/schedule/constants.d.ts +4 -0
- package/dist/client/triggers/schedule/index.d.ts +15 -0
- package/dist/common/collections/jobs.js +7 -0
- package/dist/externalVersion.js +12 -12
- package/dist/locale/zh-CN.json +1 -0
- package/dist/node_modules/cron-parser/lib/parser.js +1 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -0
- package/dist/node_modules/joi/lib/annotate.js +175 -0
- package/dist/node_modules/joi/lib/base.js +1069 -0
- package/dist/node_modules/joi/lib/cache.js +143 -0
- package/dist/node_modules/joi/lib/common.js +216 -0
- package/dist/node_modules/joi/lib/compile.js +283 -0
- package/dist/node_modules/joi/lib/errors.js +271 -0
- package/dist/node_modules/joi/lib/extend.js +312 -0
- package/dist/node_modules/joi/lib/index.d.ts +2365 -0
- package/dist/node_modules/joi/lib/index.js +1 -0
- package/dist/node_modules/joi/lib/manifest.js +476 -0
- package/dist/node_modules/joi/lib/messages.js +178 -0
- package/dist/node_modules/joi/lib/modify.js +267 -0
- package/dist/node_modules/joi/lib/ref.js +414 -0
- package/dist/node_modules/joi/lib/schemas.js +302 -0
- package/dist/node_modules/joi/lib/state.js +166 -0
- package/dist/node_modules/joi/lib/template.js +463 -0
- package/dist/node_modules/joi/lib/trace.js +346 -0
- package/dist/node_modules/joi/lib/types/alternatives.js +364 -0
- package/dist/node_modules/joi/lib/types/any.js +174 -0
- package/dist/node_modules/joi/lib/types/array.js +809 -0
- package/dist/node_modules/joi/lib/types/binary.js +100 -0
- package/dist/node_modules/joi/lib/types/boolean.js +150 -0
- package/dist/node_modules/joi/lib/types/date.js +233 -0
- package/dist/node_modules/joi/lib/types/function.js +93 -0
- package/dist/node_modules/joi/lib/types/keys.js +1067 -0
- package/dist/node_modules/joi/lib/types/link.js +168 -0
- package/dist/node_modules/joi/lib/types/number.js +363 -0
- package/dist/node_modules/joi/lib/types/object.js +22 -0
- package/dist/node_modules/joi/lib/types/string.js +850 -0
- package/dist/node_modules/joi/lib/types/symbol.js +102 -0
- package/dist/node_modules/joi/lib/validator.js +750 -0
- package/dist/node_modules/joi/lib/values.js +263 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.d.ts +60 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.js +225 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/package.json +30 -0
- package/dist/node_modules/joi/package.json +1 -0
- package/dist/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +10 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.js +1692 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.min.js +1 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/{mjs → esm/browser}/index.js +537 -179
- package/dist/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/dist/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/dist/node_modules/lru-cache/dist/esm/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/{cjs → esm}/index.js +538 -184
- package/dist/node_modules/lru-cache/dist/esm/index.min.js +2 -0
- package/dist/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +7 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.js +1688 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.js +1 -1
- package/dist/node_modules/nodejs-snowflake/package.json +1 -1
- package/dist/server/Plugin.d.ts +1 -0
- package/dist/server/Plugin.js +28 -3
- package/dist/server/actions/nodes.d.ts +5 -0
- package/dist/server/actions/nodes.js +38 -5
- package/dist/server/actions/workflows.d.ts +6 -0
- package/dist/server/actions/workflows.js +38 -0
- package/dist/server/instructions/ConditionInstruction.d.ts +2 -0
- package/dist/server/instructions/ConditionInstruction.js +17 -0
- package/dist/server/instructions/CreateInstruction.d.ts +3 -0
- package/dist/server/instructions/CreateInstruction.js +25 -0
- package/dist/server/instructions/DestroyInstruction.d.ts +3 -0
- package/dist/server/instructions/DestroyInstruction.js +25 -0
- package/dist/server/instructions/EndInstruction.d.ts +2 -0
- package/dist/server/instructions/EndInstruction.js +4 -0
- package/dist/server/instructions/MultiConditionsInstruction.d.ts +2 -0
- package/dist/server/instructions/MultiConditionsInstruction.js +23 -0
- package/dist/server/instructions/OutputInstruction.d.ts +2 -0
- package/dist/server/instructions/OutputInstruction.js +14 -0
- package/dist/server/instructions/QueryInstruction.d.ts +3 -0
- package/dist/server/instructions/QueryInstruction.js +30 -0
- package/dist/server/instructions/UpdateInstruction.d.ts +3 -0
- package/dist/server/instructions/UpdateInstruction.js +27 -0
- package/dist/server/instructions/index.d.ts +6 -1
- package/dist/server/instructions/index.js +18 -0
- package/dist/server/triggers/CollectionTrigger.d.ts +3 -0
- package/dist/server/triggers/CollectionTrigger.js +28 -0
- package/dist/server/triggers/ScheduleTrigger/index.d.ts +3 -0
- package/dist/server/triggers/ScheduleTrigger/index.js +18 -3
- package/dist/server/triggers/index.d.ts +3 -0
- package/dist/server/triggers/index.js +18 -0
- package/dist/server/utils.d.ts +2 -0
- package/dist/server/utils.js +22 -2
- package/package.json +4 -3
- package/dist/client/10.54a0831f49cae121.js +0 -10
- package/dist/client/626.7d24ff2a47742f1b.js +0 -10
- package/dist/client/771.5e7be8b4d4ac579f.js +0 -10
- package/dist/client/781.d46db08dcfead1b0.js +0 -10
- package/dist/node_modules/lru-cache/LICENSE +0 -15
- package/dist/node_modules/lru-cache/dist/cjs/index-cjs.d.ts +0 -7
- package/dist/node_modules/lru-cache/dist/cjs/index-cjs.js +0 -1
- package/dist/node_modules/lru-cache/dist/cjs/index.d.ts +0 -807
- package/dist/node_modules/lru-cache/dist/cjs/index.min.js +0 -2
- package/dist/node_modules/lru-cache/dist/mjs/index.d.ts +0 -807
- package/dist/node_modules/lru-cache/dist/mjs/index.min.js +0 -2
- /package/dist/node_modules/lru-cache/dist/{cjs → commonjs}/package.json +0 -0
- /package/dist/node_modules/lru-cache/dist/{mjs → esm}/package.json +0 -0
|
@@ -1,26 +1,31 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* @module LRUCache
|
|
4
3
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
4
|
+
import { metrics, tracing } from './diagnostics-channel.js';
|
|
5
|
+
const hasSubscribers = () => metrics.hasSubscribers || tracing.hasSubscribers;
|
|
6
|
+
const defaultPerf = (typeof performance === 'object' &&
|
|
8
7
|
performance &&
|
|
9
|
-
typeof performance.now === 'function'
|
|
10
|
-
|
|
8
|
+
typeof performance.now === 'function') ?
|
|
9
|
+
performance
|
|
11
10
|
: Date;
|
|
12
11
|
const warned = new Set();
|
|
12
|
+
/* c8 ignore start */
|
|
13
|
+
const PROCESS = (typeof process === 'object' && !!process ?
|
|
14
|
+
process
|
|
15
|
+
: {});
|
|
16
|
+
/* c8 ignore stop */
|
|
13
17
|
const emitWarning = (msg, type, code, fn) => {
|
|
14
|
-
typeof
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
if (typeof PROCESS.emitWarning === 'function') {
|
|
19
|
+
PROCESS.emitWarning(msg, type, code, fn);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
//oxlint-disable-next-line no-console
|
|
23
|
+
console.error(`[${code}] ${type}: ${msg}`);
|
|
24
|
+
}
|
|
19
25
|
};
|
|
20
26
|
const shouldWarn = (code) => !warned.has(code);
|
|
21
27
|
const TYPE = Symbol('type');
|
|
22
|
-
const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
23
|
-
/* c8 ignore start */
|
|
28
|
+
const isPosInt = (n) => !!n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
24
29
|
// This is a little bit ridiculous, tbh.
|
|
25
30
|
// The maximum array length is 2^32-1 or thereabouts on most JS impls.
|
|
26
31
|
// And well before that point, you're caching the entire world, I mean,
|
|
@@ -29,16 +34,12 @@ const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
|
29
34
|
// zeroes at init time is brutal when you get that big.
|
|
30
35
|
// But why not be complete?
|
|
31
36
|
// Maybe in the future, these limits will have expanded.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
: max <= Math.pow(2, 8)
|
|
35
|
-
?
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
: max <= Math.pow(2, 32)
|
|
39
|
-
? Uint32Array
|
|
40
|
-
: max <= Number.MAX_SAFE_INTEGER
|
|
41
|
-
? ZeroArray
|
|
37
|
+
/* c8 ignore start */
|
|
38
|
+
const getUintArray = (max) => !isPosInt(max) ? null
|
|
39
|
+
: max <= Math.pow(2, 8) ? Uint8Array
|
|
40
|
+
: max <= Math.pow(2, 16) ? Uint16Array
|
|
41
|
+
: max <= Math.pow(2, 32) ? Uint32Array
|
|
42
|
+
: max <= Number.MAX_SAFE_INTEGER ? ZeroArray
|
|
42
43
|
: null;
|
|
43
44
|
/* c8 ignore stop */
|
|
44
45
|
class ZeroArray extends Array {
|
|
@@ -80,21 +81,34 @@ class Stack {
|
|
|
80
81
|
/**
|
|
81
82
|
* Default export, the thing you're using this module to get.
|
|
82
83
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* The `K` and `V` types define the key and value types, respectively. The
|
|
85
|
+
* optional `FC` type defines the type of the `context` object passed to
|
|
86
|
+
* `cache.fetch()` and `cache.memo()`.
|
|
87
|
+
*
|
|
88
|
+
* Keys and values **must not** be `null` or `undefined`.
|
|
89
|
+
*
|
|
90
|
+
* All properties from the options object (with the exception of `max`,
|
|
91
|
+
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
|
|
92
|
+
* added as normal public members. (The listed options are read-only getters.)
|
|
93
|
+
*
|
|
94
|
+
* Changing any of these will alter the defaults for subsequent method calls.
|
|
88
95
|
*/
|
|
89
|
-
class LRUCache {
|
|
90
|
-
//
|
|
91
|
-
// really *need* to be protected. The rest can be modified, as they just
|
|
92
|
-
// set defaults for various methods.
|
|
96
|
+
export class LRUCache {
|
|
97
|
+
// options that cannot be changed without disaster
|
|
93
98
|
#max;
|
|
94
99
|
#maxSize;
|
|
95
100
|
#dispose;
|
|
101
|
+
#onInsert;
|
|
96
102
|
#disposeAfter;
|
|
97
103
|
#fetchMethod;
|
|
104
|
+
#memoMethod;
|
|
105
|
+
#perf;
|
|
106
|
+
/**
|
|
107
|
+
* {@link LRUCache.OptionsBase.perf}
|
|
108
|
+
*/
|
|
109
|
+
get perf() {
|
|
110
|
+
return this.#perf;
|
|
111
|
+
}
|
|
98
112
|
/**
|
|
99
113
|
* {@link LRUCache.OptionsBase.ttl}
|
|
100
114
|
*/
|
|
@@ -170,9 +184,11 @@ class LRUCache {
|
|
|
170
184
|
#sizes;
|
|
171
185
|
#starts;
|
|
172
186
|
#ttls;
|
|
187
|
+
#autopurgeTimers;
|
|
173
188
|
#hasDispose;
|
|
174
189
|
#hasFetchMethod;
|
|
175
190
|
#hasDisposeAfter;
|
|
191
|
+
#hasOnInsert;
|
|
176
192
|
/**
|
|
177
193
|
* Do not call this method unless you need to inspect the
|
|
178
194
|
* inner workings of the cache. If anything returned by this
|
|
@@ -187,6 +203,7 @@ class LRUCache {
|
|
|
187
203
|
// properties
|
|
188
204
|
starts: c.#starts,
|
|
189
205
|
ttls: c.#ttls,
|
|
206
|
+
autopurgeTimers: c.#autopurgeTimers,
|
|
190
207
|
sizes: c.#sizes,
|
|
191
208
|
keyMap: c.#keyMap,
|
|
192
209
|
keyList: c.#keyList,
|
|
@@ -240,12 +257,21 @@ class LRUCache {
|
|
|
240
257
|
get fetchMethod() {
|
|
241
258
|
return this.#fetchMethod;
|
|
242
259
|
}
|
|
260
|
+
get memoMethod() {
|
|
261
|
+
return this.#memoMethod;
|
|
262
|
+
}
|
|
243
263
|
/**
|
|
244
264
|
* {@link LRUCache.OptionsBase.dispose} (read-only)
|
|
245
265
|
*/
|
|
246
266
|
get dispose() {
|
|
247
267
|
return this.#dispose;
|
|
248
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* {@link LRUCache.OptionsBase.onInsert} (read-only)
|
|
271
|
+
*/
|
|
272
|
+
get onInsert() {
|
|
273
|
+
return this.#onInsert;
|
|
274
|
+
}
|
|
249
275
|
/**
|
|
250
276
|
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
|
|
251
277
|
*/
|
|
@@ -253,7 +279,13 @@ class LRUCache {
|
|
|
253
279
|
return this.#disposeAfter;
|
|
254
280
|
}
|
|
255
281
|
constructor(options) {
|
|
256
|
-
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, } = options;
|
|
282
|
+
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;
|
|
283
|
+
if (perf !== undefined) {
|
|
284
|
+
if (typeof perf?.now !== 'function') {
|
|
285
|
+
throw new TypeError('perf option must have a now() method if specified');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
this.#perf = perf ?? defaultPerf;
|
|
257
289
|
if (max !== 0 && !isPosInt(max)) {
|
|
258
290
|
throw new TypeError('max option must be a nonnegative integer');
|
|
259
291
|
}
|
|
@@ -273,15 +305,18 @@ class LRUCache {
|
|
|
273
305
|
throw new TypeError('sizeCalculation set to non-function');
|
|
274
306
|
}
|
|
275
307
|
}
|
|
276
|
-
if (
|
|
277
|
-
|
|
308
|
+
if (memoMethod !== undefined && typeof memoMethod !== 'function') {
|
|
309
|
+
throw new TypeError('memoMethod must be a function if defined');
|
|
310
|
+
}
|
|
311
|
+
this.#memoMethod = memoMethod;
|
|
312
|
+
if (fetchMethod !== undefined && typeof fetchMethod !== 'function') {
|
|
278
313
|
throw new TypeError('fetchMethod must be a function if specified');
|
|
279
314
|
}
|
|
280
315
|
this.#fetchMethod = fetchMethod;
|
|
281
316
|
this.#hasFetchMethod = !!fetchMethod;
|
|
282
317
|
this.#keyMap = new Map();
|
|
283
|
-
this.#keyList =
|
|
284
|
-
this.#valList =
|
|
318
|
+
this.#keyList = Array.from({ length: max }).fill(undefined);
|
|
319
|
+
this.#valList = Array.from({ length: max }).fill(undefined);
|
|
285
320
|
this.#next = new UintArray(max);
|
|
286
321
|
this.#prev = new UintArray(max);
|
|
287
322
|
this.#head = 0;
|
|
@@ -292,6 +327,9 @@ class LRUCache {
|
|
|
292
327
|
if (typeof dispose === 'function') {
|
|
293
328
|
this.#dispose = dispose;
|
|
294
329
|
}
|
|
330
|
+
if (typeof onInsert === 'function') {
|
|
331
|
+
this.#onInsert = onInsert;
|
|
332
|
+
}
|
|
295
333
|
if (typeof disposeAfter === 'function') {
|
|
296
334
|
this.#disposeAfter = disposeAfter;
|
|
297
335
|
this.#disposed = [];
|
|
@@ -301,6 +339,7 @@ class LRUCache {
|
|
|
301
339
|
this.#disposed = undefined;
|
|
302
340
|
}
|
|
303
341
|
this.#hasDispose = !!this.#dispose;
|
|
342
|
+
this.#hasOnInsert = !!this.#onInsert;
|
|
304
343
|
this.#hasDisposeAfter = !!this.#disposeAfter;
|
|
305
344
|
this.noDisposeOnSet = !!noDisposeOnSet;
|
|
306
345
|
this.noUpdateTTL = !!noUpdateTTL;
|
|
@@ -325,9 +364,7 @@ class LRUCache {
|
|
|
325
364
|
this.updateAgeOnGet = !!updateAgeOnGet;
|
|
326
365
|
this.updateAgeOnHas = !!updateAgeOnHas;
|
|
327
366
|
this.ttlResolution =
|
|
328
|
-
isPosInt(ttlResolution) || ttlResolution === 0
|
|
329
|
-
? ttlResolution
|
|
330
|
-
: 1;
|
|
367
|
+
isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
|
|
331
368
|
this.ttlAutopurge = !!ttlAutopurge;
|
|
332
369
|
this.ttl = ttl || 0;
|
|
333
370
|
if (this.ttl) {
|
|
@@ -351,7 +388,8 @@ class LRUCache {
|
|
|
351
388
|
}
|
|
352
389
|
}
|
|
353
390
|
/**
|
|
354
|
-
* Return the
|
|
391
|
+
* Return the number of ms left in the item's TTL. If item is not in cache,
|
|
392
|
+
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
|
|
355
393
|
*/
|
|
356
394
|
getRemainingTTL(key) {
|
|
357
395
|
return this.#keyMap.has(key) ? Infinity : 0;
|
|
@@ -361,41 +399,68 @@ class LRUCache {
|
|
|
361
399
|
const starts = new ZeroArray(this.#max);
|
|
362
400
|
this.#ttls = ttls;
|
|
363
401
|
this.#starts = starts;
|
|
364
|
-
|
|
402
|
+
const purgeTimers = this.ttlAutopurge ?
|
|
403
|
+
Array.from({
|
|
404
|
+
length: this.#max,
|
|
405
|
+
})
|
|
406
|
+
: undefined;
|
|
407
|
+
this.#autopurgeTimers = purgeTimers;
|
|
408
|
+
this.#setItemTTL = (index, ttl, start = this.#perf.now()) => {
|
|
365
409
|
starts[index] = ttl !== 0 ? start : 0;
|
|
366
410
|
ttls[index] = ttl;
|
|
367
|
-
|
|
368
|
-
const t = setTimeout(() => {
|
|
369
|
-
if (this.#isStale(index)) {
|
|
370
|
-
this.delete(this.#keyList[index]);
|
|
371
|
-
}
|
|
372
|
-
}, ttl + 1);
|
|
373
|
-
// unref() not supported on all platforms
|
|
374
|
-
/* c8 ignore start */
|
|
375
|
-
if (t.unref) {
|
|
376
|
-
t.unref();
|
|
377
|
-
}
|
|
378
|
-
/* c8 ignore stop */
|
|
379
|
-
}
|
|
411
|
+
setPurgetTimer(index, ttl);
|
|
380
412
|
};
|
|
381
413
|
this.#updateItemAge = index => {
|
|
382
|
-
starts[index] = ttls[index] !== 0 ? perf.now() : 0;
|
|
414
|
+
starts[index] = ttls[index] !== 0 ? this.#perf.now() : 0;
|
|
415
|
+
setPurgetTimer(index, ttls[index]);
|
|
383
416
|
};
|
|
417
|
+
// clear out the purge timer if we're setting TTL to 0, and
|
|
418
|
+
// previously had a ttl purge timer running, so it doesn't
|
|
419
|
+
// fire unnecessarily. Don't need to do this if we're not doing
|
|
420
|
+
// autopurge.
|
|
421
|
+
const setPurgetTimer = !this.ttlAutopurge ?
|
|
422
|
+
() => { }
|
|
423
|
+
: (index, ttl) => {
|
|
424
|
+
if (purgeTimers?.[index]) {
|
|
425
|
+
clearTimeout(purgeTimers[index]);
|
|
426
|
+
purgeTimers[index] = undefined;
|
|
427
|
+
}
|
|
428
|
+
if (ttl && ttl !== 0 && purgeTimers) {
|
|
429
|
+
const t = setTimeout(() => {
|
|
430
|
+
if (this.#isStale(index)) {
|
|
431
|
+
this.#delete(this.#keyList[index], 'expire');
|
|
432
|
+
}
|
|
433
|
+
}, ttl + 1);
|
|
434
|
+
// unref() not supported on all platforms
|
|
435
|
+
/* c8 ignore start */
|
|
436
|
+
if (t.unref) {
|
|
437
|
+
t.unref();
|
|
438
|
+
}
|
|
439
|
+
/* c8 ignore stop */
|
|
440
|
+
purgeTimers[index] = t;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
384
443
|
this.#statusTTL = (status, index) => {
|
|
385
444
|
if (ttls[index]) {
|
|
386
445
|
const ttl = ttls[index];
|
|
387
446
|
const start = starts[index];
|
|
447
|
+
/* c8 ignore start */
|
|
448
|
+
if (!ttl || !start) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
/* c8 ignore stop */
|
|
388
452
|
status.ttl = ttl;
|
|
389
453
|
status.start = start;
|
|
390
454
|
status.now = cachedNow || getNow();
|
|
391
|
-
|
|
455
|
+
const age = status.now - start;
|
|
456
|
+
status.remainingTTL = ttl - age;
|
|
392
457
|
}
|
|
393
458
|
};
|
|
394
459
|
// debounce calls to perf.now() to 1s so we're not hitting
|
|
395
460
|
// that costly call repeatedly.
|
|
396
461
|
let cachedNow = 0;
|
|
397
462
|
const getNow = () => {
|
|
398
|
-
const n = perf.now();
|
|
463
|
+
const n = this.#perf.now();
|
|
399
464
|
if (this.ttlResolution > 0) {
|
|
400
465
|
cachedNow = n;
|
|
401
466
|
const t = setTimeout(() => (cachedNow = 0), this.ttlResolution);
|
|
@@ -413,14 +478,18 @@ class LRUCache {
|
|
|
413
478
|
if (index === undefined) {
|
|
414
479
|
return 0;
|
|
415
480
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
481
|
+
const ttl = ttls[index];
|
|
482
|
+
const start = starts[index];
|
|
483
|
+
if (!ttl || !start) {
|
|
484
|
+
return Infinity;
|
|
485
|
+
}
|
|
486
|
+
const age = (cachedNow || getNow()) - start;
|
|
487
|
+
return ttl - age;
|
|
419
488
|
};
|
|
420
489
|
this.#isStale = index => {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
490
|
+
const s = starts[index];
|
|
491
|
+
const t = ttls[index];
|
|
492
|
+
return !!t && !!s && (cachedNow || getNow()) - s > t;
|
|
424
493
|
};
|
|
425
494
|
}
|
|
426
495
|
// conditionally set private methods related to TTL
|
|
@@ -486,10 +555,7 @@ class LRUCache {
|
|
|
486
555
|
};
|
|
487
556
|
*#indexes({ allowStale = this.allowStale } = {}) {
|
|
488
557
|
if (this.#size) {
|
|
489
|
-
for (let i = this.#tail;
|
|
490
|
-
if (!this.#isValidIndex(i)) {
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
558
|
+
for (let i = this.#tail; this.#isValidIndex(i);) {
|
|
493
559
|
if (allowStale || !this.#isStale(i)) {
|
|
494
560
|
yield i;
|
|
495
561
|
}
|
|
@@ -504,10 +570,7 @@ class LRUCache {
|
|
|
504
570
|
}
|
|
505
571
|
*#rindexes({ allowStale = this.allowStale } = {}) {
|
|
506
572
|
if (this.#size) {
|
|
507
|
-
for (let i = this.#head;
|
|
508
|
-
if (!this.#isValidIndex(i)) {
|
|
509
|
-
break;
|
|
510
|
-
}
|
|
573
|
+
for (let i = this.#head; this.#isValidIndex(i);) {
|
|
511
574
|
if (allowStale || !this.#isStale(i)) {
|
|
512
575
|
yield i;
|
|
513
576
|
}
|
|
@@ -559,8 +622,7 @@ class LRUCache {
|
|
|
559
622
|
*keys() {
|
|
560
623
|
for (const i of this.#indexes()) {
|
|
561
624
|
const k = this.#keyList[i];
|
|
562
|
-
if (k !== undefined &&
|
|
563
|
-
!this.#isBackgroundFetch(this.#valList[i])) {
|
|
625
|
+
if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
|
|
564
626
|
yield k;
|
|
565
627
|
}
|
|
566
628
|
}
|
|
@@ -574,8 +636,7 @@ class LRUCache {
|
|
|
574
636
|
*rkeys() {
|
|
575
637
|
for (const i of this.#rindexes()) {
|
|
576
638
|
const k = this.#keyList[i];
|
|
577
|
-
if (k !== undefined &&
|
|
578
|
-
!this.#isBackgroundFetch(this.#valList[i])) {
|
|
639
|
+
if (k !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
|
|
579
640
|
yield k;
|
|
580
641
|
}
|
|
581
642
|
}
|
|
@@ -587,8 +648,7 @@ class LRUCache {
|
|
|
587
648
|
*values() {
|
|
588
649
|
for (const i of this.#indexes()) {
|
|
589
650
|
const v = this.#valList[i];
|
|
590
|
-
if (v !== undefined &&
|
|
591
|
-
!this.#isBackgroundFetch(this.#valList[i])) {
|
|
651
|
+
if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
|
|
592
652
|
yield this.#valList[i];
|
|
593
653
|
}
|
|
594
654
|
}
|
|
@@ -602,8 +662,7 @@ class LRUCache {
|
|
|
602
662
|
*rvalues() {
|
|
603
663
|
for (const i of this.#rindexes()) {
|
|
604
664
|
const v = this.#valList[i];
|
|
605
|
-
if (v !== undefined &&
|
|
606
|
-
!this.#isBackgroundFetch(this.#valList[i])) {
|
|
665
|
+
if (v !== undefined && !this.#isBackgroundFetch(this.#valList[i])) {
|
|
607
666
|
yield this.#valList[i];
|
|
608
667
|
}
|
|
609
668
|
}
|
|
@@ -615,35 +674,42 @@ class LRUCache {
|
|
|
615
674
|
[Symbol.iterator]() {
|
|
616
675
|
return this.entries();
|
|
617
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* A String value that is used in the creation of the default string
|
|
679
|
+
* description of an object. Called by the built-in method
|
|
680
|
+
* `Object.prototype.toString`.
|
|
681
|
+
*/
|
|
682
|
+
[Symbol.toStringTag] = 'LRUCache';
|
|
618
683
|
/**
|
|
619
684
|
* Find a value for which the supplied fn method returns a truthy value,
|
|
620
|
-
* similar to Array.find()
|
|
685
|
+
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
|
|
621
686
|
*/
|
|
622
687
|
find(fn, getOptions = {}) {
|
|
623
688
|
for (const i of this.#indexes()) {
|
|
624
689
|
const v = this.#valList[i];
|
|
625
|
-
const value = this.#isBackgroundFetch(v)
|
|
626
|
-
? v.__staleWhileFetching
|
|
627
|
-
: v;
|
|
690
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
628
691
|
if (value === undefined)
|
|
629
692
|
continue;
|
|
630
693
|
if (fn(value, this.#keyList[i], this)) {
|
|
631
|
-
return this
|
|
694
|
+
return this.#get(this.#keyList[i], getOptions);
|
|
632
695
|
}
|
|
633
696
|
}
|
|
634
697
|
}
|
|
635
698
|
/**
|
|
636
|
-
* Call the supplied function on each item in the cache, in order from
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
699
|
+
* Call the supplied function on each item in the cache, in order from most
|
|
700
|
+
* recently used to least recently used.
|
|
701
|
+
*
|
|
702
|
+
* `fn` is called as `fn(value, key, cache)`.
|
|
703
|
+
*
|
|
704
|
+
* If `thisp` is provided, function will be called in the `this`-context of
|
|
705
|
+
* the provided object, or the cache if no `thisp` object is provided.
|
|
706
|
+
*
|
|
707
|
+
* Does not update age or recenty of use, or iterate over stale values.
|
|
640
708
|
*/
|
|
641
709
|
forEach(fn, thisp = this) {
|
|
642
710
|
for (const i of this.#indexes()) {
|
|
643
711
|
const v = this.#valList[i];
|
|
644
|
-
const value = this.#isBackgroundFetch(v)
|
|
645
|
-
? v.__staleWhileFetching
|
|
646
|
-
: v;
|
|
712
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
647
713
|
if (value === undefined)
|
|
648
714
|
continue;
|
|
649
715
|
fn.call(thisp, value, this.#keyList[i], this);
|
|
@@ -656,9 +722,7 @@ class LRUCache {
|
|
|
656
722
|
rforEach(fn, thisp = this) {
|
|
657
723
|
for (const i of this.#rindexes()) {
|
|
658
724
|
const v = this.#valList[i];
|
|
659
|
-
const value = this.#isBackgroundFetch(v)
|
|
660
|
-
? v.__staleWhileFetching
|
|
661
|
-
: v;
|
|
725
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
662
726
|
if (value === undefined)
|
|
663
727
|
continue;
|
|
664
728
|
fn.call(thisp, value, this.#keyList[i], this);
|
|
@@ -672,24 +736,69 @@ class LRUCache {
|
|
|
672
736
|
let deleted = false;
|
|
673
737
|
for (const i of this.#rindexes({ allowStale: true })) {
|
|
674
738
|
if (this.#isStale(i)) {
|
|
675
|
-
this
|
|
739
|
+
this.#delete(this.#keyList[i], 'expire');
|
|
676
740
|
deleted = true;
|
|
677
741
|
}
|
|
678
742
|
}
|
|
679
743
|
return deleted;
|
|
680
744
|
}
|
|
745
|
+
/**
|
|
746
|
+
* Get the extended info about a given entry, to get its value, size, and
|
|
747
|
+
* TTL info simultaneously. Returns `undefined` if the key is not present.
|
|
748
|
+
*
|
|
749
|
+
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
|
|
750
|
+
* serialization, the `start` value is always the current timestamp, and the
|
|
751
|
+
* `ttl` is a calculated remaining time to live (negative if expired).
|
|
752
|
+
*
|
|
753
|
+
* Always returns stale values, if their info is found in the cache, so be
|
|
754
|
+
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
|
|
755
|
+
* if relevant.
|
|
756
|
+
*/
|
|
757
|
+
info(key) {
|
|
758
|
+
const i = this.#keyMap.get(key);
|
|
759
|
+
if (i === undefined)
|
|
760
|
+
return undefined;
|
|
761
|
+
const v = this.#valList[i];
|
|
762
|
+
/* c8 ignore start - this isn't tested for the info function,
|
|
763
|
+
* but it's the same logic as found in other places. */
|
|
764
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
765
|
+
if (value === undefined)
|
|
766
|
+
return undefined;
|
|
767
|
+
/* c8 ignore stop */
|
|
768
|
+
const entry = { value };
|
|
769
|
+
if (this.#ttls && this.#starts) {
|
|
770
|
+
const ttl = this.#ttls[i];
|
|
771
|
+
const start = this.#starts[i];
|
|
772
|
+
if (ttl && start) {
|
|
773
|
+
const remain = ttl - (this.#perf.now() - start);
|
|
774
|
+
entry.ttl = remain;
|
|
775
|
+
entry.start = Date.now();
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
if (this.#sizes) {
|
|
779
|
+
entry.size = this.#sizes[i];
|
|
780
|
+
}
|
|
781
|
+
return entry;
|
|
782
|
+
}
|
|
681
783
|
/**
|
|
682
784
|
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
|
|
683
|
-
* passed to
|
|
785
|
+
* passed to {@link LRUCache#load}.
|
|
786
|
+
*
|
|
787
|
+
* The `start` fields are calculated relative to a portable `Date.now()`
|
|
788
|
+
* timestamp, even if `performance.now()` is available.
|
|
789
|
+
*
|
|
790
|
+
* Stale entries are always included in the `dump`, even if
|
|
791
|
+
* {@link LRUCache.OptionsBase.allowStale} is false.
|
|
792
|
+
*
|
|
793
|
+
* Note: this returns an actual array, not a generator, so it can be more
|
|
794
|
+
* easily passed around.
|
|
684
795
|
*/
|
|
685
796
|
dump() {
|
|
686
797
|
const arr = [];
|
|
687
798
|
for (const i of this.#indexes({ allowStale: true })) {
|
|
688
799
|
const key = this.#keyList[i];
|
|
689
800
|
const v = this.#valList[i];
|
|
690
|
-
const value = this.#isBackgroundFetch(v)
|
|
691
|
-
? v.__staleWhileFetching
|
|
692
|
-
: v;
|
|
801
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
693
802
|
if (value === undefined || key === undefined)
|
|
694
803
|
continue;
|
|
695
804
|
const entry = { value };
|
|
@@ -697,7 +806,7 @@ class LRUCache {
|
|
|
697
806
|
entry.ttl = this.#ttls[i];
|
|
698
807
|
// always dump the start relative to a portable timestamp
|
|
699
808
|
// it's ok for this to be a bit slow, it's a rare operation.
|
|
700
|
-
const age = perf.now() - this.#starts[i];
|
|
809
|
+
const age = this.#perf.now() - this.#starts[i];
|
|
701
810
|
entry.start = Math.floor(Date.now() - age);
|
|
702
811
|
}
|
|
703
812
|
if (this.#sizes) {
|
|
@@ -709,8 +818,12 @@ class LRUCache {
|
|
|
709
818
|
}
|
|
710
819
|
/**
|
|
711
820
|
* Reset the cache and load in the items in entries in the order listed.
|
|
712
|
-
*
|
|
713
|
-
*
|
|
821
|
+
*
|
|
822
|
+
* The shape of the resulting cache may be different if the same options are
|
|
823
|
+
* not used in both caches.
|
|
824
|
+
*
|
|
825
|
+
* The `start` fields are assumed to be calculated relative to a portable
|
|
826
|
+
* `Date.now()` timestamp, even if `performance.now()` is available.
|
|
714
827
|
*/
|
|
715
828
|
load(arr) {
|
|
716
829
|
this.clear();
|
|
@@ -723,38 +836,85 @@ class LRUCache {
|
|
|
723
836
|
//
|
|
724
837
|
// it's ok for this to be a bit slow, it's a rare operation.
|
|
725
838
|
const age = Date.now() - entry.start;
|
|
726
|
-
entry.start = perf.now() - age;
|
|
839
|
+
entry.start = this.#perf.now() - age;
|
|
727
840
|
}
|
|
728
|
-
this
|
|
841
|
+
this.#set(key, entry.value, entry);
|
|
729
842
|
}
|
|
730
843
|
}
|
|
731
844
|
/**
|
|
732
845
|
* Add a value to the cache.
|
|
846
|
+
*
|
|
847
|
+
* Note: if `undefined` is specified as a value, this is an alias for
|
|
848
|
+
* {@link LRUCache#delete}
|
|
849
|
+
*
|
|
850
|
+
* Fields on the {@link LRUCache.SetOptions} options param will override
|
|
851
|
+
* their corresponding values in the constructor options for the scope
|
|
852
|
+
* of this single `set()` operation.
|
|
853
|
+
*
|
|
854
|
+
* If `start` is provided, then that will set the effective start
|
|
855
|
+
* time for the TTL calculation. Note that this must be a previous
|
|
856
|
+
* value of `performance.now()` if supported, or a previous value of
|
|
857
|
+
* `Date.now()` if not.
|
|
858
|
+
*
|
|
859
|
+
* Options object may also include `size`, which will prevent
|
|
860
|
+
* calling the `sizeCalculation` function and just use the specified
|
|
861
|
+
* number if it is a positive integer, and `noDisposeOnSet` which
|
|
862
|
+
* will prevent calling a `dispose` function in the case of
|
|
863
|
+
* overwrites.
|
|
864
|
+
*
|
|
865
|
+
* If the `size` (or return value of `sizeCalculation`) for a given
|
|
866
|
+
* entry is greater than `maxEntrySize`, then the item will not be
|
|
867
|
+
* added to the cache.
|
|
868
|
+
*
|
|
869
|
+
* Will update the recency of the entry.
|
|
870
|
+
*
|
|
871
|
+
* If the value is `undefined`, then this is an alias for
|
|
872
|
+
* `cache.delete(key)`. `undefined` is never stored in the cache.
|
|
733
873
|
*/
|
|
734
874
|
set(k, v, setOptions = {}) {
|
|
875
|
+
const { status = metrics.hasSubscribers ? {} : undefined } = setOptions;
|
|
876
|
+
setOptions.status = status;
|
|
877
|
+
if (status) {
|
|
878
|
+
status.op = 'set';
|
|
879
|
+
status.key = k;
|
|
880
|
+
if (v !== undefined)
|
|
881
|
+
status.value = v;
|
|
882
|
+
}
|
|
883
|
+
const result = this.#set(k, v, setOptions);
|
|
884
|
+
if (status && metrics.hasSubscribers) {
|
|
885
|
+
metrics.publish(status);
|
|
886
|
+
}
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
#set(k, v, setOptions = {}) {
|
|
735
890
|
const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status, } = setOptions;
|
|
891
|
+
if (v === undefined) {
|
|
892
|
+
if (status)
|
|
893
|
+
status.set = 'deleted';
|
|
894
|
+
this.delete(k);
|
|
895
|
+
return this;
|
|
896
|
+
}
|
|
736
897
|
let { noUpdateTTL = this.noUpdateTTL } = setOptions;
|
|
737
|
-
|
|
898
|
+
if (status && !this.#isBackgroundFetch(v))
|
|
899
|
+
status.value = v;
|
|
900
|
+
const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation, status);
|
|
738
901
|
// if the item doesn't fit, don't do anything
|
|
739
902
|
// NB: maxEntrySize set to maxSize by default
|
|
740
903
|
if (this.maxEntrySize && size > this.maxEntrySize) {
|
|
904
|
+
// have to delete, in case something is there already.
|
|
905
|
+
this.#delete(k, 'set');
|
|
741
906
|
if (status) {
|
|
742
907
|
status.set = 'miss';
|
|
743
908
|
status.maxEntrySizeExceeded = true;
|
|
744
909
|
}
|
|
745
|
-
// have to delete, in case something is there already.
|
|
746
|
-
this.delete(k);
|
|
747
910
|
return this;
|
|
748
911
|
}
|
|
749
912
|
let index = this.#size === 0 ? undefined : this.#keyMap.get(k);
|
|
750
913
|
if (index === undefined) {
|
|
751
914
|
// addition
|
|
752
|
-
index = (this.#size === 0
|
|
753
|
-
? this.#
|
|
754
|
-
|
|
755
|
-
? this.#free.pop()
|
|
756
|
-
: this.#size === this.#max
|
|
757
|
-
? this.#evict(false)
|
|
915
|
+
index = (this.#size === 0 ? this.#tail
|
|
916
|
+
: this.#free.length !== 0 ? this.#free.pop()
|
|
917
|
+
: this.#size === this.#max ? this.#evict(false)
|
|
758
918
|
: this.#size);
|
|
759
919
|
this.#keyList[index] = k;
|
|
760
920
|
this.#valList[index] = v;
|
|
@@ -767,6 +927,9 @@ class LRUCache {
|
|
|
767
927
|
if (status)
|
|
768
928
|
status.set = 'add';
|
|
769
929
|
noUpdateTTL = false;
|
|
930
|
+
if (this.#hasOnInsert) {
|
|
931
|
+
this.#onInsert?.(v, k, 'add');
|
|
932
|
+
}
|
|
770
933
|
}
|
|
771
934
|
else {
|
|
772
935
|
// update
|
|
@@ -775,6 +938,15 @@ class LRUCache {
|
|
|
775
938
|
if (v !== oldVal) {
|
|
776
939
|
if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
|
|
777
940
|
oldVal.__abortController.abort(new Error('replaced'));
|
|
941
|
+
const { __staleWhileFetching: s } = oldVal;
|
|
942
|
+
if (s !== undefined && !noDisposeOnSet) {
|
|
943
|
+
if (this.#hasDispose) {
|
|
944
|
+
this.#dispose?.(s, k, 'set');
|
|
945
|
+
}
|
|
946
|
+
if (this.#hasDisposeAfter) {
|
|
947
|
+
this.#disposed?.push([s, k, 'set']);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
778
950
|
}
|
|
779
951
|
else if (!noDisposeOnSet) {
|
|
780
952
|
if (this.#hasDispose) {
|
|
@@ -789,8 +961,8 @@ class LRUCache {
|
|
|
789
961
|
this.#valList[index] = v;
|
|
790
962
|
if (status) {
|
|
791
963
|
status.set = 'replace';
|
|
792
|
-
const oldValue = oldVal && this.#isBackgroundFetch(oldVal)
|
|
793
|
-
|
|
964
|
+
const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ?
|
|
965
|
+
oldVal.__staleWhileFetching
|
|
794
966
|
: oldVal;
|
|
795
967
|
if (oldValue !== undefined)
|
|
796
968
|
status.oldValue = oldValue;
|
|
@@ -799,6 +971,9 @@ class LRUCache {
|
|
|
799
971
|
else if (status) {
|
|
800
972
|
status.set = 'update';
|
|
801
973
|
}
|
|
974
|
+
if (this.#hasOnInsert) {
|
|
975
|
+
this.onInsert?.(v, k, v === oldVal ? 'update' : 'replace');
|
|
976
|
+
}
|
|
802
977
|
}
|
|
803
978
|
if (ttl !== 0 && !this.#ttls) {
|
|
804
979
|
this.#initializeTTLTracking();
|
|
@@ -864,6 +1039,10 @@ class LRUCache {
|
|
|
864
1039
|
}
|
|
865
1040
|
}
|
|
866
1041
|
this.#removeItemSize(head);
|
|
1042
|
+
if (this.#autopurgeTimers?.[head]) {
|
|
1043
|
+
clearTimeout(this.#autopurgeTimers[head]);
|
|
1044
|
+
this.#autopurgeTimers[head] = undefined;
|
|
1045
|
+
}
|
|
867
1046
|
// if we aren't about to use the index, then null these out
|
|
868
1047
|
if (free) {
|
|
869
1048
|
this.#keyList[head] = undefined;
|
|
@@ -886,10 +1065,30 @@ class LRUCache {
|
|
|
886
1065
|
* Will return false if the item is stale, even though it is technically
|
|
887
1066
|
* in the cache.
|
|
888
1067
|
*
|
|
1068
|
+
* Check if a key is in the cache, without updating the recency of
|
|
1069
|
+
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
|
|
1070
|
+
* to `true` in either the options or the constructor.
|
|
1071
|
+
*
|
|
1072
|
+
* Will return `false` if the item is stale, even though it is technically in
|
|
1073
|
+
* the cache. The difference can be determined (if it matters) by using a
|
|
1074
|
+
* `status` argument, and inspecting the `has` field.
|
|
1075
|
+
*
|
|
889
1076
|
* Will not update item age unless
|
|
890
1077
|
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
|
|
891
1078
|
*/
|
|
892
1079
|
has(k, hasOptions = {}) {
|
|
1080
|
+
const { status = metrics.hasSubscribers ? {} : undefined } = hasOptions;
|
|
1081
|
+
hasOptions.status = status;
|
|
1082
|
+
if (status) {
|
|
1083
|
+
status.op = 'has';
|
|
1084
|
+
status.key = k;
|
|
1085
|
+
}
|
|
1086
|
+
const result = this.#has(k, hasOptions);
|
|
1087
|
+
if (metrics.hasSubscribers)
|
|
1088
|
+
metrics.publish(status);
|
|
1089
|
+
return result;
|
|
1090
|
+
}
|
|
1091
|
+
#has(k, hasOptions = {}) {
|
|
893
1092
|
const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
|
|
894
1093
|
const index = this.#keyMap.get(k);
|
|
895
1094
|
if (index !== undefined) {
|
|
@@ -926,14 +1125,38 @@ class LRUCache {
|
|
|
926
1125
|
* {@link LRUCache.OptionsBase.allowStale} is set.
|
|
927
1126
|
*/
|
|
928
1127
|
peek(k, peekOptions = {}) {
|
|
929
|
-
const {
|
|
1128
|
+
const { status = hasSubscribers() ? {} : undefined } = peekOptions;
|
|
1129
|
+
if (status) {
|
|
1130
|
+
status.op = 'peek';
|
|
1131
|
+
status.key = k;
|
|
1132
|
+
}
|
|
1133
|
+
peekOptions.status = status;
|
|
1134
|
+
const result = this.#peek(k, peekOptions);
|
|
1135
|
+
if (metrics.hasSubscribers) {
|
|
1136
|
+
metrics.publish(status);
|
|
1137
|
+
}
|
|
1138
|
+
return result;
|
|
1139
|
+
}
|
|
1140
|
+
#peek(k, peekOptions) {
|
|
1141
|
+
const { status, allowStale = this.allowStale } = peekOptions;
|
|
930
1142
|
const index = this.#keyMap.get(k);
|
|
931
|
-
if (index
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1143
|
+
if (index === undefined || (!allowStale && this.#isStale(index))) {
|
|
1144
|
+
if (status)
|
|
1145
|
+
status.peek = index === undefined ? 'miss' : 'stale';
|
|
1146
|
+
return undefined;
|
|
1147
|
+
}
|
|
1148
|
+
const v = this.#valList[index];
|
|
1149
|
+
const val = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
1150
|
+
if (status) {
|
|
1151
|
+
if (val !== undefined) {
|
|
1152
|
+
status.peek = 'hit';
|
|
1153
|
+
status.value = val;
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
status.peek = 'miss';
|
|
1157
|
+
}
|
|
936
1158
|
}
|
|
1159
|
+
return val;
|
|
937
1160
|
}
|
|
938
1161
|
#backgroundFetch(k, index, options, context) {
|
|
939
1162
|
const v = index === undefined ? undefined : this.#valList[index];
|
|
@@ -954,6 +1177,8 @@ class LRUCache {
|
|
|
954
1177
|
const cb = (v, updateCache = false) => {
|
|
955
1178
|
const { aborted } = ac.signal;
|
|
956
1179
|
const ignoreAbort = options.ignoreFetchAbort && v !== undefined;
|
|
1180
|
+
const proceed = options.ignoreFetchAbort ||
|
|
1181
|
+
!!(options.allowStaleOnFetchAbort && v !== undefined);
|
|
957
1182
|
if (options.status) {
|
|
958
1183
|
if (aborted && !updateCache) {
|
|
959
1184
|
options.status.fetchAborted = true;
|
|
@@ -966,23 +1191,27 @@ class LRUCache {
|
|
|
966
1191
|
}
|
|
967
1192
|
}
|
|
968
1193
|
if (aborted && !ignoreAbort && !updateCache) {
|
|
969
|
-
return fetchFail(ac.signal.reason);
|
|
1194
|
+
return fetchFail(ac.signal.reason, proceed);
|
|
970
1195
|
}
|
|
971
1196
|
// either we didn't abort, and are still here, or we did, and ignored
|
|
972
1197
|
const bf = p;
|
|
973
|
-
if
|
|
1198
|
+
// if nothing else has been written there but we're set to update the
|
|
1199
|
+
// cache and ignore the abort, or if it's still pending on this specific
|
|
1200
|
+
// background request, then write it to the cache.
|
|
1201
|
+
const vl = this.#valList[index];
|
|
1202
|
+
if (vl === p || (vl === undefined && ignoreAbort && updateCache)) {
|
|
974
1203
|
if (v === undefined) {
|
|
975
|
-
if (bf.__staleWhileFetching) {
|
|
1204
|
+
if (bf.__staleWhileFetching !== undefined) {
|
|
976
1205
|
this.#valList[index] = bf.__staleWhileFetching;
|
|
977
1206
|
}
|
|
978
1207
|
else {
|
|
979
|
-
this
|
|
1208
|
+
this.#delete(k, 'fetch');
|
|
980
1209
|
}
|
|
981
1210
|
}
|
|
982
1211
|
else {
|
|
983
1212
|
if (options.status)
|
|
984
1213
|
options.status.fetchUpdated = true;
|
|
985
|
-
this
|
|
1214
|
+
this.#set(k, v, fetchOpts.options);
|
|
986
1215
|
}
|
|
987
1216
|
}
|
|
988
1217
|
return v;
|
|
@@ -992,9 +1221,10 @@ class LRUCache {
|
|
|
992
1221
|
options.status.fetchRejected = true;
|
|
993
1222
|
options.status.fetchError = er;
|
|
994
1223
|
}
|
|
995
|
-
|
|
1224
|
+
// do not pass go, do not collect $200
|
|
1225
|
+
return fetchFail(er, false);
|
|
996
1226
|
};
|
|
997
|
-
const fetchFail = (er) => {
|
|
1227
|
+
const fetchFail = (er, proceed) => {
|
|
998
1228
|
const { aborted } = ac.signal;
|
|
999
1229
|
const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
|
|
1000
1230
|
const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
|
|
@@ -1003,9 +1233,9 @@ class LRUCache {
|
|
|
1003
1233
|
if (this.#valList[index] === p) {
|
|
1004
1234
|
// if we allow stale on fetch rejections, then we need to ensure that
|
|
1005
1235
|
// the stale value is not removed from the cache when the fetch fails.
|
|
1006
|
-
const del = !noDelete || bf.__staleWhileFetching === undefined;
|
|
1236
|
+
const del = !noDelete || (!proceed && bf.__staleWhileFetching === undefined);
|
|
1007
1237
|
if (del) {
|
|
1008
|
-
this
|
|
1238
|
+
this.#delete(k, 'fetch');
|
|
1009
1239
|
}
|
|
1010
1240
|
else if (!allowStaleAborted) {
|
|
1011
1241
|
// still replace the *promise* with the stale value,
|
|
@@ -1028,15 +1258,14 @@ class LRUCache {
|
|
|
1028
1258
|
const pcall = (res, rej) => {
|
|
1029
1259
|
const fmp = this.#fetchMethod?.(k, v, fetchOpts);
|
|
1030
1260
|
if (fmp && fmp instanceof Promise) {
|
|
1031
|
-
fmp.then(v => res(v), rej);
|
|
1261
|
+
fmp.then(v => res(v === undefined ? undefined : v), rej);
|
|
1032
1262
|
}
|
|
1033
1263
|
// ignored, we go until we finish, regardless.
|
|
1034
1264
|
// defer check until we are actually aborting,
|
|
1035
1265
|
// so fetchMethod can override.
|
|
1036
1266
|
ac.signal.addEventListener('abort', () => {
|
|
1037
|
-
if (!options.ignoreFetchAbort ||
|
|
1038
|
-
|
|
1039
|
-
res();
|
|
1267
|
+
if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
|
|
1268
|
+
res(undefined);
|
|
1040
1269
|
// when it eventually resolves, update the cache.
|
|
1041
1270
|
if (options.allowStaleOnFetchAbort) {
|
|
1042
1271
|
res = v => cb(v, true);
|
|
@@ -1054,7 +1283,7 @@ class LRUCache {
|
|
|
1054
1283
|
});
|
|
1055
1284
|
if (index === undefined) {
|
|
1056
1285
|
// internal, don't expose status.
|
|
1057
|
-
this
|
|
1286
|
+
this.#set(k, bf, { ...fetchOpts.options, status: undefined });
|
|
1058
1287
|
index = this.#keyMap.get(k);
|
|
1059
1288
|
}
|
|
1060
1289
|
else {
|
|
@@ -1071,7 +1300,23 @@ class LRUCache {
|
|
|
1071
1300
|
b.hasOwnProperty('__staleWhileFetching') &&
|
|
1072
1301
|
b.__abortController instanceof AbortController);
|
|
1073
1302
|
}
|
|
1074
|
-
|
|
1303
|
+
fetch(k, fetchOptions = {}) {
|
|
1304
|
+
const ths = tracing.hasSubscribers;
|
|
1305
|
+
const { status = hasSubscribers() ? {} : undefined } = fetchOptions;
|
|
1306
|
+
fetchOptions.status = status;
|
|
1307
|
+
if (status && fetchOptions.context) {
|
|
1308
|
+
status.context = fetchOptions.context;
|
|
1309
|
+
}
|
|
1310
|
+
const p = this.#fetch(k, fetchOptions);
|
|
1311
|
+
if (status && hasSubscribers()) {
|
|
1312
|
+
if (ths) {
|
|
1313
|
+
status.trace = true;
|
|
1314
|
+
tracing.tracePromise(() => p, status).catch(() => { });
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return p;
|
|
1318
|
+
}
|
|
1319
|
+
async #fetch(k, fetchOptions = {}) {
|
|
1075
1320
|
const {
|
|
1076
1321
|
// get options
|
|
1077
1322
|
allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet,
|
|
@@ -1079,10 +1324,16 @@ class LRUCache {
|
|
|
1079
1324
|
ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL,
|
|
1080
1325
|
// fetch exclusive options
|
|
1081
1326
|
noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal, } = fetchOptions;
|
|
1327
|
+
if (status) {
|
|
1328
|
+
status.op = 'fetch';
|
|
1329
|
+
status.key = k;
|
|
1330
|
+
if (forceRefresh)
|
|
1331
|
+
status.forceRefresh = true;
|
|
1332
|
+
}
|
|
1082
1333
|
if (!this.#hasFetchMethod) {
|
|
1083
1334
|
if (status)
|
|
1084
1335
|
status.fetch = 'get';
|
|
1085
|
-
return this
|
|
1336
|
+
return this.#get(k, {
|
|
1086
1337
|
allowStale,
|
|
1087
1338
|
updateAgeOnGet,
|
|
1088
1339
|
noDeleteOnStaleGet,
|
|
@@ -1151,6 +1402,71 @@ class LRUCache {
|
|
|
1151
1402
|
return staleVal ? p.__staleWhileFetching : (p.__returned = p);
|
|
1152
1403
|
}
|
|
1153
1404
|
}
|
|
1405
|
+
forceFetch(k, fetchOptions = {}) {
|
|
1406
|
+
const ths = tracing.hasSubscribers;
|
|
1407
|
+
const { status = hasSubscribers() ? {} : undefined } = fetchOptions;
|
|
1408
|
+
fetchOptions.status = status;
|
|
1409
|
+
if (status && fetchOptions.context) {
|
|
1410
|
+
status.context = fetchOptions.context;
|
|
1411
|
+
}
|
|
1412
|
+
const p = this.#forceFetch(k, fetchOptions);
|
|
1413
|
+
if (status && hasSubscribers()) {
|
|
1414
|
+
if (ths) {
|
|
1415
|
+
status.trace = true;
|
|
1416
|
+
tracing.tracePromise(() => p, status).catch(() => { });
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
return p;
|
|
1420
|
+
}
|
|
1421
|
+
async #forceFetch(k, fetchOptions = {}) {
|
|
1422
|
+
const v = await this.#fetch(k, fetchOptions);
|
|
1423
|
+
if (v === undefined)
|
|
1424
|
+
throw new Error('fetch() returned undefined');
|
|
1425
|
+
return v;
|
|
1426
|
+
}
|
|
1427
|
+
memo(k, memoOptions = {}) {
|
|
1428
|
+
const { status = metrics.hasSubscribers ? {} : undefined } = memoOptions;
|
|
1429
|
+
memoOptions.status = status;
|
|
1430
|
+
if (status) {
|
|
1431
|
+
status.op = 'memo';
|
|
1432
|
+
status.key = k;
|
|
1433
|
+
if (memoOptions.context) {
|
|
1434
|
+
status.context = memoOptions.context;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const result = this.#memo(k, memoOptions);
|
|
1438
|
+
if (status)
|
|
1439
|
+
status.value = result;
|
|
1440
|
+
if (metrics.hasSubscribers)
|
|
1441
|
+
metrics.publish(status);
|
|
1442
|
+
return result;
|
|
1443
|
+
}
|
|
1444
|
+
#memo(k, memoOptions = {}) {
|
|
1445
|
+
const memoMethod = this.#memoMethod;
|
|
1446
|
+
if (!memoMethod) {
|
|
1447
|
+
throw new Error('no memoMethod provided to constructor');
|
|
1448
|
+
}
|
|
1449
|
+
const { context, status, forceRefresh, ...options } = memoOptions;
|
|
1450
|
+
if (status && forceRefresh)
|
|
1451
|
+
status.forceRefresh = true;
|
|
1452
|
+
const v = this.#get(k, options);
|
|
1453
|
+
const refresh = forceRefresh || v === undefined;
|
|
1454
|
+
if (status) {
|
|
1455
|
+
status.memo = refresh ? 'miss' : 'hit';
|
|
1456
|
+
if (!refresh)
|
|
1457
|
+
status.value = v;
|
|
1458
|
+
}
|
|
1459
|
+
if (!refresh)
|
|
1460
|
+
return v;
|
|
1461
|
+
const vv = memoMethod(k, v, {
|
|
1462
|
+
options,
|
|
1463
|
+
context,
|
|
1464
|
+
});
|
|
1465
|
+
if (status)
|
|
1466
|
+
status.value = vv;
|
|
1467
|
+
this.#set(k, vv, options);
|
|
1468
|
+
return vv;
|
|
1469
|
+
}
|
|
1154
1470
|
/**
|
|
1155
1471
|
* Return a value from the cache. Will update the recency of the cache
|
|
1156
1472
|
* entry found.
|
|
@@ -1158,55 +1474,70 @@ class LRUCache {
|
|
|
1158
1474
|
* If the key is not found, get() will return `undefined`.
|
|
1159
1475
|
*/
|
|
1160
1476
|
get(k, getOptions = {}) {
|
|
1477
|
+
const { status = metrics.hasSubscribers ? {} : undefined } = getOptions;
|
|
1478
|
+
getOptions.status = status;
|
|
1479
|
+
if (status) {
|
|
1480
|
+
status.op = 'get';
|
|
1481
|
+
status.key = k;
|
|
1482
|
+
}
|
|
1483
|
+
const result = this.#get(k, getOptions);
|
|
1484
|
+
if (status) {
|
|
1485
|
+
if (result !== undefined)
|
|
1486
|
+
status.value = result;
|
|
1487
|
+
if (metrics.hasSubscribers)
|
|
1488
|
+
metrics.publish(status);
|
|
1489
|
+
}
|
|
1490
|
+
return result;
|
|
1491
|
+
}
|
|
1492
|
+
#get(k, getOptions = {}) {
|
|
1161
1493
|
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status, } = getOptions;
|
|
1162
1494
|
const index = this.#keyMap.get(k);
|
|
1163
|
-
if (index
|
|
1164
|
-
const value = this.#valList[index];
|
|
1165
|
-
const fetching = this.#isBackgroundFetch(value);
|
|
1495
|
+
if (index === undefined) {
|
|
1166
1496
|
if (status)
|
|
1167
|
-
|
|
1168
|
-
|
|
1497
|
+
status.get = 'miss';
|
|
1498
|
+
return undefined;
|
|
1499
|
+
}
|
|
1500
|
+
const value = this.#valList[index];
|
|
1501
|
+
const fetching = this.#isBackgroundFetch(value);
|
|
1502
|
+
if (status)
|
|
1503
|
+
this.#statusTTL(status, index);
|
|
1504
|
+
if (this.#isStale(index)) {
|
|
1505
|
+
// delete only if not an in-flight background fetch
|
|
1506
|
+
if (!fetching) {
|
|
1507
|
+
if (!noDeleteOnStaleGet) {
|
|
1508
|
+
this.#delete(k, 'expire');
|
|
1509
|
+
}
|
|
1169
1510
|
if (status)
|
|
1170
1511
|
status.get = 'stale';
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
if (!noDeleteOnStaleGet) {
|
|
1174
|
-
this.delete(k);
|
|
1175
|
-
}
|
|
1176
|
-
if (status && allowStale)
|
|
1177
|
-
status.returnedStale = true;
|
|
1178
|
-
return allowStale ? value : undefined;
|
|
1179
|
-
}
|
|
1180
|
-
else {
|
|
1181
|
-
if (status &&
|
|
1182
|
-
allowStale &&
|
|
1183
|
-
value.__staleWhileFetching !== undefined) {
|
|
1512
|
+
if (allowStale) {
|
|
1513
|
+
if (status)
|
|
1184
1514
|
status.returnedStale = true;
|
|
1185
|
-
|
|
1186
|
-
return allowStale ? value.__staleWhileFetching : undefined;
|
|
1515
|
+
return value;
|
|
1187
1516
|
}
|
|
1517
|
+
return undefined;
|
|
1188
1518
|
}
|
|
1189
|
-
|
|
1519
|
+
if (status)
|
|
1520
|
+
status.get = 'stale-fetching';
|
|
1521
|
+
if (allowStale && value.__staleWhileFetching !== undefined) {
|
|
1190
1522
|
if (status)
|
|
1191
|
-
status.
|
|
1192
|
-
|
|
1193
|
-
// it's not stale, which means this isn't a staleWhileRefetching.
|
|
1194
|
-
// If it's not stale, and fetching, AND has a __staleWhileFetching
|
|
1195
|
-
// value, then that means the user fetched with {forceRefresh:true},
|
|
1196
|
-
// so it's safe to return that value.
|
|
1197
|
-
if (fetching) {
|
|
1198
|
-
return value.__staleWhileFetching;
|
|
1199
|
-
}
|
|
1200
|
-
this.#moveToTail(index);
|
|
1201
|
-
if (updateAgeOnGet) {
|
|
1202
|
-
this.#updateItemAge(index);
|
|
1203
|
-
}
|
|
1204
|
-
return value;
|
|
1523
|
+
status.returnedStale = true;
|
|
1524
|
+
return value.__staleWhileFetching;
|
|
1205
1525
|
}
|
|
1526
|
+
return undefined;
|
|
1206
1527
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1528
|
+
// not stale
|
|
1529
|
+
if (status)
|
|
1530
|
+
status.get = fetching ? 'fetching' : 'hit';
|
|
1531
|
+
// if we're currently fetching it, we don't actually have it yet
|
|
1532
|
+
// it's not stale, which means this isn't a staleWhileRefetching.
|
|
1533
|
+
// If it's not stale, and fetching, AND has a __staleWhileFetching
|
|
1534
|
+
// value, then that means the user fetched with {forceRefresh:true},
|
|
1535
|
+
// so it's safe to return that value.
|
|
1536
|
+
this.#moveToTail(index);
|
|
1537
|
+
if (updateAgeOnGet) {
|
|
1538
|
+
this.#updateItemAge(index);
|
|
1209
1539
|
}
|
|
1540
|
+
return fetching ? value.__staleWhileFetching : value;
|
|
1210
1541
|
}
|
|
1211
1542
|
#connect(p, n) {
|
|
1212
1543
|
this.#prev[n] = p;
|
|
@@ -1234,16 +1565,31 @@ class LRUCache {
|
|
|
1234
1565
|
}
|
|
1235
1566
|
/**
|
|
1236
1567
|
* Deletes a key out of the cache.
|
|
1568
|
+
*
|
|
1237
1569
|
* Returns true if the key was deleted, false otherwise.
|
|
1238
1570
|
*/
|
|
1239
1571
|
delete(k) {
|
|
1572
|
+
return this.#delete(k, 'delete');
|
|
1573
|
+
}
|
|
1574
|
+
#delete(k, reason) {
|
|
1575
|
+
if (metrics.hasSubscribers) {
|
|
1576
|
+
metrics.publish({
|
|
1577
|
+
op: 'delete',
|
|
1578
|
+
delete: reason,
|
|
1579
|
+
key: k,
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1240
1582
|
let deleted = false;
|
|
1241
1583
|
if (this.#size !== 0) {
|
|
1242
1584
|
const index = this.#keyMap.get(k);
|
|
1243
1585
|
if (index !== undefined) {
|
|
1586
|
+
if (this.#autopurgeTimers?.[index]) {
|
|
1587
|
+
clearTimeout(this.#autopurgeTimers?.[index]);
|
|
1588
|
+
this.#autopurgeTimers[index] = undefined;
|
|
1589
|
+
}
|
|
1244
1590
|
deleted = true;
|
|
1245
1591
|
if (this.#size === 1) {
|
|
1246
|
-
this
|
|
1592
|
+
this.#clear(reason);
|
|
1247
1593
|
}
|
|
1248
1594
|
else {
|
|
1249
1595
|
this.#removeItemSize(index);
|
|
@@ -1253,10 +1599,10 @@ class LRUCache {
|
|
|
1253
1599
|
}
|
|
1254
1600
|
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
|
1255
1601
|
if (this.#hasDispose) {
|
|
1256
|
-
this.#dispose?.(v, k,
|
|
1602
|
+
this.#dispose?.(v, k, reason);
|
|
1257
1603
|
}
|
|
1258
1604
|
if (this.#hasDisposeAfter) {
|
|
1259
|
-
this.#disposed?.push([v, k,
|
|
1605
|
+
this.#disposed?.push([v, k, reason]);
|
|
1260
1606
|
}
|
|
1261
1607
|
}
|
|
1262
1608
|
this.#keyMap.delete(k);
|
|
@@ -1269,8 +1615,10 @@ class LRUCache {
|
|
|
1269
1615
|
this.#head = this.#next[index];
|
|
1270
1616
|
}
|
|
1271
1617
|
else {
|
|
1272
|
-
|
|
1273
|
-
this.#
|
|
1618
|
+
const pi = this.#prev[index];
|
|
1619
|
+
this.#next[pi] = this.#next[index];
|
|
1620
|
+
const ni = this.#next[index];
|
|
1621
|
+
this.#prev[ni] = this.#prev[index];
|
|
1274
1622
|
}
|
|
1275
1623
|
this.#size--;
|
|
1276
1624
|
this.#free.push(index);
|
|
@@ -1290,6 +1638,9 @@ class LRUCache {
|
|
|
1290
1638
|
* Clear the cache entirely, throwing away all values.
|
|
1291
1639
|
*/
|
|
1292
1640
|
clear() {
|
|
1641
|
+
return this.#clear('delete');
|
|
1642
|
+
}
|
|
1643
|
+
#clear(reason) {
|
|
1293
1644
|
for (const index of this.#rindexes({ allowStale: true })) {
|
|
1294
1645
|
const v = this.#valList[index];
|
|
1295
1646
|
if (this.#isBackgroundFetch(v)) {
|
|
@@ -1298,10 +1649,10 @@ class LRUCache {
|
|
|
1298
1649
|
else {
|
|
1299
1650
|
const k = this.#keyList[index];
|
|
1300
1651
|
if (this.#hasDispose) {
|
|
1301
|
-
this.#dispose?.(v, k,
|
|
1652
|
+
this.#dispose?.(v, k, reason);
|
|
1302
1653
|
}
|
|
1303
1654
|
if (this.#hasDisposeAfter) {
|
|
1304
|
-
this.#disposed?.push([v, k,
|
|
1655
|
+
this.#disposed?.push([v, k, reason]);
|
|
1305
1656
|
}
|
|
1306
1657
|
}
|
|
1307
1658
|
}
|
|
@@ -1311,6 +1662,11 @@ class LRUCache {
|
|
|
1311
1662
|
if (this.#ttls && this.#starts) {
|
|
1312
1663
|
this.#ttls.fill(0);
|
|
1313
1664
|
this.#starts.fill(0);
|
|
1665
|
+
for (const t of this.#autopurgeTimers ?? []) {
|
|
1666
|
+
if (t !== undefined)
|
|
1667
|
+
clearTimeout(t);
|
|
1668
|
+
}
|
|
1669
|
+
this.#autopurgeTimers?.fill(undefined);
|
|
1314
1670
|
}
|
|
1315
1671
|
if (this.#sizes) {
|
|
1316
1672
|
this.#sizes.fill(0);
|
|
@@ -1329,6 +1685,4 @@ class LRUCache {
|
|
|
1329
1685
|
}
|
|
1330
1686
|
}
|
|
1331
1687
|
}
|
|
1332
|
-
exports.LRUCache = LRUCache;
|
|
1333
|
-
exports.default = LRUCache;
|
|
1334
1688
|
//# sourceMappingURL=index.js.map
|