layercache 1.2.5 → 1.2.7
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 +190 -21
- package/README.md +254 -912
- package/dist/{chunk-7V7XAB74.js → chunk-4PPBOOXT.js} +37 -3
- package/dist/{chunk-QHWG7QS5.js → chunk-BQLL6IM5.js} +47 -1
- package/dist/{chunk-JC26W3KK.js → chunk-GJBKCFE6.js} +38 -3
- package/dist/cli.cjs +83 -3
- package/dist/cli.js +2 -2
- package/dist/{edge-P07GCO2Y.d.ts → edge-BMmPVqaD.d.cts} +28 -21
- package/dist/{edge-P07GCO2Y.d.cts → edge-BMmPVqaD.d.ts} +28 -21
- package/dist/edge.cjs +74 -5
- package/dist/edge.d.cts +1 -1
- package/dist/edge.d.ts +1 -1
- package/dist/edge.js +2 -2
- package/dist/index.cjs +1671 -837
- package/dist/index.d.cts +42 -4
- package/dist/index.d.ts +42 -4
- package/dist/index.js +1327 -608
- package/package.json +29 -3
- package/packages/nestjs/dist/index.cjs +1296 -732
- package/packages/nestjs/dist/index.d.cts +19 -20
- package/packages/nestjs/dist/index.d.ts +19 -20
- package/packages/nestjs/dist/index.js +1296 -732
|
@@ -10,19 +10,47 @@ function isStoredValueEnvelope(value) {
|
|
|
10
10
|
if (v.kind !== "value" && v.kind !== "empty") {
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
|
-
if (v.freshUntil !== null && typeof v.freshUntil !== "number") {
|
|
13
|
+
if (v.freshUntil !== null && (!Number.isFinite(v.freshUntil) || typeof v.freshUntil !== "number")) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
|
-
if (v.staleUntil !== null && typeof v.staleUntil !== "number") {
|
|
16
|
+
if (v.staleUntil !== null && (!Number.isFinite(v.staleUntil) || typeof v.staleUntil !== "number")) {
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
if (v.errorUntil !== null && typeof v.errorUntil !== "number") {
|
|
19
|
+
if (v.errorUntil !== null && (!Number.isFinite(v.errorUntil) || typeof v.errorUntil !== "number")) {
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
const maxTimestamp = Date.now() + 10 * 365 * 24 * 60 * 60 * 1e3;
|
|
23
23
|
if (typeof v.freshUntil === "number" && v.freshUntil > maxTimestamp) {
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
|
+
if (typeof v.staleUntil === "number" && v.staleUntil > maxTimestamp) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (typeof v.errorUntil === "number" && v.errorUntil > maxTimestamp) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (v.freshUntil === null && (v.staleUntil !== null || v.errorUntil !== null)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (typeof v.freshUntil === "number" && typeof v.staleUntil === "number" && v.staleUntil < v.freshUntil) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (typeof v.freshUntil === "number" && typeof v.errorUntil === "number" && v.errorUntil < v.freshUntil) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const maxTtlSeconds = 10 * 365 * 24 * 60 * 60;
|
|
42
|
+
if (!isValidEnvelopeTtlSeconds(v.freshTtlSeconds, maxTtlSeconds)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (!isValidEnvelopeTtlSeconds(v.staleWhileRevalidateSeconds, maxTtlSeconds)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (!isValidEnvelopeTtlSeconds(v.staleIfErrorSeconds, maxTtlSeconds)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (v.freshTtlSeconds == null && (v.staleWhileRevalidateSeconds != null || v.staleIfErrorSeconds != null)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
26
54
|
return true;
|
|
27
55
|
}
|
|
28
56
|
function createStoredValueEnvelope(options) {
|
|
@@ -121,6 +149,12 @@ function normalizePositiveSeconds(value) {
|
|
|
121
149
|
}
|
|
122
150
|
return value;
|
|
123
151
|
}
|
|
152
|
+
function isValidEnvelopeTtlSeconds(value, maxTtlSeconds) {
|
|
153
|
+
if (value == null) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= maxTtlSeconds;
|
|
157
|
+
}
|
|
124
158
|
|
|
125
159
|
// src/invalidation/PatternMatcher.ts
|
|
126
160
|
var PatternMatcher = class _PatternMatcher {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PatternMatcher
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4PPBOOXT.js";
|
|
4
4
|
|
|
5
5
|
// src/invalidation/RedisTagIndex.ts
|
|
6
6
|
var RedisTagIndex = class {
|
|
@@ -48,6 +48,17 @@ var RedisTagIndex = class {
|
|
|
48
48
|
async keysForTag(tag) {
|
|
49
49
|
return this.client.smembers(this.tagKeysKey(tag));
|
|
50
50
|
}
|
|
51
|
+
async forEachKeyForTag(tag, visitor) {
|
|
52
|
+
let cursor = "0";
|
|
53
|
+
const tagKey = this.tagKeysKey(tag);
|
|
54
|
+
do {
|
|
55
|
+
const [nextCursor, keys] = await this.client.sscan(tagKey, cursor, "COUNT", this.scanCount);
|
|
56
|
+
cursor = nextCursor;
|
|
57
|
+
for (const key of keys) {
|
|
58
|
+
await visitor(key);
|
|
59
|
+
}
|
|
60
|
+
} while (cursor !== "0");
|
|
61
|
+
}
|
|
51
62
|
async keysForPrefix(prefix) {
|
|
52
63
|
const matches = [];
|
|
53
64
|
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
@@ -60,6 +71,20 @@ var RedisTagIndex = class {
|
|
|
60
71
|
}
|
|
61
72
|
return matches;
|
|
62
73
|
}
|
|
74
|
+
async forEachKeyForPrefix(prefix, visitor) {
|
|
75
|
+
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
76
|
+
let cursor = "0";
|
|
77
|
+
do {
|
|
78
|
+
const [nextCursor, keys] = await this.client.sscan(knownKeysKey, cursor, "COUNT", this.scanCount);
|
|
79
|
+
cursor = nextCursor;
|
|
80
|
+
for (const key of keys) {
|
|
81
|
+
if (key.startsWith(prefix)) {
|
|
82
|
+
await visitor(key);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} while (cursor !== "0");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
63
88
|
async tagsForKey(key) {
|
|
64
89
|
return this.client.smembers(this.keyTagsKey(key));
|
|
65
90
|
}
|
|
@@ -82,6 +107,27 @@ var RedisTagIndex = class {
|
|
|
82
107
|
}
|
|
83
108
|
return matches;
|
|
84
109
|
}
|
|
110
|
+
async forEachKeyMatchingPattern(pattern, visitor) {
|
|
111
|
+
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
112
|
+
let cursor = "0";
|
|
113
|
+
do {
|
|
114
|
+
const [nextCursor, keys] = await this.client.sscan(
|
|
115
|
+
knownKeysKey,
|
|
116
|
+
cursor,
|
|
117
|
+
"MATCH",
|
|
118
|
+
pattern,
|
|
119
|
+
"COUNT",
|
|
120
|
+
this.scanCount
|
|
121
|
+
);
|
|
122
|
+
cursor = nextCursor;
|
|
123
|
+
for (const key of keys) {
|
|
124
|
+
if (PatternMatcher.matches(pattern, key)) {
|
|
125
|
+
await visitor(key);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} while (cursor !== "0");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
85
131
|
async clear() {
|
|
86
132
|
const indexKeys = await this.scanIndexKeys();
|
|
87
133
|
if (indexKeys.length === 0) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
unwrapStoredValue
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4PPBOOXT.js";
|
|
4
4
|
|
|
5
5
|
// src/layers/MemoryLayer.ts
|
|
6
6
|
var MemoryLayer = class {
|
|
@@ -118,6 +118,12 @@ var MemoryLayer = class {
|
|
|
118
118
|
this.pruneExpired();
|
|
119
119
|
return [...this.entries.keys()];
|
|
120
120
|
}
|
|
121
|
+
async forEachKey(visitor) {
|
|
122
|
+
this.pruneExpired();
|
|
123
|
+
for (const key of this.entries.keys()) {
|
|
124
|
+
await visitor(key);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
121
127
|
exportState() {
|
|
122
128
|
this.pruneExpired();
|
|
123
129
|
return [...this.entries.entries()].map(([key, entry]) => ({
|
|
@@ -226,6 +232,11 @@ var TagIndex = class {
|
|
|
226
232
|
async keysForTag(tag) {
|
|
227
233
|
return [...this.tagToKeys.get(tag) ?? /* @__PURE__ */ new Set()];
|
|
228
234
|
}
|
|
235
|
+
async forEachKeyForTag(tag, visitor) {
|
|
236
|
+
for (const key of this.tagToKeys.get(tag) ?? /* @__PURE__ */ new Set()) {
|
|
237
|
+
await visitor(key);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
229
240
|
async keysForPrefix(prefix) {
|
|
230
241
|
const node = this.findNode(prefix);
|
|
231
242
|
if (!node) {
|
|
@@ -235,6 +246,13 @@ var TagIndex = class {
|
|
|
235
246
|
this.collectFromNode(node, prefix, matches);
|
|
236
247
|
return matches;
|
|
237
248
|
}
|
|
249
|
+
async forEachKeyForPrefix(prefix, visitor) {
|
|
250
|
+
const node = this.findNode(prefix);
|
|
251
|
+
if (!node) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
await this.visitFromNode(node, prefix, visitor);
|
|
255
|
+
}
|
|
238
256
|
async tagsForKey(key) {
|
|
239
257
|
return [...this.keyToTags.get(key) ?? /* @__PURE__ */ new Set()];
|
|
240
258
|
}
|
|
@@ -243,6 +261,12 @@ var TagIndex = class {
|
|
|
243
261
|
this.collectPatternMatches(this.root, "", pattern, 0, matches, /* @__PURE__ */ new Set(), 0);
|
|
244
262
|
return [...matches];
|
|
245
263
|
}
|
|
264
|
+
async forEachKeyMatchingPattern(pattern, visitor) {
|
|
265
|
+
const matches = await this.matchPattern(pattern);
|
|
266
|
+
for (const key of matches) {
|
|
267
|
+
await visitor(key);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
246
270
|
async clear() {
|
|
247
271
|
this.tagToKeys.clear();
|
|
248
272
|
this.keyToTags.clear();
|
|
@@ -292,6 +316,14 @@ var TagIndex = class {
|
|
|
292
316
|
this.collectFromNode(child, `${prefix}${character}`, matches);
|
|
293
317
|
}
|
|
294
318
|
}
|
|
319
|
+
async visitFromNode(node, prefix, visitor) {
|
|
320
|
+
if (node.terminal) {
|
|
321
|
+
await visitor(prefix);
|
|
322
|
+
}
|
|
323
|
+
for (const [character, child] of node.children) {
|
|
324
|
+
await this.visitFromNode(child, `${prefix}${character}`, visitor);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
295
327
|
collectPatternMatches(node, prefix, pattern, patternIndex, matches, visited, depth) {
|
|
296
328
|
if (depth > MAX_PATTERN_RECURSION_DEPTH) {
|
|
297
329
|
return;
|
|
@@ -416,14 +448,17 @@ function createHonoCacheMiddleware(cache, options = {}) {
|
|
|
416
448
|
await next();
|
|
417
449
|
return;
|
|
418
450
|
}
|
|
451
|
+
if (!options.keyResolver && options.allowPrivateCaching !== true) {
|
|
452
|
+
await next();
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
419
455
|
const rawPath = context.req.path ?? context.req.url ?? "/";
|
|
420
456
|
const key = options.keyResolver ? options.keyResolver(context.req) : `${method}:${normalizeUrl(rawPath)}`;
|
|
421
457
|
const cached = await cache.get(key, void 0, options);
|
|
422
458
|
if (cached !== null) {
|
|
423
459
|
context.header?.("x-cache", "HIT");
|
|
424
460
|
context.header?.("content-type", "application/json; charset=utf-8");
|
|
425
|
-
context.json(cached);
|
|
426
|
-
return;
|
|
461
|
+
return context.json(cached);
|
|
427
462
|
}
|
|
428
463
|
const originalJson = context.json.bind(context);
|
|
429
464
|
context.json = (body, status) => {
|
package/dist/cli.cjs
CHANGED
|
@@ -48,19 +48,47 @@ function isStoredValueEnvelope(value) {
|
|
|
48
48
|
if (v.kind !== "value" && v.kind !== "empty") {
|
|
49
49
|
return false;
|
|
50
50
|
}
|
|
51
|
-
if (v.freshUntil !== null && typeof v.freshUntil !== "number") {
|
|
51
|
+
if (v.freshUntil !== null && (!Number.isFinite(v.freshUntil) || typeof v.freshUntil !== "number")) {
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
|
-
if (v.staleUntil !== null && typeof v.staleUntil !== "number") {
|
|
54
|
+
if (v.staleUntil !== null && (!Number.isFinite(v.staleUntil) || typeof v.staleUntil !== "number")) {
|
|
55
55
|
return false;
|
|
56
56
|
}
|
|
57
|
-
if (v.errorUntil !== null && typeof v.errorUntil !== "number") {
|
|
57
|
+
if (v.errorUntil !== null && (!Number.isFinite(v.errorUntil) || typeof v.errorUntil !== "number")) {
|
|
58
58
|
return false;
|
|
59
59
|
}
|
|
60
60
|
const maxTimestamp = Date.now() + 10 * 365 * 24 * 60 * 60 * 1e3;
|
|
61
61
|
if (typeof v.freshUntil === "number" && v.freshUntil > maxTimestamp) {
|
|
62
62
|
return false;
|
|
63
63
|
}
|
|
64
|
+
if (typeof v.staleUntil === "number" && v.staleUntil > maxTimestamp) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (typeof v.errorUntil === "number" && v.errorUntil > maxTimestamp) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (v.freshUntil === null && (v.staleUntil !== null || v.errorUntil !== null)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (typeof v.freshUntil === "number" && typeof v.staleUntil === "number" && v.staleUntil < v.freshUntil) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (typeof v.freshUntil === "number" && typeof v.errorUntil === "number" && v.errorUntil < v.freshUntil) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const maxTtlSeconds = 10 * 365 * 24 * 60 * 60;
|
|
80
|
+
if (!isValidEnvelopeTtlSeconds(v.freshTtlSeconds, maxTtlSeconds)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (!isValidEnvelopeTtlSeconds(v.staleWhileRevalidateSeconds, maxTtlSeconds)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
if (!isValidEnvelopeTtlSeconds(v.staleIfErrorSeconds, maxTtlSeconds)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (v.freshTtlSeconds == null && (v.staleWhileRevalidateSeconds != null || v.staleIfErrorSeconds != null)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
64
92
|
return true;
|
|
65
93
|
}
|
|
66
94
|
function resolveStoredValue(stored, now = Date.now()) {
|
|
@@ -87,6 +115,12 @@ function unwrapStoredValue(stored) {
|
|
|
87
115
|
}
|
|
88
116
|
return stored.value ?? null;
|
|
89
117
|
}
|
|
118
|
+
function isValidEnvelopeTtlSeconds(value, maxTtlSeconds) {
|
|
119
|
+
if (value == null) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= maxTtlSeconds;
|
|
123
|
+
}
|
|
90
124
|
|
|
91
125
|
// src/invalidation/PatternMatcher.ts
|
|
92
126
|
var PatternMatcher = class _PatternMatcher {
|
|
@@ -182,6 +216,17 @@ var RedisTagIndex = class {
|
|
|
182
216
|
async keysForTag(tag) {
|
|
183
217
|
return this.client.smembers(this.tagKeysKey(tag));
|
|
184
218
|
}
|
|
219
|
+
async forEachKeyForTag(tag, visitor) {
|
|
220
|
+
let cursor = "0";
|
|
221
|
+
const tagKey = this.tagKeysKey(tag);
|
|
222
|
+
do {
|
|
223
|
+
const [nextCursor, keys] = await this.client.sscan(tagKey, cursor, "COUNT", this.scanCount);
|
|
224
|
+
cursor = nextCursor;
|
|
225
|
+
for (const key of keys) {
|
|
226
|
+
await visitor(key);
|
|
227
|
+
}
|
|
228
|
+
} while (cursor !== "0");
|
|
229
|
+
}
|
|
185
230
|
async keysForPrefix(prefix) {
|
|
186
231
|
const matches = [];
|
|
187
232
|
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
@@ -194,6 +239,20 @@ var RedisTagIndex = class {
|
|
|
194
239
|
}
|
|
195
240
|
return matches;
|
|
196
241
|
}
|
|
242
|
+
async forEachKeyForPrefix(prefix, visitor) {
|
|
243
|
+
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
244
|
+
let cursor = "0";
|
|
245
|
+
do {
|
|
246
|
+
const [nextCursor, keys] = await this.client.sscan(knownKeysKey, cursor, "COUNT", this.scanCount);
|
|
247
|
+
cursor = nextCursor;
|
|
248
|
+
for (const key of keys) {
|
|
249
|
+
if (key.startsWith(prefix)) {
|
|
250
|
+
await visitor(key);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} while (cursor !== "0");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
197
256
|
async tagsForKey(key) {
|
|
198
257
|
return this.client.smembers(this.keyTagsKey(key));
|
|
199
258
|
}
|
|
@@ -216,6 +275,27 @@ var RedisTagIndex = class {
|
|
|
216
275
|
}
|
|
217
276
|
return matches;
|
|
218
277
|
}
|
|
278
|
+
async forEachKeyMatchingPattern(pattern, visitor) {
|
|
279
|
+
for (const knownKeysKey of this.knownKeysKeys()) {
|
|
280
|
+
let cursor = "0";
|
|
281
|
+
do {
|
|
282
|
+
const [nextCursor, keys] = await this.client.sscan(
|
|
283
|
+
knownKeysKey,
|
|
284
|
+
cursor,
|
|
285
|
+
"MATCH",
|
|
286
|
+
pattern,
|
|
287
|
+
"COUNT",
|
|
288
|
+
this.scanCount
|
|
289
|
+
);
|
|
290
|
+
cursor = nextCursor;
|
|
291
|
+
for (const key of keys) {
|
|
292
|
+
if (PatternMatcher.matches(pattern, key)) {
|
|
293
|
+
await visitor(key);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
} while (cursor !== "0");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
219
299
|
async clear() {
|
|
220
300
|
const indexKeys = await this.scanIndexKeys();
|
|
221
301
|
if (indexKeys.length === 0) {
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
RedisTagIndex
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BQLL6IM5.js";
|
|
5
5
|
import {
|
|
6
6
|
isStoredValueEnvelope,
|
|
7
7
|
resolveStoredValue
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4PPBOOXT.js";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
|
11
11
|
import Redis from "ioredis";
|
|
@@ -66,6 +66,7 @@ interface CacheLayer {
|
|
|
66
66
|
clear(): Promise<void>;
|
|
67
67
|
deleteMany?(keys: string[]): Promise<void>;
|
|
68
68
|
keys?(): Promise<string[]>;
|
|
69
|
+
forEachKey?(visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
69
70
|
ping?(): Promise<boolean>;
|
|
70
71
|
dispose?(): Promise<void>;
|
|
71
72
|
/**
|
|
@@ -140,10 +141,13 @@ interface CacheTagIndex {
|
|
|
140
141
|
track(key: string, tags: string[]): Promise<void>;
|
|
141
142
|
remove(key: string): Promise<void>;
|
|
142
143
|
keysForTag(tag: string): Promise<string[]>;
|
|
144
|
+
forEachKeyForTag?(tag: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
143
145
|
keysForPrefix?(prefix: string): Promise<string[]>;
|
|
146
|
+
forEachKeyForPrefix?(prefix: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
144
147
|
/** Returns the tags associated with a specific key, or an empty array. */
|
|
145
148
|
tagsForKey?(key: string): Promise<string[]>;
|
|
146
149
|
matchPattern(pattern: string): Promise<string[]>;
|
|
150
|
+
forEachKeyMatchingPattern?(pattern: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
147
151
|
clear(): Promise<void>;
|
|
148
152
|
}
|
|
149
153
|
interface CacheLayerSetManyEntry {
|
|
@@ -203,6 +207,9 @@ interface CacheStackOptions {
|
|
|
203
207
|
singleFlightPollMs?: number;
|
|
204
208
|
singleFlightRenewIntervalMs?: number;
|
|
205
209
|
snapshotBaseDir?: string | false;
|
|
210
|
+
snapshotMaxBytes?: number | false;
|
|
211
|
+
snapshotMaxEntries?: number | false;
|
|
212
|
+
invalidationMaxKeys?: number | false;
|
|
206
213
|
/**
|
|
207
214
|
* Maximum number of entries in `accessProfiles` and `circuitBreakers` maps
|
|
208
215
|
* before the oldest entries are pruned. Prevents unbounded memory growth.
|
|
@@ -396,6 +403,7 @@ declare class MemoryLayer implements CacheLayer {
|
|
|
396
403
|
ping(): Promise<boolean>;
|
|
397
404
|
dispose(): Promise<void>;
|
|
398
405
|
keys(): Promise<string[]>;
|
|
406
|
+
forEachKey(visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
399
407
|
exportState(): MemoryLayerSnapshotEntry[];
|
|
400
408
|
importState(entries: MemoryLayerSnapshotEntry[]): void;
|
|
401
409
|
private evict;
|
|
@@ -437,14 +445,18 @@ declare class TagIndex implements CacheTagIndex {
|
|
|
437
445
|
track(key: string, tags: string[]): Promise<void>;
|
|
438
446
|
remove(key: string): Promise<void>;
|
|
439
447
|
keysForTag(tag: string): Promise<string[]>;
|
|
448
|
+
forEachKeyForTag(tag: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
440
449
|
keysForPrefix(prefix: string): Promise<string[]>;
|
|
450
|
+
forEachKeyForPrefix(prefix: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
441
451
|
tagsForKey(key: string): Promise<string[]>;
|
|
442
452
|
matchPattern(pattern: string): Promise<string[]>;
|
|
453
|
+
forEachKeyMatchingPattern(pattern: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
443
454
|
clear(): Promise<void>;
|
|
444
455
|
private createTrieNode;
|
|
445
456
|
private insertKnownKey;
|
|
446
457
|
private findNode;
|
|
447
458
|
private collectFromNode;
|
|
459
|
+
private visitFromNode;
|
|
448
460
|
private collectPatternMatches;
|
|
449
461
|
private pruneKnownKeysIfNeeded;
|
|
450
462
|
private removeKey;
|
|
@@ -494,6 +506,10 @@ declare class CacheNamespace {
|
|
|
494
506
|
*/
|
|
495
507
|
namespace(childPrefix: string): CacheNamespace;
|
|
496
508
|
qualify(key: string): string;
|
|
509
|
+
private qualifyTag;
|
|
510
|
+
private qualifyGetOptions;
|
|
511
|
+
private qualifyWrapOptions;
|
|
512
|
+
private qualifyWriteOptions;
|
|
497
513
|
private trackMetrics;
|
|
498
514
|
private getMetricsMutex;
|
|
499
515
|
}
|
|
@@ -523,13 +539,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
523
539
|
private readonly snapshotSerializer;
|
|
524
540
|
private readonly backgroundRefreshes;
|
|
525
541
|
private readonly layerDegradedUntil;
|
|
542
|
+
private readonly maintenance;
|
|
526
543
|
private readonly ttlResolver;
|
|
527
544
|
private readonly circuitBreakerManager;
|
|
528
545
|
private currentGeneration?;
|
|
529
|
-
private readonly writeBehindQueue;
|
|
530
|
-
private writeBehindTimer?;
|
|
531
|
-
private writeBehindFlushPromise?;
|
|
532
|
-
private generationCleanupPromise?;
|
|
533
546
|
private isDisconnecting;
|
|
534
547
|
private disconnectPromise?;
|
|
535
548
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
@@ -641,35 +654,23 @@ declare class CacheStack extends EventEmitter {
|
|
|
641
654
|
private sleep;
|
|
642
655
|
private withTimeout;
|
|
643
656
|
private shouldBroadcastL1Invalidation;
|
|
644
|
-
private shouldCleanupGenerations;
|
|
645
|
-
private generationCleanupBatchSize;
|
|
646
657
|
private scheduleGenerationCleanup;
|
|
647
658
|
private cleanupGeneration;
|
|
648
659
|
private initializeWriteBehind;
|
|
649
660
|
private shouldWriteBehind;
|
|
650
661
|
private enqueueWriteBehind;
|
|
651
662
|
private flushWriteBehindQueue;
|
|
663
|
+
private runWriteBehindBatch;
|
|
652
664
|
private buildLayerSetEntry;
|
|
653
665
|
private intersectKeys;
|
|
654
666
|
private qualifyKey;
|
|
655
667
|
private qualifyPattern;
|
|
656
668
|
private stripQualifiedKey;
|
|
657
|
-
private generationPrefix;
|
|
658
669
|
private deleteKeysFromLayers;
|
|
659
670
|
private validateConfiguration;
|
|
660
671
|
private validateWriteOptions;
|
|
661
|
-
private validateLayerNumberOption;
|
|
662
|
-
private validatePositiveNumber;
|
|
663
|
-
private validateRateLimitOptions;
|
|
664
|
-
private validateNonNegativeNumber;
|
|
665
|
-
private validateCacheKey;
|
|
666
|
-
private validatePattern;
|
|
667
|
-
private validateTtlPolicy;
|
|
668
672
|
private assertActive;
|
|
669
673
|
private awaitStartup;
|
|
670
|
-
private serializeOptions;
|
|
671
|
-
private validateAdaptiveTtlOptions;
|
|
672
|
-
private validateCircuitBreakerOptions;
|
|
673
674
|
private applyFreshReadPolicies;
|
|
674
675
|
private shouldSkipLayer;
|
|
675
676
|
private handleLayerFailure;
|
|
@@ -678,11 +679,14 @@ declare class CacheStack extends EventEmitter {
|
|
|
678
679
|
private recordCircuitFailure;
|
|
679
680
|
private isNegativeStoredValue;
|
|
680
681
|
private emitError;
|
|
681
|
-
private serializeKeyPart;
|
|
682
682
|
private isCacheSnapshotEntries;
|
|
683
683
|
private sanitizeSnapshotValue;
|
|
684
|
-
private
|
|
685
|
-
private
|
|
684
|
+
private snapshotMaxBytes;
|
|
685
|
+
private snapshotMaxEntries;
|
|
686
|
+
private invalidationMaxKeys;
|
|
687
|
+
private collectKeysForTag;
|
|
688
|
+
private assertWithinInvalidationKeyLimit;
|
|
689
|
+
private visitExportEntries;
|
|
686
690
|
}
|
|
687
691
|
|
|
688
692
|
interface HonoLikeRequest {
|
|
@@ -690,6 +694,8 @@ interface HonoLikeRequest {
|
|
|
690
694
|
url?: string;
|
|
691
695
|
path?: string;
|
|
692
696
|
query?: Record<string, unknown>;
|
|
697
|
+
headers?: Headers | Record<string, unknown>;
|
|
698
|
+
header?: (name: string) => string | undefined;
|
|
693
699
|
}
|
|
694
700
|
interface HonoLikeContext {
|
|
695
701
|
req: HonoLikeRequest;
|
|
@@ -699,7 +705,8 @@ interface HonoLikeContext {
|
|
|
699
705
|
interface HonoCacheMiddlewareOptions extends CacheGetOptions {
|
|
700
706
|
keyResolver?: (request: HonoLikeRequest) => string;
|
|
701
707
|
methods?: string[];
|
|
708
|
+
allowPrivateCaching?: boolean;
|
|
702
709
|
}
|
|
703
|
-
declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<
|
|
710
|
+
declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<unknown>;
|
|
704
711
|
|
|
705
712
|
export { type CacheStatsSnapshot as A, type CacheTtlPolicy as B, type CacheLogger as C, type CacheTtlPolicyContext as D, type CacheWarmEntry as E, type CacheWarmOptions as F, type CacheWarmProgress as G, type CacheWriteBehindOptions as H, type InvalidationBus as I, type CacheWriteOptions as J, type EvictionPolicy as K, type LayerTtlMap as L, MemoryLayer as M, type MemoryLayerOptions as N, type MemoryLayerSnapshotEntry as O, PatternMatcher as P, createHonoCacheMiddleware as Q, TagIndex as T, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheDegradationOptions as m, type CacheHealthCheckResult as n, type CacheHitRateSnapshot as o, type CacheInspectResult as p, type CacheLayerLatency as q, type CacheMGetEntry as r, type CacheMSetEntry as s, type CacheMetricsSnapshot as t, CacheMissError as u, CacheNamespace as v, type CacheRateLimitOptions as w, type CacheSnapshotEntry as x, type CacheStackEvents as y, type CacheStackOptions as z };
|
|
@@ -66,6 +66,7 @@ interface CacheLayer {
|
|
|
66
66
|
clear(): Promise<void>;
|
|
67
67
|
deleteMany?(keys: string[]): Promise<void>;
|
|
68
68
|
keys?(): Promise<string[]>;
|
|
69
|
+
forEachKey?(visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
69
70
|
ping?(): Promise<boolean>;
|
|
70
71
|
dispose?(): Promise<void>;
|
|
71
72
|
/**
|
|
@@ -140,10 +141,13 @@ interface CacheTagIndex {
|
|
|
140
141
|
track(key: string, tags: string[]): Promise<void>;
|
|
141
142
|
remove(key: string): Promise<void>;
|
|
142
143
|
keysForTag(tag: string): Promise<string[]>;
|
|
144
|
+
forEachKeyForTag?(tag: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
143
145
|
keysForPrefix?(prefix: string): Promise<string[]>;
|
|
146
|
+
forEachKeyForPrefix?(prefix: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
144
147
|
/** Returns the tags associated with a specific key, or an empty array. */
|
|
145
148
|
tagsForKey?(key: string): Promise<string[]>;
|
|
146
149
|
matchPattern(pattern: string): Promise<string[]>;
|
|
150
|
+
forEachKeyMatchingPattern?(pattern: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
147
151
|
clear(): Promise<void>;
|
|
148
152
|
}
|
|
149
153
|
interface CacheLayerSetManyEntry {
|
|
@@ -203,6 +207,9 @@ interface CacheStackOptions {
|
|
|
203
207
|
singleFlightPollMs?: number;
|
|
204
208
|
singleFlightRenewIntervalMs?: number;
|
|
205
209
|
snapshotBaseDir?: string | false;
|
|
210
|
+
snapshotMaxBytes?: number | false;
|
|
211
|
+
snapshotMaxEntries?: number | false;
|
|
212
|
+
invalidationMaxKeys?: number | false;
|
|
206
213
|
/**
|
|
207
214
|
* Maximum number of entries in `accessProfiles` and `circuitBreakers` maps
|
|
208
215
|
* before the oldest entries are pruned. Prevents unbounded memory growth.
|
|
@@ -396,6 +403,7 @@ declare class MemoryLayer implements CacheLayer {
|
|
|
396
403
|
ping(): Promise<boolean>;
|
|
397
404
|
dispose(): Promise<void>;
|
|
398
405
|
keys(): Promise<string[]>;
|
|
406
|
+
forEachKey(visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
399
407
|
exportState(): MemoryLayerSnapshotEntry[];
|
|
400
408
|
importState(entries: MemoryLayerSnapshotEntry[]): void;
|
|
401
409
|
private evict;
|
|
@@ -437,14 +445,18 @@ declare class TagIndex implements CacheTagIndex {
|
|
|
437
445
|
track(key: string, tags: string[]): Promise<void>;
|
|
438
446
|
remove(key: string): Promise<void>;
|
|
439
447
|
keysForTag(tag: string): Promise<string[]>;
|
|
448
|
+
forEachKeyForTag(tag: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
440
449
|
keysForPrefix(prefix: string): Promise<string[]>;
|
|
450
|
+
forEachKeyForPrefix(prefix: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
441
451
|
tagsForKey(key: string): Promise<string[]>;
|
|
442
452
|
matchPattern(pattern: string): Promise<string[]>;
|
|
453
|
+
forEachKeyMatchingPattern(pattern: string, visitor: (key: string) => void | Promise<void>): Promise<void>;
|
|
443
454
|
clear(): Promise<void>;
|
|
444
455
|
private createTrieNode;
|
|
445
456
|
private insertKnownKey;
|
|
446
457
|
private findNode;
|
|
447
458
|
private collectFromNode;
|
|
459
|
+
private visitFromNode;
|
|
448
460
|
private collectPatternMatches;
|
|
449
461
|
private pruneKnownKeysIfNeeded;
|
|
450
462
|
private removeKey;
|
|
@@ -494,6 +506,10 @@ declare class CacheNamespace {
|
|
|
494
506
|
*/
|
|
495
507
|
namespace(childPrefix: string): CacheNamespace;
|
|
496
508
|
qualify(key: string): string;
|
|
509
|
+
private qualifyTag;
|
|
510
|
+
private qualifyGetOptions;
|
|
511
|
+
private qualifyWrapOptions;
|
|
512
|
+
private qualifyWriteOptions;
|
|
497
513
|
private trackMetrics;
|
|
498
514
|
private getMetricsMutex;
|
|
499
515
|
}
|
|
@@ -523,13 +539,10 @@ declare class CacheStack extends EventEmitter {
|
|
|
523
539
|
private readonly snapshotSerializer;
|
|
524
540
|
private readonly backgroundRefreshes;
|
|
525
541
|
private readonly layerDegradedUntil;
|
|
542
|
+
private readonly maintenance;
|
|
526
543
|
private readonly ttlResolver;
|
|
527
544
|
private readonly circuitBreakerManager;
|
|
528
545
|
private currentGeneration?;
|
|
529
|
-
private readonly writeBehindQueue;
|
|
530
|
-
private writeBehindTimer?;
|
|
531
|
-
private writeBehindFlushPromise?;
|
|
532
|
-
private generationCleanupPromise?;
|
|
533
546
|
private isDisconnecting;
|
|
534
547
|
private disconnectPromise?;
|
|
535
548
|
constructor(layers: CacheLayer[], options?: CacheStackOptions);
|
|
@@ -641,35 +654,23 @@ declare class CacheStack extends EventEmitter {
|
|
|
641
654
|
private sleep;
|
|
642
655
|
private withTimeout;
|
|
643
656
|
private shouldBroadcastL1Invalidation;
|
|
644
|
-
private shouldCleanupGenerations;
|
|
645
|
-
private generationCleanupBatchSize;
|
|
646
657
|
private scheduleGenerationCleanup;
|
|
647
658
|
private cleanupGeneration;
|
|
648
659
|
private initializeWriteBehind;
|
|
649
660
|
private shouldWriteBehind;
|
|
650
661
|
private enqueueWriteBehind;
|
|
651
662
|
private flushWriteBehindQueue;
|
|
663
|
+
private runWriteBehindBatch;
|
|
652
664
|
private buildLayerSetEntry;
|
|
653
665
|
private intersectKeys;
|
|
654
666
|
private qualifyKey;
|
|
655
667
|
private qualifyPattern;
|
|
656
668
|
private stripQualifiedKey;
|
|
657
|
-
private generationPrefix;
|
|
658
669
|
private deleteKeysFromLayers;
|
|
659
670
|
private validateConfiguration;
|
|
660
671
|
private validateWriteOptions;
|
|
661
|
-
private validateLayerNumberOption;
|
|
662
|
-
private validatePositiveNumber;
|
|
663
|
-
private validateRateLimitOptions;
|
|
664
|
-
private validateNonNegativeNumber;
|
|
665
|
-
private validateCacheKey;
|
|
666
|
-
private validatePattern;
|
|
667
|
-
private validateTtlPolicy;
|
|
668
672
|
private assertActive;
|
|
669
673
|
private awaitStartup;
|
|
670
|
-
private serializeOptions;
|
|
671
|
-
private validateAdaptiveTtlOptions;
|
|
672
|
-
private validateCircuitBreakerOptions;
|
|
673
674
|
private applyFreshReadPolicies;
|
|
674
675
|
private shouldSkipLayer;
|
|
675
676
|
private handleLayerFailure;
|
|
@@ -678,11 +679,14 @@ declare class CacheStack extends EventEmitter {
|
|
|
678
679
|
private recordCircuitFailure;
|
|
679
680
|
private isNegativeStoredValue;
|
|
680
681
|
private emitError;
|
|
681
|
-
private serializeKeyPart;
|
|
682
682
|
private isCacheSnapshotEntries;
|
|
683
683
|
private sanitizeSnapshotValue;
|
|
684
|
-
private
|
|
685
|
-
private
|
|
684
|
+
private snapshotMaxBytes;
|
|
685
|
+
private snapshotMaxEntries;
|
|
686
|
+
private invalidationMaxKeys;
|
|
687
|
+
private collectKeysForTag;
|
|
688
|
+
private assertWithinInvalidationKeyLimit;
|
|
689
|
+
private visitExportEntries;
|
|
686
690
|
}
|
|
687
691
|
|
|
688
692
|
interface HonoLikeRequest {
|
|
@@ -690,6 +694,8 @@ interface HonoLikeRequest {
|
|
|
690
694
|
url?: string;
|
|
691
695
|
path?: string;
|
|
692
696
|
query?: Record<string, unknown>;
|
|
697
|
+
headers?: Headers | Record<string, unknown>;
|
|
698
|
+
header?: (name: string) => string | undefined;
|
|
693
699
|
}
|
|
694
700
|
interface HonoLikeContext {
|
|
695
701
|
req: HonoLikeRequest;
|
|
@@ -699,7 +705,8 @@ interface HonoLikeContext {
|
|
|
699
705
|
interface HonoCacheMiddlewareOptions extends CacheGetOptions {
|
|
700
706
|
keyResolver?: (request: HonoLikeRequest) => string;
|
|
701
707
|
methods?: string[];
|
|
708
|
+
allowPrivateCaching?: boolean;
|
|
702
709
|
}
|
|
703
|
-
declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<
|
|
710
|
+
declare function createHonoCacheMiddleware(cache: CacheStack, options?: HonoCacheMiddlewareOptions): (context: HonoLikeContext, next: () => Promise<void>) => Promise<unknown>;
|
|
704
711
|
|
|
705
712
|
export { type CacheStatsSnapshot as A, type CacheTtlPolicy as B, type CacheLogger as C, type CacheTtlPolicyContext as D, type CacheWarmEntry as E, type CacheWarmOptions as F, type CacheWarmProgress as G, type CacheWriteBehindOptions as H, type InvalidationBus as I, type CacheWriteOptions as J, type EvictionPolicy as K, type LayerTtlMap as L, MemoryLayer as M, type MemoryLayerOptions as N, type MemoryLayerSnapshotEntry as O, PatternMatcher as P, createHonoCacheMiddleware as Q, TagIndex as T, type InvalidationMessage as a, type CacheTagIndex as b, CacheStack as c, type CacheWrapOptions as d, type CacheGetOptions as e, type CacheLayer as f, type CacheSerializer as g, type CacheLayerSetManyEntry as h, type CacheSingleFlightCoordinator as i, type CacheSingleFlightExecutionOptions as j, type CacheAdaptiveTtlOptions as k, type CacheCircuitBreakerOptions as l, type CacheDegradationOptions as m, type CacheHealthCheckResult as n, type CacheHitRateSnapshot as o, type CacheInspectResult as p, type CacheLayerLatency as q, type CacheMGetEntry as r, type CacheMSetEntry as s, type CacheMetricsSnapshot as t, CacheMissError as u, CacheNamespace as v, type CacheRateLimitOptions as w, type CacheSnapshotEntry as x, type CacheStackEvents as y, type CacheStackOptions as z };
|