@leejpsd/nextjs-cache-handler 0.2.0 → 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 +59 -2
- package/README.md +47 -25
- package/dist/cache-components/index.cjs +235 -46
- 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 +227 -46
- 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 +313 -70
- 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 +305 -70
- 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-Dq1q6qXd.d.cts → types-Bl-rkLKX.d.cts} +37 -1
- package/dist/{types-Dq1q6qXd.d.ts → types-Bl-rkLKX.d.ts} +37 -1
- package/package.json +20 -3
|
@@ -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,26 @@ 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/cache-components/index.ts
|
|
232
|
+
init_cjs_shims();
|
|
233
|
+
|
|
234
|
+
// src/cache-components/handler.ts
|
|
235
|
+
init_cjs_shims();
|
|
236
|
+
|
|
175
237
|
// src/shared/abort.ts
|
|
238
|
+
init_cjs_shims();
|
|
176
239
|
var CacheTimeoutError = class extends Error {
|
|
177
240
|
constructor(opName, ms) {
|
|
178
241
|
super(`[@leejpsd/nextjs-cache-handler] ${opName} timed out after ${ms}ms`);
|
|
@@ -204,7 +267,41 @@ async function withAbortSignal(opName, ms, fn) {
|
|
|
204
267
|
}
|
|
205
268
|
}
|
|
206
269
|
|
|
270
|
+
// src/shared/compress.ts
|
|
271
|
+
init_cjs_shims();
|
|
272
|
+
var gzipAsync = util.promisify(zlib.gzip);
|
|
273
|
+
var gunzipAsync = util.promisify(zlib.gunzip);
|
|
274
|
+
var brotliCompressAsync = util.promisify(zlib.brotliCompress);
|
|
275
|
+
var brotliDecompressAsync = util.promisify(zlib.brotliDecompress);
|
|
276
|
+
var GZIP_MARKER = "__ncgz__:";
|
|
277
|
+
var BROTLI_MARKER = "__ncbr__:";
|
|
278
|
+
var MIN_COMPRESS_BYTES = 1024;
|
|
279
|
+
var BROTLI_OPTS = {
|
|
280
|
+
params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 }
|
|
281
|
+
};
|
|
282
|
+
async function compressValue(value, algo) {
|
|
283
|
+
if (!algo || Buffer.byteLength(value) < MIN_COMPRESS_BYTES) return value;
|
|
284
|
+
const input = Buffer.from(value);
|
|
285
|
+
if (algo === "gzip") {
|
|
286
|
+
return GZIP_MARKER + (await gzipAsync(input)).toString("base64");
|
|
287
|
+
}
|
|
288
|
+
return BROTLI_MARKER + (await brotliCompressAsync(input, BROTLI_OPTS)).toString("base64");
|
|
289
|
+
}
|
|
290
|
+
async function decompressValue(value) {
|
|
291
|
+
if (value === null) return null;
|
|
292
|
+
if (value.startsWith(GZIP_MARKER)) {
|
|
293
|
+
const buf = Buffer.from(value.slice(GZIP_MARKER.length), "base64");
|
|
294
|
+
return (await gunzipAsync(buf)).toString("utf8");
|
|
295
|
+
}
|
|
296
|
+
if (value.startsWith(BROTLI_MARKER)) {
|
|
297
|
+
const buf = Buffer.from(value.slice(BROTLI_MARKER.length), "base64");
|
|
298
|
+
return (await brotliDecompressAsync(buf)).toString("utf8");
|
|
299
|
+
}
|
|
300
|
+
return value;
|
|
301
|
+
}
|
|
302
|
+
|
|
207
303
|
// src/shared/client/index.ts
|
|
304
|
+
init_cjs_shims();
|
|
208
305
|
async function buildClient(source) {
|
|
209
306
|
if (typeof source === "function") {
|
|
210
307
|
return await source();
|
|
@@ -222,6 +319,10 @@ async function buildClient(source) {
|
|
|
222
319
|
const { adaptCluster: adaptCluster2, createIoredisCluster: createIoredisCluster2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
223
320
|
return adaptCluster2(createIoredisCluster2(source));
|
|
224
321
|
}
|
|
322
|
+
case "sentinel": {
|
|
323
|
+
const { adaptIoredis: adaptIoredis2, createIoredisSentinel: createIoredisSentinel2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
324
|
+
return adaptIoredis2(createIoredisSentinel2(source));
|
|
325
|
+
}
|
|
225
326
|
default: {
|
|
226
327
|
const exhaustive = source;
|
|
227
328
|
throw new Error(
|
|
@@ -231,28 +332,45 @@ async function buildClient(source) {
|
|
|
231
332
|
}
|
|
232
333
|
}
|
|
233
334
|
var ConnectionManager = class {
|
|
234
|
-
constructor(source, onError) {
|
|
335
|
+
constructor(source, onError, retry = {}) {
|
|
235
336
|
this.source = source;
|
|
236
337
|
this.onError = onError;
|
|
338
|
+
this.baseCooldownMs = retry.baseCooldownMs ?? 1e3;
|
|
339
|
+
this.maxCooldownMs = retry.maxCooldownMs ?? 3e4;
|
|
237
340
|
}
|
|
238
341
|
source;
|
|
239
342
|
onError;
|
|
240
343
|
client = null;
|
|
241
344
|
connecting = null;
|
|
242
|
-
|
|
345
|
+
consecutiveFailures = 0;
|
|
346
|
+
lastFailureAt = 0;
|
|
347
|
+
baseCooldownMs;
|
|
348
|
+
maxCooldownMs;
|
|
349
|
+
cooldownMs() {
|
|
350
|
+
if (this.consecutiveFailures === 0) return 0;
|
|
351
|
+
return Math.min(
|
|
352
|
+
this.maxCooldownMs,
|
|
353
|
+
this.baseCooldownMs * 2 ** (this.consecutiveFailures - 1)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
243
356
|
async getOrConnect() {
|
|
244
357
|
if (this.client?.isOpen) return this.client;
|
|
245
|
-
if (this.failed) return null;
|
|
246
358
|
if (this.connecting) return this.connecting;
|
|
359
|
+
if (Date.now() - this.lastFailureAt < this.cooldownMs()) return null;
|
|
360
|
+
const stale = this.client;
|
|
361
|
+
this.client = null;
|
|
247
362
|
this.connecting = (async () => {
|
|
363
|
+
disposeQuietly(stale);
|
|
248
364
|
try {
|
|
249
365
|
const c = await buildClient(this.source);
|
|
250
366
|
c.on("error", (err) => this.onError(err));
|
|
251
367
|
if (!c.isOpen) await c.connect();
|
|
252
368
|
this.client = c;
|
|
369
|
+
this.consecutiveFailures = 0;
|
|
253
370
|
return c;
|
|
254
371
|
} catch (err) {
|
|
255
|
-
this.
|
|
372
|
+
this.consecutiveFailures += 1;
|
|
373
|
+
this.lastFailureAt = Date.now();
|
|
256
374
|
this.onError(err);
|
|
257
375
|
return null;
|
|
258
376
|
} finally {
|
|
@@ -262,13 +380,24 @@ var ConnectionManager = class {
|
|
|
262
380
|
return this.connecting;
|
|
263
381
|
}
|
|
264
382
|
reset() {
|
|
383
|
+
disposeQuietly(this.client);
|
|
265
384
|
this.client = null;
|
|
266
385
|
this.connecting = null;
|
|
267
|
-
this.
|
|
386
|
+
this.consecutiveFailures = 0;
|
|
387
|
+
this.lastFailureAt = 0;
|
|
268
388
|
}
|
|
269
389
|
};
|
|
390
|
+
function disposeQuietly(client) {
|
|
391
|
+
if (!client) return;
|
|
392
|
+
const c = client;
|
|
393
|
+
try {
|
|
394
|
+
(c.dispose ?? c.destroy ?? c.disconnect)?.call(c);
|
|
395
|
+
} catch {
|
|
396
|
+
}
|
|
397
|
+
}
|
|
270
398
|
|
|
271
399
|
// src/shared/logger.ts
|
|
400
|
+
init_cjs_shims();
|
|
272
401
|
var defaultLogger = {
|
|
273
402
|
debug: () => {
|
|
274
403
|
},
|
|
@@ -284,6 +413,9 @@ var defaultLogger = {
|
|
|
284
413
|
}
|
|
285
414
|
};
|
|
286
415
|
|
|
416
|
+
// src/shared/lua/index.ts
|
|
417
|
+
init_cjs_shims();
|
|
418
|
+
|
|
287
419
|
// src/shared/lua/set-with-tags.lua
|
|
288
420
|
var set_with_tags_default = `-- set-with-tags.lua
|
|
289
421
|
--
|
|
@@ -387,13 +519,19 @@ async function execLuaScript(client, name, keys, args) {
|
|
|
387
519
|
}
|
|
388
520
|
|
|
389
521
|
// src/shared/memory-fallback.ts
|
|
522
|
+
init_cjs_shims();
|
|
390
523
|
var MAX_TIMER_MS = 2147483647;
|
|
391
524
|
function clampTimerMs(ms) {
|
|
392
525
|
return Math.min(Math.max(0, ms), MAX_TIMER_MS);
|
|
393
526
|
}
|
|
527
|
+
var DEFAULT_MAX_ENTRIES = 1e3;
|
|
394
528
|
var MemoryStore = class {
|
|
395
529
|
kv = /* @__PURE__ */ new Map();
|
|
396
530
|
timers = /* @__PURE__ */ new Map();
|
|
531
|
+
maxEntries;
|
|
532
|
+
constructor(maxEntries = DEFAULT_MAX_ENTRIES) {
|
|
533
|
+
this.maxEntries = Math.max(1, maxEntries);
|
|
534
|
+
}
|
|
397
535
|
set(key, value, ttlSeconds) {
|
|
398
536
|
this.delete(key);
|
|
399
537
|
const expiresAt = Date.now() + ttlSeconds * 1e3;
|
|
@@ -403,6 +541,10 @@ var MemoryStore = class {
|
|
|
403
541
|
timer.unref();
|
|
404
542
|
}
|
|
405
543
|
this.timers.set(key, timer);
|
|
544
|
+
while (this.kv.size > this.maxEntries) {
|
|
545
|
+
const oldest = this.kv.keys().next().value;
|
|
546
|
+
this.delete(oldest);
|
|
547
|
+
}
|
|
406
548
|
}
|
|
407
549
|
get(key) {
|
|
408
550
|
const entry = this.kv.get(key);
|
|
@@ -411,6 +553,8 @@ var MemoryStore = class {
|
|
|
411
553
|
this.delete(key);
|
|
412
554
|
return null;
|
|
413
555
|
}
|
|
556
|
+
this.kv.delete(key);
|
|
557
|
+
this.kv.set(key, entry);
|
|
414
558
|
return entry.value;
|
|
415
559
|
}
|
|
416
560
|
delete(key) {
|
|
@@ -445,13 +589,19 @@ var MemorySetStore = class {
|
|
|
445
589
|
sets = /* @__PURE__ */ new Map();
|
|
446
590
|
expiresAt = /* @__PURE__ */ new Map();
|
|
447
591
|
timers = /* @__PURE__ */ new Map();
|
|
592
|
+
maxSets;
|
|
593
|
+
constructor(maxSets = DEFAULT_MAX_ENTRIES) {
|
|
594
|
+
this.maxSets = Math.max(1, maxSets);
|
|
595
|
+
}
|
|
448
596
|
sAdd(key, member) {
|
|
449
597
|
const members = Array.isArray(member) ? member : [member];
|
|
450
598
|
let set = this.sets.get(key);
|
|
451
599
|
if (!set) {
|
|
452
600
|
set = /* @__PURE__ */ new Set();
|
|
453
|
-
|
|
601
|
+
} else {
|
|
602
|
+
this.sets.delete(key);
|
|
454
603
|
}
|
|
604
|
+
this.sets.set(key, set);
|
|
455
605
|
let added = 0;
|
|
456
606
|
for (const m of members) {
|
|
457
607
|
if (!set.has(m)) {
|
|
@@ -459,6 +609,10 @@ var MemorySetStore = class {
|
|
|
459
609
|
added += 1;
|
|
460
610
|
}
|
|
461
611
|
}
|
|
612
|
+
while (this.sets.size > this.maxSets) {
|
|
613
|
+
const oldest = this.sets.keys().next().value;
|
|
614
|
+
this.delete(oldest);
|
|
615
|
+
}
|
|
462
616
|
return added;
|
|
463
617
|
}
|
|
464
618
|
sMembers(key) {
|
|
@@ -511,6 +665,7 @@ var MemorySetStore = class {
|
|
|
511
665
|
};
|
|
512
666
|
|
|
513
667
|
// src/shared/metrics.ts
|
|
668
|
+
init_cjs_shims();
|
|
514
669
|
var counters = /* @__PURE__ */ new Map();
|
|
515
670
|
function bump(event) {
|
|
516
671
|
const existing = counters.get(event.type);
|
|
@@ -539,6 +694,7 @@ function createEmitter(onMetric) {
|
|
|
539
694
|
}
|
|
540
695
|
|
|
541
696
|
// src/shared/namespace.ts
|
|
697
|
+
init_cjs_shims();
|
|
542
698
|
var FALLBACK = "unversioned";
|
|
543
699
|
function resolveBuildNamespace(override) {
|
|
544
700
|
if (override !== void 0) {
|
|
@@ -552,6 +708,7 @@ function buildKey(prefix, namespace, rest, hashTag = false) {
|
|
|
552
708
|
}
|
|
553
709
|
|
|
554
710
|
// src/shared/build-phase.ts
|
|
711
|
+
init_cjs_shims();
|
|
555
712
|
var PHASE_PRODUCTION_BUILD = "phase-production-build";
|
|
556
713
|
function isBuildPhase() {
|
|
557
714
|
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
|
|
@@ -564,6 +721,7 @@ function shouldUseRedis(opts) {
|
|
|
564
721
|
}
|
|
565
722
|
|
|
566
723
|
// src/cache-components/serialize.ts
|
|
724
|
+
init_cjs_shims();
|
|
567
725
|
async function readStreamFully(stream) {
|
|
568
726
|
const reader = stream.getReader();
|
|
569
727
|
const chunks = [];
|
|
@@ -606,6 +764,7 @@ function decodeEnvelope(raw) {
|
|
|
606
764
|
}
|
|
607
765
|
|
|
608
766
|
// src/cache-components/swr.ts
|
|
767
|
+
init_cjs_shims();
|
|
609
768
|
var SECOND_MS = 1e3;
|
|
610
769
|
function partitionEntry(entry, now = Date.now()) {
|
|
611
770
|
const ageMs = now - entry.timestamp;
|
|
@@ -664,8 +823,8 @@ function init(opts) {
|
|
|
664
823
|
logger,
|
|
665
824
|
emit,
|
|
666
825
|
conn,
|
|
667
|
-
memEntries: new MemoryStore(),
|
|
668
|
-
memTags: new MemorySetStore(),
|
|
826
|
+
memEntries: new MemoryStore(opts.memoryMaxEntries),
|
|
827
|
+
memTags: new MemorySetStore(opts.memoryMaxEntries),
|
|
669
828
|
memTagExp: /* @__PURE__ */ new Map(),
|
|
670
829
|
localTagTimestamps: /* @__PURE__ */ new Map(),
|
|
671
830
|
resolveNs: () => resolveBuildNamespace(opts.buildNamespace),
|
|
@@ -782,6 +941,12 @@ async function getImpl(state, cacheKey, softTags) {
|
|
|
782
941
|
state.emit({ type: "cache.miss", ms: Date.now() - start });
|
|
783
942
|
return void 0;
|
|
784
943
|
}
|
|
944
|
+
try {
|
|
945
|
+
raw = await decompressValue(raw);
|
|
946
|
+
} catch {
|
|
947
|
+
state.emit({ type: "cache.miss", meta: { reason: "decode-error" } });
|
|
948
|
+
return void 0;
|
|
949
|
+
}
|
|
785
950
|
envelope = decodeEnvelope(raw);
|
|
786
951
|
if (!envelope) {
|
|
787
952
|
state.emit({ type: "cache.miss", meta: { reason: "decode-error" } });
|
|
@@ -910,10 +1075,14 @@ async function setImpl(state, cacheKey, pendingEntry) {
|
|
|
910
1075
|
}
|
|
911
1076
|
return;
|
|
912
1077
|
}
|
|
1078
|
+
const wirePayload = await compressValue(
|
|
1079
|
+
payload,
|
|
1080
|
+
state.opts.rest.compression
|
|
1081
|
+
);
|
|
913
1082
|
if (entry.tags.length === 0) {
|
|
914
|
-
await client.set(eKey,
|
|
1083
|
+
await client.set(eKey, wirePayload, { EX: ttl });
|
|
915
1084
|
} else {
|
|
916
|
-
await luaSetWithTags(client, state, eKey,
|
|
1085
|
+
await luaSetWithTags(client, state, eKey, wirePayload, ttl, entry.tags);
|
|
917
1086
|
}
|
|
918
1087
|
}
|
|
919
1088
|
);
|
|
@@ -949,28 +1118,36 @@ async function refreshTagsImpl(state) {
|
|
|
949
1118
|
async () => {
|
|
950
1119
|
const client = await state.conn.getOrConnect();
|
|
951
1120
|
if (!client) return;
|
|
952
|
-
const
|
|
953
|
-
const
|
|
1121
|
+
const ns = state.opts.hashTag ? `{${state.resolveNs()}}` : state.resolveNs();
|
|
1122
|
+
const pattern = `${escapeMatch(
|
|
1123
|
+
`${state.opts.keyPrefix}${TAG_EXP_SUFFIX}${ns}:`
|
|
1124
|
+
)}*`;
|
|
1125
|
+
const scanStartMs = Date.now();
|
|
1126
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
954
1127
|
for await (const chunk of client.scanIterator({
|
|
955
1128
|
MATCH: pattern,
|
|
956
1129
|
COUNT: 100
|
|
957
1130
|
})) {
|
|
958
1131
|
const keys = Array.isArray(chunk) ? chunk.map(String) : [String(chunk)];
|
|
959
|
-
|
|
960
|
-
|
|
1132
|
+
if (keys.length === 0) continue;
|
|
1133
|
+
const values = await client.mGet(keys);
|
|
1134
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
1135
|
+
const v = values[i];
|
|
1136
|
+
if (!v) continue;
|
|
1137
|
+
const ts = Number.parseInt(v, 10);
|
|
1138
|
+
if (!Number.isFinite(ts)) continue;
|
|
1139
|
+
const key = keys[i];
|
|
1140
|
+
if (key === void 0) continue;
|
|
1141
|
+
const tag = stripExpPrefix(state, key);
|
|
1142
|
+
if (tag) fresh.set(tag, ts);
|
|
1143
|
+
}
|
|
961
1144
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
if (!v) continue;
|
|
967
|
-
const ts = Number.parseInt(v, 10);
|
|
968
|
-
if (!Number.isFinite(ts)) continue;
|
|
969
|
-
const key = seen[i];
|
|
970
|
-
if (key === void 0) continue;
|
|
971
|
-
const tag = stripExpPrefix(state, key);
|
|
972
|
-
if (tag) state.localTagTimestamps.set(tag, ts);
|
|
1145
|
+
for (const [tag, ts] of state.localTagTimestamps) {
|
|
1146
|
+
if (ts >= scanStartMs && (fresh.get(tag) ?? 0) < ts) {
|
|
1147
|
+
fresh.set(tag, ts);
|
|
1148
|
+
}
|
|
973
1149
|
}
|
|
1150
|
+
state.localTagTimestamps = fresh;
|
|
974
1151
|
}
|
|
975
1152
|
);
|
|
976
1153
|
} catch (err) {
|
|
@@ -979,6 +1156,19 @@ async function refreshTagsImpl(state) {
|
|
|
979
1156
|
});
|
|
980
1157
|
}
|
|
981
1158
|
}
|
|
1159
|
+
function escapeMatch(s) {
|
|
1160
|
+
return s.replace(/[\\*?[\]]/g, "\\$&");
|
|
1161
|
+
}
|
|
1162
|
+
var MAX_LOCAL_TAG_ENTRIES = 1e4;
|
|
1163
|
+
function pruneOldestByTimestamp(map, maxEntries) {
|
|
1164
|
+
if (map.size <= maxEntries) return;
|
|
1165
|
+
const byAge = [...map.entries()].sort((a, b) => a[1] - b[1]);
|
|
1166
|
+
const drop = map.size - maxEntries;
|
|
1167
|
+
for (let i = 0; i < drop; i += 1) {
|
|
1168
|
+
const entry = byAge[i];
|
|
1169
|
+
if (entry) map.delete(entry[0]);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
982
1172
|
function stripExpPrefix(state, fullKey) {
|
|
983
1173
|
const ns = state.resolveNs();
|
|
984
1174
|
const prefix = state.opts.hashTag ? `${state.opts.keyPrefix}${TAG_EXP_SUFFIX}{${ns}}:` : `${state.opts.keyPrefix}${TAG_EXP_SUFFIX}${ns}:`;
|
|
@@ -1030,6 +1220,7 @@ async function updateTagsImpl(state, tags, durations) {
|
|
|
1030
1220
|
state.localTagTimestamps.set(t, now);
|
|
1031
1221
|
state.memTagExp.set(t, now);
|
|
1032
1222
|
}
|
|
1223
|
+
pruneOldestByTimestamp(state.memTagExp, MAX_LOCAL_TAG_ENTRIES);
|
|
1033
1224
|
if (!gateRedis(state)) {
|
|
1034
1225
|
if (isHardExpire) {
|
|
1035
1226
|
for (const t of tags) {
|
|
@@ -1059,20 +1250,18 @@ async function updateTagsImpl(state, tags, durations) {
|
|
|
1059
1250
|
}
|
|
1060
1251
|
return;
|
|
1061
1252
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1253
|
+
await Promise.all(
|
|
1254
|
+
tags.map(
|
|
1255
|
+
(t) => isHardExpire ? execLuaScript(
|
|
1065
1256
|
client,
|
|
1066
1257
|
"revalidateHard",
|
|
1067
1258
|
[tagKey(state, t), tagExpKey(state, t)],
|
|
1068
1259
|
[String(now), String(TAG_EXP_MARKER_TTL_SEC)]
|
|
1069
|
-
)
|
|
1070
|
-
} else {
|
|
1071
|
-
await client.set(tagExpKey(state, t), String(now), {
|
|
1260
|
+
) : client.set(tagExpKey(state, t), String(now), {
|
|
1072
1261
|
EX: TAG_EXP_MARKER_TTL_SEC
|
|
1073
|
-
})
|
|
1074
|
-
|
|
1075
|
-
|
|
1262
|
+
})
|
|
1263
|
+
)
|
|
1264
|
+
);
|
|
1076
1265
|
}
|
|
1077
1266
|
);
|
|
1078
1267
|
state.emit({
|