@leejpsd/nextjs-cache-handler 0.2.0 → 0.3.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +67 -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 +27 -5
@@ -1,4 +1,4 @@
1
- import { d as MetricEventType } from '../types-Dq1q6qXd.cjs';
1
+ import { d as MetricEventType } from '../types-Bl-rkLKX.cjs';
2
2
 
3
3
  /**
4
4
  * Process-local metric counters with an optional emit hook.
@@ -1,4 +1,4 @@
1
- import { d as MetricEventType } from '../types-Dq1q6qXd.js';
1
+ import { d as MetricEventType } from '../types-Bl-rkLKX.js';
2
2
 
3
3
  /**
4
4
  * Process-local metric counters with an optional emit hook.
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
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
+ }
24
+
25
+ // src/otel/index.ts
26
+ var ATTR_ALLOWLIST = ["freshness", "backend", "reason", "op"];
27
+ function lowCardinalityAttrs(event) {
28
+ const out = { type: event.type };
29
+ const meta = event.meta ?? {};
30
+ for (const key of ATTR_ALLOWLIST) {
31
+ const v = meta[key];
32
+ if (typeof v === "string") out[key] = v;
33
+ }
34
+ return out;
35
+ }
36
+ function resolveApi() {
37
+ try {
38
+ return nodeRequire("@opentelemetry/api");
39
+ } catch {
40
+ throw new Error(
41
+ "[next-cache] createOtelMetricEmitter needs @opentelemetry/api. Install it in your app (npm i @opentelemetry/api) and configure a MeterProvider, or pass the module via the `api` option."
42
+ );
43
+ }
44
+ }
45
+ function createOtelMetricEmitter(options = {}) {
46
+ const api = options.api ?? resolveApi();
47
+ const meter = api.metrics.getMeter(
48
+ options.meterName ?? "nextjs-cache-handler"
49
+ );
50
+ const counter = meter.createCounter(
51
+ options.counterName ?? "nextjs_cache.events_total",
52
+ { description: "Cache handler events by type" }
53
+ );
54
+ const histogram = meter.createHistogram(
55
+ options.histogramName ?? "nextjs_cache.op_latency_ms",
56
+ {
57
+ description: "Per-op latency for events that carry an `ms` field",
58
+ unit: "ms"
59
+ }
60
+ );
61
+ return (event) => {
62
+ const attrs = lowCardinalityAttrs(event);
63
+ counter.add(1, attrs);
64
+ if (typeof event.ms === "number") {
65
+ histogram.record(event.ms, attrs);
66
+ }
67
+ };
68
+ }
69
+
70
+ exports.createOtelMetricEmitter = createOtelMetricEmitter;
71
+ //# sourceMappingURL=index.cjs.map
72
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../node_modules/tsup/assets/cjs_shims.js","../../src/shared/node-require.ts","../../src/otel/index.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;;;AC2CA,IAAM,cAAA,GAAiB,CAAC,WAAA,EAAa,SAAA,EAAW,UAAU,IAAI,CAAA;AAE9D,SAAS,oBAAoB,KAAA,EAA4C;AACvE,EAAA,MAAM,GAAA,GAA8B,EAAE,IAAA,EAAM,KAAA,CAAM,IAAA,EAAK;AACvD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,IAAQ,EAAC;AAC5B,EAAA,KAAA,MAAW,OAAO,cAAA,EAAgB;AAChC,IAAA,MAAM,CAAA,GAAI,KAAK,GAAG,CAAA;AAClB,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,GAAA,CAAI,GAAG,CAAA,GAAI,CAAA;AAAA,EACxC;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,UAAA,GAA0B;AACjC,EAAA,IAAI;AAGF,IAAA,OAAO,YAAY,oBAAoB,CAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAGF;AAAA,EACF;AACF;AAOO,SAAS,uBAAA,CACd,OAAA,GAA8B,EAAC,EAChB;AACf,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,IAAO,UAAA,EAAW;AACtC,EAAA,MAAM,KAAA,GAAQ,IAAI,OAAA,CAAQ,QAAA;AAAA,IACxB,QAAQ,SAAA,IAAa;AAAA,GACvB;AACA,EAAA,MAAM,UAAU,KAAA,CAAM,aAAA;AAAA,IACpB,QAAQ,WAAA,IAAe,2BAAA;AAAA,IACvB,EAAE,aAAa,8BAAA;AAA+B,GAChD;AACA,EAAA,MAAM,YAAY,KAAA,CAAM,eAAA;AAAA,IACtB,QAAQ,aAAA,IAAiB,4BAAA;AAAA,IACzB;AAAA,MACE,WAAA,EAAa,oDAAA;AAAA,MACb,IAAA,EAAM;AAAA;AACR,GACF;AAEA,EAAA,OAAO,CAAC,KAAA,KAAuB;AAC7B,IAAA,MAAM,KAAA,GAAQ,oBAAoB,KAAK,CAAA;AACvC,IAAA,OAAA,CAAQ,GAAA,CAAI,GAAG,KAAK,CAAA;AACpB,IAAA,IAAI,OAAO,KAAA,CAAM,EAAA,KAAO,QAAA,EAAU;AAChC,MAAA,SAAA,CAAU,MAAA,CAAO,KAAA,CAAM,EAAA,EAAI,KAAK,CAAA;AAAA,IAClC;AAAA,EACF,CAAA;AACF","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 * Built-in OpenTelemetry metric emitter.\n *\n * `@opentelemetry/api` stays out of this package's dependency tree: the\n * module talks to it through structural types and resolves it at runtime\n * (injectable for tests / custom setups). Install `@opentelemetry/api` and\n * configure a MeterProvider (e.g. `@opentelemetry/sdk-node`) in your app,\n * then:\n *\n * ```ts\n * import { createOtelMetricEmitter } from \"@leejpsd/nextjs-cache-handler/otel\";\n *\n * createCacheComponentsHandler({\n * client: { type: \"redis\", url: process.env.REDIS_URL },\n * onMetric: createOtelMetricEmitter(),\n * });\n * ```\n *\n * Instruments:\n * - counter `nextjs_cache.events_total` — one increment per event\n * - histogram `nextjs_cache.op_latency_ms` — for events carrying `ms`\n *\n * Cardinality discipline: only an allowlist of meta fields (freshness,\n * backend, reason, op) is promoted to attributes. Cache keys and tag names\n * never enter the metric pipeline.\n */\n\nimport type { MetricEmitter, MetricEvent } from \"../types.js\";\nimport { nodeRequire } from \"../shared/node-require.js\";\n\nexport interface OtelCounterLike {\n add(value: number, attributes?: Record<string, string>): void;\n}\n\nexport interface OtelHistogramLike {\n record(value: number, attributes?: Record<string, string>): void;\n}\n\nexport interface OtelMeterLike {\n createCounter(\n name: string,\n options?: { description?: string }\n ): OtelCounterLike;\n createHistogram(\n name: string,\n options?: { description?: string; unit?: string }\n ): OtelHistogramLike;\n}\n\n/** The subset of `@opentelemetry/api` this adapter touches. */\nexport interface OtelApiLike {\n metrics: {\n getMeter(name: string, version?: string): OtelMeterLike;\n };\n}\n\nexport interface OtelEmitterOptions {\n /**\n * The `@opentelemetry/api` module (or a compatible object). Defaults to\n * `require(\"@opentelemetry/api\")` (via createRequire, so it works from\n * both the CJS and ESM builds) — pass explicitly in tests or custom setups.\n */\n api?: OtelApiLike;\n /** Meter name. Default: \"nextjs-cache-handler\". */\n meterName?: string;\n /** Counter instrument name. Default: \"nextjs_cache.events_total\". */\n counterName?: string;\n /** Histogram instrument name. Default: \"nextjs_cache.op_latency_ms\". */\n histogramName?: string;\n}\n\nconst ATTR_ALLOWLIST = [\"freshness\", \"backend\", \"reason\", \"op\"] as const;\n\nfunction lowCardinalityAttrs(event: MetricEvent): Record<string, string> {\n const out: Record<string, string> = { type: event.type };\n const meta = event.meta ?? {};\n for (const key of ATTR_ALLOWLIST) {\n const v = meta[key];\n if (typeof v === \"string\") out[key] = v;\n }\n return out;\n}\n\nfunction resolveApi(): OtelApiLike {\n try {\n // Runtime-only lookup — @opentelemetry/api is NOT a dependency of this\n // package. It must come from the application.\n return nodeRequire(\"@opentelemetry/api\") as OtelApiLike;\n } catch {\n throw new Error(\n \"[next-cache] createOtelMetricEmitter needs @opentelemetry/api. \" +\n \"Install it in your app (npm i @opentelemetry/api) and configure a \" +\n \"MeterProvider, or pass the module via the `api` option.\"\n );\n }\n}\n\n/**\n * Build a `MetricEmitter` that forwards every handler event to OpenTelemetry.\n * Wire it to the `onMetric` option — emitter errors are already swallowed by\n * the handlers, so telemetry can never break the cache path.\n */\nexport function createOtelMetricEmitter(\n options: OtelEmitterOptions = {}\n): MetricEmitter {\n const api = options.api ?? resolveApi();\n const meter = api.metrics.getMeter(\n options.meterName ?? \"nextjs-cache-handler\"\n );\n const counter = meter.createCounter(\n options.counterName ?? \"nextjs_cache.events_total\",\n { description: \"Cache handler events by type\" }\n );\n const histogram = meter.createHistogram(\n options.histogramName ?? \"nextjs_cache.op_latency_ms\",\n {\n description: \"Per-op latency for events that carry an `ms` field\",\n unit: \"ms\",\n }\n );\n\n return (event: MetricEvent) => {\n const attrs = lowCardinalityAttrs(event);\n counter.add(1, attrs);\n if (typeof event.ms === \"number\") {\n histogram.record(event.ms, attrs);\n }\n };\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import { M as MetricEmitter } from '../types-Bl-rkLKX.cjs';
2
+
3
+ /**
4
+ * Built-in OpenTelemetry metric emitter.
5
+ *
6
+ * `@opentelemetry/api` stays out of this package's dependency tree: the
7
+ * module talks to it through structural types and resolves it at runtime
8
+ * (injectable for tests / custom setups). Install `@opentelemetry/api` and
9
+ * configure a MeterProvider (e.g. `@opentelemetry/sdk-node`) in your app,
10
+ * then:
11
+ *
12
+ * ```ts
13
+ * import { createOtelMetricEmitter } from "@leejpsd/nextjs-cache-handler/otel";
14
+ *
15
+ * createCacheComponentsHandler({
16
+ * client: { type: "redis", url: process.env.REDIS_URL },
17
+ * onMetric: createOtelMetricEmitter(),
18
+ * });
19
+ * ```
20
+ *
21
+ * Instruments:
22
+ * - counter `nextjs_cache.events_total` — one increment per event
23
+ * - histogram `nextjs_cache.op_latency_ms` — for events carrying `ms`
24
+ *
25
+ * Cardinality discipline: only an allowlist of meta fields (freshness,
26
+ * backend, reason, op) is promoted to attributes. Cache keys and tag names
27
+ * never enter the metric pipeline.
28
+ */
29
+
30
+ interface OtelCounterLike {
31
+ add(value: number, attributes?: Record<string, string>): void;
32
+ }
33
+ interface OtelHistogramLike {
34
+ record(value: number, attributes?: Record<string, string>): void;
35
+ }
36
+ interface OtelMeterLike {
37
+ createCounter(name: string, options?: {
38
+ description?: string;
39
+ }): OtelCounterLike;
40
+ createHistogram(name: string, options?: {
41
+ description?: string;
42
+ unit?: string;
43
+ }): OtelHistogramLike;
44
+ }
45
+ /** The subset of `@opentelemetry/api` this adapter touches. */
46
+ interface OtelApiLike {
47
+ metrics: {
48
+ getMeter(name: string, version?: string): OtelMeterLike;
49
+ };
50
+ }
51
+ interface OtelEmitterOptions {
52
+ /**
53
+ * The `@opentelemetry/api` module (or a compatible object). Defaults to
54
+ * `require("@opentelemetry/api")` (via createRequire, so it works from
55
+ * both the CJS and ESM builds) — pass explicitly in tests or custom setups.
56
+ */
57
+ api?: OtelApiLike;
58
+ /** Meter name. Default: "nextjs-cache-handler". */
59
+ meterName?: string;
60
+ /** Counter instrument name. Default: "nextjs_cache.events_total". */
61
+ counterName?: string;
62
+ /** Histogram instrument name. Default: "nextjs_cache.op_latency_ms". */
63
+ histogramName?: string;
64
+ }
65
+ /**
66
+ * Build a `MetricEmitter` that forwards every handler event to OpenTelemetry.
67
+ * Wire it to the `onMetric` option — emitter errors are already swallowed by
68
+ * the handlers, so telemetry can never break the cache path.
69
+ */
70
+ declare function createOtelMetricEmitter(options?: OtelEmitterOptions): MetricEmitter;
71
+
72
+ export { type OtelApiLike, type OtelCounterLike, type OtelEmitterOptions, type OtelHistogramLike, type OtelMeterLike, createOtelMetricEmitter };
@@ -0,0 +1,72 @@
1
+ import { M as MetricEmitter } from '../types-Bl-rkLKX.js';
2
+
3
+ /**
4
+ * Built-in OpenTelemetry metric emitter.
5
+ *
6
+ * `@opentelemetry/api` stays out of this package's dependency tree: the
7
+ * module talks to it through structural types and resolves it at runtime
8
+ * (injectable for tests / custom setups). Install `@opentelemetry/api` and
9
+ * configure a MeterProvider (e.g. `@opentelemetry/sdk-node`) in your app,
10
+ * then:
11
+ *
12
+ * ```ts
13
+ * import { createOtelMetricEmitter } from "@leejpsd/nextjs-cache-handler/otel";
14
+ *
15
+ * createCacheComponentsHandler({
16
+ * client: { type: "redis", url: process.env.REDIS_URL },
17
+ * onMetric: createOtelMetricEmitter(),
18
+ * });
19
+ * ```
20
+ *
21
+ * Instruments:
22
+ * - counter `nextjs_cache.events_total` — one increment per event
23
+ * - histogram `nextjs_cache.op_latency_ms` — for events carrying `ms`
24
+ *
25
+ * Cardinality discipline: only an allowlist of meta fields (freshness,
26
+ * backend, reason, op) is promoted to attributes. Cache keys and tag names
27
+ * never enter the metric pipeline.
28
+ */
29
+
30
+ interface OtelCounterLike {
31
+ add(value: number, attributes?: Record<string, string>): void;
32
+ }
33
+ interface OtelHistogramLike {
34
+ record(value: number, attributes?: Record<string, string>): void;
35
+ }
36
+ interface OtelMeterLike {
37
+ createCounter(name: string, options?: {
38
+ description?: string;
39
+ }): OtelCounterLike;
40
+ createHistogram(name: string, options?: {
41
+ description?: string;
42
+ unit?: string;
43
+ }): OtelHistogramLike;
44
+ }
45
+ /** The subset of `@opentelemetry/api` this adapter touches. */
46
+ interface OtelApiLike {
47
+ metrics: {
48
+ getMeter(name: string, version?: string): OtelMeterLike;
49
+ };
50
+ }
51
+ interface OtelEmitterOptions {
52
+ /**
53
+ * The `@opentelemetry/api` module (or a compatible object). Defaults to
54
+ * `require("@opentelemetry/api")` (via createRequire, so it works from
55
+ * both the CJS and ESM builds) — pass explicitly in tests or custom setups.
56
+ */
57
+ api?: OtelApiLike;
58
+ /** Meter name. Default: "nextjs-cache-handler". */
59
+ meterName?: string;
60
+ /** Counter instrument name. Default: "nextjs_cache.events_total". */
61
+ counterName?: string;
62
+ /** Histogram instrument name. Default: "nextjs_cache.op_latency_ms". */
63
+ histogramName?: string;
64
+ }
65
+ /**
66
+ * Build a `MetricEmitter` that forwards every handler event to OpenTelemetry.
67
+ * Wire it to the `onMetric` option — emitter errors are already swallowed by
68
+ * the handlers, so telemetry can never break the cache path.
69
+ */
70
+ declare function createOtelMetricEmitter(options?: OtelEmitterOptions): MetricEmitter;
71
+
72
+ export { type OtelApiLike, type OtelCounterLike, type OtelEmitterOptions, type OtelHistogramLike, type OtelMeterLike, createOtelMetricEmitter };
@@ -0,0 +1,64 @@
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
+ }
16
+
17
+ // src/otel/index.ts
18
+ var ATTR_ALLOWLIST = ["freshness", "backend", "reason", "op"];
19
+ function lowCardinalityAttrs(event) {
20
+ const out = { type: event.type };
21
+ const meta = event.meta ?? {};
22
+ for (const key of ATTR_ALLOWLIST) {
23
+ const v = meta[key];
24
+ if (typeof v === "string") out[key] = v;
25
+ }
26
+ return out;
27
+ }
28
+ function resolveApi() {
29
+ try {
30
+ return nodeRequire("@opentelemetry/api");
31
+ } catch {
32
+ throw new Error(
33
+ "[next-cache] createOtelMetricEmitter needs @opentelemetry/api. Install it in your app (npm i @opentelemetry/api) and configure a MeterProvider, or pass the module via the `api` option."
34
+ );
35
+ }
36
+ }
37
+ function createOtelMetricEmitter(options = {}) {
38
+ const api = options.api ?? resolveApi();
39
+ const meter = api.metrics.getMeter(
40
+ options.meterName ?? "nextjs-cache-handler"
41
+ );
42
+ const counter = meter.createCounter(
43
+ options.counterName ?? "nextjs_cache.events_total",
44
+ { description: "Cache handler events by type" }
45
+ );
46
+ const histogram = meter.createHistogram(
47
+ options.histogramName ?? "nextjs_cache.op_latency_ms",
48
+ {
49
+ description: "Per-op latency for events that carry an `ms` field",
50
+ unit: "ms"
51
+ }
52
+ );
53
+ return (event) => {
54
+ const attrs = lowCardinalityAttrs(event);
55
+ counter.add(1, attrs);
56
+ if (typeof event.ms === "number") {
57
+ histogram.record(event.ms, attrs);
58
+ }
59
+ };
60
+ }
61
+
62
+ export { createOtelMetricEmitter };
63
+ //# sourceMappingURL=index.js.map
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shared/node-require.ts","../../src/otel/index.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;;;AC2CA,IAAM,cAAA,GAAiB,CAAC,WAAA,EAAa,SAAA,EAAW,UAAU,IAAI,CAAA;AAE9D,SAAS,oBAAoB,KAAA,EAA4C;AACvE,EAAA,MAAM,GAAA,GAA8B,EAAE,IAAA,EAAM,KAAA,CAAM,IAAA,EAAK;AACvD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,IAAQ,EAAC;AAC5B,EAAA,KAAA,MAAW,OAAO,cAAA,EAAgB;AAChC,IAAA,MAAM,CAAA,GAAI,KAAK,GAAG,CAAA;AAClB,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,GAAA,CAAI,GAAG,CAAA,GAAI,CAAA;AAAA,EACxC;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,UAAA,GAA0B;AACjC,EAAA,IAAI;AAGF,IAAA,OAAO,YAAY,oBAAoB,CAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAGF;AAAA,EACF;AACF;AAOO,SAAS,uBAAA,CACd,OAAA,GAA8B,EAAC,EAChB;AACf,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,IAAO,UAAA,EAAW;AACtC,EAAA,MAAM,KAAA,GAAQ,IAAI,OAAA,CAAQ,QAAA;AAAA,IACxB,QAAQ,SAAA,IAAa;AAAA,GACvB;AACA,EAAA,MAAM,UAAU,KAAA,CAAM,aAAA;AAAA,IACpB,QAAQ,WAAA,IAAe,2BAAA;AAAA,IACvB,EAAE,aAAa,8BAAA;AAA+B,GAChD;AACA,EAAA,MAAM,YAAY,KAAA,CAAM,eAAA;AAAA,IACtB,QAAQ,aAAA,IAAiB,4BAAA;AAAA,IACzB;AAAA,MACE,WAAA,EAAa,oDAAA;AAAA,MACb,IAAA,EAAM;AAAA;AACR,GACF;AAEA,EAAA,OAAO,CAAC,KAAA,KAAuB;AAC7B,IAAA,MAAM,KAAA,GAAQ,oBAAoB,KAAK,CAAA;AACvC,IAAA,OAAA,CAAQ,GAAA,CAAI,GAAG,KAAK,CAAA;AACpB,IAAA,IAAI,OAAO,KAAA,CAAM,EAAA,KAAO,QAAA,EAAU;AAChC,MAAA,SAAA,CAAU,MAAA,CAAO,KAAA,CAAM,EAAA,EAAI,KAAK,CAAA;AAAA,IAClC;AAAA,EACF,CAAA;AACF","file":"index.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 * Built-in OpenTelemetry metric emitter.\n *\n * `@opentelemetry/api` stays out of this package's dependency tree: the\n * module talks to it through structural types and resolves it at runtime\n * (injectable for tests / custom setups). Install `@opentelemetry/api` and\n * configure a MeterProvider (e.g. `@opentelemetry/sdk-node`) in your app,\n * then:\n *\n * ```ts\n * import { createOtelMetricEmitter } from \"@leejpsd/nextjs-cache-handler/otel\";\n *\n * createCacheComponentsHandler({\n * client: { type: \"redis\", url: process.env.REDIS_URL },\n * onMetric: createOtelMetricEmitter(),\n * });\n * ```\n *\n * Instruments:\n * - counter `nextjs_cache.events_total` — one increment per event\n * - histogram `nextjs_cache.op_latency_ms` — for events carrying `ms`\n *\n * Cardinality discipline: only an allowlist of meta fields (freshness,\n * backend, reason, op) is promoted to attributes. Cache keys and tag names\n * never enter the metric pipeline.\n */\n\nimport type { MetricEmitter, MetricEvent } from \"../types.js\";\nimport { nodeRequire } from \"../shared/node-require.js\";\n\nexport interface OtelCounterLike {\n add(value: number, attributes?: Record<string, string>): void;\n}\n\nexport interface OtelHistogramLike {\n record(value: number, attributes?: Record<string, string>): void;\n}\n\nexport interface OtelMeterLike {\n createCounter(\n name: string,\n options?: { description?: string }\n ): OtelCounterLike;\n createHistogram(\n name: string,\n options?: { description?: string; unit?: string }\n ): OtelHistogramLike;\n}\n\n/** The subset of `@opentelemetry/api` this adapter touches. */\nexport interface OtelApiLike {\n metrics: {\n getMeter(name: string, version?: string): OtelMeterLike;\n };\n}\n\nexport interface OtelEmitterOptions {\n /**\n * The `@opentelemetry/api` module (or a compatible object). Defaults to\n * `require(\"@opentelemetry/api\")` (via createRequire, so it works from\n * both the CJS and ESM builds) — pass explicitly in tests or custom setups.\n */\n api?: OtelApiLike;\n /** Meter name. Default: \"nextjs-cache-handler\". */\n meterName?: string;\n /** Counter instrument name. Default: \"nextjs_cache.events_total\". */\n counterName?: string;\n /** Histogram instrument name. Default: \"nextjs_cache.op_latency_ms\". */\n histogramName?: string;\n}\n\nconst ATTR_ALLOWLIST = [\"freshness\", \"backend\", \"reason\", \"op\"] as const;\n\nfunction lowCardinalityAttrs(event: MetricEvent): Record<string, string> {\n const out: Record<string, string> = { type: event.type };\n const meta = event.meta ?? {};\n for (const key of ATTR_ALLOWLIST) {\n const v = meta[key];\n if (typeof v === \"string\") out[key] = v;\n }\n return out;\n}\n\nfunction resolveApi(): OtelApiLike {\n try {\n // Runtime-only lookup — @opentelemetry/api is NOT a dependency of this\n // package. It must come from the application.\n return nodeRequire(\"@opentelemetry/api\") as OtelApiLike;\n } catch {\n throw new Error(\n \"[next-cache] createOtelMetricEmitter needs @opentelemetry/api. \" +\n \"Install it in your app (npm i @opentelemetry/api) and configure a \" +\n \"MeterProvider, or pass the module via the `api` option.\"\n );\n }\n}\n\n/**\n * Build a `MetricEmitter` that forwards every handler event to OpenTelemetry.\n * Wire it to the `onMetric` option — emitter errors are already swallowed by\n * the handlers, so telemetry can never break the cache path.\n */\nexport function createOtelMetricEmitter(\n options: OtelEmitterOptions = {}\n): MetricEmitter {\n const api = options.api ?? resolveApi();\n const meter = api.metrics.getMeter(\n options.meterName ?? \"nextjs-cache-handler\"\n );\n const counter = meter.createCounter(\n options.counterName ?? \"nextjs_cache.events_total\",\n { description: \"Cache handler events by type\" }\n );\n const histogram = meter.createHistogram(\n options.histogramName ?? \"nextjs_cache.op_latency_ms\",\n {\n description: \"Per-op latency for events that carry an `ms` field\",\n unit: \"ms\",\n }\n );\n\n return (event: MetricEvent) => {\n const attrs = lowCardinalityAttrs(event);\n counter.add(1, attrs);\n if (typeof event.ms === \"number\") {\n histogram.record(event.ms, attrs);\n }\n };\n}\n"]}
@@ -1,11 +1,26 @@
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-ioredis.ts
11
26
  function adapt(client, isClusterClient = false) {
@@ -89,6 +104,9 @@ function adapt(client, isClusterClient = false) {
89
104
  on: (event, listener) => {
90
105
  client.on(event, listener);
91
106
  return client;
107
+ },
108
+ dispose: () => {
109
+ client.disconnect();
92
110
  }
93
111
  };
94
112
  }
