@trieb.work/nextjs-turbo-redis-cache 1.16.2 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/.github/workflows/ci.yml +11 -2
  2. package/CHANGELOG.md +7 -0
  3. package/README.md +4 -1
  4. package/package.json +2 -2
  5. package/test/README.md +3 -3
  6. package/test/nextjs-test-projects/next-app-15-4-11/pnpm-lock.yaml +1 -1
  7. package/test/nextjs-test-projects/next-app-16-0-11/pnpm-lock.yaml +1 -1
  8. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/pnpm-lock.yaml +1 -1
  9. package/test/nextjs-test-projects/next-app-16-2-6/pnpm-lock.yaml +1 -1
  10. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/pnpm-lock.yaml +1 -1
  11. package/test/nextjs-test-projects/next-app-16-3-0/README.md +36 -0
  12. package/test/nextjs-test-projects/next-app-16-3-0/eslint.config.mjs +18 -0
  13. package/test/nextjs-test-projects/next-app-16-3-0/next.config.ts +7 -0
  14. package/test/nextjs-test-projects/next-app-16-3-0/package.json +28 -0
  15. package/test/nextjs-test-projects/next-app-16-3-0/pnpm-lock.yaml +4284 -0
  16. package/test/nextjs-test-projects/next-app-16-3-0/postcss.config.mjs +7 -0
  17. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/cached-static-fetch/route.ts +18 -0
  18. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +27 -0
  19. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidatePath/route.ts +15 -0
  20. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidateTag/route.ts +20 -0
  21. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidated-fetch/route.ts +17 -0
  22. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/uncached-fetch/route.ts +15 -0
  23. package/test/nextjs-test-projects/next-app-16-3-0/src/app/favicon.ico +0 -0
  24. package/test/nextjs-test-projects/next-app-16-3-0/src/app/globals.css +26 -0
  25. package/test/nextjs-test-projects/next-app-16-3-0/src/app/layout.tsx +59 -0
  26. package/test/nextjs-test-projects/next-app-16-3-0/src/app/page.tsx +755 -0
  27. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +19 -0
  28. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +34 -0
  29. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
  30. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/no-fetch/default-page/page.tsx +55 -0
  31. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +19 -0
  32. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +35 -0
  33. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
  34. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +19 -0
  35. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +32 -0
  36. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +25 -0
  37. package/test/nextjs-test-projects/next-app-16-3-0/src/app/revalidation-interface.tsx +267 -0
  38. package/test/nextjs-test-projects/next-app-16-3-0/src/app/update-tag-test/page.tsx +25 -0
  39. package/test/nextjs-test-projects/next-app-16-3-0/tsconfig.json +34 -0
  40. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/README.md +36 -0
  41. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/cache-handler.js +3 -0
  42. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/eslint.config.mjs +18 -0
  43. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/next.config.ts +13 -0
  44. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/package.json +28 -0
  45. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/pnpm-lock.yaml +4284 -0
  46. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/postcss.config.mjs +7 -0
  47. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/file.svg +1 -0
  48. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/globe.svg +1 -0
  49. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/next.svg +1 -0
  50. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/vercel.svg +1 -0
  51. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/window.svg +1 -0
  52. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-static-fetch/route.ts +19 -0
  53. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-cachelife/route.ts +24 -0
  54. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-tag/route.ts +21 -0
  55. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidate-tag/route.ts +19 -0
  56. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidated-fetch/route.ts +19 -0
  57. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/cachelife-short/page.tsx +110 -0
  58. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/page.tsx +90 -0
  59. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +127 -0
  60. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +130 -0
  61. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +127 -0
  62. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +110 -0
  63. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/favicon.ico +0 -0
  64. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/globals.css +26 -0
  65. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/layout.tsx +57 -0
  66. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/page.tsx +755 -0
  67. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/revalidation-interface.tsx +267 -0
  68. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/update-tag-test/page.tsx +22 -0
  69. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/tsconfig.json +34 -0
  70. package/test/nextjs-test-projects/next-pages-16-2-6/pnpm-lock.yaml +4 -4
  71. package/test/nextjs-test-projects/next-pages-16-3-0/README.md +16 -0
  72. package/test/nextjs-test-projects/next-pages-16-3-0/eslint.config.mjs +18 -0
  73. package/test/nextjs-test-projects/next-pages-16-3-0/next.config.ts +7 -0
  74. package/test/nextjs-test-projects/next-pages-16-3-0/package.json +26 -0
  75. package/test/nextjs-test-projects/next-pages-16-3-0/pnpm-lock.yaml +3939 -0
  76. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/api/revalidate.ts +24 -0
  77. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/index.tsx +11 -0
  78. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/isr/[slug].tsx +49 -0
  79. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/static-forever.tsx +20 -0
  80. package/test/nextjs-test-projects/next-pages-16-3-0/tsconfig.json +34 -0
  81. package/test/vitest/integration/nextjs-cache-handler.integration.test.ts +51 -32
