@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.
Files changed (43) hide show
  1. package/CHANGELOG.md +59 -2
  2. package/README.md +47 -25
  3. package/dist/cache-components/index.cjs +235 -46
  4. package/dist/cache-components/index.cjs.map +1 -1
  5. package/dist/cache-components/index.d.cts +1 -1
  6. package/dist/cache-components/index.d.ts +1 -1
  7. package/dist/cache-components/index.js +227 -46
  8. package/dist/cache-components/index.js.map +1 -1
  9. package/dist/incremental/index.cjs +231 -41
  10. package/dist/incremental/index.cjs.map +1 -1
  11. package/dist/incremental/index.d.cts +42 -3
  12. package/dist/incremental/index.d.ts +42 -3
  13. package/dist/incremental/index.js +223 -41
  14. package/dist/incremental/index.js.map +1 -1
  15. package/dist/index.cjs +313 -70
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +305 -70
  20. package/dist/index.js.map +1 -1
  21. package/dist/ops/index.d.cts +1 -1
  22. package/dist/ops/index.d.ts +1 -1
  23. package/dist/otel/index.cjs +72 -0
  24. package/dist/otel/index.cjs.map +1 -0
  25. package/dist/otel/index.d.cts +72 -0
  26. package/dist/otel/index.d.ts +72 -0
  27. package/dist/otel/index.js +64 -0
  28. package/dist/otel/index.js.map +1 -0
  29. package/dist/shared/client/adapter-ioredis.cjs +49 -10
  30. package/dist/shared/client/adapter-ioredis.cjs.map +1 -1
  31. package/dist/shared/client/adapter-ioredis.d.cts +5 -2
  32. package/dist/shared/client/adapter-ioredis.d.ts +5 -2
  33. package/dist/shared/client/adapter-ioredis.js +43 -11
  34. package/dist/shared/client/adapter-ioredis.js.map +1 -1
  35. package/dist/shared/client/adapter-redis.cjs +22 -7
  36. package/dist/shared/client/adapter-redis.cjs.map +1 -1
  37. package/dist/shared/client/adapter-redis.d.cts +1 -1
  38. package/dist/shared/client/adapter-redis.d.ts +1 -1
  39. package/dist/shared/client/adapter-redis.js +16 -7
  40. package/dist/shared/client/adapter-redis.js.map +1 -1
  41. package/dist/{types-Dq1q6qXd.d.cts → types-Bl-rkLKX.d.cts} +37 -1
  42. package/dist/{types-Dq1q6qXd.d.ts → types-Bl-rkLKX.d.ts} +37 -1
  43. package/package.json +20 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/shared/client/adapter-ioredis.ts"],"names":[],"mappings":"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","file":"adapter-ioredis.js","sourcesContent":["/**\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\";\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 opts?.EX !== undefined\n ? client.set(k, v, \"EX\", opts.EX)\n : client.set(k, v),\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 };\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 = require(\"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 });\n}\n\nexport function createIoredisCluster(\n config: Extract<RedisClientConfig, { type: \"cluster\" }>\n): Cluster {\n \n const IORedis = require(\"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 });\n}\n"]}
1
+ {"version":3,"sources":["../../../src/shared/node-require.ts","../../../src/shared/client/adapter-ioredis.ts"],"names":[],"mappings":"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","file":"adapter-ioredis.js","sourcesContent":["/**\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 `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 opts?.EX !== undefined\n ? client.set(k, v, \"EX\", opts.EX)\n : client.set(k, v),\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 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"]}
@@ -1,18 +1,33 @@
1
1
  'use strict';
2
2
 
3
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
- }) : x)(function(x) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x + '" is not supported');
8
- });
3
+ var module$1 = require('module');
4
+ var path = require('path');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var path__default = /*#__PURE__*/_interopDefault(path);
9
+
10
+ // node_modules/tsup/assets/cjs_shims.js
11
+ var 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;
12
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
13
+ var packageRequire = module$1.createRequire(importMetaUrl);
14
+ var cwdRequire = module$1.createRequire(
15
+ path__default.default.join(process.cwd(), "__resolve-anchor__.js")
16
+ );
17
+ function nodeRequire(id) {
18
+ try {
19
+ return packageRequire(id);
20
+ } catch {
21
+ return cwdRequire(id);
22
+ }
23
+ }
9
24
 
10
25
  // src/shared/client/adapter-redis.ts
11
26
  function adaptRedisV5(client) {
12
27
  return client;
13
28
  }
