@trieb.work/nextjs-turbo-redis-cache 1.18.0 → 1.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/dist/index.js +27 -20
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +27 -20
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +6 -1
  6. package/.cursor/skills/testing/SKILL.md +0 -121
  7. package/.github/workflows/ci.yml +0 -309
  8. package/.github/workflows/pages.yml +0 -38
  9. package/.github/workflows/release.yml +0 -58
  10. package/.prettierrc.json +0 -6
  11. package/.vscode/settings.json +0 -10
  12. package/ARCHITECTURE.md +0 -470
  13. package/commitlint.config.cjs +0 -4
  14. package/docker/redis.conf +0 -1
  15. package/docs/index.html +0 -140
  16. package/docs/robots.txt +0 -4
  17. package/docs/sitemap.xml +0 -8
  18. package/docs/styles.css +0 -141
  19. package/eslint.config.mjs +0 -26
  20. package/hooks/commit-msg +0 -10
  21. package/hooks/pre-commit +0 -11
  22. package/playwright.config.ts +0 -18
  23. package/release.config.cjs +0 -12
  24. package/scripts/prepare.sh +0 -7
  25. package/scripts/setup-git.sh +0 -8
  26. package/scripts/setup-repo-name.sh +0 -17
  27. package/scripts/vitest-run-staged.cjs +0 -44
  28. package/src/CacheComponentsHandler.ts +0 -597
  29. package/src/CachedHandler.ts +0 -53
  30. package/src/DeduplicatedRequestHandler.ts +0 -110
  31. package/src/RedisStringsHandler.ts +0 -949
  32. package/src/SyncedMap.ts +0 -496
  33. package/src/ZodHandler.ts +0 -45
  34. package/src/index.ts +0 -23
  35. package/src/serializer.ts +0 -59
  36. package/src/utils/cacheTtl.ts +0 -71
  37. package/src/utils/compareAndUnlink.ts +0 -29
  38. package/src/utils/debug.ts +0 -30
  39. package/src/utils/json.ts +0 -49
  40. package/src/utils/prefix.ts +0 -44
  41. package/src/utils/redisConnection.ts +0 -17
  42. package/src/utils/tagRevalidation.ts +0 -162
  43. package/test/README.md +0 -194
  44. package/test/nextjs-test-projects/next-app-15-4-11/README.md +0 -36
  45. package/test/nextjs-test-projects/next-app-15-4-11/eslint.config.mjs +0 -16
  46. package/test/nextjs-test-projects/next-app-15-4-11/next.config.js +0 -9
  47. package/test/nextjs-test-projects/next-app-15-4-11/package-lock.json +0 -5969
  48. package/test/nextjs-test-projects/next-app-15-4-11/package.json +0 -29
  49. package/test/nextjs-test-projects/next-app-15-4-11/pnpm-lock.yaml +0 -3726
  50. package/test/nextjs-test-projects/next-app-15-4-11/postcss.config.mjs +0 -5
  51. package/test/nextjs-test-projects/next-app-15-4-11/public/file.svg +0 -1
  52. package/test/nextjs-test-projects/next-app-15-4-11/public/globe.svg +0 -1
  53. package/test/nextjs-test-projects/next-app-15-4-11/public/next.svg +0 -1
  54. package/test/nextjs-test-projects/next-app-15-4-11/public/vercel.svg +0 -1
  55. package/test/nextjs-test-projects/next-app-15-4-11/public/window.svg +0 -1
  56. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/cached-static-fetch/route.ts +0 -18
  57. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  58. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidatePath/route.ts +0 -15
  59. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidateTag/route.ts +0 -15
  60. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidated-fetch/route.ts +0 -17
  61. package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/uncached-fetch/route.ts +0 -15
  62. package/test/nextjs-test-projects/next-app-15-4-11/src/app/globals.css +0 -26
  63. package/test/nextjs-test-projects/next-app-15-4-11/src/app/layout.tsx +0 -59
  64. package/test/nextjs-test-projects/next-app-15-4-11/src/app/page.tsx +0 -755
  65. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  66. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  67. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  68. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  69. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  70. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  71. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  72. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  73. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  74. package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  75. package/test/nextjs-test-projects/next-app-15-4-11/src/app/revalidation-interface.tsx +0 -267
  76. package/test/nextjs-test-projects/next-app-15-4-11/tsconfig.json +0 -27
  77. package/test/nextjs-test-projects/next-app-16-0-11/README.md +0 -36
  78. package/test/nextjs-test-projects/next-app-16-0-11/eslint.config.mjs +0 -18
  79. package/test/nextjs-test-projects/next-app-16-0-11/next.config.ts +0 -10
  80. package/test/nextjs-test-projects/next-app-16-0-11/package.json +0 -28
  81. package/test/nextjs-test-projects/next-app-16-0-11/pnpm-lock.yaml +0 -4163
  82. package/test/nextjs-test-projects/next-app-16-0-11/postcss.config.mjs +0 -7
  83. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/cached-static-fetch/route.ts +0 -18
  84. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  85. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidatePath/route.ts +0 -15
  86. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidateTag/route.ts +0 -20
  87. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidated-fetch/route.ts +0 -17
  88. package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/uncached-fetch/route.ts +0 -15
  89. package/test/nextjs-test-projects/next-app-16-0-11/src/app/favicon.ico +0 -0
  90. package/test/nextjs-test-projects/next-app-16-0-11/src/app/globals.css +0 -26
  91. package/test/nextjs-test-projects/next-app-16-0-11/src/app/layout.tsx +0 -59
  92. package/test/nextjs-test-projects/next-app-16-0-11/src/app/page.tsx +0 -755
  93. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  94. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  95. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  96. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  97. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  98. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  99. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  100. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  101. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  102. package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  103. package/test/nextjs-test-projects/next-app-16-0-11/src/app/revalidation-interface.tsx +0 -267
  104. package/test/nextjs-test-projects/next-app-16-0-11/src/app/update-tag-test/page.tsx +0 -25
  105. package/test/nextjs-test-projects/next-app-16-0-11/tsconfig.json +0 -34
  106. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/README.md +0 -36
  107. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/cache-handler.js +0 -3
  108. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/eslint.config.mjs +0 -18
  109. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/next.config.ts +0 -15
  110. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/package.json +0 -28
  111. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/pnpm-lock.yaml +0 -4206
  112. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/postcss.config.mjs +0 -7
  113. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/file.svg +0 -1
  114. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/globe.svg +0 -1
  115. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/next.svg +0 -1
  116. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/vercel.svg +0 -1
  117. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/window.svg +0 -1
  118. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
  119. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
  120. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
  121. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/expire-matrix/revalidate/route.ts +0 -34
  122. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/expire-matrix/route.ts +0 -23
  123. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
  124. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  125. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  126. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/page.tsx +0 -112
  127. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
  128. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  129. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  130. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  131. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  132. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/use-cache-remote/page.tsx +0 -85
  133. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/favicon.ico +0 -0
  134. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/globals.css +0 -26
  135. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/layout.tsx +0 -57
  136. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/page.tsx +0 -755
  137. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/revalidation-interface.tsx +0 -267
  138. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/update-tag-test/page.tsx +0 -22
  139. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/tsconfig.json +0 -34
  140. package/test/nextjs-test-projects/next-app-16-2-6/README.md +0 -36
  141. package/test/nextjs-test-projects/next-app-16-2-6/eslint.config.mjs +0 -18
  142. package/test/nextjs-test-projects/next-app-16-2-6/next.config.ts +0 -7
  143. package/test/nextjs-test-projects/next-app-16-2-6/package.json +0 -28
  144. package/test/nextjs-test-projects/next-app-16-2-6/pnpm-lock.yaml +0 -4165
  145. package/test/nextjs-test-projects/next-app-16-2-6/postcss.config.mjs +0 -7
  146. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/cached-static-fetch/route.ts +0 -18
  147. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  148. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidatePath/route.ts +0 -15
  149. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidateTag/route.ts +0 -20
  150. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidated-fetch/route.ts +0 -17
  151. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/uncached-fetch/route.ts +0 -15
  152. package/test/nextjs-test-projects/next-app-16-2-6/src/app/favicon.ico +0 -0
  153. package/test/nextjs-test-projects/next-app-16-2-6/src/app/globals.css +0 -26
  154. package/test/nextjs-test-projects/next-app-16-2-6/src/app/layout.tsx +0 -59
  155. package/test/nextjs-test-projects/next-app-16-2-6/src/app/page.tsx +0 -755
  156. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  157. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  158. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  159. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  160. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  161. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  162. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  163. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  164. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  165. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  166. package/test/nextjs-test-projects/next-app-16-2-6/src/app/revalidation-interface.tsx +0 -267
  167. package/test/nextjs-test-projects/next-app-16-2-6/src/app/update-tag-test/page.tsx +0 -25
  168. package/test/nextjs-test-projects/next-app-16-2-6/tsconfig.json +0 -34
  169. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/README.md +0 -36
  170. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/cache-handler.js +0 -3
  171. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/eslint.config.mjs +0 -18
  172. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/next.config.ts +0 -15
  173. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/package.json +0 -28
  174. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/pnpm-lock.yaml +0 -4165
  175. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/postcss.config.mjs +0 -7
  176. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/file.svg +0 -1
  177. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/globe.svg +0 -1
  178. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/next.svg +0 -1
  179. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/vercel.svg +0 -1
  180. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/window.svg +0 -1
  181. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
  182. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
  183. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
  184. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/expire-matrix/revalidate/route.ts +0 -34
  185. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/expire-matrix/route.ts +0 -23
  186. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
  187. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  188. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  189. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/page.tsx +0 -112
  190. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
  191. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  192. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  193. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  194. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  195. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/use-cache-remote/page.tsx +0 -85
  196. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/favicon.ico +0 -0
  197. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/globals.css +0 -26
  198. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/layout.tsx +0 -57
  199. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/page.tsx +0 -755
  200. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/revalidation-interface.tsx +0 -267
  201. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/update-tag-test/page.tsx +0 -22
  202. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/tsconfig.json +0 -34
  203. package/test/nextjs-test-projects/next-app-16-3-0/README.md +0 -36
  204. package/test/nextjs-test-projects/next-app-16-3-0/eslint.config.mjs +0 -18
  205. package/test/nextjs-test-projects/next-app-16-3-0/next.config.ts +0 -7
  206. package/test/nextjs-test-projects/next-app-16-3-0/package.json +0 -28
  207. package/test/nextjs-test-projects/next-app-16-3-0/pnpm-lock.yaml +0 -4284
  208. package/test/nextjs-test-projects/next-app-16-3-0/postcss.config.mjs +0 -7
  209. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/cached-static-fetch/route.ts +0 -18
  210. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  211. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidatePath/route.ts +0 -15
  212. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidateTag/route.ts +0 -20
  213. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidated-fetch/route.ts +0 -17
  214. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/uncached-fetch/route.ts +0 -15
  215. package/test/nextjs-test-projects/next-app-16-3-0/src/app/favicon.ico +0 -0
  216. package/test/nextjs-test-projects/next-app-16-3-0/src/app/globals.css +0 -26
  217. package/test/nextjs-test-projects/next-app-16-3-0/src/app/layout.tsx +0 -59
  218. package/test/nextjs-test-projects/next-app-16-3-0/src/app/page.tsx +0 -755
  219. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  220. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  221. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  222. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  223. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  224. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  225. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  226. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  227. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  228. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  229. package/test/nextjs-test-projects/next-app-16-3-0/src/app/revalidation-interface.tsx +0 -267
  230. package/test/nextjs-test-projects/next-app-16-3-0/src/app/update-tag-test/page.tsx +0 -25
  231. package/test/nextjs-test-projects/next-app-16-3-0/tsconfig.json +0 -34
  232. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/README.md +0 -36
  233. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/cache-handler.js +0 -3
  234. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/eslint.config.mjs +0 -18
  235. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/next.config.ts +0 -15
  236. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/package.json +0 -28
  237. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/pnpm-lock.yaml +0 -4284
  238. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/postcss.config.mjs +0 -7
  239. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/file.svg +0 -1
  240. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/globe.svg +0 -1
  241. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/next.svg +0 -1
  242. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/vercel.svg +0 -1
  243. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/window.svg +0 -1
  244. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
  245. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
  246. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
  247. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/expire-matrix/revalidate/route.ts +0 -34
  248. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/expire-matrix/route.ts +0 -23
  249. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
  250. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  251. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  252. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/page.tsx +0 -112
  253. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
  254. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  255. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  256. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  257. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  258. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/use-cache-remote/page.tsx +0 -85
  259. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/favicon.ico +0 -0
  260. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/globals.css +0 -26
  261. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/layout.tsx +0 -57
  262. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/page.tsx +0 -755
  263. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/revalidation-interface.tsx +0 -267
  264. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/update-tag-test/page.tsx +0 -22
  265. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/tsconfig.json +0 -34
  266. package/test/nextjs-test-projects/next-app-customized/README.md +0 -36
  267. package/test/nextjs-test-projects/next-app-customized/customized-cache-handler.js +0 -34
  268. package/test/nextjs-test-projects/next-app-customized/eslint.config.mjs +0 -16
  269. package/test/nextjs-test-projects/next-app-customized/next.config.js +0 -6
  270. package/test/nextjs-test-projects/next-pages-16-2-6/README.md +0 -16
  271. package/test/nextjs-test-projects/next-pages-16-2-6/eslint.config.mjs +0 -18
  272. package/test/nextjs-test-projects/next-pages-16-2-6/next.config.ts +0 -7
  273. package/test/nextjs-test-projects/next-pages-16-2-6/package.json +0 -26
  274. package/test/nextjs-test-projects/next-pages-16-2-6/pnpm-lock.yaml +0 -3896
  275. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/api/revalidate.ts +0 -24
  276. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/index.tsx +0 -11
  277. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/isr/[slug].tsx +0 -49
  278. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/static-forever.tsx +0 -20
  279. package/test/nextjs-test-projects/next-pages-16-2-6/tsconfig.json +0 -34
  280. package/test/nextjs-test-projects/next-pages-16-3-0/README.md +0 -16
  281. package/test/nextjs-test-projects/next-pages-16-3-0/eslint.config.mjs +0 -18
  282. package/test/nextjs-test-projects/next-pages-16-3-0/next.config.ts +0 -7
  283. package/test/nextjs-test-projects/next-pages-16-3-0/package.json +0 -26
  284. package/test/nextjs-test-projects/next-pages-16-3-0/pnpm-lock.yaml +0 -3939
  285. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/api/revalidate.ts +0 -24
  286. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/index.tsx +0 -11
  287. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/isr/[slug].tsx +0 -49
  288. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/static-forever.tsx +0 -20
  289. package/test/nextjs-test-projects/next-pages-16-3-0/tsconfig.json +0 -34
  290. package/test/playwright/cache-lab.spec.ts +0 -232
  291. package/test/playwright/update-tag.spec.ts +0 -33
  292. package/test/vitest/integration/build-id-prefix.integration.test.ts +0 -102
  293. package/test/vitest/integration/cache-components/cache-components.integration.test.ts +0 -389
  294. package/test/vitest/integration/cache-components/redis-kill-reconnect.test.ts +0 -65
  295. package/test/vitest/integration/cache-components/redis-quit-vs-disconnect.test.ts +0 -59
  296. package/test/vitest/integration/cache-components/redis-subscriber-outage.test.ts +0 -100
  297. package/test/vitest/integration/cache-components/scripts/redis-kill-reconnect.ts +0 -243
  298. package/test/vitest/integration/cache-components/scripts/redis-quit-vs-disconnect.ts +0 -113
  299. package/test/vitest/integration/cache-components/scripts/redis-subscriber-outage.ts +0 -379
  300. package/test/vitest/integration/cache-components/scripts/redis-test-helpers.ts +0 -155
  301. package/test/vitest/integration/nextjs-cache-handler.integration.test.ts +0 -959
  302. package/test/vitest/integration/pages-router.integration.test.ts +0 -430
  303. package/test/vitest/unit/SyncedMap-orphan-cleanup.test.ts +0 -111
  304. package/test/vitest/unit/SyncedMap-reconnect-repro.test.ts +0 -154
  305. package/test/vitest/unit/cache-components-update-tags.test.ts +0 -350
  306. package/test/vitest/unit/cache-ttl.test.ts +0 -67
  307. package/test/vitest/unit/compare-and-unlink.test.ts +0 -22
  308. package/test/vitest/unit/index.test.ts +0 -190
  309. package/test/vitest/unit/pages-router-kinds.test.ts +0 -303
  310. package/test/vitest/unit/reconnect-socket-already-opened.test.ts +0 -117
  311. package/test/vitest/unit/redis-connection.test.ts +0 -39
  312. package/test/vitest/unit/serializer.test.ts +0 -182
  313. package/test/vitest/unit/tag-revalidation.test.ts +0 -178
  314. package/test/vitest/unit/utils/prefix.test.ts +0 -115
  315. package/tsconfig.json +0 -18
  316. package/tsup.config.ts +0 -14
  317. package/vite.config.ts +0 -34
  318. package/vitest.cache-components.config.ts +0 -16