@@ -99,18 +117,36 @@ function adaptCluster(cluster) {
99
117
  return adapt(cluster, true);
100
118
  }
101
119
  function createIoredisClient(config) {
102
- const IORedis = __require("ioredis");
120
+ const IORedis = nodeRequire("ioredis");
103
121
  const Ctor = IORedis.default ?? IORedis;
104
122
  return new Ctor(config.url, {
105
123
  password: config.password,
106
124
  connectTimeout: config.connectTimeout ?? 1500,
107
125
  tls: config.tls ? {} : void 0,
108
126
  lazyConnect: true,
109
- maxRetriesPerRequest: 1
127
+ maxRetriesPerRequest: 1,
128
+ // Batch same-tick commands into one RTT (matches redis@5's default
129
+ // behavior) — makes Promise.all fan-outs a single pipeline.
130
+ enableAutoPipelining: true
131
+ });
132
+ }
133
+ function createIoredisSentinel(config) {
134
+ const IORedis = nodeRequire("ioredis");
135
+ const Ctor = IORedis.default ?? IORedis;
136
+ return new Ctor({
137
+ sentinels: config.sentinels,
138
+ name: config.name,
139
+ password: config.password,
140
+ sentinelPassword: config.sentinelPassword,
141
+ connectTimeout: config.connectTimeout ?? 1500,
142
+ tls: config.tls ? {} : void 0,
143
+ lazyConnect: true,
144
+ maxRetriesPerRequest: 1,
145
+ enableAutoPipelining: true
110
146
  });
111
147
  }
