@trieb.work/nextjs-turbo-redis-cache 1.12.0-beta.1 → 1.13.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.
@@ -8,21 +8,17 @@ on:
8
8
  branches:
9
9
  - main
10
10
 
11
+ # Default-deny: every job inherits read-only access. Jobs that need more
12
+ # elevate explicitly via their own `permissions:` block (see `build` below).
11
13
  permissions:
12
- contents: write
13
- pull-requests: write
14
- deployments: write
15
- packages: write
16
- statuses: write
17
- issues: write
18
- actions: write
19
- discussions: write
14
+ contents: read
20
15
 
21
16
  jobs:
22
17
  build:
23
18
  runs-on: ubuntu-latest
24
19
  permissions:
25
- pull-requests: write # Grant write access to pull request comments
20
+ contents: read # Required for actions/checkout
21
+ pull-requests: write # Required for the coverage-comments action on PRs
26
22
  strategy:
27
23
  matrix:
28
24
  include:
@@ -51,7 +47,9 @@ jobs:
51
47
  cache: 'pnpm'
52
48
 
53
49
  - name: Install dependencies
54
- run: pnpm install
50
+ # --ignore-scripts blocks lifecycle scripts of all dependencies to mitigate
51
+ # supply-chain attacks via compromised postinstall hooks.
52
+ run: pnpm install --ignore-scripts
55
53
 
56
54
  - name: Run lint
57
55
  run: pnpm lint
@@ -6,15 +6,15 @@ on:
6
6
  - main
7
7
  - beta
8
8
 
9
+ # Minimal permissions:
10
+ # contents: semantic-release pushes the release commit + tag to the branch
11
+ # issues: @semantic-release/github comments on referenced issues
12
+ # pull-requests: @semantic-release/github comments on referenced PRs
13
+ # id-token: npm Trusted Publishing OIDC token exchange
9
14
  permissions:
10
15
  contents: write
11
- pull-requests: write
12
- deployments: write
13
- packages: write
14
- statuses: write
15
16
  issues: write
16
- actions: write
17
- discussions: write
17
+ pull-requests: write
18
18
  id-token: write
19
19
 
20
20
  jobs:
@@ -24,6 +24,13 @@ jobs:
24
24
  steps:
25
25
  - name: Checkout code
26
26
  uses: actions/checkout@v6
27
+ with:
28
+ # Need full history so the post-release audit can diff against pre-release SHA.
29
+ fetch-depth: 0
30
+
31
+ - name: Capture pre-release SHA
32
+ id: pre
33
+ run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
27
34
 
28
35
  - name: Install pnpm
29
36
  run: corepack enable
@@ -35,19 +42,73 @@ jobs:
35
42
  cache: 'pnpm'
36
43
 
37
44
  - name: Install dependencies
38
- run: pnpm install --frozen-lockfile
45
+ # --ignore-scripts blocks lifecycle scripts (preinstall/install/postinstall/prepare)
46
+ # of all dependencies. This is the primary defence against supply-chain attacks
47
+ # injected via a compromised transitive dep's postinstall hook.
48
+ run: pnpm install --frozen-lockfile --ignore-scripts
39
49
  - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
40
50
  run: npm audit signatures
41
51
 
42
52
  - name: Build project
43
53
  run: pnpm build
44
54
 
55
+ - name: Verify working tree is clean before release
56
+ # If install/build silently modified tracked files, abort before semantic-release
57
+ # can include them in the release commit.
58
+ run: |
59
+ if [ -n "$(git status --porcelain)" ]; then
60
+ echo "::error::Working tree is dirty before semantic-release. Aborting."
61
+ git status --short
62
+ git diff --stat
63
+ exit 1
64
+ fi
65
+
45
66
  - name: Run Semantic Release
46
67
  env:
47
68
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub token for Semantic Release
48
69
  NPM_CONFIG_PROVENANCE: 'true'
49
70
  run: pnpm exec semantic-release
50
71
 
