@leejpsd/nextjs-cache-handler 0.3.4 → 0.4.1
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 +42 -0
- package/README.md +10 -3
- package/bin/cli.cjs +10 -0
- package/dist/cache-components/index.cjs +150 -4
- 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 +150 -4
- package/dist/cache-components/index.js.map +1 -1
- package/dist/cli/index.cjs +938 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +28 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.js +928 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/incremental/index.cjs +81 -6
- package/dist/incremental/index.cjs.map +1 -1
- package/dist/incremental/index.d.cts +1 -1
- package/dist/incremental/index.d.ts +1 -1
- package/dist/incremental/index.js +81 -6
- package/dist/incremental/index.js.map +1 -1
- package/dist/index.cjs +157 -8
- 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 +157 -8
- 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.d.cts +1 -1
- package/dist/otel/index.d.ts +1 -1
- package/dist/seed/index.cjs +561 -0
- package/dist/seed/index.cjs.map +1 -0
- package/dist/seed/index.d.cts +53 -0
- package/dist/seed/index.d.ts +53 -0
- package/dist/seed/index.js +550 -0
- package/dist/seed/index.js.map +1 -0
- package/dist/shared/client/adapter-ioredis.cjs +40 -1
- package/dist/shared/client/adapter-ioredis.cjs.map +1 -1
- package/dist/shared/client/adapter-ioredis.d.cts +1 -1
- package/dist/shared/client/adapter-ioredis.d.ts +1 -1
- package/dist/shared/client/adapter-ioredis.js +40 -1
- package/dist/shared/client/adapter-ioredis.js.map +1 -1
- package/dist/shared/client/adapter-redis.cjs +34 -1
- 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 +34 -1
- package/dist/shared/client/adapter-redis.js.map +1 -1
- package/dist/{types-Bl-rkLKX.d.cts → types-C1vJ_sED.d.cts} +25 -1
- package/dist/{types-Bl-rkLKX.d.ts → types-C1vJ_sED.d.ts} +25 -1
- package/package.json +22 -2
- package/setup-instructions/setup.md +31 -9
- package/skills/nextjs-redis-cache/SKILL.md +15 -0
package/dist/ops/index.d.cts
CHANGED
package/dist/ops/index.d.ts
CHANGED
package/dist/otel/index.d.cts
CHANGED
package/dist/otel/index.d.ts
CHANGED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var module$1 = require('module');
|
|
4
|
+
var path2 = require('path');
|
|
5
|
+
var fs = require('fs');
|
|
6
|
+
var util = require('util');
|
|
7
|
+
var zlib = require('zlib');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
12
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
13
|
+
|
|
14
|
+
var __defProp = Object.defineProperty;
|
|
15
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
16
|
+
var __esm = (fn, res) => function __init() {
|
|
17
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
25
|
+
var getImportMetaUrl, importMetaUrl;
|
|
26
|
+
var init_cjs_shims = __esm({
|
|
27
|
+
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
28
|
+
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;
|
|
29
|
+
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
function nodeRequire(id) {
|
|
33
|
+
try {
|
|
34
|
+
return packageRequire(id);
|
|
35
|
+
} catch {
|
|
36
|
+
return cwdRequire(id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
var packageRequire, cwdRequire;
|
|
40
|
+
var init_node_require = __esm({
|
|
41
|
+
"src/shared/node-require.ts"() {
|
|
42
|
+
init_cjs_shims();
|
|
43
|
+
packageRequire = module$1.createRequire(importMetaUrl);
|
|
44
|
+
cwdRequire = module$1.createRequire(
|
|
45
|
+
path2__default.default.join(process.cwd(), "__resolve-anchor__.js")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// src/shared/client/adapter-redis.ts
|
|
51
|
+
var adapter_redis_exports = {};
|
|
52
|
+
__export(adapter_redis_exports, {
|
|
53
|
+
adaptRedisV5: () => adaptRedisV5,
|
|
54
|
+
createRedisV5Client: () => createRedisV5Client
|
|
55
|
+
});
|
|
56
|
+
function adaptRedisV5(client) {
|
|
57
|
+
const like = client;
|
|
58
|
+
like.dispose = () => {
|
|
59
|
+
try {
|
|
60
|
+
client.destroy();
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
like.subscribe = async (channel, onMessage, onDown) => {
|
|
65
|
+
const sub = client.duplicate();
|
|
66
|
+
const teardown = () => {
|
|
67
|
+
try {
|
|
68
|
+
sub.destroy();
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
let down = false;
|
|
73
|
+
const markDown = () => {
|
|
74
|
+
if (down) return;
|
|
75
|
+
down = true;
|
|
76
|
+
teardown();
|
|
77
|
+
onDown?.();
|
|
78
|
+
};
|
|
79
|
+
sub.on("error", markDown);
|
|
80
|
+
sub.on("end", markDown);
|
|
81
|
+
try {
|
|
82
|
+
await sub.connect();
|
|
83
|
+
await sub.subscribe(channel, (message) => onMessage(message));
|
|
84
|
+
} catch (err) {
|
|
85
|
+
teardown();
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
return async () => teardown();
|
|
89
|
+
};
|
|
90
|
+
return like;
|
|
91
|
+
}
|
|
92
|
+
function createRedisV5Client(config) {
|
|
93
|
+
const { createClient } = nodeRequire("redis");
|
|
94
|
+
const useTls = config.tls ?? config.url.startsWith("rediss://");
|
|
95
|
+
const opts = {
|
|
96
|
+
url: config.url,
|
|
97
|
+
socket: {
|
|
98
|
+
connectTimeout: config.connectTimeout ?? 1500,
|
|
99
|
+
reconnectStrategy: false,
|
|
100
|
+
...useTls ? { tls: true } : {}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
if (config.password !== void 0) opts.password = config.password;
|
|
104
|
+
return createClient(opts);
|
|
105
|
+
}
|
|
106
|
+
var init_adapter_redis = __esm({
|
|
107
|
+
"src/shared/client/adapter-redis.ts"() {
|
|
108
|
+
init_cjs_shims();
|
|
109
|
+
init_node_require();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// src/shared/client/adapter-ioredis.ts
|
|
114
|
+
var adapter_ioredis_exports = {};
|
|
115
|
+
__export(adapter_ioredis_exports, {
|
|
116
|
+
adaptCluster: () => adaptCluster,
|
|
117
|
+
adaptIoredis: () => adaptIoredis,
|
|
118
|
+
createIoredisClient: () => createIoredisClient,
|
|
119
|
+
createIoredisCluster: () => createIoredisCluster,
|
|
120
|
+
createIoredisSentinel: () => createIoredisSentinel
|
|
121
|
+
});
|
|
122
|
+
function adapt(client, isClusterClient = false) {
|
|
123
|
+
return {
|
|
124
|
+
get isOpen() {
|
|
125
|
+
return client.status === "ready";
|
|
126
|
+
},
|
|
127
|
+
connect: async () => {
|
|
128
|
+
if (client.status !== "ready" && client.status !== "connecting") {
|
|
129
|
+
await client.connect();
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
get: (k) => client.get(k),
|
|
133
|
+
set: (k, v, opts) => {
|
|
134
|
+
const args = [];
|
|
135
|
+
if (opts?.EX !== void 0) args.push("EX", opts.EX);
|
|
136
|
+
if (opts?.NX) args.push("NX");
|
|
137
|
+
return client.set(k, v, ...args);
|
|
138
|
+
},
|
|
139
|
+
del: async (keys) => {
|
|
140
|
+
const arr = Array.isArray(keys) ? keys : [keys];
|
|
141
|
+
if (arr.length === 0) return 0;
|
|
142
|
+
return client.del(...arr);
|
|
143
|
+
},
|
|
144
|
+
sAdd: async (k, m) => {
|
|
145
|
+
const arr = Array.isArray(m) ? m : [m];
|
|
146
|
+
if (arr.length === 0) return 0;
|
|
147
|
+
return client.sadd(k, ...arr);
|
|
148
|
+
},
|
|
149
|
+
sMembers: (k) => client.smembers(k),
|
|
150
|
+
expire: async (k, s) => {
|
|
151
|
+
const r = await client.expire(k, s);
|
|
152
|
+
return r;
|
|
153
|
+
},
|
|
154
|
+
mGet: async (keys) => {
|
|
155
|
+
if (keys.length === 0) return [];
|
|
156
|
+
return client.mget(...keys);
|
|
157
|
+
},
|
|
158
|
+
eval: (script, opts) => client.eval(
|
|
159
|
+
script,
|
|
160
|
+
opts.keys.length,
|
|
161
|
+
...opts.keys,
|
|
162
|
+
...opts.arguments
|
|
163
|
+
),
|
|
164
|
+
evalSha: (sha, opts) => client.evalsha(
|
|
165
|
+
sha,
|
|
166
|
+
opts.keys.length,
|
|
167
|
+
...opts.keys,
|
|
168
|
+
...opts.arguments
|
|
169
|
+
),
|
|
170
|
+
scriptLoad: async (script) => await client.script("LOAD", script),
|
|
171
|
+
scanIterator: async function* ({ MATCH, COUNT }) {
|
|
172
|
+
if (isClusterClient) {
|
|
173
|
+
const cluster = client;
|
|
174
|
+
for (const node of cluster.nodes("master")) {
|
|
175
|
+
let cursor = "0";
|
|
176
|
+
do {
|
|
177
|
+
const [next, batch] = await node.scan(
|
|
178
|
+
cursor,
|
|
179
|
+
"MATCH",
|
|
180
|
+
MATCH,
|
|
181
|
+
"COUNT",
|
|
182
|
+
COUNT ?? 100
|
|
183
|
+
);
|
|
184
|
+
cursor = next;
|
|
185
|
+
if (batch.length > 0) yield batch;
|
|
186
|
+
} while (cursor !== "0");
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
const redis = client;
|
|
190
|
+
let cursor = "0";
|
|
191
|
+
do {
|
|
192
|
+
const [next, batch] = await redis.scan(
|
|
193
|
+
cursor,
|
|
194
|
+
"MATCH",
|
|
195
|
+
MATCH,
|
|
196
|
+
"COUNT",
|
|
197
|
+
COUNT ?? 100
|
|
198
|
+
);
|
|
199
|
+
cursor = next;
|
|
200
|
+
if (batch.length > 0) yield batch;
|
|
201
|
+
} while (cursor !== "0");
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
ping: () => client.ping(),
|
|
205
|
+
on: (event, listener) => {
|
|
206
|
+
client.on(event, listener);
|
|
207
|
+
return client;
|
|
208
|
+
},
|
|
209
|
+
publish: (channel, message) => client.publish(channel, message),
|
|
210
|
+
...isClusterClient ? {} : {
|
|
211
|
+
subscribe: async (channel, onMessage, onDown) => {
|
|
212
|
+
const sub = client.duplicate();
|
|
213
|
+
let down = false;
|
|
214
|
+
const markDown = () => {
|
|
215
|
+
if (down) return;
|
|
216
|
+
down = true;
|
|
217
|
+
try {
|
|
218
|
+
sub.disconnect();
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
onDown?.();
|
|
222
|
+
};
|
|
223
|
+
sub.on("error", markDown);
|
|
224
|
+
sub.on("end", markDown);
|
|
225
|
+
try {
|
|
226
|
+
if (sub.status !== "ready" && sub.status !== "connecting") {
|
|
227
|
+
await sub.connect();
|
|
228
|
+
}
|
|
229
|
+
await sub.subscribe(channel);
|
|
230
|
+
} catch (err) {
|
|
231
|
+
markDown();
|
|
232
|
+
throw err;
|
|
233
|
+
}
|
|
234
|
+
sub.on("message", (ch, message) => {
|
|
235
|
+
if (ch === channel) onMessage(message);
|
|
236
|
+
});
|
|
237
|
+
return async () => {
|
|
238
|
+
down = true;
|
|
239
|
+
sub.disconnect();
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
dispose: () => {
|
|
244
|
+
client.disconnect();
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function adaptIoredis(client) {
|
|
249
|
+
return adapt(client, false);
|
|
250
|
+
}
|
|
251
|
+
function adaptCluster(cluster) {
|
|
252
|
+
return adapt(cluster, true);
|
|
253
|
+
}
|
|
254
|
+
function createIoredisClient(config) {
|
|
255
|
+
const IORedis = nodeRequire("ioredis");
|
|
256
|
+
const Ctor = IORedis.default ?? IORedis;
|
|
257
|
+
return new Ctor(config.url, {
|
|
258
|
+
password: config.password,
|
|
259
|
+
connectTimeout: config.connectTimeout ?? 1500,
|
|
260
|
+
tls: config.tls ? {} : void 0,
|
|
261
|
+
lazyConnect: true,
|
|
262
|
+
maxRetriesPerRequest: 1,
|
|
263
|
+
// Batch same-tick commands into one RTT (matches redis@5's default
|
|
264
|
+
// behavior) — makes Promise.all fan-outs a single pipeline.
|
|
265
|
+
enableAutoPipelining: true
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
function createIoredisSentinel(config) {
|
|
269
|
+
const IORedis = nodeRequire("ioredis");
|
|
270
|
+
const Ctor = IORedis.default ?? IORedis;
|
|
271
|
+
return new Ctor({
|
|
272
|
+
sentinels: config.sentinels,
|
|
273
|
+
name: config.name,
|
|
274
|
+
password: config.password,
|
|
275
|
+
sentinelPassword: config.sentinelPassword,
|
|
276
|
+
connectTimeout: config.connectTimeout ?? 1500,
|
|
277
|
+
tls: config.tls ? {} : void 0,
|
|
278
|
+
lazyConnect: true,
|
|
279
|
+
maxRetriesPerRequest: 1,
|
|
280
|
+
enableAutoPipelining: true
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function createIoredisCluster(config) {
|
|
284
|
+
const IORedis = nodeRequire("ioredis");
|
|
285
|
+
const ClusterCtor = IORedis.Cluster ?? IORedis.default.Cluster;
|
|
286
|
+
return new ClusterCtor(config.nodes, {
|
|
287
|
+
redisOptions: {
|
|
288
|
+
password: config.password,
|
|
289
|
+
tls: config.tls ? {} : void 0
|
|
290
|
+
},
|
|
291
|
+
enableReadyCheck: true,
|
|
292
|
+
lazyConnect: true,
|
|
293
|
+
// Same-slot commands issued in the same tick share one pipeline.
|
|
294
|
+
enableAutoPipelining: true
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
var init_adapter_ioredis = __esm({
|
|
298
|
+
"src/shared/client/adapter-ioredis.ts"() {
|
|
299
|
+
init_cjs_shims();
|
|
300
|
+
init_node_require();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// src/seed/index.ts
|
|
305
|
+
init_cjs_shims();
|
|
306
|
+
|
|
307
|
+
// src/shared/client/index.ts
|
|
308
|
+
init_cjs_shims();
|
|
309
|
+
async function buildClient(source) {
|
|
310
|
+
if (typeof source === "function") {
|
|
311
|
+
return await source();
|
|
312
|
+
}
|
|
313
|
+
switch (source.type) {
|
|
314
|
+
case "redis": {
|
|
315
|
+
const { adaptRedisV5: adaptRedisV52, createRedisV5Client: createRedisV5Client2 } = await Promise.resolve().then(() => (init_adapter_redis(), adapter_redis_exports));
|
|
316
|
+
return adaptRedisV52(createRedisV5Client2(source));
|
|
317
|
+
}
|
|
318
|
+
case "ioredis": {
|
|
319
|
+
const { adaptIoredis: adaptIoredis2, createIoredisClient: createIoredisClient2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
320
|
+
return adaptIoredis2(createIoredisClient2(source));
|
|
321
|
+
}
|
|
322
|
+
case "cluster": {
|
|
323
|
+
const { adaptCluster: adaptCluster2, createIoredisCluster: createIoredisCluster2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
324
|
+
return adaptCluster2(createIoredisCluster2(source));
|
|
325
|
+
}
|
|
326
|
+
case "sentinel": {
|
|
327
|
+
const { adaptIoredis: adaptIoredis2, createIoredisSentinel: createIoredisSentinel2 } = await Promise.resolve().then(() => (init_adapter_ioredis(), adapter_ioredis_exports));
|
|
328
|
+
return adaptIoredis2(createIoredisSentinel2(source));
|
|
329
|
+
}
|
|
330
|
+
default: {
|
|
331
|
+
const exhaustive = source;
|
|
332
|
+
throw new Error(
|
|
333
|
+
`[next-cache] unknown client config: ${JSON.stringify(exhaustive)}`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/shared/compress.ts
|
|
340
|
+
init_cjs_shims();
|
|
341
|
+
var gzipAsync = util.promisify(zlib.gzip);
|
|
342
|
+
util.promisify(zlib.gunzip);
|
|
343
|
+
var brotliCompressAsync = util.promisify(zlib.brotliCompress);
|
|
344
|
+
util.promisify(zlib.brotliDecompress);
|
|
345
|
+
var GZIP_MARKER = "__ncgz__:";
|
|
346
|
+
var BROTLI_MARKER = "__ncbr__:";
|
|
347
|
+
var MIN_COMPRESS_BYTES = 1024;
|
|
348
|
+
var BROTLI_OPTS = {
|
|
349
|
+
params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 }
|
|
350
|
+
};
|
|
351
|
+
async function compressValue(value, algo) {
|
|
352
|
+
if (!algo || Buffer.byteLength(value) < MIN_COMPRESS_BYTES) return value;
|
|
353
|
+
const input = Buffer.from(value);
|
|
354
|
+
if (algo === "gzip") {
|
|
355
|
+
return GZIP_MARKER + (await gzipAsync(input)).toString("base64");
|
|
356
|
+
}
|
|
357
|
+
return BROTLI_MARKER + (await brotliCompressAsync(input, BROTLI_OPTS)).toString("base64");
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/shared/namespace.ts
|
|
361
|
+
init_cjs_shims();
|
|
362
|
+
var FALLBACK = "unversioned";
|
|
363
|
+
function resolveBuildNamespace(override) {
|
|
364
|
+
if (override !== void 0) {
|
|
365
|
+
return typeof override === "function" ? override() : override;
|
|
366
|
+
}
|
|
367
|
+
return process.env.DEPLOYMENT_VERSION ?? process.env.GIT_HASH ?? process.env.NEXT_DEPLOYMENT_ID ?? FALLBACK;
|
|
368
|
+
}
|
|
369
|
+
function buildKey(prefix, namespace, rest, hashTag = false) {
|
|
370
|
+
const ns = hashTag ? `{${namespace}}` : namespace;
|
|
371
|
+
return `${prefix}${ns}:${rest}`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/incremental/serialize.ts
|
|
375
|
+
init_cjs_shims();
|
|
376
|
+
function replacer(key, value) {
|
|
377
|
+
const raw = this[key];
|
|
378
|
+
if (Buffer.isBuffer(raw)) {
|
|
379
|
+
const env = {
|
|
380
|
+
__type: "Buffer",
|
|
381
|
+
data: raw.toString("base64")
|
|
382
|
+
};
|
|
383
|
+
return env;
|
|
384
|
+
}
|
|
385
|
+
if (value instanceof Map) {
|
|
386
|
+
const env = {
|
|
387
|
+
__type: "Map",
|
|
388
|
+
entries: Array.from(value.entries())
|
|
389
|
+
};
|
|
390
|
+
return env;
|
|
391
|
+
}
|
|
392
|
+
return value;
|
|
393
|
+
}
|
|
394
|
+
function serializeCacheRecord(record) {
|
|
395
|
+
return JSON.stringify(record, replacer);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/seed/index.ts
|
|
399
|
+
var ONE_YEAR_SEC = 60 * 60 * 24 * 365;
|
|
400
|
+
var MIN_TTL_SEC = 60;
|
|
401
|
+
var DEFAULT_KEY_PREFIX = "next-incremental:";
|
|
402
|
+
function clampTtl(revalidate) {
|
|
403
|
+
if (revalidate === false || revalidate === void 0) return ONE_YEAR_SEC;
|
|
404
|
+
if (typeof revalidate === "number" && revalidate > 0) {
|
|
405
|
+
return Math.min(Math.max(Math.ceil(revalidate), MIN_TTL_SEC), ONE_YEAR_SEC);
|
|
406
|
+
}
|
|
407
|
+
return MIN_TTL_SEC;
|
|
408
|
+
}
|
|
409
|
+
function routeToFileBase(route) {
|
|
410
|
+
return route === "/" ? "/index" : route;
|
|
411
|
+
}
|
|
412
|
+
function readMeta(file) {
|
|
413
|
+
try {
|
|
414
|
+
return JSON.parse(fs__default.default.readFileSync(file, "utf8"));
|
|
415
|
+
} catch {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
async function writeRecord(client, key, value, revalidateSec, opts) {
|
|
420
|
+
const record = {
|
|
421
|
+
lastModified: Date.now(),
|
|
422
|
+
value,
|
|
423
|
+
revalidateSec: clampTtl(revalidateSec)
|
|
424
|
+
};
|
|
425
|
+
const redisKey = buildKey(`${opts.keyPrefix}entry:`, opts.ns, key, opts.hashTag);
|
|
426
|
+
const payload = await compressValue(
|
|
427
|
+
serializeCacheRecord(record),
|
|
428
|
+
opts.compression
|
|
429
|
+
);
|
|
430
|
+
const result = await client.set(redisKey, payload, {
|
|
431
|
+
EX: clampTtl(revalidateSec),
|
|
432
|
+
NX: true
|
|
433
|
+
});
|
|
434
|
+
return result === null ? "skipped" : "written";
|
|
435
|
+
}
|
|
436
|
+
async function seedBuildOutput(options) {
|
|
437
|
+
const dir = path2__default.default.resolve(options.dir ?? ".next");
|
|
438
|
+
const keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;
|
|
439
|
+
const hashTag = options.hashTag ?? false;
|
|
440
|
+
const ns = resolveBuildNamespace(options.buildNamespace);
|
|
441
|
+
const warn = options.logger?.warn ?? (() => {
|
|
442
|
+
});
|
|
443
|
+
const summary = {
|
|
444
|
+
routes: 0,
|
|
445
|
+
pages: 0,
|
|
446
|
+
fetch: 0,
|
|
447
|
+
skippedExisting: 0,
|
|
448
|
+
skippedIncomplete: 0,
|
|
449
|
+
skippedRouteHandlers: 0,
|
|
450
|
+
errors: []
|
|
451
|
+
};
|
|
452
|
+
const manifestPath = path2__default.default.join(dir, "prerender-manifest.json");
|
|
453
|
+
if (!fs__default.default.existsSync(manifestPath)) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
`[next-cache] no prerender-manifest.json in ${dir} \u2014 run \`next build\` first`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
const manifest = JSON.parse(fs__default.default.readFileSync(manifestPath, "utf8"));
|
|
459
|
+
const client = await buildClient(options.client);
|
|
460
|
+
if (!client.isOpen) await client.connect();
|
|
461
|
+
const writeOpts = { keyPrefix, hashTag, ns, ...options.compression ? { compression: options.compression } : {} };
|
|
462
|
+
try {
|
|
463
|
+
for (const [route, info] of Object.entries(manifest.routes ?? {})) {
|
|
464
|
+
try {
|
|
465
|
+
const isPages = typeof info.dataRoute === "string" && info.dataRoute.endsWith(".json");
|
|
466
|
+
const base = routeToFileBase(route);
|
|
467
|
+
if (isPages) {
|
|
468
|
+
const html = path2__default.default.join(dir, "server", "pages", `${base.slice(1)}.html`);
|
|
469
|
+
const data = path2__default.default.join(dir, "server", "pages", `${base.slice(1)}.json`);
|
|
470
|
+
if (!fs__default.default.existsSync(html)) {
|
|
471
|
+
summary.skippedIncomplete += 1;
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const value2 = {
|
|
475
|
+
kind: "PAGES",
|
|
476
|
+
html: fs__default.default.readFileSync(html, "utf8"),
|
|
477
|
+
pageData: fs__default.default.existsSync(data) ? JSON.parse(fs__default.default.readFileSync(data, "utf8")) : {},
|
|
478
|
+
headers: void 0,
|
|
479
|
+
status: void 0
|
|
480
|
+
};
|
|
481
|
+
const r2 = await writeRecord(client, route, value2, info.initialRevalidateSeconds, writeOpts);
|
|
482
|
+
if (r2 === "written") summary.pages += 1;
|
|
483
|
+
else summary.skippedExisting += 1;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
const htmlPath = path2__default.default.join(dir, "server", "app", `${base.slice(1)}.html`);
|
|
487
|
+
const rscPath = path2__default.default.join(dir, "server", "app", `${base.slice(1)}.rsc`);
|
|
488
|
+
const metaPath = path2__default.default.join(dir, "server", "app", `${base.slice(1)}.meta`);
|
|
489
|
+
if (!fs__default.default.existsSync(htmlPath) || !fs__default.default.existsSync(metaPath)) {
|
|
490
|
+
if (fs__default.default.existsSync(path2__default.default.join(dir, "server", "app", `${base.slice(1)}.body`))) {
|
|
491
|
+
summary.skippedRouteHandlers += 1;
|
|
492
|
+
} else {
|
|
493
|
+
summary.skippedIncomplete += 1;
|
|
494
|
+
}
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
const meta = readMeta(metaPath) ?? {};
|
|
498
|
+
if (meta.postponed) {
|
|
499
|
+
summary.skippedIncomplete += 1;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
let segmentData;
|
|
503
|
+
if (Array.isArray(meta.segmentPaths) && meta.segmentPaths.length > 0) {
|
|
504
|
+
const segDir = path2__default.default.join(dir, "server", "app", `${base.slice(1)}.segments`);
|
|
505
|
+
segmentData = /* @__PURE__ */ new Map();
|
|
506
|
+
for (const segPath of meta.segmentPaths) {
|
|
507
|
+
const segFile = path2__default.default.join(segDir, `${segPath.slice(1)}.segment.rsc`);
|
|
508
|
+
if (fs__default.default.existsSync(segFile)) {
|
|
509
|
+
segmentData.set(segPath, fs__default.default.readFileSync(segFile));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (segmentData.size !== meta.segmentPaths.length) {
|
|
513
|
+
summary.skippedIncomplete += 1;
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const value = {
|
|
518
|
+
kind: "APP_PAGE",
|
|
519
|
+
html: fs__default.default.readFileSync(htmlPath, "utf8"),
|
|
520
|
+
rscData: fs__default.default.existsSync(rscPath) ? fs__default.default.readFileSync(rscPath) : void 0,
|
|
521
|
+
headers: meta.headers,
|
|
522
|
+
status: meta.status
|
|
523
|
+
};
|
|
524
|
+
if (segmentData) value.segmentData = segmentData;
|
|
525
|
+
const r = await writeRecord(client, route, value, info.initialRevalidateSeconds, writeOpts);
|
|
526
|
+
if (r === "written") summary.routes += 1;
|
|
527
|
+
else summary.skippedExisting += 1;
|
|
528
|
+
} catch (err) {
|
|
529
|
+
summary.errors.push(`${route}: ${err.message}`);
|
|
530
|
+
warn("seed: route failed", { route, message: err.message });
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const fetchDir = path2__default.default.join(dir, "cache", "fetch-cache");
|
|
534
|
+
if (fs__default.default.existsSync(fetchDir)) {
|
|
535
|
+
for (const file of fs__default.default.readdirSync(fetchDir)) {
|
|
536
|
+
if (file.startsWith(".")) continue;
|
|
537
|
+
try {
|
|
538
|
+
const raw = fs__default.default.readFileSync(path2__default.default.join(fetchDir, file), "utf8");
|
|
539
|
+
const value = JSON.parse(raw);
|
|
540
|
+
if (value.kind !== "FETCH") continue;
|
|
541
|
+
const r = await writeRecord(client, file, value, value.revalidate, writeOpts);
|
|
542
|
+
if (r === "written") summary.fetch += 1;
|
|
543
|
+
else summary.skippedExisting += 1;
|
|
544
|
+
} catch (err) {
|
|
545
|
+
summary.errors.push(`fetch:${file}: ${err.message}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} finally {
|
|
550
|
+
const c = client;
|
|
551
|
+
try {
|
|
552
|
+
(c.dispose ?? c.destroy ?? c.disconnect)?.call(c);
|
|
553
|
+
} catch {
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return summary;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
exports.seedBuildOutput = seedBuildOutput;
|
|
560
|
+
//# sourceMappingURL=index.cjs.map
|
|
561
|
+
//# sourceMappingURL=index.cjs.map
|