@leejpsd/nextjs-cache-handler 0.3.4 → 0.4.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 +32 -0
- package/README.md +5 -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 +937 -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 +927 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/incremental/index.cjs +77 -3
- 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 +77 -3
- package/dist/incremental/index.js.map +1 -1
- package/dist/index.cjs +153 -5
- 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 +153 -5
- 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 +560 -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 +549 -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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../node_modules/tsup/assets/cjs_shims.js","../../src/shared/node-require.ts","../../src/shared/client/adapter-redis.ts","../../src/shared/client/adapter-ioredis.ts","../../src/seed/index.ts","../../src/shared/client/index.ts","../../src/shared/compress.ts","../../src/shared/namespace.ts","../../src/incremental/serialize.ts"],"names":["createRequire","path","adaptRedisV5","createRedisV5Client","adaptIoredis","createIoredisClient","adaptCluster","createIoredisCluster","createIoredisSentinel","promisify","gzip","gunzip","brotliCompress","brotliDecompress","constants","fs","value","r"],"mappings":"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","file":"index.cjs","sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\n * A require() that works from BOTH build outputs.\n *\n * The client/OTel factories load optional peers (`redis`, `ioredis`,\n * `@opentelemetry/api`) lazily at runtime. A bare `require()` compiles fine\n * for CJS but becomes esbuild's `__require` fallback in the ESM build, which\n * throws \"Dynamic require of X is not supported\" in pure-ESM consumers.\n * `createRequire(import.meta.url)` is real in ESM, and tsup's `shims: true`\n * provides an `import.meta.url` polyfill for the CJS build.\n */\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nconst packageRequire = createRequire(import.meta.url);\nconst cwdRequire = createRequire(\n path.join(process.cwd(), \"__resolve-anchor__.js\")\n);\n\nexport function nodeRequire(id: string): unknown {\n try {\n return packageRequire(id);\n } catch {\n // Symlinked installs (npm i <local-path>, pnpm's virtual store) resolve\n // import.meta.url to the package's REAL location, outside the app tree —\n // so peers installed by the app aren't reachable from that anchor. Retry\n // from the process CWD, which under a Next.js server is the app root.\n return cwdRequire(id);\n }\n}\n","/**\n * Adapter for `redis@5` (the official `node-redis` client).\n *\n * v5 already uses camelCase methods that match `RedisClientLike` almost\n * exactly, so this adapter is mostly a type assertion plus the\n * `createRedisV5Client` factory that codifies the \"1.5s connectTimeout,\n * reconnectStrategy: false\" defaults validated in production by the reference\n * implementation.\n */\n\nimport type { RedisClientType } from \"redis\";\n\nimport type { RedisClientConfig, RedisClientLike } from \"../../types.js\";\nimport { nodeRequire } from \"../node-require.js\";\n\nexport function adaptRedisV5(client: RedisClientType): RedisClientLike {\n const like = client as unknown as RedisClientLike;\n like.dispose = () => {\n try {\n client.destroy();\n } catch {\n /* already closed */\n }\n };\n // redis@5 exposes publish natively; subscribe needs a duplicate connection.\n like.subscribe = async (channel, onMessage, onDown) => {\n const sub = client.duplicate();\n const teardown = () => {\n try {\n sub.destroy();\n } catch {\n /* already closed */\n }\n };\n let down = false;\n const markDown = () => {\n if (down) return;\n down = true;\n teardown();\n onDown?.();\n };\n sub.on(\"error\", markDown);\n // reconnectStrategy is false on duplicates — a dropped socket is final,\n // so surface it instead of latching a dead subscription as active.\n sub.on(\"end\", markDown);\n try {\n await sub.connect();\n await sub.subscribe(channel, (message: string) => onMessage(message));\n } catch (err) {\n // CRITICAL: without this, every failed SUBSCRIBE (e.g. ACL without\n // channel permissions) leaks one connected duplicate per retry.\n teardown();\n throw err;\n }\n return async () => teardown();\n };\n return like;\n}\n\nexport function createRedisV5Client(\n config: Extract<RedisClientConfig, { type: \"redis\" }>\n): RedisClientType {\n // Lazy require so consumers using ioredis only don't pay the cost.\n // We do `require` instead of `await import` here because the parent\n // `buildClient` is already in an async context that handles awaiting.\n \n const { createClient } = nodeRequire(\"redis\") as typeof import(\"redis\");\n const useTls = config.tls ?? config.url.startsWith(\"rediss://\");\n\n // redis@5 has a discriminated socket union (TCP / TLS / IPC) and disallows\n // explicit `undefined` under exactOptionalPropertyTypes. Build the options\n // object incrementally so optional fields stay absent when not set.\n \n const opts: any = {\n url: config.url,\n socket: {\n connectTimeout: config.connectTimeout ?? 1500,\n reconnectStrategy: false,\n ...(useTls ? { tls: true } : {}),\n },\n };\n if (config.password !== undefined) opts.password = config.password;\n\n return createClient(opts) as RedisClientType;\n}\n","/**\n * Adapter for `ioredis` (and `ioredis.Cluster`).\n *\n * ioredis uses snake_case method names (`sadd`, `smembers`, `mget`) and a\n * stream-based scan. We normalize both into the camelCase / async-iterable\n * `RedisClientLike` contract so the handlers don't need to know which client\n * is underneath.\n */\n\nimport type { Cluster, Redis } from \"ioredis\";\n\nimport type { RedisClientConfig, RedisClientLike } from \"../../types.js\";\nimport { nodeRequire } from \"../node-require.js\";\n\ntype AnyRedis = Redis | Cluster;\n\nfunction adapt(client: AnyRedis, isClusterClient = false): RedisClientLike {\n return {\n get isOpen() {\n // ioredis exposes a `status` string. Both single-node and cluster\n // report \"ready\" once connected.\n return client.status === \"ready\";\n },\n connect: async () => {\n if (client.status !== \"ready\" && client.status !== \"connecting\") {\n await client.connect();\n }\n },\n get: (k) => client.get(k),\n set: (k, v, opts) => {\n const args: (string | number)[] = [];\n if (opts?.EX !== undefined) args.push(\"EX\", opts.EX);\n if (opts?.NX) args.push(\"NX\");\n return (client.set as (...a: unknown[]) => Promise<unknown>)(k, v, ...args);\n },\n del: async (keys) => {\n const arr = Array.isArray(keys) ? keys : [keys];\n if (arr.length === 0) return 0;\n return client.del(...arr);\n },\n sAdd: async (k, m) => {\n const arr = Array.isArray(m) ? m : [m];\n if (arr.length === 0) return 0;\n return client.sadd(k, ...arr);\n },\n sMembers: (k) => client.smembers(k),\n expire: async (k, s) => {\n const r = await client.expire(k, s);\n return r;\n },\n mGet: async (keys) => {\n if (keys.length === 0) return [];\n return client.mget(...keys);\n },\n eval: (script, opts) =>\n client.eval(\n script,\n opts.keys.length,\n ...opts.keys,\n ...opts.arguments\n ) as Promise<unknown>,\n evalSha: (sha, opts) =>\n client.evalsha(\n sha,\n opts.keys.length,\n ...opts.keys,\n ...opts.arguments\n ) as Promise<unknown>,\n scriptLoad: async (script) =>\n (await client.script(\"LOAD\", script)) as string,\n scanIterator: async function* ({ MATCH, COUNT }) {\n // Cluster does not support a single SCAN cursor across slots; use\n // ioredis's per-node iterator there. Single-node: standard SCAN cursor.\n if (isClusterClient) {\n const cluster = client as Cluster;\n for (const node of cluster.nodes(\"master\")) {\n let cursor = \"0\";\n do {\n const [next, batch]: [string, string[]] = await node.scan(\n cursor,\n \"MATCH\",\n MATCH,\n \"COUNT\",\n COUNT ?? 100\n );\n cursor = next;\n if (batch.length > 0) yield batch;\n } while (cursor !== \"0\");\n }\n } else {\n const redis = client as Redis;\n let cursor = \"0\";\n do {\n const [next, batch]: [string, string[]] = await redis.scan(\n cursor,\n \"MATCH\",\n MATCH,\n \"COUNT\",\n COUNT ?? 100\n );\n cursor = next;\n if (batch.length > 0) yield batch;\n } while (cursor !== \"0\");\n }\n },\n ping: () => client.ping(),\n on: (event, listener) => {\n client.on(event, listener);\n return client;\n },\n publish: (channel, message) => client.publish(channel, message),\n ...(isClusterClient\n ? {}\n : {\n subscribe: async (\n channel: string,\n onMessage: (message: string) => void,\n onDown?: () => void\n ) => {\n const sub = (client as Redis).duplicate();\n let down = false;\n const markDown = () => {\n if (down) return;\n down = true;\n try {\n sub.disconnect();\n } catch {\n /* already closed */\n }\n onDown?.();\n };\n sub.on(\"error\", markDown);\n sub.on(\"end\", markDown);\n try {\n if (sub.status !== \"ready\" && sub.status !== \"connecting\") {\n await sub.connect();\n }\n await sub.subscribe(channel);\n } catch (err) {\n markDown();\n throw err;\n }\n sub.on(\"message\", (ch: string, message: string) => {\n if (ch === channel) onMessage(message);\n });\n return async () => {\n down = true;\n sub.disconnect();\n };\n },\n }),\n dispose: () => {\n client.disconnect();\n },\n };\n}\n\nexport function adaptIoredis(client: Redis): RedisClientLike {\n return adapt(client, false);\n}\n\nexport function adaptCluster(cluster: Cluster): RedisClientLike {\n return adapt(cluster, true);\n}\n\nexport function createIoredisClient(\n config: Extract<RedisClientConfig, { type: \"ioredis\" }>\n): Redis {\n \n const IORedis = nodeRequire(\"ioredis\") as typeof import(\"ioredis\");\n // ioredis exports the class as both `default` and a named property.\n // Hitting the default works for both ESM and CJS consumers.\n const Ctor = IORedis.default ?? (IORedis as unknown as typeof import(\"ioredis\").default);\n return new Ctor(config.url, {\n password: config.password,\n connectTimeout: config.connectTimeout ?? 1500,\n tls: config.tls ? {} : undefined,\n lazyConnect: true,\n maxRetriesPerRequest: 1,\n // Batch same-tick commands into one RTT (matches redis@5's default\n // behavior) — makes Promise.all fan-outs a single pipeline.\n enableAutoPipelining: true,\n });\n}\n\nexport function createIoredisSentinel(\n config: Extract<RedisClientConfig, { type: \"sentinel\" }>\n): Redis {\n const IORedis = nodeRequire(\"ioredis\") as typeof import(\"ioredis\");\n const Ctor = IORedis.default ?? (IORedis as unknown as typeof import(\"ioredis\").default);\n return new Ctor({\n sentinels: config.sentinels,\n name: config.name,\n password: config.password,\n sentinelPassword: config.sentinelPassword,\n connectTimeout: config.connectTimeout ?? 1500,\n tls: config.tls ? {} : undefined,\n lazyConnect: true,\n maxRetriesPerRequest: 1,\n enableAutoPipelining: true,\n });\n}\n\nexport function createIoredisCluster(\n config: Extract<RedisClientConfig, { type: \"cluster\" }>\n): Cluster {\n \n const IORedis = nodeRequire(\"ioredis\") as typeof import(\"ioredis\");\n const ClusterCtor =\n IORedis.Cluster ??\n (IORedis.default as unknown as { Cluster: typeof import(\"ioredis\").Cluster })\n .Cluster;\n return new ClusterCtor(config.nodes, {\n redisOptions: {\n password: config.password,\n tls: config.tls ? {} : undefined,\n },\n enableReadyCheck: true,\n lazyConnect: true,\n // Same-slot commands issued in the same tick share one pipeline.\n enableAutoPipelining: true,\n });\n}\n","/**\n * Build-output cache seeding.\n *\n * `next build` prerenders pages and fetch-cache entries into `.next/`, but a\n * fresh deployment's Redis is empty — every first request pays a full\n * regeneration (and N instances pay it N times). `seedBuildOutput()` walks\n * the build output and inserts it into Redis in the exact record format the\n * incremental handler reads, using **NX semantics**: an entry that a running\n * instance has already written (necessarily newer) is never overwritten.\n *\n * Run it once per deploy, after `next build` and before (or while) traffic\n * shifts — e.g. as a Docker entrypoint step or CI job:\n *\n * npx nextjs-cache-handler seed # uses REDIS_URL / DEPLOYMENT_VERSION\n * npx nextjs-cache-handler seed --dir .next\n *\n * Seeds:\n * - App Router routes (`.next/server/app/<route>.{html,rsc,meta}` +\n * PPR `.segments/`) → APP_PAGE records\n * - Pages Router routes (`.next/server/pages/<route>.{html,json}`) → PAGES\n * - fetch cache (`.next/cache/fetch-cache/<hash>`) → FETCH records\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { buildClient } from \"../shared/client/index.js\";\nimport { compressValue } from \"../shared/compress.js\";\nimport { buildKey, resolveBuildNamespace } from \"../shared/namespace.js\";\nimport { serializeCacheRecord } from \"../incremental/serialize.js\";\nimport type {\n Logger,\n RedisClientConfig,\n RedisClientFactory,\n RedisClientLike,\n} from \"../types.js\";\n\nconst ONE_YEAR_SEC = 60 * 60 * 24 * 365;\nconst MIN_TTL_SEC = 60;\nconst DEFAULT_KEY_PREFIX = \"next-incremental:\";\n\nexport interface SeedOptions {\n client: RedisClientFactory | RedisClientConfig;\n /** Path to the build output. Default: `./.next`. */\n dir?: string;\n keyPrefix?: string;\n buildNamespace?: string | (() => string);\n compression?: \"gzip\" | \"brotli\";\n hashTag?: boolean;\n logger?: Pick<Logger, \"warn\">;\n}\n\nexport interface SeedSummary {\n /** App Router routes written. */\n routes: number;\n /** Pages Router routes written. */\n pages: number;\n /** fetch-cache entries written. */\n fetch: number;\n /** Entries skipped because a (newer) live entry already existed (NX). */\n skippedExisting: number;\n /** Routes skipped because their files were incomplete or PPR-postponed. */\n skippedIncomplete: number;\n /** Prerendered route handlers (.body) — never seeded, by design. */\n skippedRouteHandlers: number;\n errors: string[];\n}\n\ninterface ManifestRoute {\n initialRevalidateSeconds?: number | false;\n dataRoute?: string | null;\n srcRoute?: string | null;\n}\n\nfunction clampTtl(revalidate: number | false | undefined): number {\n if (revalidate === false || revalidate === undefined) return ONE_YEAR_SEC;\n if (typeof revalidate === \"number\" && revalidate > 0) {\n return Math.min(Math.max(Math.ceil(revalidate), MIN_TTL_SEC), ONE_YEAR_SEC);\n }\n return MIN_TTL_SEC;\n}\n\nfunction routeToFileBase(route: string): string {\n return route === \"/\" ? \"/index\" : route;\n}\n\nfunction readMeta(file: string): {\n status?: number;\n headers?: Record<string, string>;\n segmentPaths?: string[];\n postponed?: string;\n} | null {\n try {\n return JSON.parse(fs.readFileSync(file, \"utf8\")) as ReturnType<typeof readMeta>;\n } catch {\n return null;\n }\n}\n\nasync function writeRecord(\n client: RedisClientLike,\n key: string,\n value: unknown,\n revalidateSec: number | false | undefined,\n opts: Required<Pick<SeedOptions, \"keyPrefix\" | \"hashTag\">> & {\n ns: string;\n compression?: \"gzip\" | \"brotli\";\n }\n): Promise<\"written\" | \"skipped\"> {\n const record = {\n lastModified: Date.now(),\n value,\n revalidateSec: clampTtl(revalidateSec),\n };\n const redisKey = buildKey(`${opts.keyPrefix}entry:`, opts.ns, key, opts.hashTag);\n const payload = await compressValue(\n serializeCacheRecord(record),\n opts.compression\n );\n const result = await client.set(redisKey, payload, {\n EX: clampTtl(revalidateSec),\n NX: true,\n });\n // Redis returns null (nil) when NX blocks the write.\n return result === null ? \"skipped\" : \"written\";\n}\n\nexport async function seedBuildOutput(options: SeedOptions): Promise<SeedSummary> {\n const dir = path.resolve(options.dir ?? \".next\");\n const keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX;\n const hashTag = options.hashTag ?? false;\n const ns = resolveBuildNamespace(options.buildNamespace);\n const warn = options.logger?.warn ?? (() => {});\n const summary: SeedSummary = {\n routes: 0,\n pages: 0,\n fetch: 0,\n skippedExisting: 0,\n skippedIncomplete: 0,\n skippedRouteHandlers: 0,\n errors: [],\n };\n\n const manifestPath = path.join(dir, \"prerender-manifest.json\");\n if (!fs.existsSync(manifestPath)) {\n throw new Error(\n `[next-cache] no prerender-manifest.json in ${dir} — run \\`next build\\` first`\n );\n }\n const manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf8\")) as {\n routes?: Record<string, ManifestRoute>;\n };\n\n const client = await buildClient(options.client);\n if (!client.isOpen) await client.connect();\n\n const writeOpts = { keyPrefix, hashTag, ns, ...(options.compression ? { compression: options.compression } : {}) };\n\n try {\n // ── 1) Prerendered routes ────────────────────────────────────────────────\n for (const [route, info] of Object.entries(manifest.routes ?? {})) {\n try {\n const isPages = typeof info.dataRoute === \"string\" && info.dataRoute.endsWith(\".json\");\n const base = routeToFileBase(route);\n\n if (isPages) {\n const html = path.join(dir, \"server\", \"pages\", `${base.slice(1)}.html`);\n const data = path.join(dir, \"server\", \"pages\", `${base.slice(1)}.json`);\n if (!fs.existsSync(html)) {\n summary.skippedIncomplete += 1;\n continue;\n }\n const value = {\n kind: \"PAGES\",\n html: fs.readFileSync(html, \"utf8\"),\n pageData: fs.existsSync(data)\n ? (JSON.parse(fs.readFileSync(data, \"utf8\")) as unknown)\n : {},\n headers: undefined,\n status: undefined,\n };\n const r = await writeRecord(client, route, value, info.initialRevalidateSeconds, writeOpts);\n if (r === \"written\") summary.pages += 1;\n else summary.skippedExisting += 1;\n continue;\n }\n\n // App Router\n const htmlPath = path.join(dir, \"server\", \"app\", `${base.slice(1)}.html`);\n const rscPath = path.join(dir, \"server\", \"app\", `${base.slice(1)}.rsc`);\n const metaPath = path.join(dir, \"server\", \"app\", `${base.slice(1)}.meta`);\n if (!fs.existsSync(htmlPath) || !fs.existsSync(metaPath)) {\n // Prerendered route handlers emit .body/.meta instead of .html —\n // they are intentionally not seeded, and not \"incomplete\".\n if (fs.existsSync(path.join(dir, \"server\", \"app\", `${base.slice(1)}.body`))) {\n summary.skippedRouteHandlers += 1;\n } else {\n summary.skippedIncomplete += 1;\n }\n continue;\n }\n const meta = readMeta(metaPath) ?? {};\n if (meta.postponed) {\n // PPR routes with resume state cannot be faithfully seeded from\n // static files (the runtime needs `postponed` to resume dynamic\n // holes, and Next intentionally omits the .rsc for them). Serving\n // a seeded copy would freeze the unresolved shell as final HTML.\n summary.skippedIncomplete += 1;\n continue;\n }\n\n let segmentData: Map<string, Buffer> | undefined;\n if (Array.isArray(meta.segmentPaths) && meta.segmentPaths.length > 0) {\n const segDir = path.join(dir, \"server\", \"app\", `${base.slice(1)}.segments`);\n segmentData = new Map();\n for (const segPath of meta.segmentPaths) {\n const segFile = path.join(segDir, `${segPath.slice(1)}.segment.rsc`);\n if (fs.existsSync(segFile)) {\n segmentData.set(segPath, fs.readFileSync(segFile));\n }\n }\n if (segmentData.size !== meta.segmentPaths.length) {\n // Partial segment sets would break PPR resumes — safer to skip.\n summary.skippedIncomplete += 1;\n continue;\n }\n }\n\n const value: Record<string, unknown> = {\n kind: \"APP_PAGE\",\n html: fs.readFileSync(htmlPath, \"utf8\"),\n rscData: fs.existsSync(rscPath) ? fs.readFileSync(rscPath) : undefined,\n headers: meta.headers,\n status: meta.status,\n };\n if (segmentData) value.segmentData = segmentData;\n\n const r = await writeRecord(client, route, value, info.initialRevalidateSeconds, writeOpts);\n if (r === \"written\") summary.routes += 1;\n else summary.skippedExisting += 1;\n } catch (err) {\n summary.errors.push(`${route}: ${(err as Error).message}`);\n warn(\"seed: route failed\", { route, message: (err as Error).message });\n }\n }\n\n // ── 2) fetch cache ───────────────────────────────────────────────────────\n const fetchDir = path.join(dir, \"cache\", \"fetch-cache\");\n if (fs.existsSync(fetchDir)) {\n for (const file of fs.readdirSync(fetchDir)) {\n if (file.startsWith(\".\")) continue;\n try {\n const raw = fs.readFileSync(path.join(fetchDir, file), \"utf8\");\n const value = JSON.parse(raw) as { kind?: string; revalidate?: number };\n if (value.kind !== \"FETCH\") continue;\n const r = await writeRecord(client, file, value, value.revalidate, writeOpts);\n if (r === \"written\") summary.fetch += 1;\n else summary.skippedExisting += 1;\n } catch (err) {\n summary.errors.push(`fetch:${file}: ${(err as Error).message}`);\n }\n }\n }\n } finally {\n const c = client as RedisClientLike & {\n destroy?: () => unknown;\n disconnect?: () => unknown;\n };\n try {\n (c.dispose ?? c.destroy ?? c.disconnect)?.call(c);\n } catch {\n /* best-effort */\n }\n }\n\n return summary;\n}\n","/**\n * Client factory. Resolves a `RedisClientFactory | RedisClientConfig` to a\n * connected `RedisClientLike`, with idempotent connect.\n *\n * The factory caches the resolved client per-handler so repeated calls don't\n * spawn parallel connections. Adapter modules (`adapter-redis`,\n * `adapter-ioredis`) are lazy-imported so peer-deps you don't use stay out of\n * your bundle.\n */\n\nimport type {\n RedisClientFactory,\n RedisClientConfig,\n RedisClientLike,\n} from \"../../types.js\";\n\nexport async function buildClient(\n source: RedisClientFactory | RedisClientConfig\n): Promise<RedisClientLike> {\n if (typeof source === \"function\") {\n return await source();\n }\n switch (source.type) {\n case \"redis\": {\n const { adaptRedisV5, createRedisV5Client } = await import(\n \"./adapter-redis.js\"\n );\n return adaptRedisV5(createRedisV5Client(source));\n }\n case \"ioredis\": {\n const { adaptIoredis, createIoredisClient } = await import(\n \"./adapter-ioredis.js\"\n );\n return adaptIoredis(createIoredisClient(source));\n }\n case \"cluster\": {\n const { adaptCluster, createIoredisCluster } = await import(\n \"./adapter-ioredis.js\"\n );\n return adaptCluster(createIoredisCluster(source));\n }\n case \"sentinel\": {\n const { adaptIoredis, createIoredisSentinel } = await import(\n \"./adapter-ioredis.js\"\n );\n return adaptIoredis(createIoredisSentinel(source));\n }\n default: {\n const exhaustive: never = source;\n throw new Error(\n `[next-cache] unknown client config: ${JSON.stringify(exhaustive)}`\n );\n }\n }\n}\n\nexport interface ConnectionRetryOptions {\n /** Cooldown before the first retry after a failed connect (ms). Default 1000. */\n baseCooldownMs?: number;\n /** Upper bound for the exponential cooldown (ms). Default 30000. */\n maxCooldownMs?: number;\n}\n\n/**\n * Manage connect state without launching parallel connect calls. The reference\n * implementation's `connectPromise` pattern is preserved here.\n *\n * A failed connect does NOT latch the manager into a dead state: retries are\n * allowed after an exponential cooldown (base 1s, doubling per consecutive\n * failure, capped at 30s). During the cooldown `getOrConnect()` returns `null`\n * immediately so request paths fast-fail to the memory fallback instead of\n * queueing behind doomed connect attempts. A dropped connection (client\n * present but no longer open) is replaced with a fresh client on the next\n * call; the dead client is disposed best-effort.\n */\nexport class ConnectionManager {\n private client: RedisClientLike | null = null;\n private connecting: Promise<RedisClientLike | null> | null = null;\n private consecutiveFailures = 0;\n private lastFailureAt = 0;\n private readonly baseCooldownMs: number;\n private readonly maxCooldownMs: number;\n\n constructor(\n private readonly source: RedisClientFactory | RedisClientConfig,\n private readonly onError: (err: Error) => void,\n retry: ConnectionRetryOptions = {}\n ) {\n this.baseCooldownMs = retry.baseCooldownMs ?? 1000;\n this.maxCooldownMs = retry.maxCooldownMs ?? 30_000;\n }\n\n private cooldownMs(): number {\n if (this.consecutiveFailures === 0) return 0;\n return Math.min(\n this.maxCooldownMs,\n this.baseCooldownMs * 2 ** (this.consecutiveFailures - 1)\n );\n }\n\n async getOrConnect(): Promise<RedisClientLike | null> {\n if (this.client?.isOpen) return this.client;\n if (this.connecting) return this.connecting;\n if (Date.now() - this.lastFailureAt < this.cooldownMs()) return null;\n\n const stale = this.client;\n this.client = null;\n\n this.connecting = (async () => {\n disposeQuietly(stale);\n try {\n const c = await buildClient(this.source);\n c.on(\"error\", (err) => this.onError(err));\n if (!c.isOpen) await c.connect();\n this.client = c;\n this.consecutiveFailures = 0;\n return c;\n } catch (err) {\n this.consecutiveFailures += 1;\n this.lastFailureAt = Date.now();\n this.onError(err as Error);\n return null;\n } finally {\n this.connecting = null;\n }\n })();\n\n return this.connecting;\n }\n\n reset(): void {\n disposeQuietly(this.client);\n this.client = null;\n this.connecting = null;\n this.consecutiveFailures = 0;\n this.lastFailureAt = 0;\n }\n}\n\n/**\n * Close a replaced client so it stops reconnect loops and frees its socket.\n * The adapters expose `dispose`; raw clients passed via a factory may expose\n * `destroy` (redis@5) or `disconnect` (ioredis) instead.\n */\nfunction disposeQuietly(client: RedisClientLike | null): void {\n if (!client) return;\n const c = client as RedisClientLike & {\n destroy?: () => unknown;\n disconnect?: () => unknown;\n };\n try {\n (c.dispose ?? c.destroy ?? c.disconnect)?.call(c);\n } catch {\n // Best-effort: a client that fails to close is abandoned to GC.\n }\n}\n","/**\n * Transparent value compression for Redis-bound entries (node:zlib — zero\n * added dependencies).\n *\n * Storage format: `<marker><base64>` with marker `__ncgz__:` (gzip) or\n * `__ncbr__:` (brotli). Values without a marker pass through untouched, so\n * mixed caches stay readable: entries written before compression was enabled,\n * or by instances configured differently, decode fine — decompression is\n * always active regardless of the local `compression` option.\n *\n * Base64 re-inflates the compressed bytes by ~33% (our client contract is\n * string-typed), but RSC/HTML payloads are text-heavy enough that the net\n * reduction is typically 3–5×. Payloads under 1 KiB are stored uncompressed —\n * at that size marker+header overhead can exceed the savings.\n *\n * Only entry values are compressed. Tag markers and tag states are a few\n * bytes each and stay plain.\n */\n\nimport { promisify } from \"node:util\";\nimport {\n brotliCompress,\n brotliDecompress,\n constants,\n gunzip,\n gzip,\n} from \"node:zlib\";\n\nconst gzipAsync = promisify(gzip);\nconst gunzipAsync = promisify(gunzip);\nconst brotliCompressAsync = promisify(brotliCompress);\nconst brotliDecompressAsync = promisify(brotliDecompress);\n\nexport type CompressionAlgo = \"gzip\" | \"brotli\";\n\nconst GZIP_MARKER = \"__ncgz__:\";\nconst BROTLI_MARKER = \"__ncbr__:\";\nconst MIN_COMPRESS_BYTES = 1024;\n\n/**\n * Brotli's default quality (11) is tuned for static assets and is far too\n * slow for a request-path cache write. 5 compresses close to gzip speed\n * while still beating it on ratio for text.\n */\nconst BROTLI_OPTS = {\n params: { [constants.BROTLI_PARAM_QUALITY]: 5 },\n};\n\nexport async function compressValue(\n value: string,\n algo: CompressionAlgo | undefined\n): Promise<string> {\n if (!algo || Buffer.byteLength(value) < MIN_COMPRESS_BYTES) return value;\n const input = Buffer.from(value);\n if (algo === \"gzip\") {\n return GZIP_MARKER + (await gzipAsync(input)).toString(\"base64\");\n }\n return (\n BROTLI_MARKER +\n (await brotliCompressAsync(input, BROTLI_OPTS)).toString(\"base64\")\n );\n}\n\n/**\n * Marker-dispatched decompression. Unmarked values are returned as-is.\n * Throws on corrupt compressed data — callers treat that as a cache miss.\n */\nexport async function decompressValue(\n value: string | null\n): Promise<string | null> {\n if (value === null) return null;\n if (value.startsWith(GZIP_MARKER)) {\n const buf = Buffer.from(value.slice(GZIP_MARKER.length), \"base64\");\n return (await gunzipAsync(buf)).toString(\"utf8\");\n }\n if (value.startsWith(BROTLI_MARKER)) {\n const buf = Buffer.from(value.slice(BROTLI_MARKER.length), \"base64\");\n return (await brotliDecompressAsync(buf)).toString(\"utf8\");\n }\n return value;\n}\n","/**\n * Build namespace resolution.\n *\n * Why this matters: the reference implementation's \"static chunk 404\" incident\n * was caused by old prerender HTML from a previous deployment hitting in Redis.\n * Two deployments shared the same cache key prefix, so a new build's request\n * could deserialize an entry that referenced static chunks deleted by the\n * deployment swap.\n *\n * Embedding a per-deployment namespace into every entry key fixes this:\n * next-incremental:entry:<commit-sha>:<path>\n *\n * Rolling forward to a new SHA invalidates everything atomically without\n * needing a manual flush. Tags remain shared across deployments so\n * `revalidateTag()` keeps cross-deployment semantics.\n */\n\nconst FALLBACK = \"unversioned\";\n\n/**\n * Resolve the namespace value. Pure helper used at runtime when constructing\n * keys.\n */\nexport function resolveBuildNamespace(\n override?: string | (() => string)\n): string {\n if (override !== undefined) {\n return typeof override === \"function\" ? override() : override;\n }\n return (\n process.env.DEPLOYMENT_VERSION ??\n process.env.GIT_HASH ??\n process.env.NEXT_DEPLOYMENT_ID ??\n FALLBACK\n );\n}\n\n/**\n * Build a namespaced key. When `hashTag` is true, the namespace is wrapped in\n * `{}` so multi-key Lua scripts on Redis Cluster all hash to the same slot.\n *\n * Example:\n * buildKey(\"next-incremental:entry:\", \"ns42\", \"/blog/hello\", false)\n * → \"next-incremental:entry:ns42:/blog/hello\"\n * buildKey(\"next-cache:tag:\", \"ns42\", \"post-1\", true)\n * → \"next-cache:tag:{ns42}:post-1\"\n */\nexport function buildKey(\n prefix: string,\n namespace: string,\n rest: string,\n hashTag = false\n): string {\n const ns = hashTag ? `{${namespace}}` : namespace;\n return `${prefix}${ns}:${rest}`;\n}\n","/**\n * JSON serialization with Buffer / Map support for ISR cache records.\n *\n * Next.js's IncrementalCacheValue can contain Buffer (rendered HTML body) and\n * Map instances (RSC payload metadata). Plain JSON.stringify destroys both.\n *\n * The `__type` discriminator approach is borrowed from the reference handler\n * in next-redis-cache-demo. The reviver also accepts the legacy\n * `{ type: \"Buffer\", data: number[] }` shape that Node.js's default\n * Buffer.toJSON produces.\n */\n\ninterface BufferEnvelope {\n __type: \"Buffer\";\n data: string;\n}\ninterface MapEnvelope {\n __type: \"Map\";\n entries: Array<[unknown, unknown]>;\n}\ntype Envelope = BufferEnvelope | MapEnvelope;\n\nfunction isEnvelope(value: unknown): value is Envelope {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__type\" in value &&\n typeof (value as { __type: unknown }).__type === \"string\"\n );\n}\n\ninterface LegacyBufferShape {\n type: \"Buffer\";\n data: number[];\n}\n\nfunction isLegacyBufferShape(value: unknown): value is LegacyBufferShape {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { type?: unknown }).type === \"Buffer\" &&\n Array.isArray((value as { data?: unknown }).data)\n );\n}\n\nfunction replacer(_key: string, value: unknown): unknown {\n if (Buffer.isBuffer(value)) {\n const env: BufferEnvelope = {\n __type: \"Buffer\",\n data: value.toString(\"base64\"),\n };\n return env;\n }\n if (value instanceof Map) {\n const env: MapEnvelope = {\n __type: \"Map\",\n entries: Array.from(value.entries()) as Array<[unknown, unknown]>,\n };\n return env;\n }\n return value;\n}\n\nfunction reviver(_key: string, value: unknown): unknown {\n if (isLegacyBufferShape(value)) {\n return Buffer.from(value.data);\n }\n if (!isEnvelope(value)) return value;\n if (value.__type === \"Buffer\") {\n return Buffer.from((value as BufferEnvelope).data, \"base64\");\n }\n if (value.__type === \"Map\") {\n return new Map((value as MapEnvelope).entries);\n }\n return value;\n}\n\nexport function serializeCacheRecord(record: unknown): string {\n return JSON.stringify(record, replacer);\n}\n\nexport function deserializeCacheRecord<T = unknown>(serialized: string): T | null {\n try {\n return JSON.parse(serialized, reviver) as T;\n } catch {\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { b as RedisClientFactory, a as RedisClientConfig, L as Logger } from '../types-C1vJ_sED.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build-output cache seeding.
|
|
5
|
+
*
|
|
6
|
+
* `next build` prerenders pages and fetch-cache entries into `.next/`, but a
|
|
7
|
+
* fresh deployment's Redis is empty — every first request pays a full
|
|
8
|
+
* regeneration (and N instances pay it N times). `seedBuildOutput()` walks
|
|
9
|
+
* the build output and inserts it into Redis in the exact record format the
|
|
10
|
+
* incremental handler reads, using **NX semantics**: an entry that a running
|
|
11
|
+
* instance has already written (necessarily newer) is never overwritten.
|
|
12
|
+
*
|
|
13
|
+
* Run it once per deploy, after `next build` and before (or while) traffic
|
|
14
|
+
* shifts — e.g. as a Docker entrypoint step or CI job:
|
|
15
|
+
*
|
|
16
|
+
* npx nextjs-cache-handler seed # uses REDIS_URL / DEPLOYMENT_VERSION
|
|
17
|
+
* npx nextjs-cache-handler seed --dir .next
|
|
18
|
+
*
|
|
19
|
+
* Seeds:
|
|
20
|
+
* - App Router routes (`.next/server/app/<route>.{html,rsc,meta}` +
|
|
21
|
+
* PPR `.segments/`) → APP_PAGE records
|
|
22
|
+
* - Pages Router routes (`.next/server/pages/<route>.{html,json}`) → PAGES
|
|
23
|
+
* - fetch cache (`.next/cache/fetch-cache/<hash>`) → FETCH records
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface SeedOptions {
|
|
27
|
+
client: RedisClientFactory | RedisClientConfig;
|
|
28
|
+
/** Path to the build output. Default: `./.next`. */
|
|
29
|
+
dir?: string;
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
buildNamespace?: string | (() => string);
|
|
32
|
+
compression?: "gzip" | "brotli";
|
|
33
|
+
hashTag?: boolean;
|
|
34
|
+
logger?: Pick<Logger, "warn">;
|
|
35
|
+
}
|
|
36
|
+
interface SeedSummary {
|
|
37
|
+
/** App Router routes written. */
|
|
38
|
+
routes: number;
|
|
39
|
+
/** Pages Router routes written. */
|
|
40
|
+
pages: number;
|
|
41
|
+
/** fetch-cache entries written. */
|
|
42
|
+
fetch: number;
|
|
43
|
+
/** Entries skipped because a (newer) live entry already existed (NX). */
|
|
44
|
+
skippedExisting: number;
|
|
45
|
+
/** Routes skipped because their files were incomplete or PPR-postponed. */
|
|
46
|
+
skippedIncomplete: number;
|
|
47
|
+
/** Prerendered route handlers (.body) — never seeded, by design. */
|
|
48
|
+
skippedRouteHandlers: number;
|
|
49
|
+
errors: string[];
|
|
50
|
+
}
|
|
51
|
+
declare function seedBuildOutput(options: SeedOptions): Promise<SeedSummary>;
|
|
52
|
+
|
|
53
|
+
export { type SeedOptions, type SeedSummary, seedBuildOutput };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { b as RedisClientFactory, a as RedisClientConfig, L as Logger } from '../types-C1vJ_sED.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build-output cache seeding.
|
|
5
|
+
*
|
|
6
|
+
* `next build` prerenders pages and fetch-cache entries into `.next/`, but a
|
|
7
|
+
* fresh deployment's Redis is empty — every first request pays a full
|
|
8
|
+
* regeneration (and N instances pay it N times). `seedBuildOutput()` walks
|
|
9
|
+
* the build output and inserts it into Redis in the exact record format the
|
|
10
|
+
* incremental handler reads, using **NX semantics**: an entry that a running
|
|
11
|
+
* instance has already written (necessarily newer) is never overwritten.
|
|
12
|
+
*
|
|
13
|
+
* Run it once per deploy, after `next build` and before (or while) traffic
|
|
14
|
+
* shifts — e.g. as a Docker entrypoint step or CI job:
|
|
15
|
+
*
|
|
16
|
+
* npx nextjs-cache-handler seed # uses REDIS_URL / DEPLOYMENT_VERSION
|
|
17
|
+
* npx nextjs-cache-handler seed --dir .next
|
|
18
|
+
*
|
|
19
|
+
* Seeds:
|
|
20
|
+
* - App Router routes (`.next/server/app/<route>.{html,rsc,meta}` +
|
|
21
|
+
* PPR `.segments/`) → APP_PAGE records
|
|
22
|
+
* - Pages Router routes (`.next/server/pages/<route>.{html,json}`) → PAGES
|
|
23
|
+
* - fetch cache (`.next/cache/fetch-cache/<hash>`) → FETCH records
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
interface SeedOptions {
|
|
27
|
+
client: RedisClientFactory | RedisClientConfig;
|
|
28
|
+
/** Path to the build output. Default: `./.next`. */
|
|
29
|
+
dir?: string;
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
buildNamespace?: string | (() => string);
|
|
32
|
+
compression?: "gzip" | "brotli";
|
|
33
|
+
hashTag?: boolean;
|
|
34
|
+
logger?: Pick<Logger, "warn">;
|
|
35
|
+
}
|
|
36
|
+
interface SeedSummary {
|
|
37
|
+
/** App Router routes written. */
|
|
38
|
+
routes: number;
|
|
39
|
+
/** Pages Router routes written. */
|
|
40
|
+
pages: number;
|
|
41
|
+
/** fetch-cache entries written. */
|
|
42
|
+
fetch: number;
|
|
43
|
+
/** Entries skipped because a (newer) live entry already existed (NX). */
|
|
44
|
+
skippedExisting: number;
|
|
45
|
+
/** Routes skipped because their files were incomplete or PPR-postponed. */
|
|
46
|
+
skippedIncomplete: number;
|
|
47
|
+
/** Prerendered route handlers (.body) — never seeded, by design. */
|
|
48
|
+
skippedRouteHandlers: number;
|
|
49
|
+
errors: string[];
|
|
50
|
+
}
|
|
51
|
+
declare function seedBuildOutput(options: SeedOptions): Promise<SeedSummary>;
|
|
52
|
+
|
|
53
|
+
export { type SeedOptions, type SeedSummary, seedBuildOutput };
|