14
29
  function createRedisV5Client(config) {
15
- const { createClient } = __require("redis");
30
+ const { createClient } = nodeRequire("redis");
16
31
  const useTls = config.tls ?? config.url.startsWith("rediss://");
17
32
  const opts = {
18
33
  url: config.url,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/shared/client/adapter-redis.ts"],"names":[],"mappings":";;;;;;;;;;AAcO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBACd,MAAA,EACiB;AAKjB,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,SAAA,CAAQ,OAAO,CAAA;AACxC,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,IAAO,MAAA,CAAO,GAAA,CAAI,WAAW,WAAW,CAAA;AAM9D,EAAA,MAAM,IAAA,GAAY;AAAA,IAChB,KAAK,MAAA,CAAO,GAAA;AAAA,IACZ,MAAA,EAAQ;AAAA,MACN,cAAA,EAAgB,OAAO,cAAA,IAAkB,IAAA;AAAA,MACzC,iBAAA,EAAmB,KAAA;AAAA,MACnB,GAAI,MAAA,GAAS,EAAE,GAAA,EAAK,IAAA,KAAS;AAAC;AAChC,GACF;AACA,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,EAAW,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AAE1D,EAAA,OAAO,aAAa,IAAI,CAAA;AAC1B","file":"adapter-redis.cjs","sourcesContent":["/**\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\";\n\nexport function adaptRedisV5(client: RedisClientType): RedisClientLike {\n return client as unknown as RedisClientLike;\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 } = require(\"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"]}
1
+ {"version":3,"sources":["../../../node_modules/tsup/assets/cjs_shims.js","../../../src/shared/node-require.ts","../../../src/shared/client/adapter-redis.ts"],"names":["createRequire","path"],"mappings":";;;;;;;;;;AAKA,IAAM,gBAAA,GAAmB,MACvB,OAAO,QAAA,KAAa,WAAA,GAChB,IAAI,GAAA,CAAI,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAE,CAAA,CAAE,IAAA,GAC7B,QAAA,CAAS,aAAA,IAAiB,QAAA,CAAS,aAAA,CAAc,OAAA,CAAQ,WAAA,EAAY,KAAM,QAAA,GAC1E,QAAA,CAAS,aAAA,CAAc,GAAA,GACvB,IAAI,GAAA,CAAI,SAAA,EAAW,QAAA,CAAS,OAAO,CAAA,CAAE,IAAA;AAEtC,IAAM,gCAAgC,gBAAA,EAAiB;ACC9D,IAAM,cAAA,GAAiBA,uBAAc,aAAe,CAAA;AACpD,IAAM,UAAA,GAAaA,sBAAA;AAAA,EACjBC,qBAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,GAAA,IAAO,uBAAuB;AAClD,CAAA;AAEO,SAAS,YAAY,EAAA,EAAqB;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO,eAAe,EAAE,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AAKN,IAAA,OAAO,WAAW,EAAE,CAAA;AAAA,EACtB;AACF;;;ACbO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBACd,MAAA,EACiB;AAKjB,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,WAAA,CAAY,OAAO,CAAA;AAC5C,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,IAAO,MAAA,CAAO,GAAA,CAAI,WAAW,WAAW,CAAA;AAM9D,EAAA,MAAM,IAAA,GAAY;AAAA,IAChB,KAAK,MAAA,CAAO,GAAA;AAAA,IACZ,MAAA,EAAQ;AAAA,MACN,cAAA,EAAgB,OAAO,cAAA,IAAkB,IAAA;AAAA,MACzC,iBAAA,EAAmB,KAAA;AAAA,MACnB,GAAI,MAAA,GAAS,EAAE,GAAA,EAAK,IAAA,KAAS;AAAC;AAChC,GACF;AACA,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,EAAW,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AAE1D,EAAA,OAAO,aAAa,IAAI,CAAA;AAC1B","file":"adapter-redis.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 return client as unknown as RedisClientLike;\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"]}
@@ -1,5 +1,5 @@
1
1
  import { RedisClientType } from 'redis';
2
- import { R as RedisClientLike, a as RedisClientConfig } from '../../types-Dq1q6qXd.cjs';
2
+ import { R as RedisClientLike, a as RedisClientConfig } from '../../types-Bl-rkLKX.cjs';
3
3
 
4
4
  /**
5
5
  * Adapter for `redis@5` (the official `node-redis` client).
@@ -1,5 +1,5 @@
1
1
  import { RedisClientType } from 'redis';
2
- import { R as RedisClientLike, a as RedisClientConfig } from '../../types-Dq1q6qXd.js';
2
+ import { R as RedisClientLike, a as RedisClientConfig } from '../../types-Bl-rkLKX.js';
3
3
 
4
4
  /**
5
5
  * Adapter for `redis@5` (the official `node-redis` client).
@@ -1,16 +1,25 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
1
+ import { createRequire } from 'module';
2
+ import path from 'path';
3
+
4
+ // src/shared/node-require.ts
5
+ var packageRequire = createRequire(import.meta.url);
6
+ var cwdRequire = createRequire(
7
+ path.join(process.cwd(), "__resolve-anchor__.js")
8
+ );
9
+ function nodeRequire(id) {
10
+ try {
11
+ return packageRequire(id);
12
+ } catch {
13
+ return cwdRequire(id);
14
+ }
15
+ }
7
16
 
8
17
  // src/shared/client/adapter-redis.ts
9
18
  function adaptRedisV5(client) {
10
19
  return client;
11
20
  }
12
21
  function createRedisV5Client(config) {
13
- const { createClient } = __require("redis");
22
+ const { createClient } = nodeRequire("redis");
14
23
  const useTls = config.tls ?? config.url.startsWith("rediss://");
15
24
  const opts = {
16
25
  url: config.url,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/shared/client/adapter-redis.ts"],"names":[],"mappings":";;;;;;;;AAcO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBACd,MAAA,EACiB;AAKjB,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,SAAA,CAAQ,OAAO,CAAA;AACxC,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,IAAO,MAAA,CAAO,GAAA,CAAI,WAAW,WAAW,CAAA;AAM9D,EAAA,MAAM,IAAA,GAAY;AAAA,IAChB,KAAK,MAAA,CAAO,GAAA;AAAA,IACZ,MAAA,EAAQ;AAAA,MACN,cAAA,EAAgB,OAAO,cAAA,IAAkB,IAAA;AAAA,MACzC,iBAAA,EAAmB,KAAA;AAAA,MACnB,GAAI,MAAA,GAAS,EAAE,GAAA,EAAK,IAAA,KAAS;AAAC;AAChC,GACF;AACA,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,EAAW,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AAE1D,EAAA,OAAO,aAAa,IAAI,CAAA;AAC1B","file":"adapter-redis.js","sourcesContent":["/**\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\";\n\nexport function adaptRedisV5(client: RedisClientType): RedisClientLike {\n return client as unknown as RedisClientLike;\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 } = require(\"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"]}
1
+ {"version":3,"sources":["../../../src/shared/node-require.ts","../../../src/shared/client/adapter-redis.ts"],"names":[],"mappings":";;;;AAaA,IAAM,cAAA,GAAiB,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACpD,IAAM,UAAA,GAAa,aAAA;AAAA,EACjB,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,GAAA,IAAO,uBAAuB;AAClD,CAAA;AAEO,SAAS,YAAY,EAAA,EAAqB;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO,eAAe,EAAE,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AAKN,IAAA,OAAO,WAAW,EAAE,CAAA;AAAA,EACtB;AACF;;;ACbO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,oBACd,MAAA,EACiB;AAKjB,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,WAAA,CAAY,OAAO,CAAA;AAC5C,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,IAAO,MAAA,CAAO,GAAA,CAAI,WAAW,WAAW,CAAA;AAM9D,EAAA,MAAM,IAAA,GAAY;AAAA,IAChB,KAAK,MAAA,CAAO,GAAA;AAAA,IACZ,MAAA,EAAQ;AAAA,MACN,cAAA,EAAgB,OAAO,cAAA,IAAkB,IAAA;AAAA,MACzC,iBAAA,EAAmB,KAAA;AAAA,MACnB,GAAI,MAAA,GAAS,EAAE,GAAA,EAAK,IAAA,KAAS;AAAC;AAChC,GACF;AACA,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,EAAW,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AAE1D,EAAA,OAAO,aAAa,IAAI,CAAA;AAC1B","file":"adapter-redis.js","sourcesContent":["/**\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 return client as unknown as RedisClientLike;\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"]}
@@ -32,6 +32,13 @@ interface RedisClientLike {
32
32
  }): AsyncIterable<string[] | string>;
33
33
  ping(): Promise<string>;
34
34
  on(event: "error", listener: (err: Error) => void): unknown;
35
+ /**
36
+ * Close the underlying connection without waiting for pending replies.
37
+ * Called by the connection manager when a dead client is replaced. Optional:
38
+ * raw `redis@5` clients expose `destroy` and ioredis exposes `disconnect`,
39
+ * both of which are used as fallbacks when this is absent.
40
+ */
41
+ dispose?(): void;
35
42
  }
36
43
  type RedisClientFactory = () => RedisClientLike | Promise<RedisClientLike>;
37
44
  type RedisClientConfig = {
@@ -54,6 +61,21 @@ type RedisClientConfig = {
54
61
  }>;
55
62
  password?: string;
56
63
  tls?: boolean;
64
+ } | {
65
+ type: "sentinel";
66
+ /** Sentinel endpoints (not the data nodes — those are discovered). */
67
+ sentinels: Array<{
68
+ host: string;
69
+ port: number;
70
+ }>;
71
+ /** Master group name as configured in sentinel.conf (e.g. "mymaster"). */
72
+ name: string;
73
+ /** Password for the discovered Redis data nodes. */
74
+ password?: string;
75
+ /** Password for the sentinel processes themselves, when set. */
76
+ sentinelPassword?: string;
77
+ tls?: boolean;
78
+ connectTimeout?: number;
57
79
  };
58
80
  /**
59
81
  * Fallback strategy when Redis is unavailable.
@@ -71,7 +93,7 @@ type FallbackStrategy = "auto" | "always" | "never";
71
93
  * Optional — when not provided, only the process-local counters in
72
94
  * `src/shared/metrics.ts` are updated.
73
95
  */
74
- type MetricEventType = "cache.hit" | "cache.miss" | "cache.stale" | "cache.stale.refresh.leader" | "cache.stale.refresh.follower" | "cache.stale.refresh.skipped" | "cache.set" | "cache.set.failed" | "tag.invalidate.soft" | "tag.invalidate.hard" | "tag.expiration.read" | "redis.connect.failed" | "redis.timeout" | "fallback.activated" | "build_phase.skip";
96
+ type MetricEventType = "cache.hit" | "cache.miss" | "cache.get.deduped" | "cache.stale" | "cache.stale.refresh.leader" | "cache.stale.refresh.follower" | "cache.set" | "cache.set.failed" | "tag.invalidate.soft" | "tag.invalidate.hard" | "tag.expiration.read" | "redis.connect.failed" | "redis.timeout" | "fallback.activated" | "build_phase.skip";
75
97
  interface MetricEvent {
76
98
  type: MetricEventType;
77
99
  /** Operation latency in milliseconds, when measurable. */
@@ -134,6 +156,20 @@ interface CacheHandlerOptions {
134
156
  abortTimeoutMs?: number;
135
157
  /** Fallback strategy. See {@link FallbackStrategy}. */
136
158
  fallback?: FallbackStrategy;
159
+ /**
160
+ * Maximum number of entries kept by the in-memory fallback store (and the
161
+ * same cap for its tag-set index). Least-recently-used entries are evicted
162
+ * beyond the cap, so a long Redis outage on a busy site degrades to partial
163
+ * caching instead of unbounded process memory growth. Default: 1000.
164
+ */
165
+ memoryMaxEntries?: number;
166
+ /**
167
+ * Compress entry values before writing them to Redis (node:zlib, no added
168
+ * dependencies). Reads always auto-detect: entries written with a different
169
+ * setting (or none) stay readable, so this can be enabled or switched on a
170
+ * live cache. Payloads under 1 KiB are stored uncompressed. Default: off.
171
+ */
172
+ compression?: "gzip" | "brotli";
137
173
  /**
138
174
  * Whether to keep returning a stale entry in the SWR window
139
175
  * (`revalidate < age < expire`) while Next.js triggers a background refresh.
@@ -32,6 +32,13 @@ interface RedisClientLike {
32
32
  }): AsyncIterable<string[] | string>;
33
33
  ping(): Promise<string>;
34
34
  on(event: "error", listener: (err: Error) => void): unknown;
35
+ /**
36
+ * Close the underlying connection without waiting for pending replies.
37
+ * Called by the connection manager when a dead client is replaced. Optional:
38
+ * raw `redis@5` clients expose `destroy` and ioredis exposes `disconnect`,
39
+ * both of which are used as fallbacks when this is absent.
40
+ */
41
+ dispose?(): void;
35
42
  }
36
43
  type RedisClientFactory = () => RedisClientLike | Promise<RedisClientLike>;
37
44
  type RedisClientConfig = {
@@ -54,6 +61,21 @@ type RedisClientConfig = {
54
61
  }>;
55
62
  password?: string;
56
63
  tls?: boolean;
64
+ } | {
65
+ type: "sentinel";
66
+ /** Sentinel endpoints (not the data nodes — those are discovered). */
67
+ sentinels: Array<{
68
+ host: string;
69
+ port: number;
70
+ }>;
71
+ /** Master group name as configured in sentinel.conf (e.g. "mymaster"). */
72
+ name: string;
73
+ /** Password for the discovered Redis data nodes. */
74
+ password?: string;
75
+ /** Password for the sentinel processes themselves, when set. */
76
+ sentinelPassword?: string;
77
+ tls?: boolean;
78
+ connectTimeout?: number;
57
79
  };
58
80
  /**
59
81
  * Fallback strategy when Redis is unavailable.
@@ -71,7 +93,7 @@ type FallbackStrategy = "auto" | "always" | "never";
71
93
  * Optional — when not provided, only the process-local counters in
72
94
  * `src/shared/metrics.ts` are updated.
73
95
  */
74
- type MetricEventType = "cache.hit" | "cache.miss" | "cache.stale" | "cache.stale.refresh.leader" | "cache.stale.refresh.follower" | "cache.stale.refresh.skipped" | "cache.set" | "cache.set.failed" | "tag.invalidate.soft" | "tag.invalidate.hard" | "tag.expiration.read" | "redis.connect.failed" | "redis.timeout" | "fallback.activated" | "build_phase.skip";
96
+ type MetricEventType = "cache.hit" | "cache.miss" | "cache.get.deduped" | "cache.stale" | "cache.stale.refresh.leader" | "cache.stale.refresh.follower" | "cache.set" | "cache.set.failed" | "tag.invalidate.soft" | "tag.invalidate.hard" | "tag.expiration.read" | "redis.connect.failed" | "redis.timeout" | "fallback.activated" | "build_phase.skip";
75
97
  interface MetricEvent {
76
98
  type: MetricEventType;
77
99
  /** Operation latency in milliseconds, when measurable. */
@@ -134,6 +156,20 @@ interface CacheHandlerOptions {
134
156
  abortTimeoutMs?: number;
135
157
  /** Fallback strategy. See {@link FallbackStrategy}. */
136
158
  fallback?: FallbackStrategy;
159
+ /**
160
+ * Maximum number of entries kept by the in-memory fallback store (and the
161
+ * same cap for its tag-set index). Least-recently-used entries are evicted
162
+ * beyond the cap, so a long Redis outage on a busy site degrades to partial
163
+ * caching instead of unbounded process memory growth. Default: 1000.
164
+ */
165
+ memoryMaxEntries?: number;
166
+ /**
167
+ * Compress entry values before writing them to Redis (node:zlib, no added
168
+ * dependencies). Reads always auto-detect: entries written with a different
169
+ * setting (or none) stay readable, so this can be enabled or switched on a
170
+ * live cache. Payloads under 1 KiB are stored uncompressed. Default: off.
171
+ */
172
+ compression?: "gzip" | "brotli";
137
173
  /**
138
174
  * Whether to keep returning a stale entry in the SWR window
139
175
  * (`revalidate < age < expire`) while Next.js triggers a background refresh.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leejpsd/nextjs-cache-handler",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The only Redis cache handler for Next.js 16 that ships both cacheHandler (ISR) and cacheHandlers ('use cache') — production-validated for multi-instance deployments where @fortedigital lists 'Help needed'.",
5
5
  "keywords": [
6
6
  "next",
@@ -47,6 +47,9 @@
47
47
  ],
48
48
  "ops": [
49
49
  "./dist/ops/index.d.ts"
50
+ ],
51
+ "otel": [
52
+ "./dist/otel/index.d.ts"
50
53
  ]
51
54
  }
52
55
  },
@@ -111,6 +114,16 @@
111
114
  "default": "./dist/ops/index.cjs"
112
115
  }
113
116
  },
117
+ "./otel": {
118
+ "import": {
119
+ "types": "./dist/otel/index.d.ts",
120
+ "default": "./dist/otel/index.js"
121
+ },
122
+ "require": {
123
+ "types": "./dist/otel/index.d.cts",
124
+ "default": "./dist/otel/index.cjs"
125
+ }
126
+ },
114
127
  "./package.json": "./package.json"
115
128
  },
116
129
  "files": [
@@ -141,9 +154,10 @@
141
154
  "prepublishOnly": "npm run verify && npm run publint && npm run attw"
142
155
  },
143
156
  "peerDependencies": {
144
- "next": ">=16.1.5 <17",
157
+ "next": ">=15.0.0 <17",
145
158
  "redis": ">=5.0.0",
146
- "ioredis": ">=5.0.0"
159
+ "ioredis": ">=5.0.0",
160
+ "@opentelemetry/api": ">=1.0.0"
147
161
  },
148
162
  "peerDependenciesMeta": {
149
163
  "redis": {
@@ -151,6 +165,9 @@
151
165
  },
152
166
  "ioredis": {
153
167
  "optional": true
168
+ },
169
+ "@opentelemetry/api": {
170
+ "optional": true
154
171
  }
155
172
  },
156
173
  "devDependencies": {