@leejpsd/nextjs-cache-handler 0.1.1 → 0.3.0
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/CHANGELOG.md +117 -2
- package/README.md +131 -30
- package/dist/cache-components/index.cjs +297 -52
- package/dist/cache-components/index.cjs.map +1 -1
- package/dist/cache-components/index.d.cts +1 -1
- package/dist/cache-components/index.d.ts +1 -1
- package/dist/cache-components/index.js +289 -52
- package/dist/cache-components/index.js.map +1 -1
- package/dist/incremental/index.cjs +231 -41
- package/dist/incremental/index.cjs.map +1 -1
- package/dist/incremental/index.d.cts +42 -3
- package/dist/incremental/index.d.ts +42 -3
- package/dist/incremental/index.js +223 -41
- package/dist/incremental/index.js.map +1 -1
- package/dist/index.cjs +375 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +367 -76
- package/dist/index.js.map +1 -1
- package/dist/ops/index.d.cts +1 -1
- package/dist/ops/index.d.ts +1 -1
- package/dist/otel/index.cjs +72 -0
- package/dist/otel/index.cjs.map +1 -0
- package/dist/otel/index.d.cts +72 -0
- package/dist/otel/index.d.ts +72 -0
- package/dist/otel/index.js +64 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/shared/client/adapter-ioredis.cjs +49 -10
- package/dist/shared/client/adapter-ioredis.cjs.map +1 -1
- package/dist/shared/client/adapter-ioredis.d.cts +5 -2
- package/dist/shared/client/adapter-ioredis.d.ts +5 -2
- package/dist/shared/client/adapter-ioredis.js +43 -11
- package/dist/shared/client/adapter-ioredis.js.map +1 -1
- package/dist/shared/client/adapter-redis.cjs +22 -7
- package/dist/shared/client/adapter-redis.cjs.map +1 -1
- package/dist/shared/client/adapter-redis.d.cts +1 -1
- package/dist/shared/client/adapter-redis.d.ts +1 -1
- package/dist/shared/client/adapter-redis.js +16 -7
- package/dist/shared/client/adapter-redis.js.map +1 -1
- package/dist/{types-CgriT7My.d.cts → types-Bl-rkLKX.d.cts} +59 -1
- package/dist/{types-CgriT7My.d.ts → types-Bl-rkLKX.d.ts} +59 -1
- package/package.json +23 -4
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var module$1 = require('module');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var util = require('util');
|
|
6
|
+
var zlib = require('zlib');
|
|
3
7
|
var crypto = require('crypto');
|
|
4
8
|
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
|
+
|
|
5
13
|
var __defProp = Object.defineProperty;
|
|
6
14
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
-
}) : x)(function(x) {
|
|
10
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
-
});
|
|
13
15
|
var __esm = (fn, res) => function __init() {
|
|
14
16
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
17
|
};
|
|
@@ -18,6 +20,32 @@ var __export = (target, all) => {
|
|
|
18
20
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
21
|
};
|
|
20
22
|
|
|
23
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
24
|
+
var getImportMetaUrl, importMetaUrl;
|
|
25
|
+
var init_cjs_shims = __esm({
|
|
26
|
+
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
27
|
+
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
28
|
+
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
function nodeRequire(id) {
|
|
32
|
+
try {
|
|
33
|
+
return packageRequire(id);
|
|
34
|
+
} catch {
|
|
35
|
+
return cwdRequire(id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
var packageRequire, cwdRequire;
|
|
39
|
+
var init_node_require = __esm({
|
|
40
|
+
"src/shared/node-require.ts"() {
|
|
41
|
+
init_cjs_shims();
|
|
42
|
+
packageRequire = module$1.createRequire(importMetaUrl);
|
|
43
|
+
cwdRequire = module$1.createRequire(
|
|
44
|
+
path__default.default.join(process.cwd(), "__resolve-anchor__.js")
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
21
49
|
// src/shared/client/adapter-redis.ts
|
|
22
50
|
var adapter_redis_exports = {};
|
|
23
51
|
__export(adapter_redis_exports, {
|
|
@@ -28,7 +56,7 @@ function adaptRedisV5(client) {
|
|
|
28
56
|
return client;
|
|
29
57
|
}
|
|
30
58
|
function createRedisV5Client(config) {
|
|
31
|
-
const { createClient } =
|
|
59
|
+
const { createClient } = nodeRequire("redis");
|
|
32
60
|
const useTls = config.tls ?? config.url.startsWith("rediss://");
|
|
33
61
|
const opts = {
|
|
34
62
|
url: config.url,
|
|
@@ -43,6 +71,8 @@ function createRedisV5Client(config) {
|
|
|
43
71
|
}
|
|
44
72
|
var init_adapter_redis = __esm({
|
|
45
73
|
"src/shared/client/adapter-redis.ts"() {
|
|
74
|
+
init_cjs_shims();
|
|
75
|
+
init_node_require();
|
|
46
76
|
}
|
|
47
77
|
});
|
|
48
78
|
|
|
@@ -52,7 +82,8 @@ __export(adapter_ioredis_exports, {
|
|
|
52
82
|
adaptCluster: () => adaptCluster,
|
|
53
83
|
adaptIoredis: () => adaptIoredis,
|
|
54
84
|
createIoredisClient: () => createIoredisClient,
|
|
55
|
-
createIoredisCluster: () => createIoredisCluster
|
|
85
|
+
createIoredisCluster: () => createIoredisCluster,
|
|
86
|
+
createIoredisSentinel: () => createIoredisSentinel
|
|
56
87
|
});
|
|
57
88
|
function adapt(client, isClusterClient = false) {
|
|
58
89
|
return {
|
|
@@ -135,6 +166,9 @@ function adapt(client, isClusterClient = false) {
|
|
|
135
166
|
on: (event, listener) => {
|
|
136
167
|
client.on(event, listener);
|
|
137
168
|
return client;
|
|
169
|
+
},
|
|
170
|
+
dispose: () => {
|
|
171
|
+
client.disconnect();
|
|
138
172
|
}
|
|
139
173
|
};
|
|
140
174
|
}
|
|
@@ -145,18 +179,36 @@ function adaptCluster(cluster) {
|
|
|
145
179
|
return adapt(cluster, true);
|
|
146
180
|
}
|
|
147
181
|
function createIoredisClient(config) {
|
|
148
|
-
const IORedis =
|
|
182
|
+
const IORedis = nodeRequire("ioredis");
|
|
149
183
|
const Ctor = IORedis.default ?? IORedis;
|
|
150
184
|
return new Ctor(config.url, {
|
|
151
185
|
password: config.password,
|
|
152
186
|
connectTimeout: config.connectTimeout ?? 1500,
|
|
153
187
|
tls: config.tls ? {} : void 0,
|
|
154
188
|
lazyConnect: true,
|
|
155
|
-
maxRetriesPerRequest: 1
|
|
189
|
+
maxRetriesPerRequest: 1,
|
|
190
|
+
// Batch same-tick commands into one RTT (matches redis@5's default
|
|
191
|
+
// behavior) — makes Promise.all fan-outs a single pipeline.
|
|
192
|
+
enableAutoPipelining: true
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function createIoredisSentinel(config) {
|
|
196
|
+
const IORedis = nodeRequire("ioredis");
|
|
197
|
+
const Ctor = IORedis.default ?? IORedis;
|
|
198
|
+
return new Ctor({
|
|
199
|
+
sentinels: config.sentinels,
|
|
200
|
+
name: config.name,
|
|
201
|
+
password: config.password,
|
|
202
|
+
sentinelPassword: config.sentinelPassword,
|
|
203
|
+
connectTimeout: config.connectTimeout ?? 1500,
|
|
204
|
+
tls: config.tls ? {} : void 0,
|
|
205
|
+
lazyConnect: true,
|
|
206
|
+
maxRetriesPerRequest: 1,
|
|
207
|
+
enableAutoPipelining: true
|
|
156
208
|
});
|
|
157
209
|
}
|
|
158
210
|
function createIoredisCluster(config) {
|
|
159
|
-
const IORedis =
|
|
211
|
+
const IORedis = nodeRequire("ioredis");
|
|
160
212
|
const ClusterCtor = IORedis.Cluster ?? IORedis.default.Cluster;
|
|
161
213
|
return new ClusterCtor(config.nodes, {
|
|
162
214
|
redisOptions: {
|
|
@@ -164,15 +216,29 @@ function createIoredisCluster(config) {
|
|
|
164
216
|
tls: config.tls ? {} : void 0
|
|
165
217
|
},
|
|
166
218
|
enableReadyCheck: true,
|
|
167
|
-
lazyConnect: true
|
|
219
|
+
lazyConnect: true,
|
|
220
|
+
// Same-slot commands issued in the same tick share one pipeline.
|
|
221
|
+
enableAutoPipelining: true
|
|
168
222
|
});
|
|
169
223
|
}
|
|
170
224
|
var init_adapter_ioredis = __esm({
|
|
171
225
|
"src/shared/client/adapter-ioredis.ts"() {
|
|
226
|
+
init_cjs_shims();
|
|
227
|
+
init_node_require();
|
|
172
228
|
}
|
|
173
229
|
});
|
|
174
230
|
|
|
231
|
+
// src/index.ts
|
|
232
|
+
init_cjs_shims();
|
|
233
|
+
|
|
234
|
+
// src/cache-components/index.ts
|
|
235
|
+
init_cjs_shims();
|
|
236
|
+
|
|
237
|
+
// src/cache-components/handler.ts
|
|
238
|
+
init_cjs_shims();
|
|
239
|
+
|
|
175
240
|
// src/shared/abort.ts
|
|
241
|
+
init_cjs_shims();
|
|
176
242
|
var CacheTimeoutError = class extends Error {
|
|
177
243
|
constructor(opName, ms) {
|
|
178
244
|
super(`[@leejpsd/nextjs-cache-handler] ${opName} timed out after ${ms}ms`);
|
|
@@ -204,7 +270,41 @@ async function withAbortSignal(opName, ms, fn) {
|
|
|
204
270
|
}
|
|
205
271
|
}
|
|
206
272
|
|
|
273
|
+
// src/shared/compress.ts
|
|
274
|
+
init_cjs_shims();
|
|
275
|
+
var gzipAsync = util.promisify(zlib.gzip);
|
|
276
|
+
var gunzipAsync = util.promisify(zlib.gunzip);
|
|
277
|
+
var brotliCompressAsync = util.promisify(zlib.brotliCompress);
|
|
278
|
+
var brotliDecompressAsync = util.promisify(zlib.brotliDecompress);
|
|
279
|
+
var GZIP_MARKER = "__ncgz__:";
|
|
280
|
+
var BROTLI_MARKER = "__ncbr__:";
|
|
281
|
+
var MIN_COMPRESS_BYTES = 1024;
|
|
282
|
+
var BROTLI_OPTS = {
|
|
283
|
+
params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 }
|
|
284
|
+
};
|
|
285
|
+
async function compressValue(value, algo) {
|
|
286
|
+
if (!algo || Buffer.byteLength(value) < MIN_COMPRESS_BYTES) return value;
|
|
287
|
+
const input = Buffer.from(value);
|
|
288
|
+
if (algo === "gzip") {
|
|
289
|
+
return GZIP_MARKER + (await gzipAsync(input)).toString("base64");
|
|
290
|
+
}
|
|
291
|
+
return BROTLI_MARKER + (await brotliCompressAsync(input, BROTLI_OPTS)).toString("base64");
|
|
292
|
+
}
|
|
293
|
+
async function decompressValue(value) {
|
|
294
|
+
if (value === null) return null;
|
|
295
|
+
if (value.startsWith(GZIP_MARKER)) {
|
|
296
|
+
const buf = Buffer.from(value.slice(GZIP_MARKER.length), "base64");
|
|
297
|
+
return (await gunzipAsync(buf)).toString("utf8");
|
|
298
|
+
}
|
|
299
|
+
if (value.startsWith(BROTLI_MARKER)) {
|
|
300
|
+
const buf = Buffer.from(value.slice(BROTLI_MARKER.length), "base64");
|
|
301
|
+
return (await brotliDecompressAsync(buf)).toString("utf8");
|
|
302
|
+
}
|
|
303
|
+
return value;
|
|
304
|
+
}
|
|
305
|
+
|
|
207
306
|
// src/shared/client/index.ts
|
|
307
|
+
init_cjs_shims();
|
|
208
308
|
async function buildClient(source) {
|
|
209
309
|
if (typeof source === "function") {
|
|
210
310
|
return await source();
|
|
@@ -222,6 +322,10 @@ async function buildClient(source) {
|
|
|
222
322
|
const { adaptCluster: adaptCluster2, createIoredisCluster: createIoredisCluster2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
223
323
|
return adaptCluster2(createIoredisCluster2(source));
|
|
224
324
|
}
|
|
325
|
+
case "sentinel": {
|
|
326
|
+
const { adaptIoredis: adaptIoredis2, createIoredisSentinel: createIoredisSentinel2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
327
|
+
return adaptIoredis2(createIoredisSentinel2(source));
|
|
328
|
+
}
|
|
225
329
|
default: {
|
|
226
330
|
const exhaustive = source;
|
|
227
331
|
throw new Error(
|
|
@@ -231,28 +335,45 @@ async function buildClient(source) {
|
|
|
231
335
|
}
|
|
232
336
|
}
|
|
233
337
|
var ConnectionManager = class {
|
|
234
|
-
constructor(source, onError) {
|
|
338
|
+
constructor(source, onError, retry = {}) {
|
|
235
339
|
this.source = source;
|
|
236
340
|
this.onError = onError;
|
|
341
|
+
this.baseCooldownMs = retry.baseCooldownMs ?? 1e3;
|
|
342
|
+
this.maxCooldownMs = retry.maxCooldownMs ?? 3e4;
|
|
237
343
|
}
|
|
238
344
|
source;
|
|
239
345
|
onError;
|
|
240
346
|
client = null;
|
|
241
347
|
connecting = null;
|
|
242
|
-
|
|
348
|
+
consecutiveFailures = 0;
|
|
349
|
+
lastFailureAt = 0;
|
|
350
|
+
baseCooldownMs;
|
|
351
|
+
maxCooldownMs;
|
|
352
|
+
cooldownMs() {
|
|
353
|
+
if (this.consecutiveFailures === 0) return 0;
|
|
354
|
+
return Math.min(
|
|
355
|
+
this.maxCooldownMs,
|
|
356
|
+
this.baseCooldownMs * 2 ** (this.consecutiveFailures - 1)
|
|
357
|
+
);
|
|
358
|
+
}
|
|
243
359
|
async getOrConnect() {
|
|
244
360
|
if (this.client?.isOpen) return this.client;
|
|
245
|
-
if (this.failed) return null;
|
|
246
361
|
if (this.connecting) return this.connecting;
|
|
362
|
+
if (Date.now() - this.lastFailureAt < this.cooldownMs()) return null;
|
|
363
|
+
const stale = this.client;
|
|
364
|
+
this.client = null;
|
|
247
365
|
this.connecting = (async () => {
|
|
366
|
+
disposeQuietly(stale);
|
|
248
367
|
try {
|
|
249
368
|
const c = await buildClient(this.source);
|
|
250
369
|
c.on("error", (err) => this.onError(err));
|
|
251
370
|
if (!c.isOpen) await c.connect();
|
|
252
371
|
this.client = c;
|
|
372
|
+
this.consecutiveFailures = 0;
|
|
253
373
|
return c;
|
|
254
374
|
} catch (err) {
|
|
255
|
-
this.
|
|
375
|
+
this.consecutiveFailures += 1;
|
|
376
|
+
this.lastFailureAt = Date.now();
|
|
256
377
|
this.onError(err);
|
|
257
378
|
return null;
|
|
258
379
|
} finally {
|
|
@@ -262,13 +383,24 @@ var ConnectionManager = class {
|
|
|
262
383
|
return this.connecting;
|
|
263
384
|
}
|
|
264
385
|
reset() {
|
|
386
|
+
disposeQuietly(this.client);
|
|
265
387
|
this.client = null;
|
|
266
388
|
this.connecting = null;
|
|
267
|
-
this.
|
|
389
|
+
this.consecutiveFailures = 0;
|
|
390
|
+
this.lastFailureAt = 0;
|
|
268
391
|
}
|
|
269
392
|
};
|
|
393
|
+
function disposeQuietly(client) {
|
|
394
|
+
if (!client) return;
|
|
395
|
+
const c = client;
|
|
396
|
+
try {
|
|
397
|
+
(c.dispose ?? c.destroy ?? c.disconnect)?.call(c);
|
|
398
|
+
} catch {
|
|
399
|
+
}
|
|
400
|
+
}
|
|
270
401
|
|
|
271
402
|
// src/shared/logger.ts
|
|
403
|
+
init_cjs_shims();
|
|
272
404
|
var defaultLogger = {
|
|
273
405
|
debug: () => {
|
|
274
406
|
},
|
|
@@ -284,6 +416,9 @@ var defaultLogger = {
|
|
|
284
416
|
}
|
|
285
417
|
};
|
|
286
418
|
|
|
419
|
+
// src/shared/lua/index.ts
|
|
420
|
+
init_cjs_shims();
|
|
421
|
+
|
|
287
422
|
// src/shared/lua/set-with-tags.lua
|
|
288
423
|
var set_with_tags_default = `-- set-with-tags.lua
|
|
289
424
|
--
|
|
@@ -387,13 +522,19 @@ async function execLuaScript(client, name, keys, args) {
|
|
|
387
522
|
}
|
|
388
523
|
|
|
389
524
|
// src/shared/memory-fallback.ts
|
|
525
|
+
init_cjs_shims();
|
|
390
526
|
var MAX_TIMER_MS = 2147483647;
|
|
391
527
|
function clampTimerMs(ms) {
|
|
392
528
|
return Math.min(Math.max(0, ms), MAX_TIMER_MS);
|
|
393
529
|
}
|
|
530
|
+
var DEFAULT_MAX_ENTRIES = 1e3;
|
|
394
531
|
var MemoryStore = class {
|
|
395
532
|
kv = /* @__PURE__ */ new Map();
|
|
396
533
|
timers = /* @__PURE__ */ new Map();
|
|
534
|
+
maxEntries;
|
|
535
|
+
constructor(maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
536
|
+
this.maxEntries = Math.max(1, maxEntries);
|
|
537
|
+
}
|
|
397
538
|
set(key, value, ttlSeconds) {
|
|
398
539
|
this.delete(key);
|
|
399
540
|
const expiresAt = Date.now() + ttlSeconds * 1e3;
|
|
@@ -403,6 +544,10 @@ var MemoryStore = class {
|
|
|
403
544
|
timer.unref();
|
|
404
545
|
}
|
|
405
546
|
this.timers.set(key, timer);
|
|
547
|
+
while (this.kv.size > this.maxEntries) {
|
|
548
|
+
const oldest = this.kv.keys().next().value;
|
|
549
|
+
this.delete(oldest);
|
|
550
|
+
}
|
|
406
551
|
}
|
|
407
552
|
get(key) {
|
|
408
553
|
const entry = this.kv.get(key);
|
|
@@ -411,6 +556,8 @@ var MemoryStore = class {
|
|
|
411
556
|
this.delete(key);
|
|
412
557
|
return null;
|
|
413
558
|
}
|
|
559
|
+
this.kv.delete(key);
|
|
560
|
+
this.kv.set(key, entry);
|
|
414
561
|
return entry.value;
|
|
415
562
|
}
|
|
416
563
|
delete(key) {
|
|
@@ -445,13 +592,19 @@ var MemorySetStore = class {
|
|
|
445
592
|
sets = /* @__PURE__ */ new Map();
|
|
446
593
|
expiresAt = /* @__PURE__ */ new Map();
|
|
447
594
|
timers = /* @__PURE__ */ new Map();
|
|
595
|
+
maxSets;
|
|
596
|
+
constructor(maxSets = DEFAULT_MAX_ENTRIES) {
|
|
597
|
+
this.maxSets = Math.max(1, maxSets);
|
|
598
|
+
}
|
|
448
599
|
sAdd(key, member) {
|
|
449
600
|
const members = Array.isArray(member) ? member : [member];
|
|
450
601
|
let set = this.sets.get(key);
|
|
451
602
|
if (!set) {
|
|
452
603
|
set = /* @__PURE__ */ new Set();
|
|
453
|
-
|
|
604
|
+
} else {
|
|
605
|
+
this.sets.delete(key);
|
|
454
606
|
}
|
|
607
|
+
this.sets.set(key, set);
|
|
455
608
|
let added = 0;
|
|
456
609
|
for (const m of members) {
|
|
457
610
|
if (!set.has(m)) {
|
|
@@ -459,6 +612,10 @@ var MemorySetStore = class {
|
|
|
459
612
|
added += 1;
|
|
460
613
|
}
|
|
461
614
|
}
|
|
615
|
+
while (this.sets.size > this.maxSets) {
|
|
616
|
+
const oldest = this.sets.keys().next().value;
|
|
617
|
+
this.delete(oldest);
|
|
618
|
+
}
|
|
462
619
|
return added;
|
|
463
620
|
}
|
|
464
621
|
sMembers(key) {
|
|
@@ -511,6 +668,7 @@ var MemorySetStore = class {
|
|
|
511
668
|
};
|
|
512
669
|
|
|
513
670
|
// src/shared/metrics.ts
|
|
671
|
+
init_cjs_shims();
|
|
514
672
|
var counters = /* @__PURE__ */ new Map();
|
|
515
673
|
function bump(event) {
|
|
516
674
|
const existing = counters.get(event.type);
|
|
@@ -550,6 +708,7 @@ function getMetricSnapshot() {
|
|
|
550
708
|
}
|
|
551
709
|
|
|
552
710
|
// src/shared/namespace.ts
|
|
711
|
+
init_cjs_shims();
|
|
553
712
|
var FALLBACK = "unversioned";
|
|
554
713
|
function resolveBuildNamespace(override) {
|
|
555
714
|
if (override !== void 0) {
|
|
@@ -563,6 +722,7 @@ function buildKey(prefix, namespace, rest, hashTag = false) {
|
|
|
563
722
|
}
|
|
564
723
|
|
|
565
724
|
// src/shared/build-phase.ts
|
|
725
|
+
init_cjs_shims();
|
|
566
726
|
var PHASE_PRODUCTION_BUILD = "phase-production-build";
|
|
567
727
|
function isBuildPhase() {
|
|
568
728
|
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
|
|
@@ -575,6 +735,7 @@ function shouldUseRedis(opts) {
|
|
|
575
735
|
}
|
|
576
736
|
|
|
577
737
|
// src/cache-components/serialize.ts
|
|
738
|
+
init_cjs_shims();
|
|
578
739
|
async function readStreamFully(stream) {
|
|
579
740
|
const reader = stream.getReader();
|
|
580
741
|
const chunks = [];
|
|
@@ -617,6 +778,7 @@ function decodeEnvelope(raw) {
|
|
|
617
778
|
}
|
|
618
779
|
|
|
619
780
|
// src/cache-components/swr.ts
|
|
781
|
+
init_cjs_shims();
|
|
620
782
|
var SECOND_MS = 1e3;
|
|
621
783
|
function partitionEntry(entry, now = Date.now()) {
|
|
622
784
|
const ageMs = now - entry.timestamp;
|
|
@@ -643,7 +805,9 @@ var DEFAULT_KEY_PREFIX = "next-cache:";
|
|
|
643
805
|
var ENTRY_SUFFIX = "entry:";
|
|
644
806
|
var TAG_SUFFIX = "tag:";
|
|
645
807
|
var TAG_EXP_SUFFIX = "tag-expiration:";
|
|
808
|
+
var LOCK_SUFFIX = "lock:";
|
|
646
809
|
var DEFAULT_ABORT_MS = 1500;
|
|
810
|
+
var DEFAULT_LOCK_TTL_SEC = 10;
|
|
647
811
|
var ONE_YEAR_SEC = 60 * 60 * 24 * 365;
|
|
648
812
|
var FALLBACK_TTL_SEC = 3600;
|
|
649
813
|
var TAG_EXP_MARKER_TTL_SEC = 60 * 60 * 24 * 7;
|
|
@@ -666,16 +830,19 @@ function init(opts) {
|
|
|
666
830
|
staleWhileRevalidate: opts.staleWhileRevalidate ?? true,
|
|
667
831
|
hashTag: opts.hashTag ?? false,
|
|
668
832
|
keyPrefix: opts.keyPrefix ?? DEFAULT_KEY_PREFIX,
|
|
833
|
+
singleFlight: opts.singleFlight ?? false,
|
|
834
|
+
singleFlightLockTtlSec: opts.singleFlightLockTtlSec ?? DEFAULT_LOCK_TTL_SEC,
|
|
669
835
|
rest: opts
|
|
670
836
|
},
|
|
671
837
|
logger,
|
|
672
838
|
emit,
|
|
673
839
|
conn,
|
|
674
|
-
memEntries: new MemoryStore(),
|
|
675
|
-
memTags: new MemorySetStore(),
|
|
840
|
+
memEntries: new MemoryStore(opts.memoryMaxEntries),
|
|
841
|
+
memTags: new MemorySetStore(opts.memoryMaxEntries),
|
|
676
842
|
memTagExp: /* @__PURE__ */ new Map(),
|
|
677
843
|
localTagTimestamps: /* @__PURE__ */ new Map(),
|
|
678
|
-
resolveNs: () => resolveBuildNamespace(opts.buildNamespace)
|
|
844
|
+
resolveNs: () => resolveBuildNamespace(opts.buildNamespace),
|
|
845
|
+
instanceId: process.env.HOSTNAME || process.env.ECS_TASK_ID || `pid-${process.pid}`
|
|
679
846
|
};
|
|
680
847
|
}
|
|
681
848
|
function entryKey(state, cacheKey) {
|
|
@@ -702,6 +869,40 @@ function tagExpKey(state, tag) {
|
|
|
702
869
|
state.opts.hashTag
|
|
703
870
|
);
|
|
704
871
|
}
|
|
872
|
+
function lockKey(state, cacheKey) {
|
|
873
|
+
return buildKey(
|
|
874
|
+
`${state.opts.keyPrefix}${LOCK_SUFFIX}`,
|
|
875
|
+
state.resolveNs(),
|
|
876
|
+
cacheKey,
|
|
877
|
+
state.opts.hashTag
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
async function tryAcquireRefreshLock(state, cacheKey) {
|
|
881
|
+
if (!state.opts.singleFlight) return false;
|
|
882
|
+
if (!gateRedis(state)) return false;
|
|
883
|
+
try {
|
|
884
|
+
return await withAbortSignal(
|
|
885
|
+
"cacheHandlers.singleFlight.lock",
|
|
886
|
+
state.opts.abortTimeoutMs,
|
|
887
|
+
async () => {
|
|
888
|
+
const client = await state.conn.getOrConnect();
|
|
889
|
+
if (!client) return false;
|
|
890
|
+
const result = await execLuaScript(
|
|
891
|
+
client,
|
|
892
|
+
"refreshTagLock",
|
|
893
|
+
[lockKey(state, cacheKey)],
|
|
894
|
+
[
|
|
895
|
+
state.instanceId,
|
|
896
|
+
String(state.opts.singleFlightLockTtlSec)
|
|
897
|
+
]
|
|
898
|
+
);
|
|
899
|
+
return result === 1;
|
|
900
|
+
}
|
|
901
|
+
);
|
|
902
|
+
} catch {
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
705
906
|
function resolveTtlSeconds(entry) {
|
|
706
907
|
if (Number.isFinite(entry.expire) && entry.expire > 0) {
|
|
707
908
|
return Math.max(60, Math.ceil(entry.expire));
|
|
@@ -754,6 +955,12 @@ async function getImpl(state, cacheKey, softTags) {
|
|
|
754
955
|
state.emit({ type: "cache.miss", ms: Date.now() - start });
|
|
755
956
|
return void 0;
|
|
756
957
|
}
|
|
958
|
+
try {
|
|
959
|
+
raw = await decompressValue(raw);
|
|
960
|
+
} catch {
|
|
961
|
+
state.emit({ type: "cache.miss", meta: { reason: "decode-error" } });
|
|
962
|
+
return void 0;
|
|
963
|
+
}
|
|
757
964
|
envelope = decodeEnvelope(raw);
|
|
758
965
|
if (!envelope) {
|
|
759
966
|
state.emit({ type: "cache.miss", meta: { reason: "decode-error" } });
|
|
@@ -796,11 +1003,28 @@ async function getImpl(state, cacheKey, softTags) {
|
|
|
796
1003
|
return void 0;
|
|
797
1004
|
}
|
|
798
1005
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1006
|
+
if (partition.freshness === "stale") {
|
|
1007
|
+
if (state.opts.singleFlight) {
|
|
1008
|
+
const isLeader = await tryAcquireRefreshLock(state, cacheKey);
|
|
1009
|
+
state.emit({
|
|
1010
|
+
type: isLeader ? "cache.stale.refresh.leader" : "cache.stale.refresh.follower",
|
|
1011
|
+
ms: Date.now() - start,
|
|
1012
|
+
meta: { freshness: partition.freshness }
|
|
1013
|
+
});
|
|
1014
|
+
} else {
|
|
1015
|
+
state.emit({
|
|
1016
|
+
type: "cache.stale",
|
|
1017
|
+
ms: Date.now() - start,
|
|
1018
|
+
meta: { freshness: partition.freshness }
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
state.emit({
|
|
1023
|
+
type: "cache.hit",
|
|
1024
|
+
ms: Date.now() - start,
|
|
1025
|
+
meta: { freshness: partition.freshness }
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
804
1028
|
return {
|
|
805
1029
|
value: bufferToStream(Buffer.from(envelope.value, "base64")),
|
|
806
1030
|
tags: envelope.tags,
|
|
@@ -865,10 +1089,14 @@ async function setImpl(state, cacheKey, pendingEntry) {
|
|
|
865
1089
|
}
|
|
866
1090
|
return;
|
|
867
1091
|
}
|
|
1092
|
+
const wirePayload = await compressValue(
|
|
1093
|
+
payload,
|
|
1094
|
+
state.opts.rest.compression
|
|
1095
|
+
);
|
|
868
1096
|
if (entry.tags.length === 0) {
|
|
869
|
-
await client.set(eKey,
|
|
1097
|
+
await client.set(eKey, wirePayload, { EX: ttl });
|
|
870
1098
|
} else {
|
|
871
|
-
await luaSetWithTags(client, state, eKey,
|
|
1099
|
+
await luaSetWithTags(client, state, eKey, wirePayload, ttl, entry.tags);
|
|
872
1100
|
}
|
|
873
1101
|
}
|
|
874
1102
|
);
|
|
@@ -904,28 +1132,36 @@ async function refreshTagsImpl(state) {
|
|
|
904
1132
|
async () => {
|
|
905
1133
|
const client = await state.conn.getOrConnect();
|
|
906
1134
|
if (!client) return;
|
|
907
|
-
const
|
|
908
|
-
const
|
|
1135
|
+
const ns = state.opts.hashTag ? `{${state.resolveNs()}}` : state.resolveNs();
|
|
1136
|
+
const pattern = `${escapeMatch(
|
|
1137
|
+
`${state.opts.keyPrefix}${TAG_EXP_SUFFIX}${ns}:`
|
|
1138
|
+
)}*`;
|
|
1139
|
+
const scanStartMs = Date.now();
|
|
1140
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
909
1141
|
for await (const chunk of client.scanIterator({
|
|
910
1142
|
MATCH: pattern,
|
|
911
1143
|
COUNT: 100
|
|
912
1144
|
})) {
|
|
913
1145
|
const keys = Array.isArray(chunk) ? chunk.map(String) : [String(chunk)];
|
|
914
|
-
|
|
915
|
-
|
|
1146
|
+
if (keys.length === 0) continue;
|
|
1147
|
+
const values = await client.mGet(keys);
|
|
1148
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1149
|
+
const v = values[i];
|
|
1150
|
+
if (!v) continue;
|
|
1151
|
+
const ts = Number.parseInt(v, 10);
|
|
1152
|
+
if (!Number.isFinite(ts)) continue;
|
|
1153
|
+
const key = keys[i];
|
|
1154
|
+
if (key === void 0) continue;
|
|
1155
|
+
const tag = stripExpPrefix(state, key);
|
|
1156
|
+
if (tag) fresh.set(tag, ts);
|
|
1157
|
+
}
|
|
916
1158
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
if (!v) continue;
|
|
922
|
-
const ts = Number.parseInt(v, 10);
|
|
923
|
-
if (!Number.isFinite(ts)) continue;
|
|
924
|
-
const key = seen[i];
|
|
925
|
-
if (key === void 0) continue;
|
|
926
|
-
const tag = stripExpPrefix(state, key);
|
|
927
|
-
if (tag) state.localTagTimestamps.set(tag, ts);
|
|
1159
|
+
for (const [tag, ts] of state.localTagTimestamps) {
|
|
1160
|
+
if (ts >= scanStartMs && (fresh.get(tag) ?? 0) < ts) {
|
|
1161
|
+
fresh.set(tag, ts);
|
|
1162
|
+
}
|
|
928
1163
|
}
|
|
1164
|
+
state.localTagTimestamps = fresh;
|
|
929
1165
|
}
|
|
930
1166
|
);
|
|
931
1167
|
} catch (err) {
|
|
@@ -934,6 +1170,19 @@ async function refreshTagsImpl(state) {
|
|
|
934
1170
|
});
|
|
935
1171
|
}
|
|
936
1172
|
}
|
|
1173
|
+
function escapeMatch(s) {
|
|
1174
|
+
return s.replace(/[\\*?[\]]/g, "\\$&");
|
|
1175
|
+
}
|
|
1176
|
+
var MAX_LOCAL_TAG_ENTRIES = 1e4;
|
|
1177
|
+
function pruneOldestByTimestamp(map, maxEntries) {
|
|
1178
|
+
if (map.size <= maxEntries) return;
|
|
1179
|
+
const byAge = [...map.entries()].sort((a, b) => a[1] - b[1]);
|
|
1180
|
+
const drop = map.size - maxEntries;
|
|
1181
|
+
for (let i = 0; i < drop; i += 1) {
|
|
1182
|
+
const entry = byAge[i];
|
|
1183
|
+
if (entry) map.delete(entry[0]);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
937
1186
|
function stripExpPrefix(state, fullKey) {
|
|
938
1187
|
const ns = state.resolveNs();
|
|
939
1188
|
const prefix = state.opts.hashTag ? `${state.opts.keyPrefix}${TAG_EXP_SUFFIX}{${ns}}:` : `${state.opts.keyPrefix}${TAG_EXP_SUFFIX}${ns}:`;
|
|
@@ -985,6 +1234,7 @@ async function updateTagsImpl(state, tags, durations) {
|
|
|
985
1234
|
state.localTagTimestamps.set(t, now);
|
|
986
1235
|
state.memTagExp.set(t, now);
|
|
987
1236
|
}
|
|
1237
|
+
pruneOldestByTimestamp(state.memTagExp, MAX_LOCAL_TAG_ENTRIES);
|
|
988
1238
|
if (!gateRedis(state)) {
|
|
989
1239
|
if (isHardExpire) {
|
|
990
1240
|
for (const t of tags) {
|
|
@@ -1014,20 +1264,18 @@ async function updateTagsImpl(state, tags, durations) {
|
|
|
1014
1264
|
}
|
|
1015
1265
|
return;
|
|
1016
1266
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1267
|
+
await Promise.all(
|
|
1268
|
+
tags.map(
|
|
1269
|
+
(t) => isHardExpire ? execLuaScript(
|
|
1020
1270
|
client,
|
|
1021
1271
|
"revalidateHard",
|
|
1022
1272
|
[tagKey(state, t), tagExpKey(state, t)],
|
|
1023
1273
|
[String(now), String(TAG_EXP_MARKER_TTL_SEC)]
|
|
1024
|
-
)
|
|
1025
|
-
} else {
|
|
1026
|
-
await client.set(tagExpKey(state, t), String(now), {
|
|
1274
|
+
) : client.set(tagExpKey(state, t), String(now), {
|
|
1027
1275
|
EX: TAG_EXP_MARKER_TTL_SEC
|
|
1028
|
-
})
|
|
1029
|
-
|
|
1030
|
-
|
|
1276
|
+
})
|
|
1277
|
+
)
|
|
1278
|
+
);
|
|
1031
1279
|
}
|
|
1032
1280
|
);
|
|
1033
1281
|
state.emit({
|
|
@@ -1057,7 +1305,14 @@ function createCacheComponentsHandler(opts) {
|
|
|
1057
1305
|
};
|
|
1058
1306
|
}
|
|
1059
1307
|
|
|
1308
|
+
// src/incremental/index.ts
|
|
1309
|
+
init_cjs_shims();
|
|
1310
|
+
|
|
1311
|
+
// src/incremental/handler.ts
|
|
1312
|
+
init_cjs_shims();
|
|
1313
|
+
|
|
1060
1314
|
// src/incremental/serialize.ts
|
|
1315
|
+
init_cjs_shims();
|
|
1061
1316
|
function isEnvelope(value) {
|
|
1062
1317
|
return typeof value === "object" && value !== null && "__type" in value && typeof value.__type === "string";
|
|
1063
1318
|
}
|
|
@@ -1139,7 +1394,7 @@ function init2(opts) {
|
|
|
1139
1394
|
logger,
|
|
1140
1395
|
emit,
|
|
1141
1396
|
conn,
|
|
1142
|
-
memEntries: new MemoryStore(),
|
|
1397
|
+
memEntries: new MemoryStore(opts.memoryMaxEntries),
|
|
1143
1398
|
memTagStates: /* @__PURE__ */ new Map(),
|
|
1144
1399
|
resolveNs: () => resolveBuildNamespace(opts.buildNamespace)
|
|
1145
1400
|
};
|
|
@@ -1198,7 +1453,7 @@ function normalizeTtlSeconds(data, ctx) {
|
|
|
1198
1453
|
return ONE_YEAR_SEC2;
|
|
1199
1454
|
}
|
|
1200
1455
|
}
|
|
1201
|
-
const revalidate = ctx?.cacheControl?.revalidate;
|
|
1456
|
+
const revalidate = ctx?.cacheControl?.revalidate ?? ctx?.revalidate;
|
|
1202
1457
|
if (revalidate === false || revalidate === void 0) return ONE_YEAR_SEC2;
|
|
1203
1458
|
if (typeof revalidate === "number" && revalidate > 0) {
|
|
1204
1459
|
return Math.min(Math.max(Math.ceil(revalidate), MIN_TTL_SEC), ONE_YEAR_SEC2);
|
|
@@ -1236,10 +1491,49 @@ async function readTagStates(state, tags) {
|
|
|
1236
1491
|
var IncrementalRedisCacheHandler = class {
|
|
1237
1492
|
state;
|
|
1238
1493
|
revalidatedTags;
|
|
1494
|
+
/**
|
|
1495
|
+
* Request-scoped memo of Redis entry reads. Next.js instantiates this class
|
|
1496
|
+
* per request (and calls resetRequestCache() at request boundaries when it
|
|
1497
|
+
* reuses an instance), so entries live at most one request. Bounded by the
|
|
1498
|
+
* number of distinct cache keys a single request touches.
|
|
1499
|
+
*/
|
|
1500
|
+
requestMemo = /* @__PURE__ */ new Map();
|
|
1239
1501
|
constructor(state, ctx) {
|
|
1240
1502
|
this.state = state;
|
|
1241
1503
|
this.revalidatedTags = normalizeTags(ctx?.revalidatedTags);
|
|
1242
1504
|
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Redis entry read, deduplicated per request: parallel RSC renders or
|
|
1507
|
+
* repeated fetch() calls hitting the same cache key share one GET. The
|
|
1508
|
+
* memoized promise never rejects — errors are converted to a miss (with
|
|
1509
|
+
* the same timeout metric the inline path emitted before).
|
|
1510
|
+
*/
|
|
1511
|
+
readEntryDeduped(eKey) {
|
|
1512
|
+
const memoized = this.requestMemo.get(eKey);
|
|
1513
|
+
if (memoized) {
|
|
1514
|
+
this.state.emit({ type: "cache.get.deduped" });
|
|
1515
|
+
return memoized;
|
|
1516
|
+
}
|
|
1517
|
+
const read = withAbortSignal(
|
|
1518
|
+
"incremental.get",
|
|
1519
|
+
this.state.opts.abortTimeoutMs,
|
|
1520
|
+
async () => {
|
|
1521
|
+
const client = await this.state.conn.getOrConnect();
|
|
1522
|
+
if (!client) return null;
|
|
1523
|
+
return await decompressValue(await client.get(eKey));
|
|
1524
|
+
}
|
|
1525
|
+
).catch((err) => {
|
|
1526
|
+
if (err instanceof CacheTimeoutError) {
|
|
1527
|
+
this.state.emit({
|
|
1528
|
+
type: "redis.timeout",
|
|
1529
|
+
meta: { op: "incremental.get" }
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
return null;
|
|
1533
|
+
});
|
|
1534
|
+
this.requestMemo.set(eKey, read);
|
|
1535
|
+
return read;
|
|
1536
|
+
}
|
|
1243
1537
|
async get(cacheKey, ctx) {
|
|
1244
1538
|
try {
|
|
1245
1539
|
const requestedTags = normalizeTags([
|
|
@@ -1251,24 +1545,11 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1251
1545
|
const useRedis = !useLocal && gateRedis2(this.state);
|
|
1252
1546
|
let raw = null;
|
|
1253
1547
|
if (useRedis) {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
async () => {
|
|
1259
|
-
const client = await this.state.conn.getOrConnect();
|
|
1260
|
-
if (!client) return null;
|
|
1261
|
-
return await client.get(eKey);
|
|
1262
|
-
}
|
|
1263
|
-
);
|
|
1264
|
-
} catch (err) {
|
|
1265
|
-
if (err instanceof CacheTimeoutError) {
|
|
1266
|
-
this.state.emit({ type: "redis.timeout", meta: { op: "incremental.get" } });
|
|
1267
|
-
}
|
|
1268
|
-
raw = null;
|
|
1269
|
-
}
|
|
1548
|
+
raw = await this.readEntryDeduped(eKey);
|
|
1549
|
+
}
|
|
1550
|
+
if (raw === null && (useLocal || this.state.opts.fallback !== "never")) {
|
|
1551
|
+
raw = this.state.memEntries.get(eKey);
|
|
1270
1552
|
}
|
|
1271
|
-
if (raw === null) raw = this.state.memEntries.get(eKey);
|
|
1272
1553
|
if (raw === null) {
|
|
1273
1554
|
this.state.emit({ type: "cache.miss" });
|
|
1274
1555
|
return null;
|
|
@@ -1281,7 +1562,7 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1281
1562
|
return null;
|
|
1282
1563
|
}
|
|
1283
1564
|
const tagStates = await readTagStates(this.state, tags);
|
|
1284
|
-
const isFetch = ctx?.kind === "FETCH";
|
|
1565
|
+
const isFetch = ctx?.kind === "FETCH" || ctx?.kindHint?.toLowerCase() === "fetch" || typeof parsed.value === "object" && parsed.value !== null && parsed.value.kind === "FETCH";
|
|
1285
1566
|
if (tagStates.some((s) => isTagStateExpired(s, parsed.lastModified, isFetch))) {
|
|
1286
1567
|
this.state.emit({ type: "cache.miss", meta: { reason: "tag-state-expired" } });
|
|
1287
1568
|
return null;
|
|
@@ -1304,6 +1585,7 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1304
1585
|
const record = { lastModified: Date.now(), value: data };
|
|
1305
1586
|
const serialized = serializeCacheRecord(record);
|
|
1306
1587
|
const eKey = entryKey2(this.state, cacheKey);
|
|
1588
|
+
this.requestMemo.delete(eKey);
|
|
1307
1589
|
const useRedis = !useLocal && gateRedis2(this.state);
|
|
1308
1590
|
if (useRedis) {
|
|
1309
1591
|
try {
|
|
@@ -1313,10 +1595,19 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1313
1595
|
async () => {
|
|
1314
1596
|
const client = await this.state.conn.getOrConnect();
|
|
1315
1597
|
if (!client) {
|
|
1316
|
-
this.state.
|
|
1598
|
+
if (this.state.opts.fallback !== "never") {
|
|
1599
|
+
this.state.memEntries.set(eKey, serialized, ttl);
|
|
1600
|
+
}
|
|
1317
1601
|
return;
|
|
1318
1602
|
}
|
|
1319
|
-
await client.set(
|
|
1603
|
+
await client.set(
|
|
1604
|
+
eKey,
|
|
1605
|
+
await compressValue(
|
|
1606
|
+
serialized,
|
|
1607
|
+
this.state.opts.rest.compression
|
|
1608
|
+
),
|
|
1609
|
+
{ EX: ttl }
|
|
1610
|
+
);
|
|
1320
1611
|
}
|
|
1321
1612
|
);
|
|
1322
1613
|
this.state.emit({ type: "cache.set", meta: { backend: "redis" } });
|
|
@@ -1327,8 +1618,15 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1327
1618
|
}
|
|
1328
1619
|
}
|
|
1329
1620
|
}
|
|
1330
|
-
this.state.
|
|
1331
|
-
|
|
1621
|
+
if (useLocal || this.state.opts.fallback !== "never") {
|
|
1622
|
+
this.state.memEntries.set(eKey, serialized, ttl);
|
|
1623
|
+
this.state.emit({ type: "cache.set", meta: { backend: "memory" } });
|
|
1624
|
+
} else {
|
|
1625
|
+
this.state.emit({
|
|
1626
|
+
type: "cache.set.failed",
|
|
1627
|
+
meta: { reason: "no-fallback" }
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1332
1630
|
} catch (err) {
|
|
1333
1631
|
this.state.logger.error("set() error", {
|
|
1334
1632
|
message: err.message
|
|
@@ -1382,6 +1680,7 @@ var IncrementalRedisCacheHandler = class {
|
|
|
1382
1680
|
}
|
|
1383
1681
|
}
|
|
1384
1682
|
resetRequestCache() {
|
|
1683
|
+
this.requestMemo.clear();
|
|
1385
1684
|
}
|
|
1386
1685
|
};
|
|
1387
1686
|
function createIncrementalCacheHandler(opts) {
|