@@ -0,0 +1,267 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+
5
+ // Define API routes for path-based revalidation
6
+ const apiRoutePaths: Record<string, string> = {
7
+ 'Cached Static Fetch': '/api/cached-static-fetch',
8
+ 'Uncached Fetch': '/api/uncached-fetch',
9
+ 'Revalidated Fetch': '/api/revalidated-fetch',
10
+ 'Nested Fetch in API Route':
11
+ '/api/nested-fetch-in-api-route/revalidated-fetch',
12
+ };
13
+
14
+ // Define API routes with tags for tag-based revalidation
15
+ const apiRouteTags: Record<string, string> = {
16
+ 'Revalidated Fetch in Nested API Route':
17
+ 'revalidated-fetch-revalidate3-nested-fetch-in-api-route',
18
+ 'Revalidated Fetch API': 'revalidated-fetch-api',
19
+ 'Cached Static Fetch API': 'cached-static-fetch-api',
20
+ 'Uncached Fetch API': 'uncached-fetch-api',
21
+ };
22
+
23
+ // Revalidation Interface Component
24
+ export function RevalidationInterface() {
25
+ const [selectedPathRoute, setSelectedPathRoute] = useState('');
26
+ const [selectedTagRoute, setSelectedTagRoute] = useState('');
27
+ const [revalidationStatus, setRevalidationStatus] = useState('');
28
+ const [isLoading, setIsLoading] = useState(false);
29
+
30
+ const handlePathRevalidate = async () => {
31
+ if (!selectedPathRoute) {
32
+ setRevalidationStatus('Please select an API route to revalidate by path');
33
+ return;
34
+ }
35
+
36
+ setIsLoading(true);
37
+ setRevalidationStatus('Revalidating API route by path...');
38
+
39
+ try {
40
+ const path = apiRoutePaths[selectedPathRoute];
41
+ const response = await fetch(`/api/revalidatePath?path=${path}`);
42
+ const data = await response.json();
43
+
44
+ if (response.ok) {
45
+ setRevalidationStatus(
46
+ `Successfully revalidated API route by path: ${selectedPathRoute} (${path})`,
47
+ );
48
+ } else {
49
+ setRevalidationStatus(`Error: ${data.error || 'Unknown error'}`);
50
+ }
51
+ } catch (error: unknown) {
52
+ const errorMessage =
53
+ error instanceof Error ? error.message : 'Unknown error';
54
+ setRevalidationStatus(`Error: ${errorMessage}`);
55
+ } finally {
56
+ setIsLoading(false);
57
+ }
58
+ };
59
+
60
+ const handleTagRevalidate = async () => {
61
+ if (!selectedTagRoute) {
62
+ setRevalidationStatus('Please select an API route to revalidate by tag');
63
+ return;
64
+ }
65
+
66
+ setIsLoading(true);
67
+ setRevalidationStatus('Revalidating API route by tag...');
68
+
69
+ try {
70
+ const tag = apiRouteTags[selectedTagRoute];
71
+ const response = await fetch(`/api/revalidateTag?tag=${tag}`);
72
+ const data = await response.json();
73
+
74
+ if (response.ok) {
75
+ setRevalidationStatus(
76
+ `Successfully revalidated API route by tag: ${selectedTagRoute} (tag: ${tag})`,
77
+ );
78
+ } else {
79
+ setRevalidationStatus(`Error: ${data.error || 'Unknown error'}`);
80
+ }
81
+ } catch (error: unknown) {
82
+ const errorMessage =
83
+ error instanceof Error ? error.message : 'Unknown error';
84
+ setRevalidationStatus(`Error: ${errorMessage}`);
85
+ } finally {
86
+ setIsLoading(false);
87
+ }
88
+ };
89
+
90
+ return (
91
+ <div
92
+ style={{
93
+ border: '1px solid #eaeaea',
94
+ padding: '25px',
95
+ borderRadius: '8px',
96
+ boxShadow: '0 4px 6px rgba(0,0,0,0.05)',
97
+ backgroundColor: '#fff',
98
+ marginBottom: '30px',
99
+ }}
100
+ >
101
+ <h3
102
+ style={{
103
+ fontSize: '1.4rem',
104
+ color: '#0070f3',
105
+ marginTop: '0',
106
+ marginBottom: '15px',
107
+ borderBottom: '1px solid #eaeaea',
108
+ paddingBottom: '10px',
109
+ }}
110
+ >
111
+ API Route Revalidation Interface
112
+ </h3>
113
+
114
+ {/* Path-based revalidation section */}
115
+ <div
116
+ style={{
117
+ padding: '15px',
118
+ marginBottom: '20px',
119
+ backgroundColor: '#f9f9f9',
120
+ borderRadius: '5px',
121
+ border: '1px solid #eaeaea',
122
+ }}
123
+ >
124
+ <h4
125
+ style={{
126
+ fontSize: '1.1rem',
127
+ color: '#0070f3',
128
+ marginTop: '0',
129
+ marginBottom: '15px',
130
+ }}
131
+ >
132
+ Revalidate API Route by Path
133
+ </h4>
134
+
135
+ <div style={{ marginBottom: '15px' }}>
136
+ <label
137
+ style={{ display: 'block', marginBottom: '8px', fontWeight: '500' }}
138
+ >
139
+ Select API Route:
140
+ </label>
141
+ <select
142
+ value={selectedPathRoute}
143
+ onChange={(e) => setSelectedPathRoute(e.target.value)}
144
+ style={{
145
+ width: '100%',
146
+ padding: '10px',
147
+ borderRadius: '5px',
148
+ border: '1px solid #ddd',
149
+ fontSize: '1rem',
150
+ }}
151
+ >
152
+ <option value="">-- Select an API route --</option>
153
+ {Object.keys(apiRoutePaths).map((route) => (
154
+ <option key={route} value={route}>
155
+ {route}
156
+ </option>
157
+ ))}
158
+ </select>
159
+ </div>
160
+
161
+ <button
162
+ onClick={handlePathRevalidate}
163
+ disabled={isLoading || !selectedPathRoute}
164
+ style={{
165
+ backgroundColor: '#0070f3',
166
+ color: 'white',
167
+ border: 'none',
168
+ padding: '10px 20px',
169
+ borderRadius: '5px',
170
+ fontSize: '1rem',
171
+ fontWeight: '500',
172
+ cursor: isLoading || !selectedPathRoute ? 'not-allowed' : 'pointer',
173
+ opacity: isLoading || !selectedPathRoute ? 0.7 : 1,
174
+ transition: 'all 0.2s',
175
+ }}
176
+ >
177
+ {isLoading ? 'Revalidating...' : 'Revalidate by Path'}
178
+ </button>
179
+ </div>
180
+
181
+ {/* Tag-based revalidation section */}
182
+ <div
183
+ style={{
184
+ padding: '15px',
185
+ marginBottom: '20px',
186
+ backgroundColor: '#f9f9f9',
187
+ borderRadius: '5px',
188
+ border: '1px solid #eaeaea',
189
+ }}
190
+ >
191
+ <h4
192
+ style={{
193
+ fontSize: '1.1rem',
194
+ color: '#0070f3',
195
+ marginTop: '0',
196
+ marginBottom: '15px',
197
+ }}
198
+ >
199
+ Revalidate API Route by Tag
200
+ </h4>
201
+
202
+ <div style={{ marginBottom: '15px' }}>
203
+ <label
204
+ style={{ display: 'block', marginBottom: '8px', fontWeight: '500' }}
205
+ >
206
+ Select API Route with Tag:
207
+ </label>
208
+ <select
209
+ value={selectedTagRoute}
210
+ onChange={(e) => setSelectedTagRoute(e.target.value)}
211
+ style={{
212
+ width: '100%',
213
+ padding: '10px',
214
+ borderRadius: '5px',
215
+ border: '1px solid #ddd',
216
+ fontSize: '1rem',
217
+ }}
218
+ >
219
+ <option value="">-- Select an API route with tag --</option>
220
+ {Object.keys(apiRouteTags).map((route) => (
221
+ <option key={route} value={route}>
222
+ {route}
223
+ </option>
224
+ ))}
225
+ </select>
226
+ </div>
227
+
228
+ <button
229
+ onClick={handleTagRevalidate}
230
+ disabled={isLoading || !selectedTagRoute}
231
+ style={{
232
+ backgroundColor: '#0070f3',
233
+ color: 'white',
234
+ border: 'none',
235
+ padding: '10px 20px',
236
+ borderRadius: '5px',
237
+ fontSize: '1rem',
238
+ fontWeight: '500',
239
+ cursor: isLoading || !selectedTagRoute ? 'not-allowed' : 'pointer',
240
+ opacity: isLoading || !selectedTagRoute ? 0.7 : 1,
241
+ transition: 'all 0.2s',
242
+ }}
243
+ >
244
+ {isLoading ? 'Revalidating...' : 'Revalidate by Tag'}
245
+ </button>
246
+ </div>
247
+
248
+ {/* Status display */}
249
+ {revalidationStatus && (
250
+ <div
251
+ style={{
252
+ marginTop: '15px',
253
+ padding: '10px',
254
+ borderRadius: '5px',
255
+ backgroundColor: revalidationStatus.includes('Error')
256
+ ? '#ffebee'
257
+ : '#e3f2fd',
258
+ color: revalidationStatus.includes('Error') ? '#c62828' : '#0070f3',
259
+ border: `1px solid ${revalidationStatus.includes('Error') ? '#ffcdd2' : '#bbdefb'}`,
260
+ }}
261
+ >
262
+ {revalidationStatus}
263
+ </div>
264
+ )}
265
+ </div>
266
+ );
267
+ }
@@ -0,0 +1,22 @@
1
+ import { updateTag } from 'next/cache';
2
+
3
+ let clicks = 0;
4
+
5
+ async function increment() {
6
+ 'use server';
7
+
8
+ clicks++;
9
+ updateTag('update-tag-test');
10
+ }
11
+
12
+ export default function UpdateTagTestPage() {
13
+ return (
14
+ <main style={{ padding: 40, fontFamily: 'system-ui, sans-serif' }}>
15
+ <h1>UpdateTag Test</h1>
16
+ <form action={increment}>
17
+ <p data-testid="clicks">Clicks: {clicks}</p>
18
+ <button type="submit">Increment</button>
19
+ </form>
20
+ </main>
21
+ );
22
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -469,7 +469,7 @@ packages:
469
469
  '@trieb.work/nextjs-turbo-redis-cache@file:../../..':
470
470
  resolution: {directory: ../../.., type: directory}
471
471
  peerDependencies:
472
- next: '>=15.0.3 <16.3.0'
472
+ next: '>=15.0.3 <17.0.0'
473
473
  redis: 4.7.0
474
474
 
475
475
  '@tybys/wasm-util@0.10.3':
@@ -2768,7 +2768,7 @@ snapshots:
2768
2768
  eslint: 9.39.5
2769
2769
  eslint-import-resolver-node: 0.3.10
2770
2770
  eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5)