@@ -1,29 +0,0 @@
1
- /**
2
- * Atomically delete `key` only if its current value still equals `expected`.
3
- * GET then UNLINK would race: another instance can SET a replacement in between.
4
- */
5
- const COMPARE_AND_UNLINK = `
6
- if redis.call('GET', KEYS[1]) == ARGV[1] then
7
- return redis.call('UNLINK', KEYS[1])
8
- end
9
- return 0
10
- `;
11
-
12
- type EvalClient = {
13
- eval(
14
- script: string,
15
- options: { keys: string[]; arguments: string[] },
16
- ): Promise<unknown>;
17
- };
18
-
19
- export async function compareAndUnlink(
20
- client: EvalClient,
21
- key: string,
22
- expected: string,
23
- ): Promise<boolean> {
24
- const deleted = await client.eval(COMPARE_AND_UNLINK, {
25
- keys: [key],
26
- arguments: [expected],
27
- });
28
- return deleted === 1 || deleted === 1n;
29
- }
@@ -1,30 +0,0 @@
1
- export function debug(
2
- color:
3
- | 'red'
4
- | 'blue'
5
- | 'green'
6
- | 'yellow'
7
- | 'cyan'
8
- | 'white'
9
- | 'none' = 'none',
10
- ...args: unknown[]
11
- ): void {
12
- const colorCode = {
13
- red: '\x1b[31m',
14
- blue: '\x1b[34m',
15
- green: '\x1b[32m',
16
- yellow: '\x1b[33m',
17
- cyan: '\x1b[36m',
18
- white: '\x1b[37m',
19
- none: '',
20
- };
21
- if (process.env.DEBUG_CACHE_HANDLER) {
22
- console.log(colorCode[color], 'DEBUG CACHE HANDLER: ', ...args);
23
- }
24
- }
25
-
26
- export function debugVerbose(color: string, ...args: unknown[]) {
27
- if (process.env.DEBUG_CACHE_HANDLER_VERBOSE_VERBOSE) {
28
- console.log('\x1b[35m', 'DEBUG SYNCED MAP: ', ...args);
29
- }
30
- }
package/src/utils/json.ts DELETED
@@ -1,49 +0,0 @@
1
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
- export function bufferAndMapReviver(_: string, value: any): any {
3
- if (value && typeof value === 'object' && typeof value.$binary === 'string') {
4
- return Buffer.from(value.$binary, 'base64');
5
- }
6
- if (
7
- value &&
8
- typeof value === 'object' &&
9
- typeof value.$map === 'object' &&
10
- !!value.$map
11
- ) {
12
- return new Map(
13
- Object.entries(value.$map).map(([key, value]) => {
14
- const revivedValue = bufferAndMapReviver('', value);
15
- return [key, revivedValue];
16
- }),
17
- );
18
- }
19
- return value;
20
- }
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- export function bufferAndMapReplacer(_: string, value: any): any {
23
- if (Buffer.isBuffer(value)) {
24
- return {
25
- $binary: value.toString('base64'),
26
- };
27
- }
28
- if (
29
- value &&
30
- typeof value === 'object' &&
31
- value?.type === 'Buffer' &&
32
- Array.isArray(value.data)
33
- ) {
34
- return {
35
- $binary: Buffer.from(value.data).toString('base64'),
36
- };
37
- }
38
- if (value && typeof value === 'object' && value instanceof Map) {
39
- return {
40
- $map: Object.fromEntries(
41
- Array.from(value.entries()).map(([key, value]) => {
42
- const replacedValue = bufferAndMapReplacer('', value);
43
- return [key, replacedValue];
44
- }),
45
- ),
46
- };
47
- }
48
- return value;
49
- }
@@ -1,44 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- export function readBuildId(serverDistDir?: string): string | undefined {
5
- try {
6
- if (serverDistDir) {
7
- const buildIdPath = path.join(serverDistDir, '..', 'BUILD_ID');
8
- const buildId = fs.readFileSync(buildIdPath, 'utf8').trim();
9
- return buildId || undefined;
10
- }
11
- } catch {
12
- // fall through to cwd-based read
13
- }
14
- try {
15
- const fromCwd = path.join(process.cwd(), '.next', 'BUILD_ID');
16
- const buildId = fs.readFileSync(fromCwd, 'utf8').trim();
17
- return buildId || undefined;
18
- } catch {
19
- return undefined;
20
- }
21
- }
22
-
23
- export function resolveKeyPrefix({
24
- optionKeyPrefix,
25
- serverDistDir,
26
- env,
27
- }: {
28
- optionKeyPrefix?: string;
29
- serverDistDir?: string;
30
- env: NodeJS.ProcessEnv;
31
- }): string {
32
- // If the option is explicitly provided, honor it even if it's an empty string
33
- if (optionKeyPrefix !== undefined) {
34
- return optionKeyPrefix;
35
- }
36
-
37
- const keyPrefixEnv =
38
- env.KEY_PREFIX && env.KEY_PREFIX.length > 0 ? env.KEY_PREFIX : undefined;
39
- const vercelUrl =
40
- env.VERCEL_URL && env.VERCEL_URL.length > 0 ? env.VERCEL_URL : undefined;
41
- const buildId = readBuildId(serverDistDir);
42
-
43
- return keyPrefixEnv ?? vercelUrl ?? buildId ?? 'UNDEFINED_URL_';
44
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * Matches `PHASE_PRODUCTION_BUILD` from `next/constants`.
3
- *
4
- * Hardcoded so ESM builds (tsup `shims: false`) never call `require()`.
5
- * A dynamic `require('next/constants')` throws in ESM, and catching that used
6
- * to cache `undefined` for the process lifetime — disabling the build-phase
7
- * Redis skip entirely.
8
- */
9
- export const PHASE_PRODUCTION_BUILD = 'phase-production-build';
10
-
11
- /**
12
- * Returns true during `next build` so handlers can skip opening Redis
13
- * connections. Matches the official Next.js cache-handler-redis example.
14
- */
15
- export function shouldDeferRedisConnection(): boolean {
16
- return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
17
- }
@@ -1,162 +0,0 @@
1
- /**
2
- * Tag manifest matching Next.js 16.0–16.3
3
- * `next/dist/server/lib/cache-handlers/default.js` `updateTags`
4
- * and `next/dist/server/lib/incremental-cache/tags-manifest.external.js`.
5
- *
6
- * `revalidateTag(tag, profile)` resolves `cacheLife[profile].expire` (seconds)
7
- * and calls `updateTags(tags, { expire })`. `updateTag` / no profile calls
8
- * `updateTags(tags)` with no durations (immediate hard expire).
9
- */
10
- export type TagManifestEntry = {
11
- stale?: number;
12
- expired?: number;
13
- };
14
-
15
- /**
16
- * Read a tag-manifest field from Redis.
17
- *
18
- * Next.js 16.0–16.3 never persists plain numbers here — `updateTags` always
19
- * writes `{ stale, expired }` via `applyTagUpdate()`. A plain number can only
20
- * appear from older releases of this package that stored `Date.now()` directly
21
- * (before the `{ stale, expired }` manifest). ISR uses a separate Redis hash
22
- * (`__revalidated_tags__`) and is unaffected.
23
- *
24
- * A future-looking plain number is not produced by Next.js and is not the same
25
- * as intentional SWR (`{ stale: now, expired: now + N }`). It can only happen
26
- * when another instance wrote the timestamp with a faster clock (NTP skew).
27
- * Clamp to `now` on read so the revalidation is not delayed on slower instances.
28
- */
29
- export function normalizeTagManifest(
30
- stored: unknown,
31
- now: number = Date.now(),
32
- ): TagManifestEntry {
33
- if (typeof stored === 'number' && Number.isFinite(stored)) {
34
- return { expired: Math.min(stored, now) };
35
- }
36
-
37
- if (stored && typeof stored === 'object') {
38
- const rec = stored as {
39
- stale?: unknown;
40
- expired?: unknown;
41
- last?: unknown;
42
- pending?: unknown;
43
- };
44
- const stale =
45
- typeof rec.stale === 'number' && Number.isFinite(rec.stale)
46
- ? rec.stale
47
- : typeof rec.last === 'number' && Number.isFinite(rec.last)
48
- ? rec.last
49
- : undefined;
50
- const expired =
51
- typeof rec.expired === 'number' && Number.isFinite(rec.expired)
52
- ? rec.expired
53
- : typeof rec.pending === 'number' && Number.isFinite(rec.pending)
54
- ? rec.pending
55
- : undefined;
56
- return {
57
- ...(stale !== undefined ? { stale } : {}),
58
- ...(expired !== undefined ? { expired } : {}),
59
- };
60
- }
61
-
62
- return {};
63
- }
64
-
65
- /**
66
- * Mirrors Next.js DefaultCacheHandler.updateTags().
67
- */
68
- export function applyTagUpdate(
69
- existing: TagManifestEntry,
70
- durations: { expire?: number } | undefined,
71
- now: number,
72
- ): TagManifestEntry {
73
- if (durations) {
74
- const updates = { ...existing };
75
- updates.stale = now;
76
- if (durations.expire !== undefined) {
77
- updates.expired = now + durations.expire * 1000;
78
- }
79
- return updates;
80
- }
81
-
82
- return {
83
- ...existing,
84
- expired: now,
85
- };
86
- }
87
-
88
- /**
89
- * Immediate hard-expires (`expired <= now`) are stored as a plain number so
90
- * older package versions that JSON.parse + numeric-compare the hash field still
91
- * see the invalidation during a rolling deploy. SWR windows stay objects.
92
- */
93
- export function persistableTagManifest(
94
- entry: TagManifestEntry,
95
- now: number,
96
- ): TagManifestEntry | number {
97
- if (
98
- typeof entry.expired === 'number' &&
99
- entry.expired <= now &&
100
- (entry.stale === undefined || entry.stale <= entry.expired)
101
- ) {
102
- return entry.expired;
103
- }
104
- return entry;
105
- }
106
-
107
- /**
108
- * Mirrors Next.js `areTagsExpired`: hard miss once `expired` has elapsed
109
- * and is newer than the entry timestamp.
110
- */
111
- export function areTagsExpired(
112
- tags: string[],
113
- entryTimestamp: number,
114
- now: number,
115
- getEntry: (tag: string) => TagManifestEntry | undefined,
116
- ): boolean {
117
- for (const tag of tags) {
118
- const expiredAt = getEntry(tag)?.expired;
119
- if (
120
- typeof expiredAt === 'number' &&
121
- expiredAt <= now &&
122
- expiredAt > entryTimestamp
123
- ) {
124
- return true;
125
- }
126
- }
127
- return false;
128
- }
129
-
130
- /**
131
- * Mirrors Next.js `areTagsStale`: SWR when `stale` is newer than the entry.
132
- */
133
- export function areTagsStale(
134
- tags: string[],
135
- entryTimestamp: number,
136
- getEntry: (tag: string) => TagManifestEntry | undefined,
137
- ): boolean {
138
- for (const tag of tags) {
139
- const staleAt = getEntry(tag)?.stale ?? 0;
140
- if (typeof staleAt === 'number' && staleAt > entryTimestamp) {
141
- return true;
142
- }
143
- }
144
- return false;
145
- }
146
-
147
- /**
148
- * Mirrors Next.js DefaultCacheHandler.getExpiration(): max `expired` or 0.
149
- */
150
- export function maxExpiredTimestamp(
151
- tags: string[],
152
- getEntry: (tag: string) => TagManifestEntry | undefined,
153
- ): number {
154
- let max = 0;
155
- for (const tag of tags) {
156
- const expired = getEntry(tag)?.expired || 0;
157
- if (expired > max) {
158
- max = expired;
159
- }
160
- }
161
- return max;
162
- }
package/test/README.md DELETED
@@ -1,194 +0,0 @@
1
- # Test Structure
2
-
3
- ```
4
- test/
5
- ├── playwright/ # E2E tests — browser automation (Playwright)
6
- ├── vitest/ # Unit + Integration tests (Vitest)
7
- │ ├── unit/ # Pure unit tests (no external deps)
8
- │ └── integration/ # Integration tests (Redis + Next.js server)
9
- │ └── cache-components/ # Cache Components integration (Next.js 16+)
10
- └── nextjs-test-projects/ # Next.js app fixtures (shared across test types)
11
- ```
12
-
13
- ## Overview
14
-
15
- | Layer | Runner | What it validates | Needs Redis? | Needs Next.js app? |
16
- | --------------- | ---------- | ----------------------------------------------------------------------- | ------------ | ------------------ |
17
- | **Unit** | Vitest | Logic in isolation (serializer, prefix resolution, reconnect handling) | No | No |
18
- | **Integration** | Vitest | Cache handler ↔ Redis ↔ Next.js HTTP responses (server-side plumbing) | Yes | Yes |
19
- | **E2E** | Playwright | User-facing behavior in a real browser (Cache Components / `use cache`) | Yes | Yes |
20
-
21
- ---
22
-
23
- ## Unit Tests (`test/vitest/unit/`)
24
-
25
- **Runner:** Vitest
26
- **Command:** `pnpm test:unit`
27
- **Config:** `vite.config.ts`
28
-
29
- Fast tests with no external dependencies. Mocks are used where needed.
30
-
31
- | File | What it tests |
32
- | ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
33
- | `serializer.test.ts` | `CacheValueSerializer` interface, JSON round-trips, singleton stability |
34
- | `index.test.ts` | `RedisStringsHandler` constructor options, default behaviors |
35
- | `utils/prefix.test.ts` | `resolveKeyPrefix` logic (BUILD_ID fallback, env var precedence) |
36
- | `reconnect-socket-already-opened.test.ts` | Regression: reconnect logic doesn't call `connect()` when socket is already open |
37
- | `pages-router-kinds.test.ts` | Pages Router cache kinds (`PAGES`, `REDIRECT`, `null`/notFound), implicit tags, TTL derivation |
38
-
39
- ```bash
40
- pnpm test:unit # single run
41
- pnpm test:unit:watch # watch mode
42
- pnpm test:unit:coverage # with coverage report (used in CI)
43
- ```
44
-
45
- ---
46
-
47
- ## Integration Tests (`test/vitest/integration/`)
48
-
49
- **Runner:** Vitest
50
- **Command:** `pnpm test:integration`
51
- **Config:** `vite.config.ts`
52
- **Requires:** Redis on localhost:6379, pre-built Next.js test app
53
-
54
- These tests spawn a real Next.js server as a child process, make `fetch()` requests against it, and verify both HTTP responses and Redis state directly.
55
-
56
- ### Standard Integration (`nextjs-cache-handler.integration.test.ts`)
57
-
58
- Full cache lifecycle: static pages, fetch caching, revalidation, tag invalidation, TTL behavior. In CI this runs against Next.js 15.4, 16.0, 16.2, and 16.3. Nested fetch entries are resolved from their explicit cache tag in Redis's shared-tags map rather than Next.js's internal fetch-key hash, which changed in Next.js 16.3.
59
-
60
- ```bash
61
- pnpm test:integration
62
- ```
63
-
64
- ### Pages Router (`pages-router.integration.test.ts`)
65
-
66
- Pages Router cache lifecycle against the `next-pages-16-2-6` and `next-pages-16-3-0` apps: `PAGES` entry format, TTL derivation from `getStaticProps` `revalidate`, `fallback: 'blocking'` first hits, `notFound: true` (null cache entries), `redirect:` results, and `revalidate: false` TTL fallback.
67
-
68
- Starts **two** `next start` instances of the same build sharing one Redis and proves that on-demand revalidation (`res.revalidate(path)`) triggered on instance A is served fresh by instance B (HTML and `/_next/data` pageData JSON) — the multi-instance ISR scenario behind a load balancer.
69
-
70
- ```bash
71
- pnpm test:integration:pages
72
- ```
73
-
74
- ### BUILD_ID Prefix (`build-id-prefix.integration.test.ts`)
75
-
76
- Verifies that when neither `KEY_PREFIX` nor `VERCEL_URL` is set, the handler falls back to `.next/BUILD_ID` as the Redis key prefix. Runs in its own CI job because it needs a clean environment without those env vars.
77
-
78
- ```bash
79
- pnpm test:integration:build-id-prefix
80
- ```
81
-
82
- ### Cache Components (`cache-components/`)
83
-
84
- Integration tests specific to Next.js 16 Cache Components (`use cache`). CI runs them against the 16.0, 16.2, and 16.3 Cache Components test apps.
85
-
86
- | File | What it tests |
87
- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
88
- | `cache-components.integration.test.ts` | `use cache` lifecycle: store, retrieve, tag invalidation, `cacheLife` expiry, and every `revalidateTag` expire setting (`max`/`default`/`seconds`/`minutes`/`hours`/`days`/`weeks`, `{ expire: N }`, `{ expire: 0 }`, omitted profile) against `next start` + Redis |
89
- | `redis-kill-reconnect.test.ts` | Graceful recovery when Redis drops and reconnects (main client ping only) |
90
- | `redis-subscriber-outage.test.ts` | Issue #86: subscriber PubSub does not recover after Redis outage (expected to fail until bug is fixed) |
91
- | `redis-quit-vs-disconnect.test.ts` | `quit()` does not reliably close a subscriber during an outage; `disconnect()` does |
92
-
93
- `redis-kill-reconnect.test.ts` uses a container runtime and auto-detects `podman` first, then `docker`. You can force runtime selection with `CONTAINER_RUNTIME=podman` or `CONTAINER_RUNTIME=docker`.
94
-
95
- ```bash
96
- pnpm test:integration:cache-components
97
- ```
98
-
99
- **Prerequisites for all integration tests:**
100
-
101
- ```bash
102
- cd test/nextjs-test-projects/<app-name>
103
- pnpm install && pnpm build
104
- ```
105
-
106
- ---
107
-
108
- ## E2E Tests (`test/playwright/`)
109
-
110
- **Runner:** Playwright
111
- **Command:** `pnpm test:e2e`
112
- **Config:** `playwright.config.ts`
113
- **Requires:** Redis on localhost:6379 (Playwright auto-starts `next-app-16-2-6-cache-components` via `webServer`)
114
-
115
- Browser-based tests that validate Cache Components behavior from the user's perspective. Playwright was introduced because the Cache Components (`use cache`) feature in Next.js 16 relies on interactions that `fetch()` alone cannot reproduce:
116
-
117
- - **Server Actions** are triggered by form submissions / button clicks — requires a real browser context
118
- - `**updateTag`\*\* must be called from within a Server Action — needs actual UI interaction to verify
119
- - **Cookie-based cache keys** depend on the browser sending cookies during navigation
120
- - **Stale-while-revalidate** effects are only observable through page reloads and DOM diffing
121
-
122
- The Vitest cache-components integration tests verify the server-side plumbing (Redis state, HTTP responses). Playwright closes the gap by testing the full user-facing flow.
123
-
124
- | File | What it tests |
125
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
126
- | `cache-lab.spec.ts` | `use cache` / `use cache: remote` stability, tag invalidation (`updateTag`/`revalidateTag`), `revalidateTag` durations (SWR stale window), runtime cookie-based cache keys, SWR behavior |
127
- | `update-tag.spec.ts` | `updateTag` via Server Actions (button click → action → UI update) |
128
-
129
- ```bash
130
- pnpm test:e2e
131
-
132
- # Test against a specific Next.js version:
133
- PLAYWRIGHT_TEST_APP=next-app-16-0-11-cache-components pnpm test:e2e
134
-
135
- # Or point at an already-running server:
136
- PLAYWRIGHT_BASE_URL=http://localhost:3001 pnpm test:e2e
137
- ```
138
-
139
- ---
140
-
141
- ## Next.js Test Projects (`test/nextjs-test-projects/`)
142
-
143
- Minimal Next.js applications used as fixtures. They are not test runners — they provide the server that tests run against.
144
-
145
- | App | Next.js | Used by |
146
- | ----------------------------------- | ------- | -------------------------------------------------------------- |
147
- | `next-app-15-4-11` | 15.4.11 | Integration (matrix, default for local), build-id-prefix |
148
- | `next-app-16-0-11` | 16.0.11 | Integration (matrix) |
149
- | `next-app-16-2-6` | 16.2.6 | Integration (matrix) |
150
- | `next-pages-16-2-6` | 16.2.6 | Integration (Pages Router, two-instance revalidation) |
151
- | `next-app-16-0-11-cache-components` | 16.0.11 | Integration (cache-components matrix), E2E (Playwright matrix) |
152
- | `next-app-16-2-6-cache-components` | 16.2.6 | Integration (cache-components matrix), E2E (Playwright matrix) |
153
- | `next-app-customized` | — | Example of custom config (referenced in project README) |
154
-
155
- ---
156
-
157
- ## CI Jobs
158
-
159
- The CI workflow (`.github/workflows/ci.yml`) is structured as:
160
-
161
- ```
162
- lint-and-unit → Lint + Unit Tests + Coverage
163
- ├── integration → Matrix: 3 Next.js versions (15.4–16.2)
164
- ├── integration-pages → Pages Router (two-instance revalidation)
165
- ├── integration-build-id-prefix → Isolated BUILD_ID prefix test
166
- ├── integration-cache-components → Matrix: 16.0.11 + 16.2.6 cache-components
167
- └── e2e → Matrix: Playwright against 16.0.11 + 16.2.6
168
- ```
169
-
170
- `lint-and-unit` runs first as a gate. All other jobs run in parallel after it passes.
171
-
172
- | CI Job | Test App(s) | What runs |
173
- | ------------------------------ | --------------------------------------------------------- | --------------------------------------------------------------- |
174
- | `lint-and-unit` | — | `pnpm lint` + `pnpm test:unit:coverage` |
175
- | `integration` | `next-app-15-4-11`, `next-app-16-0-11`, `next-app-16-2-6` | `pnpm test:integration` (per matrix entry) |
176
- | `integration-pages` | `next-pages-16-2-6` | `pnpm test:integration:pages` |
177
- | `integration-build-id-prefix` | `next-app-15-4-11` | `pnpm test:integration:build-id-prefix` |
178
- | `integration-cache-components` | `next-app-16-{0-3,2-3}-cache-components` | `pnpm test:integration:cache-components` + Redis kill/reconnect |
179
- | `e2e` | `next-app-16-{0-3,2-3}-cache-components` | `pnpm test:e2e` (Playwright) |
180
-
181
- ---
182
-
183
- ## Environment Variables
184
-
185
- | Variable | Used by | Description |
186
- | ----------------------- | ------------------------------ | ------------------------------------------------------------------------- |
187
- | `NEXT_TEST_APP` | Integration | Which test app to use (default: `next-app-15-4-11`) |
188
- | `NEXT_PAGES_TEST_APP` | Integration (Pages Router) | Which Pages Router test app to use (default: `next-pages-16-2-6`) |
189
- | `CACHE_COMPONENTS_APP` | Integration (cache-components) | Which cache-components app (default: `next-app-16-2-6-cache-components`) |
190
- | `PLAYWRIGHT_TEST_APP` | E2E | Which app Playwright starts (default: `next-app-16-2-6-cache-components`) |
191
- | `PLAYWRIGHT_BASE_URL` | E2E | Override base URL (skips `webServer` auto-start) |
192
- | `SKIP_BUILD` | Integration | Skip Next.js build if app is pre-built |
193
- | `DEBUG_INTEGRATION` | Integration | Print child process stdout/stderr |
194
- | `CACHE_COMPONENTS_PORT` | Integration (cache-components) | Port for the server (default: 3065) |
@@ -1,36 +0,0 @@
1
- This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
-
3
- ## Getting Started
4
-
5
- First, run the development server:
6
-
7
- ```bash
8
- npm run dev
9
- # or
10
- yarn dev
11
- # or
12
- pnpm dev
13
- # or
14
- bun dev
15
- ```
16
-
17
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
-
19
- You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
-
21
- This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
-
23
- ## Learn More
24
-
25
- To learn more about Next.js, take a look at the following resources:
26
-
27
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
-
30
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
-
32
- ## Deploy on Vercel
33
-
34
- The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
-
36
- Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
@@ -1,16 +0,0 @@
1
- import { dirname } from "path";
2
- import { fileURLToPath } from "url";
3
- import { FlatCompat } from "@eslint/eslintrc";
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = dirname(__filename);
7
-
8
- const compat = new FlatCompat({
9
- baseDirectory: __dirname,
10
- });
11
-
12
- const eslintConfig = [
13
- ...compat.extends("next/core-web-vitals", "next/typescript"),
14
- ];
15
-
16
- export default eslintConfig;
@@ -1,9 +0,0 @@
1
- /** @type {import('next').NextConfig} */
2
- const nextConfig = {
3
- cacheHandler: require.resolve('@trieb.work/nextjs-turbo-redis-cache'),
4
- turbopack: {
5
- root: __dirname,
6
- },
7
- };
8
-
9
- module.exports = nextConfig;