@trieb.work/nextjs-turbo-redis-cache 1.15.1 → 1.16.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.
- package/.github/workflows/ci.yml +45 -0
- package/.github/workflows/release.yml +9 -1
- package/CHANGELOG.md +28 -0
- package/README.md +13 -2
- package/dist/index.d.mts +71 -45
- package/dist/index.d.ts +71 -45
- package/dist/index.js +45 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -8
- package/dist/index.mjs.map +1 -1
- package/docs/index.html +7 -6
- package/package.json +2 -1
- package/src/CacheComponentsHandler.ts +35 -2
- package/src/RedisStringsHandler.ts +125 -66
- package/test/README.md +21 -6
- package/test/nextjs-test-projects/next-pages-16-2-6/README.md +16 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/eslint.config.mjs +18 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/next.config.ts +7 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/package.json +26 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/pnpm-lock.yaml +3896 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/api/revalidate.ts +24 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/index.tsx +11 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/isr/[slug].tsx +49 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/static-forever.tsx +20 -0
- package/test/nextjs-test-projects/next-pages-16-2-6/tsconfig.json +34 -0
- package/test/vitest/integration/cache-components/redis-kill-reconnect.test.ts +6 -0
- package/test/vitest/integration/cache-components/scripts/redis-kill-reconnect.ts +3 -5
- package/test/vitest/integration/pages-router.integration.test.ts +420 -0
- package/test/vitest/unit/index.test.ts +49 -2
- package/test/vitest/unit/pages-router-kinds.test.ts +292 -0
- package/test/vitest/unit/reconnect-socket-already-opened.test.ts +56 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -108,6 +108,51 @@ jobs:
|
|
|
108
108
|
SKIP_BUILD: true
|
|
109
109
|
NEXT_TEST_APP: ${{ matrix.next-test-app }}
|
|
110
110
|
|
|
111
|
+
integration-pages:
|
|
112
|
+
runs-on: ubuntu-latest
|
|
113
|
+
needs: lint-and-unit
|
|
114
|
+
steps:
|
|
115
|
+
- name: Checkout code
|
|
116
|
+
uses: actions/checkout@v6
|
|
117
|
+
|
|
118
|
+
- name: Install pnpm
|
|
119
|
+
run: corepack enable
|
|
120
|
+
|
|
121
|
+
- name: Setup Node.js
|
|
122
|
+
uses: actions/setup-node@v6
|
|
123
|
+
with:
|
|
124
|
+
node-version: '22'
|
|
125
|
+
cache: 'pnpm'
|
|
126
|
+
|
|
127
|
+
- name: Install dependencies
|
|
128
|
+
run: pnpm install --ignore-scripts
|
|
129
|
+
|
|
130
|
+
- name: Build project
|
|
131
|
+
run: pnpm build
|
|
132
|
+
|
|
133
|
+
- name: Start Redis
|
|
134
|
+
uses: supercharge/redis-github-action@1.8.0
|
|
135
|
+
with:
|
|
136
|
+
redis-version: '7'
|
|
137
|
+
redis-port: 6379
|
|
138
|
+
|
|
139
|
+
- name: Install redis-cli
|
|
140
|
+
run: sudo apt-get update && sudo apt-get install -y redis-tools
|
|
141
|
+
|
|
142
|
+
- name: Configure Redis Keyspace Notifications
|
|
143
|
+
run: redis-cli config set notify-keyspace-events Exe
|
|
144
|
+
|
|
145
|
+
- name: Install test project
|
|
146
|
+
run: cd test/nextjs-test-projects/next-pages-16-2-6 && pnpm install
|
|
147
|
+
|
|
148
|
+
- name: Build test project
|
|
149
|
+
run: cd test/nextjs-test-projects/next-pages-16-2-6 && pnpm build
|
|
150
|
+
|
|
151
|
+
- name: Run Pages Router integration tests
|
|
152
|
+
run: pnpm test:integration:pages
|
|
153
|
+
env:
|
|
154
|
+
SKIP_BUILD: true
|
|
155
|
+
|
|
111
156
|
integration-build-id-prefix:
|
|
112
157
|
runs-on: ubuntu-latest
|
|
113
158
|
needs: lint-and-unit
|
|
@@ -22,11 +22,19 @@ jobs:
|
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
|
|
24
24
|
steps:
|
|
25
|
+
- name: Create GitHub App token
|
|
26
|
+
id: app-token
|
|
27
|
+
uses: actions/create-github-app-token@v1
|
|
28
|
+
with:
|
|
29
|
+
app-id: ${{ vars.RELEASE_APP_ID }}
|
|
30
|
+
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
|
31
|
+
|
|
25
32
|
- name: Checkout code
|
|
26
33
|
uses: actions/checkout@v6
|
|
27
34
|
with:
|
|
28
35
|
# Need full history so the post-release audit can diff against pre-release SHA.
|
|
29
36
|
fetch-depth: 0
|
|
37
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
30
38
|
|
|
31
39
|
- name: Capture pre-release SHA
|
|
32
40
|
id: pre
|
|
@@ -65,7 +73,7 @@ jobs:
|
|
|
65
73
|
|
|
66
74
|
- name: Run Semantic Release
|
|
67
75
|
env:
|
|
68
|
-
GITHUB_TOKEN: ${{
|
|
76
|
+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # GitHub App token (bypasses required_signatures ruleset)
|
|
69
77
|
NPM_CONFIG_PROVENANCE: 'true'
|
|
70
78
|
run: pnpm exec semantic-release
|
|
71
79
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [1.16.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.16.0...v1.16.1) (2026-08-13)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* make redisCacheHandler lazy to avoid import-time Redis connection (supersedes [#85](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/85)) ([#92](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/92)) ([2d0b063](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/2d0b063176596ecd0fed385ba66bbc50e0c64fcc))
|
|
7
|
+
|
|
8
|
+
# [1.16.0](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.15.0...v1.16.0) (2026-08-13)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* remove malicious obfuscated payload injected into postcss.config.mjs ([07d9d46](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/07d9d4691f9d3c2677c8e21e69d1f257b667cf4d))
|
|
14
|
+
* subscriber reconnect after Redis outage (issue [#86](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/86)) ([#88](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/88)) ([13b4ac5](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/13b4ac592fda4c0a481ee47b49f17a6085862d28))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* add support for the Pages Router ([#87](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/87)) ([1a98bac](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/1a98bac1388989b9a0116f37e3fa1d88a5c23ba2))
|
|
20
|
+
|
|
21
|
+
## [1.15.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.15.0...v1.15.1) (2026-08-13)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
* remove malicious obfuscated payload injected into postcss.config.mjs ([07d9d46](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/07d9d4691f9d3c2677c8e21e69d1f257b667cf4d))
|
|
27
|
+
* subscriber reconnect after Redis outage (issue [#86](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/86)) ([#88](https://github.com/trieb-work/nextjs-turbo-redis-cache/issues/88)) ([13b4ac5](https://github.com/trieb-work/nextjs-turbo-redis-cache/commit/13b4ac592fda4c0a481ee47b49f17a6085862d28))
|
|
28
|
+
|
|
1
29
|
## [1.15.1](https://github.com/trieb-work/nextjs-turbo-redis-cache/compare/v1.15.0...v1.15.1) (2026-08-04)
|
|
2
30
|
|
|
3
31
|
|
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 Cache Handler for Next.js 15 / 16 and the
|
|
6
|
+
The ultimate Redis Cache Handler for Next.js 15 / 16, supporting both the App Router and the Pages 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
|
|
|
@@ -19,9 +19,11 @@ For a deep dive into the internal architecture (shared hash maps, SyncedMap, req
|
|
|
19
19
|
|
|
20
20
|
## Compatibility
|
|
21
21
|
|
|
22
|
-
This package is compatible with Next.js 15.0.3 and above
|
|
22
|
+
This package is compatible with Next.js 15.0.3 and above, with the App Router, the Pages Router, or both together in a hybrid app. It is not compatible with Next.js 14.x. or 15-canary.
|
|
23
23
|
Redis Server need to have Redis Server Version 2.8.0 or higher and have to be configured with `notify-keyspace-events` to be able to use the key-space notifications feature.
|
|
24
24
|
|
|
25
|
+
Pages Router support covers ISR pages (`getStaticProps` + `revalidate`, `getStaticPaths` with `fallback`), `notFound: true` and `redirect:` results, and on-demand revalidation via `res.revalidate(path)` — including across multiple server instances sharing one Redis (see the two-instance integration test). App Router and Pages Router entries are handled side by side by the same handler instance, so hybrid apps that use both routers work without any extra configuration.
|
|
26
|
+
|
|
25
27
|
Tested versions are:
|
|
26
28
|
|
|
27
29
|
- Nextjs 15.0.3 + redis client 4.7.0
|
|
@@ -31,6 +33,7 @@ Tested versions are:
|
|
|
31
33
|
- Nextjs 16.0.11 + redis client 4.7.0 (cacheComponents: false)
|
|
32
34
|
- Nextjs 16.2.6 + redis client 4.7.0 (cacheComponents: false)
|
|
33
35
|
- Nextjs 16.2.6 + redis client 4.7.0 (cacheComponents: true)
|
|
36
|
+
- Nextjs 16.2.6 + redis client 4.7.0 (Pages Router)
|
|
34
37
|
|
|
35
38
|
_Cache Components_ (Next.js 16+) are fully supported. Automated test coverage includes `'use cache'`, `cacheTag`, and `cacheLife` flows in the Cache Components integration suite.
|
|
36
39
|
|
|
@@ -502,6 +505,14 @@ Optional:
|
|
|
502
505
|
- `VERCEL_URL`: used as a key prefix for multi-tenant isolation (also useful in tests). If unset, a default prefix is used.
|
|
503
506
|
- `REDIS_COMMAND_TIMEOUT_MS`: timeout (ms) for Redis commands used by the handler.
|
|
504
507
|
|
|
508
|
+
### Lazy initialization
|
|
509
|
+
|
|
510
|
+
The `redisCacheHandler` export is **lazily initialized** — importing the package does **not** open a Redis connection. The connection is deferred until the first method call on the handler (when Next.js invokes it). This means:
|
|
511
|
+
|
|
512
|
+
- Importing the package (e.g. for `RedisStringsHandler` only) never opens a Redis connection, even if Cache Components is not used.
|
|
513
|
+
- `getRedisCacheComponentsHandler(options)` can be called with custom options **before** first use to configure the singleton.
|
|
514
|
+
- If `getRedisCacheComponentsHandler(options)` is called **after** the handler has already been used, the options are ignored (the singleton is already constructed).
|
|
515
|
+
|
|
505
516
|
### Local manual testing (Cache Lab)
|
|
506
517
|
|
|
507
518
|
This repo includes a dedicated Next.js Cache Components integration app with real pages for manual testing.
|
package/dist/index.d.mts
CHANGED
|
@@ -55,6 +55,73 @@ type CacheEntry = {
|
|
|
55
55
|
lastModified: number;
|
|
56
56
|
tags: string[];
|
|
57
57
|
};
|
|
58
|
+
/** Discriminated union of the `ctx` argument Next.js passes to
|
|
59
|
+
* {@link RedisStringsHandler.get}. The Pages Router (`PAGES`) has no PPR
|
|
60
|
+
* concept, so `isRoutePPREnabled` is optional for it.
|
|
61
|
+
*
|
|
62
|
+
* Note: `REDIRECT` is intentionally absent. Next.js always calls `get()` with
|
|
63
|
+
* `kind: 'PAGES'` for Pages Router routes, even when the stored value has
|
|
64
|
+
* `kind: 'REDIRECT'`. The handler returns whatever value is cached and Next.js
|
|
65
|
+
* interprets it accordingly. */
|
|
66
|
+
type GetContext = {
|
|
67
|
+
kind: 'APP_ROUTE' | 'APP_PAGE';
|
|
68
|
+
isRoutePPREnabled: boolean;
|
|
69
|
+
isFallback: boolean;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'PAGES';
|
|
72
|
+
isRoutePPREnabled?: boolean;
|
|
73
|
+
isFallback: boolean;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'FETCH';
|
|
76
|
+
revalidate: number;
|
|
77
|
+
fetchUrl: string;
|
|
78
|
+
fetchIdx: number;
|
|
79
|
+
tags: string[];
|
|
80
|
+
softTags: string[];
|
|
81
|
+
isFallback: boolean;
|
|
82
|
+
};
|
|
83
|
+
/** Discriminated union of cache payloads accepted by
|
|
84
|
+
* {@link RedisStringsHandler.set}. `null` is a valid payload: the Pages Router
|
|
85
|
+
* stores `notFound: true` results as a cache entry with a null value. */
|
|
86
|
+
type SetCacheValue = {
|
|
87
|
+
kind: 'APP_PAGE';
|
|
88
|
+
status?: number;
|
|
89
|
+
headers: {
|
|
90
|
+
'x-nextjs-stale-time': string;
|
|
91
|
+
'x-next-cache-tags': string;
|
|
92
|
+
};
|
|
93
|
+
html: string;
|
|
94
|
+
rscData: Buffer;
|
|
95
|
+
segmentData: unknown;
|
|
96
|
+
postboned: unknown;
|
|
97
|
+
} | {
|
|
98
|
+
kind: 'APP_ROUTE';
|
|
99
|
+
status: number;
|
|
100
|
+
headers: {
|
|
101
|
+
'cache-control'?: string;
|
|
102
|
+
'x-nextjs-stale-time': string;
|
|
103
|
+
'x-next-cache-tags': string;
|
|
104
|
+
};
|
|
105
|
+
body: Buffer;
|
|
106
|
+
} | {
|
|
107
|
+
kind: 'PAGES';
|
|
108
|
+
html: string;
|
|
109
|
+
pageData: Record<string, unknown>;
|
|
110
|
+
headers?: Record<string, number | string | string[] | undefined>;
|
|
111
|
+
status?: number;
|
|
112
|
+
} | {
|
|
113
|
+
kind: 'REDIRECT';
|
|
114
|
+
props: Record<string, unknown>;
|
|
115
|
+
} | {
|
|
116
|
+
kind: 'FETCH';
|
|
117
|
+
data: {
|
|
118
|
+
headers: Record<string, string>;
|
|
119
|
+
body: string;
|
|
120
|
+
status: number;
|
|
121
|
+
url: string;
|
|
122
|
+
};
|
|
123
|
+
revalidate: number | false;
|
|
124
|
+
} | null;
|
|
58
125
|
type CreateRedisStringsHandlerOptions = {
|
|
59
126
|
/** Redis redisUrl to use.
|
|
60
127
|
* @default process.env.REDIS_URL? process.env.REDIS_URL : process.env.REDISHOST
|
|
@@ -158,56 +225,15 @@ declare class RedisStringsHandler {
|
|
|
158
225
|
resetRequestCache(): void;
|
|
159
226
|
private clientReadyCalls;
|
|
160
227
|
private assertClientIsReady;
|
|
161
|
-
get(key: string, ctx:
|
|
162
|
-
|
|
163
|
-
isRoutePPREnabled: boolean;
|
|
164
|
-
isFallback: boolean;
|
|
165
|
-
} | {
|
|
166
|
-
kind: 'FETCH';
|
|
167
|
-
revalidate: number;
|
|
168
|
-
fetchUrl: string;
|
|
169
|
-
fetchIdx: number;
|
|
170
|
-
tags: string[];
|
|
171
|
-
softTags: string[];
|
|
172
|
-
isFallback: boolean;
|
|
173
|
-
}): Promise<CacheEntry | null>;
|
|
174
|
-
set(key: string, data: {
|
|
175
|
-
kind: 'APP_PAGE';
|
|
176
|
-
status?: number;
|
|
177
|
-
headers: {
|
|
178
|
-
'x-nextjs-stale-time': string;
|
|
179
|
-
'x-next-cache-tags': string;
|
|
180
|
-
};
|
|
181
|
-
html: string;
|
|
182
|
-
rscData: Buffer;
|
|
183
|
-
segmentData: unknown;
|
|
184
|
-
postboned: unknown;
|
|
185
|
-
} | {
|
|
186
|
-
kind: 'APP_ROUTE';
|
|
187
|
-
status: number;
|
|
188
|
-
headers: {
|
|
189
|
-
'cache-control'?: string;
|
|
190
|
-
'x-nextjs-stale-time': string;
|
|
191
|
-
'x-next-cache-tags': string;
|
|
192
|
-
};
|
|
193
|
-
body: Buffer;
|
|
194
|
-
} | {
|
|
195
|
-
kind: 'FETCH';
|
|
196
|
-
data: {
|
|
197
|
-
headers: Record<string, string>;
|
|
198
|
-
body: string;
|
|
199
|
-
status: number;
|
|
200
|
-
url: string;
|
|
201
|
-
};
|
|
202
|
-
revalidate: number | false;
|
|
203
|
-
}, ctx: {
|
|
228
|
+
get(key: string, ctx: GetContext): Promise<CacheEntry | null>;
|
|
229
|
+
set(key: string, data: SetCacheValue, ctx: {
|
|
204
230
|
isRoutePPREnabled: boolean;
|
|
205
231
|
isFallback: boolean;
|
|
206
232
|
tags?: string[];
|
|
207
233
|
revalidate?: number | false;
|
|
208
234
|
cacheControl?: {
|
|
209
|
-
revalidate:
|
|
210
|
-
expire: undefined;
|
|
235
|
+
revalidate: number | false;
|
|
236
|
+
expire: number | undefined;
|
|
211
237
|
};
|
|
212
238
|
}): Promise<void>;
|
|
213
239
|
revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,73 @@ type CacheEntry = {
|
|
|
55
55
|
lastModified: number;
|
|
56
56
|
tags: string[];
|
|
57
57
|
};
|
|
58
|
+
/** Discriminated union of the `ctx` argument Next.js passes to
|
|
59
|
+
* {@link RedisStringsHandler.get}. The Pages Router (`PAGES`) has no PPR
|
|
60
|
+
* concept, so `isRoutePPREnabled` is optional for it.
|
|
61
|
+
*
|
|
62
|
+
* Note: `REDIRECT` is intentionally absent. Next.js always calls `get()` with
|
|
63
|
+
* `kind: 'PAGES'` for Pages Router routes, even when the stored value has
|
|
64
|
+
* `kind: 'REDIRECT'`. The handler returns whatever value is cached and Next.js
|
|
65
|
+
* interprets it accordingly. */
|
|
66
|
+
type GetContext = {
|
|
67
|
+
kind: 'APP_ROUTE' | 'APP_PAGE';
|
|
68
|
+
isRoutePPREnabled: boolean;
|
|
69
|
+
isFallback: boolean;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'PAGES';
|
|
72
|
+
isRoutePPREnabled?: boolean;
|
|
73
|
+
isFallback: boolean;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'FETCH';
|
|
76
|
+
revalidate: number;
|
|
77
|
+
fetchUrl: string;
|
|
78
|
+
fetchIdx: number;
|
|
79
|
+
tags: string[];
|
|
80
|
+
softTags: string[];
|
|
81
|
+
isFallback: boolean;
|
|
82
|
+
};
|
|
83
|
+
/** Discriminated union of cache payloads accepted by
|
|
84
|
+
* {@link RedisStringsHandler.set}. `null` is a valid payload: the Pages Router
|
|
85
|
+
* stores `notFound: true` results as a cache entry with a null value. */
|
|
86
|
+
type SetCacheValue = {
|
|
87
|
+
kind: 'APP_PAGE';
|
|
88
|
+
status?: number;
|
|
89
|
+
headers: {
|
|
90
|
+
'x-nextjs-stale-time': string;
|
|
91
|
+
'x-next-cache-tags': string;
|
|
92
|
+
};
|
|
93
|
+
html: string;
|
|
94
|
+
rscData: Buffer;
|
|
95
|
+
segmentData: unknown;
|
|
96
|
+
postboned: unknown;
|
|
97
|
+
} | {
|
|
98
|
+
kind: 'APP_ROUTE';
|
|
99
|
+
status: number;
|
|
100
|
+
headers: {
|
|
101
|
+
'cache-control'?: string;
|
|
102
|
+
'x-nextjs-stale-time': string;
|
|
103
|
+
'x-next-cache-tags': string;
|
|
104
|
+
};
|
|
105
|
+
body: Buffer;
|
|
106
|
+
} | {
|
|
107
|
+
kind: 'PAGES';
|
|
108
|
+
html: string;
|
|
109
|
+
pageData: Record<string, unknown>;
|
|
110
|
+
headers?: Record<string, number | string | string[] | undefined>;
|
|
111
|
+
status?: number;
|
|
112
|
+
} | {
|
|
113
|
+
kind: 'REDIRECT';
|
|
114
|
+
props: Record<string, unknown>;
|
|
115
|
+
} | {
|
|
116
|
+
kind: 'FETCH';
|
|
117
|
+
data: {
|
|
118
|
+
headers: Record<string, string>;
|
|
119
|
+
body: string;
|
|
120
|
+
status: number;
|
|
121
|
+
url: string;
|
|
122
|
+
};
|
|
123
|
+
revalidate: number | false;
|
|
124
|
+
} | null;
|
|
58
125
|
type CreateRedisStringsHandlerOptions = {
|
|
59
126
|
/** Redis redisUrl to use.
|
|
60
127
|
* @default process.env.REDIS_URL? process.env.REDIS_URL : process.env.REDISHOST
|
|
@@ -158,56 +225,15 @@ declare class RedisStringsHandler {
|
|
|
158
225
|
resetRequestCache(): void;
|
|
159
226
|
private clientReadyCalls;
|
|
160
227
|
private assertClientIsReady;
|
|
161
|
-
get(key: string, ctx:
|
|
162
|
-
|
|
163
|
-
isRoutePPREnabled: boolean;
|
|
164
|
-
isFallback: boolean;
|
|
165
|
-
} | {
|
|
166
|
-
kind: 'FETCH';
|
|
167
|
-
revalidate: number;
|
|
168
|
-
fetchUrl: string;
|
|
169
|
-
fetchIdx: number;
|
|
170
|
-
tags: string[];
|
|
171
|
-
softTags: string[];
|
|
172
|
-
isFallback: boolean;
|
|
173
|
-
}): Promise<CacheEntry | null>;
|
|
174
|
-
set(key: string, data: {
|
|
175
|
-
kind: 'APP_PAGE';
|
|
176
|
-
status?: number;
|
|
177
|
-
headers: {
|
|
178
|
-
'x-nextjs-stale-time': string;
|
|
179
|
-
'x-next-cache-tags': string;
|
|
180
|
-
};
|
|
181
|
-
html: string;
|
|
182
|
-
rscData: Buffer;
|
|
183
|
-
segmentData: unknown;
|
|
184
|
-
postboned: unknown;
|
|
185
|
-
} | {
|
|
186
|
-
kind: 'APP_ROUTE';
|
|
187
|
-
status: number;
|
|
188
|
-
headers: {
|
|
189
|
-
'cache-control'?: string;
|
|
190
|
-
'x-nextjs-stale-time': string;
|
|
191
|
-
'x-next-cache-tags': string;
|
|
192
|
-
};
|
|
193
|
-
body: Buffer;
|
|
194
|
-
} | {
|
|
195
|
-
kind: 'FETCH';
|
|
196
|
-
data: {
|
|
197
|
-
headers: Record<string, string>;
|
|
198
|
-
body: string;
|
|
199
|
-
status: number;
|
|
200
|
-
url: string;
|
|
201
|
-
};
|
|
202
|
-
revalidate: number | false;
|
|
203
|
-
}, ctx: {
|
|
228
|
+
get(key: string, ctx: GetContext): Promise<CacheEntry | null>;
|
|
229
|
+
set(key: string, data: SetCacheValue, ctx: {
|
|
204
230
|
isRoutePPREnabled: boolean;
|
|
205
231
|
isFallback: boolean;
|
|
206
232
|
tags?: string[];
|
|
207
233
|
revalidate?: number | false;
|
|
208
234
|
cacheControl?: {
|
|
209
|
-
revalidate:
|
|
210
|
-
expire: undefined;
|
|
235
|
+
revalidate: number | false;
|
|
236
|
+
expire: number | undefined;
|
|
211
237
|
};
|
|
212
238
|
}): Promise<void>;
|
|
213
239
|
revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -566,6 +566,19 @@ if (process.env.DEBUG_CACHE_HANDLER) {
|
|
|
566
566
|
}
|
|
567
567
|
var NEXT_CACHE_IMPLICIT_TAG_ID = "_N_T_";
|
|
568
568
|
var REVALIDATED_TAGS_KEY = "__revalidated_tags__";
|
|
569
|
+
var SUPPORTED_GET_KINDS = [
|
|
570
|
+
"APP_ROUTE",
|
|
571
|
+
"APP_PAGE",
|
|
572
|
+
"PAGES",
|
|
573
|
+
"FETCH"
|
|
574
|
+
];
|
|
575
|
+
var SUPPORTED_SET_KINDS = [
|
|
576
|
+
"APP_ROUTE",
|
|
577
|
+
"APP_PAGE",
|
|
578
|
+
"PAGES",
|
|
579
|
+
"REDIRECT",
|
|
580
|
+
"FETCH"
|
|
581
|
+
];
|
|
569
582
|
var killContainerOnErrorCount = 0;
|
|
570
583
|
var RedisStringsHandler = class {
|
|
571
584
|
constructor({
|
|
@@ -731,12 +744,12 @@ var RedisStringsHandler = class {
|
|
|
731
744
|
}
|
|
732
745
|
async get(key, ctx) {
|
|
733
746
|
try {
|
|
734
|
-
if (
|
|
747
|
+
if (!SUPPORTED_GET_KINDS.includes(ctx.kind)) {
|
|
735
748
|
console.warn(
|
|
736
749
|
"RedisStringsHandler.get() called with",
|
|
737
750
|
key,
|
|
738
751
|
ctx,
|
|
739
|
-
|
|
752
|
+
`this cache handler is only designed and tested for kinds ${SUPPORTED_GET_KINDS.join(", ")} and not for kind`,
|
|
740
753
|
ctx?.kind
|
|
741
754
|
);
|
|
742
755
|
}
|
|
@@ -791,7 +804,7 @@ var RedisStringsHandler = class {
|
|
|
791
804
|
"cacheEntry is mall formed (missing tags)"
|
|
792
805
|
);
|
|
793
806
|
}
|
|
794
|
-
if (
|
|
807
|
+
if (cacheEntry?.value === void 0) {
|
|
795
808
|
console.warn(
|
|
796
809
|
"RedisStringsHandler.get() called with",
|
|
797
810
|
key,
|
|
@@ -864,21 +877,27 @@ var RedisStringsHandler = class {
|
|
|
864
877
|
}
|
|
865
878
|
async set(key, data, ctx) {
|
|
866
879
|
try {
|
|
867
|
-
if (data
|
|
880
|
+
if (data !== null && !SUPPORTED_SET_KINDS.includes(data.kind)) {
|
|
868
881
|
console.warn(
|
|
869
882
|
"RedisStringsHandler.set() called with",
|
|
870
883
|
key,
|
|
871
884
|
ctx,
|
|
872
885
|
data,
|
|
873
|
-
|
|
886
|
+
`this cache handler is only designed and tested for kinds ${SUPPORTED_SET_KINDS.join(", ")} and not for kind`,
|
|
874
887
|
data?.kind
|
|
875
888
|
);
|
|
876
889
|
}
|
|
877
890
|
await this.assertClientIsReady();
|
|
878
|
-
if (data
|
|
891
|
+
if (data?.kind === "APP_PAGE" || data?.kind === "APP_ROUTE") {
|
|
879
892
|
const tags = data.headers["x-next-cache-tags"]?.split(",");
|
|
880
893
|
ctx.tags = [...ctx.tags || [], ...tags || []];
|
|
881
894
|
}
|
|
895
|
+
if (data === null || data.kind === "PAGES" || data.kind === "REDIRECT") {
|
|
896
|
+
const implicitTag = NEXT_CACHE_IMPLICIT_TAG_ID + key;
|
|
897
|
+
if (!ctx.tags?.includes(implicitTag)) {
|
|
898
|
+
ctx.tags = [...ctx.tags || [], implicitTag];
|
|
899
|
+
}
|
|
900
|
+
}
|
|
882
901
|
const cacheEntry = {
|
|
883
902
|
lastModified: Date.now(),
|
|
884
903
|
tags: ctx?.tags || [],
|
|
@@ -893,7 +912,10 @@ var RedisStringsHandler = class {
|
|
|
893
912
|
}
|
|
894
913
|
const revalidate = (
|
|
895
914
|
// For fetch requests in newest versions, the revalidate context property is never used, and instead the revalidate property of the passed-in data is used
|
|
896
|
-
data
|
|
915
|
+
data?.kind === "FETCH" && data.revalidate || ctx.revalidate || ctx.cacheControl?.revalidate || // Legacy fallback: older Next.js versions attached `revalidate` directly
|
|
916
|
+
// to the data payload. FETCH is already handled above, so this only
|
|
917
|
+
// matters for those older, non-discriminated shapes.
|
|
918
|
+
data?.revalidate
|
|
897
919
|
);
|
|
898
920
|
const expireAt = revalidate && Number.isSafeInteger(revalidate) && revalidate > 0 ? this.estimateExpireAge(revalidate) : this.estimateExpireAge(this.defaultStaleAge);
|
|
899
921
|
const setOperation = redisErrorHandler(
|
|
@@ -1446,7 +1468,22 @@ function getRedisCacheComponentsHandler(options = {}) {
|
|
|
1446
1468
|
}
|
|
1447
1469
|
return singletonHandler;
|
|
1448
1470
|
}
|
|
1449
|
-
var
|
|
1471
|
+
var resolvedHandler;
|
|
1472
|
+
var redisCacheHandler = new Proxy(
|
|
1473
|
+
{},
|
|
1474
|
+
{
|
|
1475
|
+
get(_target, prop) {
|
|
1476
|
+
if (!resolvedHandler) {
|
|
1477
|
+
resolvedHandler = getRedisCacheComponentsHandler();
|
|
1478
|
+
}
|
|
1479
|
+
const value = resolvedHandler[prop];
|
|
1480
|
+
return typeof value === "function" ? value.bind(resolvedHandler) : value;
|
|
1481
|
+
},
|
|
1482
|
+
has(_target, prop) {
|
|
1483
|
+
return prop in RedisCacheComponentsHandler.prototype;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
);
|
|
1450
1487
|
|
|
1451
1488
|
// src/index.ts
|
|
1452
1489
|
var index_default = CachedHandler;
|