2771
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
2771
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
2772
2772
  eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5)
2773
2773
  eslint-plugin-react: 7.37.5(eslint@9.39.5)
2774
2774
  eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5)
@@ -2801,7 +2801,7 @@ snapshots:
2801
2801
  tinyglobby: 0.2.17
2802
2802
  unrs-resolver: 1.12.2
2803
2803
  optionalDependencies:
2804
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
2804
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
2805
2805
  transitivePeerDependencies:
2806
2806
  - supports-color
2807
2807
 
@@ -2816,7 +2816,7 @@ snapshots:
2816
2816
  transitivePeerDependencies:
2817
2817
  - supports-color
2818
2818
 
2819
- eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5):
2819
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.64.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5):
2820
2820
  dependencies:
2821
2821
  '@rtsao/scc': 1.1.0
2822
2822
  array-includes: 3.1.9
@@ -0,0 +1,16 @@
1
+ # next-pages-16-3-0
2
+
3
+ Next.js 16.3.0 **Pages Router** fixture for integration testing the Redis
4
+ cache handler with Pages Router cache entry kinds:
5
+
6
+ - `PAGES` — ISR pages via `getStaticProps` + `revalidate` and
7
+ `getStaticPaths` with `fallback: 'blocking'` (`/isr/[slug]`)
8
+ - `REDIRECT` — `getStaticProps` returning `redirect:` (`/isr/redirect`)
9
+ - `null` value entries — `getStaticProps` returning `notFound: true`
10
+ (`/isr/not-found`)
11
+ - `revalidate: false` TTL fallback (`/static-forever`)
12
+ - On-demand revalidation via `res.revalidate(path)`
13
+ (`/api/revalidate?path=...`), used by the two-instance cross-server
14
+ revalidation test
15
+
16
+ Used by `test/vitest/integration/pages-router.integration.test.ts`.
@@ -0,0 +1,18 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ const eslintConfig = defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+ // Override default ignores of eslint-config-next.
9
+ globalIgnores([
10
+ // Default ignores of eslint-config-next:
11
+ ".next/**",
12
+ "out/**",
13
+ "build/**",
14
+ "next-env.d.ts",
15
+ ]),
16
+ ]);
17
+
18
+ export default eslintConfig;
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from 'next';
2
+
3
+ const nextConfig: NextConfig = {
4
+ cacheHandler: require.resolve('@trieb.work/nextjs-turbo-redis-cache'),
5
+ };
6
+
7
+ export default nextConfig;
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "next-pages-16-3-0",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "next": "16.3.0",
13
+ "react": "19.2.0",
14
+ "react-dom": "19.2.0",
15
+ "redis": "4.7.0",
16
+ "@trieb.work/nextjs-turbo-redis-cache": "file:../../../"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^20",
20
+ "@types/react": "^19",
21
+ "@types/react-dom": "^19",
22
+ "eslint": "^9",
23
+ "eslint-config-next": "16.3.0",
24
+ "typescript": "^5"
25
+ }
26
+ }