@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.
- package/.github/workflows/ci.yml +8 -10
- package/.github/workflows/release.yml +68 -7
- package/CHANGELOG.md +27 -5
- package/README.md +28 -20
- package/dist/index.d.mts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +64 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
- package/src/CacheComponentsHandler.ts +11 -5
- package/src/CachedHandler.ts +16 -2
- package/src/RedisStringsHandler.ts +4 -2
- package/src/utils/prefix.test.ts +115 -0
- package/src/utils/prefix.ts +44 -0
- package/test/integration/build-id-prefix.integration.test.ts +102 -0
- package/test/integration/next-app-16-0-3/postcss.config.mjs +7 -7
- package/test/integration/next-app-16-1-1/postcss.config.mjs +7 -7
- package/test/integration/next-app-16-1-1-cache-components/postcss.config.mjs +7 -7
package/.github/workflows/ci.yml
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
###
|
|
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
|
-
|
|
7
|
-
|
|
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
|
-
*
|
|
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
|
[](https://www.npmjs.com/package/@trieb.work/nextjs-turbo-redis-cache)
|
|
4
4
|

|
|
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.
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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,
|