72
+ - name: Audit semantic-release commit — fail if files outside allowlist were touched
73
+ env:
74
+ PRE_SHA: ${{ steps.pre.outputs.sha }}
75
+ run: |
76
+ # Allowlist must mirror the `assets` array in release.config.cjs.
77
+ # Any file outside this list being modified by the release run is suspicious
78
+ # and blocks the npm publish step below.
79
+ ALLOWED="package.json pnpm-lock.yaml CHANGELOG.md"
80
+
81
+ if [ "$(git rev-parse HEAD)" = "$PRE_SHA" ]; then
82
+ echo "semantic-release made no commit; nothing to audit."
83
+ exit 0
84
+ fi
85
+
86
+ echo "Auditing commits ${PRE_SHA}..HEAD"
87
+ CHANGED=$(git diff --name-only "${PRE_SHA}..HEAD")
88
+ echo "Files changed:"
89
+ printf '%s\n' "$CHANGED"
90
+
91
+ UNEXPECTED=""
92
+ while IFS= read -r file; do
93
+ [ -z "$file" ] && continue
94
+ match=false
95
+ for allowed in $ALLOWED; do
96
+ if [ "$file" = "$allowed" ]; then
97
+ match=true
98
+ break
99
+ fi
100
+ done
101
+ [ "$match" = false ] && UNEXPECTED="${UNEXPECTED}\n ${file}"
102
+ done <<< "$CHANGED"
103
+
104
+ if [ -n "$UNEXPECTED" ]; then
105
+ printf '::error::semantic-release touched files outside the allowlist:%b\n' "$UNEXPECTED"
106
+ echo "::error::This may indicate a compromised dependency. Aborting publish."
107
+ exit 1
108
+ fi
109
+
110
+ echo "All changed files are within the allowlist."
111
+
51
112
  - name: Check if current version is already published
52
113
  id: version-check
53
114
  env:
package/CHANGELOG.md CHANGED
@@ -1,15 +1,37 @@
1
- # [1.12.0-beta.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.11.0...v1.12.0-beta.1) (2026-03-02)
1
+ # [1.13.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.12.0...v1.13.0) (2026-05-04)
2
2
 
3
3
 
