actly 1.1.0 → 1.1.5
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/LICENSE +0 -0
- package/README.md +284 -52
- package/dist/core/act.cjs +183 -35
- package/dist/core/act.d.ts +81 -10
- package/dist/core/act.d.ts.map +1 -1
- package/dist/core/act.js +181 -35
- package/dist/core/act.js.map +1 -1
- package/dist/core/executor.cjs +19 -9
- package/dist/core/executor.d.ts +25 -5
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +19 -9
- package/dist/core/executor.js.map +1 -1
- package/dist/index.cjs +13 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/policies/cache.cjs +85 -21
- package/dist/policies/cache.d.ts +29 -7
- package/dist/policies/cache.d.ts.map +1 -1
- package/dist/policies/cache.js +85 -21
- package/dist/policies/cache.js.map +1 -1
- package/dist/policies/dedupe.cjs +68 -20
- package/dist/policies/dedupe.d.ts +38 -13
- package/dist/policies/dedupe.d.ts.map +1 -1
- package/dist/policies/dedupe.js +68 -20
- package/dist/policies/dedupe.js.map +1 -1
- package/dist/policies/retry.cjs +65 -25
- package/dist/policies/retry.d.ts +25 -2
- package/dist/policies/retry.d.ts.map +1 -1
- package/dist/policies/retry.js +65 -25
- package/dist/policies/retry.js.map +1 -1
- package/dist/policies/timeout.cjs +87 -17
- package/dist/policies/timeout.d.ts +28 -8
- package/dist/policies/timeout.d.ts.map +1 -1
- package/dist/policies/timeout.js +87 -17
- package/dist/policies/timeout.js.map +1 -1
- package/dist/state/store.cjs +9 -2
- package/dist/state/store.d.ts +9 -0
- package/dist/state/store.d.ts.map +1 -1
- package/dist/state/store.js +9 -2
- package/dist/state/store.js.map +1 -1
- package/dist/stores/base.cjs +4 -4
- package/dist/stores/base.d.ts +32 -56
- package/dist/stores/base.d.ts.map +1 -1
- package/dist/stores/base.js +4 -4
- package/dist/stores/base.js.map +1 -1
- package/dist/stores/memory.cjs +77 -28
- package/dist/stores/memory.d.ts +44 -23
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +77 -28
- package/dist/stores/memory.js.map +1 -1
- package/dist/types/index.d.ts +141 -36
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/abort.cjs +142 -0
- package/dist/utils/abort.d.ts +55 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +136 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/backoff.cjs +43 -0
- package/dist/utils/backoff.d.ts +14 -0
- package/dist/utils/backoff.d.ts.map +1 -0
- package/dist/utils/backoff.js +41 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/validate.cjs +79 -0
- package/dist/utils/validate.d.ts +15 -0
- package/dist/utils/validate.d.ts.map +1 -0
- package/dist/utils/validate.js +72 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +19 -37
package/dist/stores/memory.cjs
CHANGED
|
@@ -5,17 +5,37 @@ function isUnrefable(t) {
|
|
|
5
5
|
return typeof t.unref === 'function';
|
|
6
6
|
}
|
|
7
7
|
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
10
|
+
*
|
|
11
|
+
* # LRU semantics
|
|
12
|
+
*
|
|
13
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
14
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
15
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
16
|
+
*
|
|
17
|
+
* # Expiry
|
|
18
|
+
*
|
|
19
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
20
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
21
|
+
*/
|
|
8
22
|
class InMemoryStore {
|
|
23
|
+
_sync = true;
|
|
24
|
+
entries = new Map();
|
|
25
|
+
maxSize;
|
|
26
|
+
cleanupTimer;
|
|
9
27
|
constructor(options = {}) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
const { autoCleanup = false, cleanupIntervalMs = 30_000, maxSize = Number.POSITIVE_INFINITY, } = options;
|
|
29
|
+
if (!Number.isFinite(maxSize) || maxSize <= 0) {
|
|
30
|
+
// Infinity is allowed (unbounded); any other non-positive finite value
|
|
31
|
+
// is a programmer error.
|
|
32
|
+
if (maxSize !== Number.POSITIVE_INFINITY) {
|
|
33
|
+
throw new RangeError(`Actly: InMemoryStore maxSize must be a positive finite number or Infinity, got ${maxSize}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
this.maxSize = maxSize;
|
|
15
37
|
if (autoCleanup) {
|
|
16
38
|
const timer = setInterval(() => this._sweep(), cleanupIntervalMs);
|
|
17
|
-
// Prevent the interval from keeping the Node.js process alive when the
|
|
18
|
-
// application has otherwise finished its work. Safe no-op in browsers.
|
|
19
39
|
if (isUnrefable(timer))
|
|
20
40
|
timer.unref();
|
|
21
41
|
this.cleanupTimer = timer;
|
|
@@ -29,47 +49,71 @@ class InMemoryStore {
|
|
|
29
49
|
this.entries.delete(key);
|
|
30
50
|
return undefined;
|
|
31
51
|
}
|
|
52
|
+
// LRU refresh: move to most-recent position.
|
|
53
|
+
// delete + set is the canonical pattern for reordering a Map.
|
|
54
|
+
this.entries.delete(key);
|
|
55
|
+
this.entries.set(key, entry);
|
|
32
56
|
return entry.value;
|
|
33
57
|
}
|
|
34
58
|
set(key, value, ttlMs) {
|
|
35
|
-
//
|
|
59
|
+
// Evict if at capacity AND adding a new key (updates don't grow size).
|
|
60
|
+
if (!this.entries.has(key) && this.entries.size >= this.maxSize) {
|
|
61
|
+
const oldest = this.entries.keys().next().value;
|
|
62
|
+
if (oldest !== undefined)
|
|
63
|
+
this.entries.delete(oldest);
|
|
64
|
+
}
|
|
36
65
|
const expiresAt = ttlMs != null && ttlMs > 0 ? Date.now() + ttlMs : null;
|
|
66
|
+
// delete + set ensures the key is moved to the most-recent position
|
|
67
|
+
// even on update, keeping LRU order consistent.
|
|
68
|
+
this.entries.delete(key);
|
|
37
69
|
this.entries.set(key, { value, expiresAt });
|
|
38
70
|
}
|
|
39
71
|
delete(key) {
|
|
40
72
|
this.entries.delete(key);
|
|
41
73
|
}
|
|
42
74
|
has(key) {
|
|
43
|
-
//
|
|
44
|
-
|
|
75
|
+
// Inline the expiry check to avoid the LRU side-effect of get().
|
|
76
|
+
// `has()` should be a pure query, not a touch.
|
|
77
|
+
const entry = this.entries.get(key);
|
|
78
|
+
if (!entry)
|
|
79
|
+
return false;
|
|
80
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
81
|
+
this.entries.delete(key);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
45
85
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Remove all entries.
|
|
48
|
-
* After this call, size() returns 0.
|
|
49
|
-
*/
|
|
50
86
|
clear() {
|
|
51
87
|
this.entries.clear();
|
|
52
88
|
}
|
|
53
89
|
/**
|
|
54
90
|
* Return the count of live (non-expired) entries.
|
|
55
91
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
92
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
93
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
94
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
95
|
+
*
|
|
96
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
58
97
|
*/
|
|
59
98
|
size() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const expired = [];
|
|
101
|
+
let count = 0;
|
|
102
|
+
for (const [key, entry] of this.entries) {
|
|
103
|
+
if (entry.expiresAt !== null && entry.expiresAt <= now) {
|
|
104
|
+
expired.push(key);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
count++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const key of expired)
|
|
111
|
+
this.entries.delete(key);
|
|
112
|
+
return count;
|
|
65
113
|
}
|
|
66
114
|
/**
|
|
67
115
|
* Stop the background cleanup timer and release internal state.
|
|
68
116
|
* Safe to call multiple times — subsequent calls are no-ops.
|
|
69
|
-
*
|
|
70
|
-
* Call destroy() when discarding a long-lived store instance to prevent
|
|
71
|
-
* timer leaks. Stores without autoCleanup enabled have nothing to release,
|
|
72
|
-
* but destroy() is safe to call on them regardless.
|
|
73
117
|
*/
|
|
74
118
|
destroy() {
|
|
75
119
|
if (this.cleanupTimer !== undefined) {
|
|
@@ -77,15 +121,20 @@ class InMemoryStore {
|
|
|
77
121
|
this.cleanupTimer = undefined;
|
|
78
122
|
}
|
|
79
123
|
}
|
|
80
|
-
|
|
81
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Sweep all entries and remove those past their expiry time.
|
|
126
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
127
|
+
*/
|
|
82
128
|
_sweep() {
|
|
83
129
|
const now = Date.now();
|
|
130
|
+
const expired = [];
|
|
84
131
|
for (const [key, entry] of this.entries) {
|
|
85
132
|
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
86
|
-
|
|
133
|
+
expired.push(key);
|
|
87
134
|
}
|
|
88
135
|
}
|
|
136
|
+
for (const key of expired)
|
|
137
|
+
this.entries.delete(key);
|
|
89
138
|
}
|
|
90
139
|
}
|
|
91
140
|
exports.InMemoryStore = InMemoryStore;
|
package/dist/stores/memory.d.ts
CHANGED
|
@@ -3,56 +3,77 @@ export interface InMemoryStoreOptions {
|
|
|
3
3
|
/**
|
|
4
4
|
* Periodically sweep and remove expired entries in the background.
|
|
5
5
|
*
|
|
6
|
-
* Disabled by default. The store evicts lazily on get()/has() access,
|
|
7
|
-
* is sufficient for most use cases. Enable autoCleanup when the
|
|
8
|
-
* long-lived and accumulates many TTL'd entries that are never
|
|
9
|
-
* example, a server-side cache that receives write-heavy
|
|
10
|
-
* subsequent read rates.
|
|
11
|
-
*
|
|
12
|
-
* The sweep does not affect observable store semantics: expired entries are
|
|
13
|
-
* already invisible to get()/has()/size() before the sweep runs.
|
|
6
|
+
* Disabled by default. The store evicts lazily on `get()` / `has()` access,
|
|
7
|
+
* which is sufficient for most use cases. Enable `autoCleanup` when the
|
|
8
|
+
* store is long-lived and accumulates many TTL'd entries that are never
|
|
9
|
+
* re-read — for example, a server-side cache that receives write-heavy
|
|
10
|
+
* traffic with low subsequent read rates.
|
|
14
11
|
*/
|
|
15
12
|
autoCleanup?: boolean;
|
|
16
13
|
/**
|
|
17
14
|
* Interval between background sweeps in milliseconds.
|
|
18
|
-
* Defaults to 30 000 (30 seconds). Ignored when autoCleanup is false.
|
|
19
|
-
*
|
|
20
|
-
* Choose a value appropriate to your TTL distribution — sweeping more often
|
|
21
|
-
* than your shortest TTL is wasteful; sweeping much less often than your
|
|
22
|
-
* longest TTL wastes memory.
|
|
15
|
+
* Defaults to 30 000 (30 seconds). Ignored when `autoCleanup` is false.
|
|
23
16
|
*/
|
|
24
17
|
cleanupIntervalMs?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum number of live entries the store will hold.
|
|
20
|
+
*
|
|
21
|
+
* When `set()` would exceed this limit, the least-recently-used entry is
|
|
22
|
+
* evicted before the new one is inserted (LRU semantics). Updates to an
|
|
23
|
+
* existing key do not trigger eviction.
|
|
24
|
+
*
|
|
25
|
+
* Defaults to `Infinity` (unbounded). Set a finite value for long-running
|
|
26
|
+
* caches with high-cardinality keys to bound memory usage.
|
|
27
|
+
*
|
|
28
|
+
* The LRU order is updated on `get()` and `set()` — both move the accessed
|
|
29
|
+
* key to the most-recent position.
|
|
30
|
+
*/
|
|
31
|
+
maxSize?: number;
|
|
25
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
35
|
+
*
|
|
36
|
+
* # LRU semantics
|
|
37
|
+
*
|
|
38
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
39
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
40
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
41
|
+
*
|
|
42
|
+
* # Expiry
|
|
43
|
+
*
|
|
44
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
45
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
46
|
+
*/
|
|
26
47
|
export declare class InMemoryStore implements SyncStateStore {
|
|
27
48
|
readonly _sync: true;
|
|
28
49
|
private readonly entries;
|
|
50
|
+
private readonly maxSize;
|
|
29
51
|
private cleanupTimer;
|
|
30
52
|
constructor(options?: InMemoryStoreOptions);
|
|
31
53
|
get<T>(key: string): T | undefined;
|
|
32
54
|
set<T>(key: string, value: T, ttlMs?: number): void;
|
|
33
55
|
delete(key: string): void;
|
|
34
56
|
has(key: string): boolean;
|
|
35
|
-
/**
|
|
36
|
-
* Remove all entries.
|
|
37
|
-
* After this call, size() returns 0.
|
|
38
|
-
*/
|
|
39
57
|
clear(): void;
|
|
40
58
|
/**
|
|
41
59
|
* Return the count of live (non-expired) entries.
|
|
42
60
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
61
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
62
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
63
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
64
|
+
*
|
|
65
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
45
66
|
*/
|
|
46
67
|
size(): number;
|
|
47
68
|
/**
|
|
48
69
|
* Stop the background cleanup timer and release internal state.
|
|
49
70
|
* Safe to call multiple times — subsequent calls are no-ops.
|
|
50
|
-
*
|
|
51
|
-
* Call destroy() when discarding a long-lived store instance to prevent
|
|
52
|
-
* timer leaks. Stores without autoCleanup enabled have nothing to release,
|
|
53
|
-
* but destroy() is safe to call on them regardless.
|
|
54
71
|
*/
|
|
55
72
|
destroy(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Sweep all entries and remove those past their expiry time.
|
|
75
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
76
|
+
*/
|
|
56
77
|
private _sweep;
|
|
57
78
|
}
|
|
58
79
|
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAwB/C,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAID;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,KAAK,EAAG,IAAI,CAAS;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,YAAY,CAA4C;gBAEpD,OAAO,GAAE,oBAAyB;IA0B9C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAiBlC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAcnD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAYzB,KAAK,IAAI,IAAI;IAIb;;;;;;;;OAQG;IACH,IAAI,IAAI,MAAM;IAiBd;;;OAGG;IACH,OAAO,IAAI,IAAI;IAOf;;;OAGG;IACH,OAAO,CAAC,MAAM;CAUf"}
|
package/dist/stores/memory.js
CHANGED
|
@@ -2,17 +2,37 @@ function isUnrefable(t) {
|
|
|
2
2
|
return typeof t.unref === 'function';
|
|
3
3
|
}
|
|
4
4
|
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
5
|
+
/**
|
|
6
|
+
* Reference `SyncStateStore` implementation backed by a `Map`.
|
|
7
|
+
*
|
|
8
|
+
* # LRU semantics
|
|
9
|
+
*
|
|
10
|
+
* `Map` iteration order is insertion order, so we implement LRU by
|
|
11
|
+
* `delete` + `set` on every access — the most-recently-touched key ends up
|
|
12
|
+
* at the end of the iteration, and the oldest is `entries.keys().next().value`.
|
|
13
|
+
*
|
|
14
|
+
* # Expiry
|
|
15
|
+
*
|
|
16
|
+
* Lazy on `get()` / `has()`: expired entries are deleted when touched.
|
|
17
|
+
* Background sweep (optional) reclaims entries that are never re-read.
|
|
18
|
+
*/
|
|
5
19
|
export class InMemoryStore {
|
|
20
|
+
_sync = true;
|
|
21
|
+
entries = new Map();
|
|
22
|
+
maxSize;
|
|
23
|
+
cleanupTimer;
|
|
6
24
|
constructor(options = {}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
25
|
+
const { autoCleanup = false, cleanupIntervalMs = 30_000, maxSize = Number.POSITIVE_INFINITY, } = options;
|
|
26
|
+
if (!Number.isFinite(maxSize) || maxSize <= 0) {
|
|
27
|
+
// Infinity is allowed (unbounded); any other non-positive finite value
|
|
28
|
+
// is a programmer error.
|
|
29
|
+
if (maxSize !== Number.POSITIVE_INFINITY) {
|
|
30
|
+
throw new RangeError(`Actly: InMemoryStore maxSize must be a positive finite number or Infinity, got ${maxSize}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this.maxSize = maxSize;
|
|
12
34
|
if (autoCleanup) {
|
|
13
35
|
const timer = setInterval(() => this._sweep(), cleanupIntervalMs);
|
|
14
|
-
// Prevent the interval from keeping the Node.js process alive when the
|
|
15
|
-
// application has otherwise finished its work. Safe no-op in browsers.
|
|
16
36
|
if (isUnrefable(timer))
|
|
17
37
|
timer.unref();
|
|
18
38
|
this.cleanupTimer = timer;
|
|
@@ -26,47 +46,71 @@ export class InMemoryStore {
|
|
|
26
46
|
this.entries.delete(key);
|
|
27
47
|
return undefined;
|
|
28
48
|
}
|
|
49
|
+
// LRU refresh: move to most-recent position.
|
|
50
|
+
// delete + set is the canonical pattern for reordering a Map.
|
|
51
|
+
this.entries.delete(key);
|
|
52
|
+
this.entries.set(key, entry);
|
|
29
53
|
return entry.value;
|
|
30
54
|
}
|
|
31
55
|
set(key, value, ttlMs) {
|
|
32
|
-
//
|
|
56
|
+
// Evict if at capacity AND adding a new key (updates don't grow size).
|
|
57
|
+
if (!this.entries.has(key) && this.entries.size >= this.maxSize) {
|
|
58
|
+
const oldest = this.entries.keys().next().value;
|
|
59
|
+
if (oldest !== undefined)
|
|
60
|
+
this.entries.delete(oldest);
|
|
61
|
+
}
|
|
33
62
|
const expiresAt = ttlMs != null && ttlMs > 0 ? Date.now() + ttlMs : null;
|
|
63
|
+
// delete + set ensures the key is moved to the most-recent position
|
|
64
|
+
// even on update, keeping LRU order consistent.
|
|
65
|
+
this.entries.delete(key);
|
|
34
66
|
this.entries.set(key, { value, expiresAt });
|
|
35
67
|
}
|
|
36
68
|
delete(key) {
|
|
37
69
|
this.entries.delete(key);
|
|
38
70
|
}
|
|
39
71
|
has(key) {
|
|
40
|
-
//
|
|
41
|
-
|
|
72
|
+
// Inline the expiry check to avoid the LRU side-effect of get().
|
|
73
|
+
// `has()` should be a pure query, not a touch.
|
|
74
|
+
const entry = this.entries.get(key);
|
|
75
|
+
if (!entry)
|
|
76
|
+
return false;
|
|
77
|
+
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
78
|
+
this.entries.delete(key);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
42
82
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Remove all entries.
|
|
45
|
-
* After this call, size() returns 0.
|
|
46
|
-
*/
|
|
47
83
|
clear() {
|
|
48
84
|
this.entries.clear();
|
|
49
85
|
}
|
|
50
86
|
/**
|
|
51
87
|
* Return the count of live (non-expired) entries.
|
|
52
88
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
89
|
+
* Pure query — does NOT touch LRU order. Expired entries discovered during
|
|
90
|
+
* the scan are evicted opportunistically (they were already invisible to
|
|
91
|
+
* `get()`, so eviction has no observable effect beyond memory reclamation).
|
|
92
|
+
*
|
|
93
|
+
* Two-pass to avoid mutating the Map during iteration (spec-safe).
|
|
55
94
|
*/
|
|
56
95
|
size() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
const expired = [];
|
|
98
|
+
let count = 0;
|
|
99
|
+
for (const [key, entry] of this.entries) {
|
|
100
|
+
if (entry.expiresAt !== null && entry.expiresAt <= now) {
|
|
101
|
+
expired.push(key);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
count++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const key of expired)
|
|
108
|
+
this.entries.delete(key);
|
|
109
|
+
return count;
|
|
62
110
|
}
|
|
63
111
|
/**
|
|
64
112
|
* Stop the background cleanup timer and release internal state.
|
|
65
113
|
* Safe to call multiple times — subsequent calls are no-ops.
|
|
66
|
-
*
|
|
67
|
-
* Call destroy() when discarding a long-lived store instance to prevent
|
|
68
|
-
* timer leaks. Stores without autoCleanup enabled have nothing to release,
|
|
69
|
-
* but destroy() is safe to call on them regardless.
|
|
70
114
|
*/
|
|
71
115
|
destroy() {
|
|
72
116
|
if (this.cleanupTimer !== undefined) {
|
|
@@ -74,15 +118,20 @@ export class InMemoryStore {
|
|
|
74
118
|
this.cleanupTimer = undefined;
|
|
75
119
|
}
|
|
76
120
|
}
|
|
77
|
-
|
|
78
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Sweep all entries and remove those past their expiry time.
|
|
123
|
+
* Called by the autoCleanup interval; not part of the public contract.
|
|
124
|
+
*/
|
|
79
125
|
_sweep() {
|
|
80
126
|
const now = Date.now();
|
|
127
|
+
const expired = [];
|
|
81
128
|
for (const [key, entry] of this.entries) {
|
|
82
129
|
if (entry.expiresAt !== null && now > entry.expiresAt) {
|
|
83
|
-
|
|
130
|
+
expired.push(key);
|
|
84
131
|
}
|
|
85
132
|
}
|
|
133
|
+
for (const key of expired)
|
|
134
|
+
this.entries.delete(key);
|
|
86
135
|
}
|
|
87
136
|
}
|
|
88
137
|
//# sourceMappingURL=memory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"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"}
|