112
148
  function createIoredisCluster(config) {
113
- const IORedis = __require("ioredis");
149
+ const IORedis = nodeRequire("ioredis");
114
150
  const ClusterCtor = IORedis.Cluster ?? IORedis.default.Cluster;
115
151
  return new ClusterCtor(config.nodes, {
116
152
  redisOptions: {
@@ -118,7 +154,9 @@ function createIoredisCluster(config) {
118
154
  tls: config.tls ? {} : void 0
119
155
  },
120
156
  enableReadyCheck: true,
121
- lazyConnect: true
157
+ lazyConnect: true,
158
+ // Same-slot commands issued in the same tick share one pipeline.
159
+ enableAutoPipelining: true
122
160
  });
123
161
  }
124
162
 
@@ -126,5 +164,6 @@ exports.adaptCluster = adaptCluster;
126
164
  exports.adaptIoredis = adaptIoredis;
127
165
  exports.createIoredisClient = createIoredisClient;
128
166
  exports.createIoredisCluster = createIoredisCluster;
167
+ exports.createIoredisSentinel = createIoredisSentinel;
129
168
  //# sourceMappingURL=adapter-ioredis.cjs.map
130
169
  //# sourceMappingURL=adapter-ioredis.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/shared/client/adapter-ioredis.ts"],"names":[],"mappings":"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","file":"adapter-ioredis.cjs","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":["../../../node_modules/tsup/assets/cjs_shims.js","../../../src/shared/node-require.ts","../../../src/shared/client/adapter-ioredis.ts"],"names":["createRequire","path"],"mappings":"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","file":"adapter-ioredis.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 `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,5 +1,5 @@
1
1
  import { Cluster, Redis } from 'ioredis';
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 `ioredis` (and `ioredis.Cluster`).
@@ -15,8 +15,11 @@ declare function adaptCluster(cluster: Cluster): RedisClientLike;
15
15
  declare function createIoredisClient(config: Extract<RedisClientConfig, {
16
16
  type: "ioredis";
17
17
  }>): Redis;
18
+ declare function createIoredisSentinel(config: Extract<RedisClientConfig, {
19
+ type: "sentinel";
20
+ }>): Redis;
18
21
  declare function createIoredisCluster(config: Extract<RedisClientConfig, {
19
22
  type: "cluster";
20
23
  }>): Cluster;
21
24
 
22
- export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster };
25
+ export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster, createIoredisSentinel };
@@ -1,5 +1,5 @@
1
1
  import { Cluster, Redis } from 'ioredis';
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 `ioredis` (and `ioredis.Cluster`).
@@ -15,8 +15,11 @@ declare function adaptCluster(cluster: Cluster): RedisClientLike;
15
15
  declare function createIoredisClient(config: Extract<RedisClientConfig, {
16
16
  type: "ioredis";
17
17
  }>): Redis;