4
- ### Bug Fixes
4
+ ### Features
5
+
6
+ * **cache:** unify key prefix resolution across Next handlers; add tests (incl. BUILD_ID integration); docs cleanup ([#72](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/72)) ([4f991f7](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/4f991f78cd6885c8ea75011a5c283c9c73f16b33))
7
+
8
+ # [1.12.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.11.1...v1.12.0) (2026-05-04)
9
+
10
+
11
+ ### Features
12
+
13
+ * update docs ([a2ab3d1](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/a2ab3d1fdebc3fdb8c06eaff73e0e51f333ecdfd))
14
+
15
+ # [1.12.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.11.1...v1.12.0) (2026-05-04)
5
16
 
6
- * **cache-components:** avoid reconnect connect() when socket already open ([a58e1c3](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/a58e1c35c03b7c161040f863577edb4f2af9f453))
7
- * **syncedmap:** prevent overlapping subscriber connect; add redis kill/reconnect test ([8b9975f](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/8b9975fdd7baef010a10fdf5b1564280eed403a0))
17
+
18
+ ### Features
19
+
20
+ * update docs ([a2ab3d1](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/a2ab3d1fdebc3fdb8c06eaff73e0e51f333ecdfd))
21
+
22
+ # [1.12.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.11.1...v1.12.0) (2026-04-29)
8
23
 
9
24
 
10
25
  ### Features
11
26
 
12
- * robust redis kill/reconnect handling (beta) ([9bfe214](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/9bfe214be8d464bdbd536ed4789cb01ee242ff6d))
27
+ * update docs ([a2ab3d1](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/a2ab3d1fdebc3fdb8c06eaff73e0e51f333ecdfd))
28
+
29
+ ## [1.11.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.11.0...v1.11.1) (2026-03-08)
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **syncedmap:** robust subscriber reconnect + redis restart test ([#69](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/69)) ([01b3a28](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/01b3a282083c23453d3e21911a1fb0f6ef5eacc1))
13
35
 
14
36
  # [1.11.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.10.3...v1.11.0) (2026-02-16)
15
37
 
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@trieb.work/nextjs-turbo-redis-cache.svg)](https://www.npmjs.com/package/@trieb.work/nextjs-turbo-redis-cache)
4
4
  ![Turbo redis cache image](https://github.com/user-attachments/assets/4103191e-4f4d-4139-a519-0b5bfab3e8b4)
5
5
 
6
- The ultimate Redis caching solution for Next.js 15 and the app router. Built for production-ready, large-scale projects, it delivers unparalleled performance and efficiency with features tailored for high-traffic applications. This package has been created after extensibly testing the @neshca package and finding several major issues with it.
6
+ The ultimate Redis caching solution for Next.js 15 / 16 and the app router. Built for production-ready, large-scale projects, it delivers unparalleled performance and efficiency with features tailored for high-traffic applications. This package has been created after extensibly testing the @neshca package and finding several major issues with it.
7
7
 
8
8
  Key Features:
9
9
 
@@ -13,7 +13,7 @@ Key Features:
13
13
  - _Efficient Tag Management_: in-memory tags map for lightning-fast revalidate operations with minimal Redis overhead.
14
14
  - _Intelligent Key-Space Notifications_: Automatic update of in-memory tags map for expired or evicted keys.
15
15
 
16
- This library offers you an easy and high performant caching solution for docker, Kubernetes or Google Cloud Run deployments of Next.js.
16
+ This library offers you an easy and high performant caching solution for docker, Kubernetes or Google Cloud Run deployments of Next.js. Read more on how it originated at [TRWK> Case Study](https://trwk.de/case-studies/nextjs-turbo-redis-cache).
17
17
 
18
18
  ## Compatibility
19
19
 
@@ -51,7 +51,15 @@ pnpm install @trieb.work/nextjs-turbo-redis-cache
51
51
  ### Setup environment variables in your project/deployment
52
52
 
53
53
  REDISHOST and REDISPORT environment variables are required.
54
- VERCEL_URL, VERCEL_ENV are optional. VERCEL_URL is used to create a key prefix for the redis keys. VERCEL_ENV is used to determine the database to use. Only VERCEL_ENV=production will show up in DB 0 (redis default db). All other values of VERCEL_ENV will use DB 1, use `redis-cli -n 1` to connect to different DB 1. This is another protection feature to avoid that different environments (e.g. staging and production) will overwrite each other.
54
+ KEY_PREFIX, VERCEL_URL, VERCEL_ENV are optional. For the bundled Next.js handlers (default cache handler and Cache Components handler), the key prefix precedence is:
55
+
56
+ - options.keyPrefix → KEY*PREFIX → VERCEL_URL → BUILD_ID (from `.next/BUILD_ID`) → `UNDEFINED_URL*`
57
+
58
+ For direct usage of `RedisStringsHandler`, the default remains framework-agnostic:
59
+
60
+ - options.keyPrefix → KEY*PREFIX → VERCEL_URL → `UNDEFINED_URL*`
61
+
62
+ VERCEL_ENV is used to determine the database to use. Only VERCEL_ENV=production will show up in DB 0 (redis default db). All other values of VERCEL_ENV will use DB 1, use `redis-cli -n 1` to connect to different DB 1. This is another protection feature to avoid that different environments (e.g. staging and production) will overwrite each other.
55
63
  Furthermore there exists the DEBUG_CACHE_HANDLER environment variable to enable debug logging of the caching handler once it is set to true.
56
64
 
57
65
  There exists also the SKIP_KEYSPACE_CONFIG_CHECK environment variable to skip the check for the keyspace configuration. This is useful if you are using redis in a cloud environment that forbids access to config commands. If you set SKIP_KEYSPACE_CONFIG_CHECK=true the check will be skipped and the keyspace configuration will be assumed to be correct (e.g. notify-keyspace-events Exe).
@@ -129,22 +137,22 @@ A working example of above can be found in the `test/integration/next-app-custom
129
137
 
130
138
  ## Available Options
131
139
 
132
- | Option | Description | Default Value |
133
- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
134
- | redisUrl | Redis connection url | `process.env.REDIS_URL? process.env.REDIS_URL : process.env.REDISHOST ? redis://${process.env.REDISHOST}:${process.env.REDISPORT} : 'redis://localhost:6379'` |
135
- | database | Redis database number to use. Uses DB 0 for production, DB 1 otherwise | `process.env.VERCEL_ENV === 'production' ? 0 : 1` |
136
- | keyPrefix | Prefix added to all Redis keys | `process.env.VERCEL_URL \|\| 'UNDEFINED_URL_'` |
137
- | sharedTagsKey | Key used to store shared tags hash map in Redis | `'__sharedTags__'` |
138
- | getTimeoutMs | Timeout in milliseconds for time critical Redis operations. If Redis get is not fulfilled within this time, returns null to avoid blocking site rendering. | `process.env.REDIS_COMMAND_TIMEOUT_MS ? (Number.parseInt(process.env.REDIS_COMMAND_TIMEOUT_MS) ?? 500) : 500` |
139
- | revalidateTagQuerySize | Number of entries to query in one batch during full sync of shared tags hash map | `250` |
140
- | avgResyncIntervalMs | Average interval in milliseconds between tag map full re-syncs | `3600000` (1 hour) |
141
- | redisGetDeduplication | Enable deduplication of Redis get requests via internal in-memory cache. | `true` |
142
- | inMemoryCachingTime | Time in milliseconds to cache Redis get results in memory. Set this to 0 to disable in-memory caching completely. | `10000` |
143
- | defaultStaleAge | Default stale age in seconds for cached items | `1209600` (14 days) |
144
- | estimateExpireAge | Function to calculate expire age (redis TTL value) from stale age | Production: `staleAge * 2`<br> Other: `staleAge * 1.2` |
145
- | socketOptions | Redis client socket options for TLS/SSL configuration (e.g., `{ tls: true, rejectUnauthorized: false }`) | `{ connectTimeout: timeoutMs }` |
146
- | clientOptions | Additional Redis client options (e.g., username, password) | `undefined` |
147
- | killContainerOnErrorThreshold | Number of consecutive errors before the container is killed. Set to 0 to disable. | `Number.parseInt(process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD) ?? 0 : 0` |
140
+ | Option | Description | Default Value |
141
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
142
+ | redisUrl | Redis connection url | `process.env.REDIS_URL? process.env.REDIS_URL : process.env.REDISHOST ? redis://${process.env.REDISHOST}:${process.env.REDISPORT} : 'redis://localhost:6379'` |
143
+ | database | Redis database number to use. Uses DB 0 for production, DB 1 otherwise | `process.env.VERCEL_ENV === 'production' ? 0 : 1` |
144
+ | keyPrefix | Prefix added to all Redis keys | `RedisStringsHandler` default: `process.env.KEY_PREFIX \|\| process.env.VERCEL_URL \|\| 'UNDEFINED_URL_'`<br> Next handlers resolve: `options.keyPrefix \|\| KEY_PREFIX \|\| VERCEL_URL \|\| BUILD_ID \|\| 'UNDEFINED_URL_'` |
145
+ | sharedTagsKey | Key used to store shared tags hash map in Redis | `'__sharedTags__'` |
146
+ | getTimeoutMs | Timeout in milliseconds for time critical Redis operations. If Redis get is not fulfilled within this time, returns null to avoid blocking site rendering. | `process.env.REDIS_COMMAND_TIMEOUT_MS ? (Number.parseInt(process.env.REDIS_COMMAND_TIMEOUT_MS) ?? 500) : 500` |
147
+ | revalidateTagQuerySize | Number of entries to query in one batch during full sync of shared tags hash map | `250` |
148
+ | avgResyncIntervalMs | Average interval in milliseconds between tag map full re-syncs | `3600000` (1 hour) |
149
+ | redisGetDeduplication | Enable deduplication of Redis get requests via internal in-memory cache. | `true` |
150
+ | inMemoryCachingTime | Time in milliseconds to cache Redis get results in memory. Set this to 0 to disable in-memory caching completely. | `10000` |
151
+ | defaultStaleAge | Default stale age in seconds for cached items | `1209600` (14 days) |
152
+ | estimateExpireAge | Function to calculate expire age (redis TTL value) from stale age | Production: `staleAge * 2`<br> Other: `staleAge * 1.2` |
153
+ | socketOptions | Redis client socket options for TLS/SSL configuration (e.g., `{ tls: true, rejectUnauthorized: false }`) | `{ connectTimeout: timeoutMs }` |
154
+ | clientOptions | Additional Redis client options (e.g., username, password) | `undefined` |
155
+ | killContainerOnErrorThreshold | Number of consecutive errors before the container is killed. Set to 0 to disable. | `Number.parseInt(process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD) ?? 0 : 0` |
148
156
 
149
157
  ## TLS Configuration
150
158
 
@@ -354,4 +362,4 @@ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
354
362
 
355
363
  ## Sponsor
356
364
 
357
- This project is created and maintained by the Next.js & Payload CMS agency [trieb.work](https://trieb.work)
365
+ This project is created and maintained by the Next.js & Payload CMS agency [TRWK>](https://trwk.de), formerly [trieb.work](https://trieb.work).
package/dist/index.d.mts CHANGED
@@ -17,7 +17,7 @@ type CreateRedisStringsHandlerOptions = {
17
17
  */
18
18
  database?: number;
19
19
  /** Prefix added to all Redis keys
20
- * @default process.env.VERCEL_URL || 'UNDEFINED_URL_'
20
+ * @default process.env.KEY_PREFIX || process.env.VERCEL_URL || 'UNDEFINED_URL_'
21
21
  */
22
22
  keyPrefix?: string;
23
23
  /** Timeout in milliseconds for time critical Redis operations (during cache get, which blocks site rendering).
@@ -141,8 +141,11 @@ declare class RedisStringsHandler {
141
141
  revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
142
142
  }
143
143
 
144
+ type NextCacheHandlerOptions = CreateRedisStringsHandlerOptions & {
145
+ serverDistDir?: string;
146
+ };
144
147
  declare class CachedHandler {
145
- constructor(options: CreateRedisStringsHandlerOptions);
148
+ constructor(options: NextCacheHandlerOptions);
146
149
  get(...args: Parameters<RedisStringsHandler['get']>): ReturnType<RedisStringsHandler['get']>;
147
150
  set(...args: Parameters<RedisStringsHandler['set']>): ReturnType<RedisStringsHandler['set']>;
148
151
  revalidateTag(...args: Parameters<RedisStringsHandler['revalidateTag']>): ReturnType<RedisStringsHandler['revalidateTag']>;
@@ -166,7 +169,9 @@ interface CacheComponentsHandler {
166
169
  expire?: number;
167
170
  }): Promise<void>;
168
171
  }
169
- type CreateCacheComponentsHandlerOptions = CreateRedisStringsHandlerOptions;
172
+ type CreateCacheComponentsHandlerOptions = CreateRedisStringsHandlerOptions & {
173
+ serverDistDir?: string;
174
+ };
170
175
  declare function getRedisCacheComponentsHandler(options?: CreateCacheComponentsHandlerOptions): CacheComponentsHandler;
171
176
  declare const redisCacheHandler: CacheComponentsHandler;
172
177
 
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ type CreateRedisStringsHandlerOptions = {
17
17
  */
18
18
  database?: number;
19
19
  /** Prefix added to all Redis keys
20
- * @default process.env.VERCEL_URL || 'UNDEFINED_URL_'
20
+ * @default process.env.KEY_PREFIX || process.env.VERCEL_URL || 'UNDEFINED_URL_'
21
21
  */
22
22
  keyPrefix?: string;
23
23
  /** Timeout in milliseconds for time critical Redis operations (during cache get, which blocks site rendering).
@@ -141,8 +141,11 @@ declare class RedisStringsHandler {
141
141
  revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
142
142
  }
143
143
 
144
+ type NextCacheHandlerOptions = CreateRedisStringsHandlerOptions & {
145
+ serverDistDir?: string;
146
+ };
144
147
  declare class CachedHandler {
145
- constructor(options: CreateRedisStringsHandlerOptions);
148
+ constructor(options: NextCacheHandlerOptions);
146
149
  get(...args: Parameters<RedisStringsHandler['get']>): ReturnType<RedisStringsHandler['get']>;
147
150
  set(...args: Parameters<RedisStringsHandler['set']>): ReturnType<RedisStringsHandler['set']>;
148
151
  revalidateTag(...args: Parameters<RedisStringsHandler['revalidateTag']>): ReturnType<RedisStringsHandler['revalidateTag']>;
@@ -166,7 +169,9 @@ interface CacheComponentsHandler {
166
169
  expire?: number;
167
170
  }): Promise<void>;
168
171
  }
169
- type CreateCacheComponentsHandlerOptions = CreateRedisStringsHandlerOptions;
172
+ type CreateCacheComponentsHandlerOptions = CreateRedisStringsHandlerOptions & {
173
+ serverDistDir?: string;
174
+ };
170
175
  declare function getRedisCacheComponentsHandler(options?: CreateCacheComponentsHandlerOptions): CacheComponentsHandler;
171
176
  declare const redisCacheHandler: CacheComponentsHandler;
172
177
 
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -512,7 +522,7 @@ var RedisStringsHandler = class {
512
522
  constructor({
513
523
  redisUrl = process.env.REDIS_URL ? process.env.REDIS_URL : process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT}` : "redis://localhost:6379",
514
524
  database = process.env.VERCEL_ENV === "production" ? 0 : 1,
515
- keyPrefix = process.env.VERCEL_URL || "UNDEFINED_URL_",
525
+ keyPrefix = process.env.KEY_PREFIX || process.env.VERCEL_URL || "UNDEFINED_URL_",
516
526
  sharedTagsKey = "__sharedTags__",
517
527
  getTimeoutMs = process.env.REDIS_COMMAND_TIMEOUT_MS ? Number.parseInt(process.env.REDIS_COMMAND_TIMEOUT_MS) ?? 500 : 500,
518
528
  revalidateTagQuerySize = 250,
@@ -959,13 +969,55 @@ var RedisStringsHandler = class {
959
969
  }
960
970
  };
961
971
 
972
+ // src/utils/prefix.ts
973
+ var import_node_fs = __toESM(require("fs"));
974
+ var import_node_path = __toESM(require("path"));
975
+ function readBuildId(serverDistDir) {
976
+ try {
977
+ if (serverDistDir) {
978
+ const buildIdPath = import_node_path.default.join(serverDistDir, "..", "BUILD_ID");
979
+ const buildId = import_node_fs.default.readFileSync(buildIdPath, "utf8").trim();
980
+ return buildId || void 0;
981
+ }
982
+ } catch {
983
+ }
984
+ try {
985
+ const fromCwd = import_node_path.default.join(process.cwd(), ".next", "BUILD_ID");
986
+ const buildId = import_node_fs.default.readFileSync(fromCwd, "utf8").trim();
987
+ return buildId || void 0;
988
+ } catch {
989
+ return void 0;
990
+ }
991
+ }
992
+ function resolveKeyPrefix({
993
+ optionKeyPrefix,
994
+ serverDistDir,
995
+ env
996
+ }) {
997
+ if (optionKeyPrefix !== void 0) {
998
+ return optionKeyPrefix;
999
+ }
1000
+ const keyPrefixEnv = env.KEY_PREFIX && env.KEY_PREFIX.length > 0 ? env.KEY_PREFIX : void 0;
1001
+ const vercelUrl = env.VERCEL_URL && env.VERCEL_URL.length > 0 ? env.VERCEL_URL : void 0;
1002
+ const buildId = readBuildId(serverDistDir);
1003
+ return keyPrefixEnv ?? vercelUrl ?? buildId ?? "UNDEFINED_URL_";
1004
+ }
1005
+
962
1006
  // src/CachedHandler.ts
963
1007
  var cachedHandler;
964
1008
  var CachedHandler = class {
965
1009
  constructor(options) {
966
1010
  if (!cachedHandler) {
967
1011
  console.log("created cached handler");
968
- cachedHandler = new RedisStringsHandler(options);
1012
+ const keyPrefix = resolveKeyPrefix({
1013
+ optionKeyPrefix: options.keyPrefix,
1014
+ serverDistDir: options.serverDistDir,
1015
+ env: process.env
1016
+ });
1017
+ cachedHandler = new RedisStringsHandler({
1018
+ ...options,
1019
+ keyPrefix
1020
+ });
969
1021
  }
970
1022
  }
971
1023
  get(...args) {
@@ -1024,16 +1076,21 @@ var RedisCacheComponentsHandler = class {
1024
1076
  constructor({
1025
1077
  redisUrl = process.env.REDIS_URL ? process.env.REDIS_URL : process.env.REDISHOST ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT}` : "redis://localhost:6379",
1026
1078
  database = process.env.VERCEL_ENV === "production" ? 0 : 1,
1027
- keyPrefix = process.env.VERCEL_URL || "UNDEFINED_URL_",
1079
+ keyPrefix,
1028
1080
  getTimeoutMs = process.env.REDIS_COMMAND_TIMEOUT_MS ? Number.parseInt(process.env.REDIS_COMMAND_TIMEOUT_MS) ?? 500 : 500,
1029
1081
  revalidateTagQuerySize = 250,
1030
1082
  avgResyncIntervalMs = 60 * 60 * 1e3,
1031
1083
  socketOptions,
1032
1084
  clientOptions,
1033
- killContainerOnErrorThreshold = process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD ? Number.parseInt(process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD) ?? 0 : 0
1085
+ killContainerOnErrorThreshold = process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD ? Number.parseInt(process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD) ?? 0 : 0,
1086
+ serverDistDir
1034
1087
  }) {
1035
1088
  try {
1036
- this.keyPrefix = keyPrefix;
1089
+ this.keyPrefix = resolveKeyPrefix({
1090
+ optionKeyPrefix: keyPrefix,
1091
+ serverDistDir,
1092
+ env: process.env
1093
+ });
1037
1094
  this.getTimeoutMs = getTimeoutMs;
1038
1095
  this.client = (0, import_redis2.createClient)({
1039
1096
  url: redisUrl,
@@ -1085,7 +1142,7 @@ var RedisCacheComponentsHandler = class {
1085
1142
  const filterKeys = (key) => key !== REVALIDATED_TAGS_KEY2 && key !== SHARED_TAGS_KEY;
1086
1143
  this.revalidatedTagsMap = new SyncedMap({
1087
1144
  client: this.client,
1088
- keyPrefix,
1145
+ keyPrefix: this.keyPrefix,
1089
1146
  redisKey: REVALIDATED_TAGS_KEY2,
1090
1147
  database,
1091
1148
  querySize: revalidateTagQuerySize,
@@ -1094,7 +1151,7 @@ var RedisCacheComponentsHandler = class {
1094
1151
  });
1095
1152
  this.sharedTagsMap = new SyncedMap({
1096
1153
  client: this.client,
1097
- keyPrefix,
1154
+ keyPrefix: this.keyPrefix,
1098
1155
  redisKey: SHARED_TAGS_KEY,
1099
1156
  database,
1100
1157
  querySize: revalidateTagQuerySize,