18
+ declare function createIoredisSentinel(config: Extract<RedisClientConfig, {
19
+ type: "sentinel";
20
+ }>): Redis;
18
21
  declare function createIoredisCluster(config: Extract<RedisClientConfig, {
19
22
  type: "cluster";
20
23
  }>): Cluster;
21
24
 
22
- export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster };
25
+ export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster, createIoredisSentinel };
@@ -1,9 +1,18 @@
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-ioredis.ts
9
18
  function adapt(client, isClusterClient = false) {
@@ -87,6 +96,9 @@ function adapt(client, isClusterClient = false) {
87
96
  on: (event, listener) => {
88
97
  client.on(event, listener);
89
98
  return client;
99
+ },
100
+ dispose: () => {
101
+ client.disconnect();
90
102
  }
91
103
  };
92
104
  }
@@ -97,18 +109,36 @@ function adaptCluster(cluster) {
97
109
  return adapt(cluster, true);
98
110
  }
99
111
  function createIoredisClient(config) {
100
- const IORedis = __require("ioredis");
112
+ const IORedis = nodeRequire("ioredis");
101
113
  const Ctor = IORedis.default ?? IORedis;
102
114
  return new Ctor(config.url, {
103
115
  password: config.password,
104
116
  connectTimeout: config.connectTimeout ?? 1500,
105
117
  tls: config.tls ? {} : void 0,
106
118
  lazyConnect: true,
107
- maxRetriesPerRequest: 1
119
+ maxRetriesPerRequest: 1,
120
+ // Batch same-tick commands into one RTT (matches redis@5's default
121
+ // behavior) — makes Promise.all fan-outs a single pipeline.
122
+ enableAutoPipelining: true
123
+ });
124
+ }
125
+ function createIoredisSentinel(config) {
126
+ const IORedis = nodeRequire("ioredis");
127
+ const Ctor = IORedis.default ?? IORedis;
128
+ return new Ctor({
129
+ sentinels: config.sentinels,
130
+ name: config.name,
131
+ password: config.password,
132
+ sentinelPassword: config.sentinelPassword,
133
+ connectTimeout: config.connectTimeout ?? 1500,
134
+ tls: config.tls ? {} : void 0,
135
+ lazyConnect: true,
136
+ maxRetriesPerRequest: 1,
137
+ enableAutoPipelining: true
108
138
  });
109
139
  }
110
140
  function createIoredisCluster(config) {
111
- const IORedis = __require("ioredis");
141
+ const IORedis = nodeRequire("ioredis");
112
142
  const ClusterCtor = IORedis.Cluster ?? IORedis.default.Cluster;
113
143
  return new ClusterCtor(config.nodes, {
114
144
  redisOptions: {
@@ -116,10 +146,12 @@ function createIoredisCluster(config) {
116
146
  tls: config.tls ? {} : void 0
117
147
  },
118
148
  enableReadyCheck: true,
119
- lazyConnect: true
149
+ lazyConnect: true,
150
+ // Same-slot commands issued in the same tick share one pipeline.
151
+ enableAutoPipelining: true
120
152
  });
121
153
  }
122
154
 
123
- export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster };
155
+ export { adaptCluster, adaptIoredis, createIoredisClient, createIoredisCluster, createIoredisSentinel };
124
156
  //# sourceMappingURL=adapter-ioredis.js.map
125
157
  //# sourceMappingURL=adapter-ioredis.js.map