@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,959 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
- import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
3
- import fetch from 'node-fetch';
4
- import { createClient, RedisClientType } from 'redis';
5
- import { join } from 'path';
6
- import { CacheEntry } from '../../../src/RedisStringsHandler';
7
- import { revalidate as revalidatedFetchRouteRevalidate } from '../../nextjs-test-projects/next-app-15-4-11/src/app/api/revalidated-fetch/route';
8
-
9
- // Select which Next.js test app to use. Can be overridden via NEXT_TEST_APP env var
10
- // Examples: next-app-15-4-11, next-app-16-0-11, next-app-16-2-6, next-app-16-3-0
11
- const NEXT_TEST_APP = process.env.NEXT_TEST_APP || 'next-app-15-4-11';
12
- const NEXT_APP_DIR = join(
13
- __dirname,
14
- '..',
15
- '..',
16
- 'nextjs-test-projects',
17
- NEXT_TEST_APP,
18
- );
19
- console.log('NEXT_APP_DIR', NEXT_APP_DIR);
20
-
21
- const SHARED_TAGS_KEY = '__sharedTags__';
22
- const NEXT_START_PORT = 3055;
23
- const NEXT_START_URL = `http://localhost:${NEXT_START_PORT}`;
24
-
25
- const REDIS_BACKGROUND_SYNC_DELAY = 250; //ms delay to prevent flaky tests in slow CI environments
26
-
27
- let nextProcess: ChildProcessWithoutNullStreams;
28
- let redisClient: RedisClientType;
29
-
30
- async function delay(ms: number) {
31
- return new Promise((resolve) => setTimeout(resolve, ms));
32
- }
33
-
34
- async function findFetchCacheEntryKey(tag: string): Promise<string> {
35
- const sharedTags = await redisClient.hGetAll(
36
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
37
- );
38
- const matches = Object.entries(sharedTags).filter(
39
- ([key, serializedTags]) =>
40
- !key.startsWith('/') &&
41
- (JSON.parse(serializedTags) as string[]).includes(tag),
42
- );
43
-
44
- expect(matches).toHaveLength(1);
45
- return matches[0]![0];
46
- }
47
-
48
- async function runCommand(cmd: string, args: string[], cwd: string) {
49
- return new Promise((resolve, reject) => {
50
- let stderr = '';
51
- let stdout = '';
52
- const proc = spawn(cmd, args, { cwd, stdio: 'pipe' });
53
-
54
- proc.stdout.on('data', (data) => {
55
- if (process.env.DEBUG_INTEGRATION) {
56
- console.log(data.toString());
57
- }
58
- stdout += data.toString();
59
- });
60
-
61
- proc.stderr.on('data', (data) => {
62
- if (process.env.DEBUG_INTEGRATION) {
63
- console.error(data.toString());
64
- }
65
- stderr += data.toString();
66
- });
67
-
68
- proc.on('exit', (code) => {
69
- if (code === 0) resolve(undefined);
70
- else {
71
- reject(
72
- new Error(
73
- `${cmd} ${args.join(' ')} failed with code ${code}\n` +
74
- `stdout: ${stdout}\n` +
75
- `stderr: ${stderr}`,
76
- ),
77
- );
78
- }
79
- });
80
- });
81
- }
82
-
83
- async function waitForServer(url: string, timeout = 20000) {
84
- const start = Date.now();
85
- while (Date.now() - start < timeout) {
86
- try {
87
- const res = await fetch(url + '/api/cached-static-fetch');
88
- if (res.ok) return;
89
- } catch {}
90
- await new Promise((r) => setTimeout(r, 300));
91
- }
92
- throw new Error('Next.js server did not start in time');
93
- }
94
-
95
- describe('Next.js Turbo Redis Cache Integration', () => {
96
- beforeAll(async () => {
97
- // If there was detected to run a server before (any old server which was not stopped correctly), kill it
98
- try {
99
- const res = await fetch(NEXT_START_URL + '/api/cached-static-fetch');
100
- if (res.ok) {
101
- await runCommand('pkill', ['next'], NEXT_APP_DIR);
102
- }
103
- } catch {}
104
-
105
- // Set up environment variables
106
- process.env.VERCEL_ENV = 'production';
107
- process.env.VERCEL_URL =
108
- 'integration-test-' + Math.random().toString(36).substring(2, 15);
109
- console.log('redis key prefix is:', process.env.VERCEL_URL);
110
-
111
- // Only override if redis env vars if not set. This can be set in the CI env.
112
- process.env.REDISHOST = process.env.REDISHOST || 'localhost';
113
- process.env.REDISPORT = process.env.REDISPORT || '6379';
114
- process.env.NEXT_START_PORT = String(NEXT_START_PORT);
115
-
116
- if (process.env.SKIP_BUILD === 'true') {
117
- console.log('skipping build');
118
- } else {
119
- // Build Next.js app first
120
- await runCommand('pnpm', ['i'], NEXT_APP_DIR);
121
- console.log('pnpm i done');
122
- await runCommand('pnpm', ['build'], NEXT_APP_DIR);
123
- console.log('pnpm build done');
124
- }
125
-
126
- // Start Next.js app
127
- nextProcess = spawn(
128
- 'npx',
129
- ['next', 'start', '-p', String(NEXT_START_PORT)],
130
- {
131
- cwd: NEXT_APP_DIR,
132
- env: {
133
- ...process.env,
134
- },
135
- stdio: 'pipe',
136
- },
137
- );
138
- if (process.env.DEBUG_INTEGRATION) {
139
- nextProcess.stdout.on('data', (data) => {
140
- console.log(`stdout: ${data}`);
141
- });
142
- }
143
-
144
- nextProcess.stderr.on('data', (data) => {
145
- console.error(`stderr: ${data}`);
146
- });
147
- await waitForServer(NEXT_START_URL);
148
- console.log('next start successful');
149
-
150
- // Connect to Redis
151
- redisClient = createClient({
152
- url: `redis://${process.env.REDISHOST}:${process.env.REDISPORT}`,
153
- });
154
- await redisClient.connect();
155
-
156
- console.log('redis key prefix is:', process.env.VERCEL_URL);
157
- }, 60_000);
158
-
159
- afterAll(async () => {
160
- if (process.env.KEEP_SERVER_RUNNING === 'true') {
161
- console.log('keeping server running');
162
- } else {
163
- if (nextProcess) nextProcess.kill();
164
- }
165
- if (redisClient) await redisClient.quit();
166
- });
167
-
168
- describe('should have the correct caching behavior for API routes', () => {
169
- describe('should cache static API routes in Redis', () => {
170
- let counter1: number;
171
-
172
- it('First request (should increment counter)', async () => {
173
- const res = await fetch(NEXT_START_URL + '/api/cached-static-fetch');
174
- const data: any = await res.json();
175
- expect(data.counter).toBe(1);
176
- counter1 = data.counter;
177
- });
178
-
179
- it('Second request (should hit cache, counter should not increment if cache works)', async () => {
180
- const res = await fetch(NEXT_START_URL + '/api/cached-static-fetch');
181
- const data: any = await res.json();
182
- // If cache is working, counter should stay 1; if not, it will increment
183
- expect(data.counter).toBe(counter1);
184
- });
185
-
186
- it('The data in the redis key should match the expected format', async () => {
187
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
188
- const keys = await redisClient.keys(process.env.VERCEL_URL + '*');
189
- expect(keys.length).toBeGreaterThan(0);
190
-
191
- // check the content of redis key
192
- const value = (await redisClient.get(
193
- process.env.VERCEL_URL + '/api/cached-static-fetch',
194
- )) as string;
195
- expect(value).toBeDefined();
196
- const cacheEntry: CacheEntry = JSON.parse(value);
197
-
198
- // The format should be as expected
199
- expect(cacheEntry).toEqual({
200
- value: {
201
- kind: 'APP_ROUTE',
202
- status: 200,
203
- body: { $binary: 'eyJjb3VudGVyIjoxfQ==' },
204
- headers: {
205
- 'cache-control': 'public, max-age=1',
206
- 'content-type': 'application/json',
207
- 'x-next-cache-tags':
208
- '_N_T_/layout,_N_T_/api/layout,_N_T_/api/cached-static-fetch/layout,_N_T_/api/cached-static-fetch/route,_N_T_/api/cached-static-fetch',
209
- },
210
- },
211
- lastModified: expect.any(Number),
212
- tags: [
213
- '_N_T_/layout',
214
- '_N_T_/api/layout',
215
- '_N_T_/api/cached-static-fetch/layout',
216
- '_N_T_/api/cached-static-fetch/route',
217
- '_N_T_/api/cached-static-fetch',
218
- ],
219
- });
220
-
221
- expect((cacheEntry.value as any).kind).toBe('APP_ROUTE');
222
- const bodyBuffer = Buffer.from(
223
- (cacheEntry.value as any)?.body?.$binary,
224
- 'base64',
225
- );
226
- const bodyJson = JSON.parse(bodyBuffer.toString('utf-8'));
227
- expect(bodyJson.counter).toBe(counter1);
228
- });
229
-
230
- it('A request to revalidatePath API should remove the route from redis (string and hashmap)', async () => {
231
- const revalidateRes = await fetch(
232
- NEXT_START_URL + '/api/revalidatePath?path=/api/cached-static-fetch',
233
- );
234
- const revalidateResJson: any = await revalidateRes.json();
235
- expect(revalidateResJson.success).toBe(true);
236
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
237
-
238
- // check Redis keys
239
- const keys = await redisClient.keys(
240
- process.env.VERCEL_URL + '/api/cached-static-fetch',
241
- );
242
- expect(keys.length).toBe(0);
243
-
244
- const hashmap = await redisClient.hGet(
245
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
246
- '/api/cached-static-fetch',
247
- );
248
- expect(hashmap).toBeNull();
249
- });
250
-
251
- it('A new request after the revalidation should increment the counter (because the route was re-evaluated)', async () => {
252
- const res = await fetch(NEXT_START_URL + '/api/cached-static-fetch');
253
- const data: any = await res.json();
254
- expect(data.counter).toBe(counter1 + 1);
255
- });
256
-
257
- it('After the new request was made the redis key and hashmap should be set again', async () => {
258
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
259
- // check Redis keys
260
- const keys = await redisClient.keys(
261
- process.env.VERCEL_URL + '/api/cached-static-fetch',
262
- );
263
- expect(keys.length).toBe(1);
264
-
265
- const hashmap = (await redisClient.hGet(
266
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
267
- '/api/cached-static-fetch',
268
- )) as string;
269
- expect(JSON.parse(hashmap)).toEqual([
270
- '_N_T_/layout',
271
- '_N_T_/api/layout',
272
- '_N_T_/api/cached-static-fetch/layout',
273
- '_N_T_/api/cached-static-fetch/route',
274
- '_N_T_/api/cached-static-fetch',
275
- ]);
276
- });
277
- });
278
-
279
- describe('should cache revalidation API routes in Redis', () => {
280
- let counter1: number;
281
-
282
- it('First request (should increment counter)', async () => {
283
- const res = await fetch(NEXT_START_URL + '/api/revalidated-fetch');
284
- const data: any = await res.json();
285
- expect(data.counter).toBe(1);
286
- counter1 = data.counter;
287
- });
288
-
289
- it('Second request which is send in revalidation time should hit cache (counter should not increment)', async () => {
290
- const res = await fetch(NEXT_START_URL + '/api/revalidated-fetch');
291
- const data: any = await res.json();
292
- expect(data.counter).toBe(counter1);
293
- });
294
-
295
- if (process.env.SKIP_OPTIONAL_LONG_RUNNER_TESTS !== 'true') {
296
- const FIRST_DELAY = 6000;
297
- const SECOND_DELAY = 1000;
298
- it('Third request which is send directly after revalidation time will still serve cache but trigger re-evaluation (stale-while-revalidate)', async () => {
299
- await delay(FIRST_DELAY);
300
- const res = await fetch(NEXT_START_URL + '/api/revalidated-fetch');
301
- const data: any = await res.json();
302
- expect(data.counter).toBe(counter1);
303
- }, 10_000);
304
-
305
- it('Third request which is send directly after revalidation time will serve re-evaluated data (stale-while-revalidate)', async () => {
306
- await delay(SECOND_DELAY);
307
- const res = await fetch(NEXT_START_URL + '/api/revalidated-fetch');
308
- const data: any = await res.json();
309
- expect(data.counter).toBe(counter1 + 1);
310
- });
311
-
312
- it('After expiration, the redis key should be removed from redis and the hashmap', async () => {
313
- const ttl = await redisClient.ttl(
314
- process.env.VERCEL_URL + '/api/revalidated-fetch',
315
- );
316
-
317
- // Next.js 16.3+ passes cacheControl.expire for ISR fetch routes (~1 year).
318
- // TTL is keyed on expire (SWR-safe), not 2 × revalidate — skip the
319
- // long-running expiry wait in that case.
320
- if (NEXT_TEST_APP.includes('16-3')) {
321
- expect(ttl).toBeGreaterThan(2 * revalidatedFetchRouteRevalidate);
322
- return;
323
- }
324
-
325
- expect(ttl).toBeLessThan(2 * revalidatedFetchRouteRevalidate);
326
- expect(ttl).toBeGreaterThan(
327
- 2 * revalidatedFetchRouteRevalidate -
328
- FIRST_DELAY -
329
- SECOND_DELAY -
330
- REDIS_BACKGROUND_SYNC_DELAY,
331
- );
332
-
333
- await delay(ttl * 1000 + 500);
334
-
335
- // check Redis keys
336
- const keys = await redisClient.keys(
337
- process.env.VERCEL_URL + '/api/revalidated-fetch',
338
- );
339
- expect(keys.length).toBe(0);
340
-
341
- await delay(1000);
342
-
343
- // The key should also be removed from the hashmap
344
- const hashmap = await redisClient.hGet(
345
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
346
- '/api/revalidated-fetch',
347
- );
348
- expect(hashmap).toBeNull();
349
- }, 15_000);
350
- }
351
- });
352
-
353
- // Next 16-only caching API tests. These routes exist only in the Next 16 test app
354
- // and exercise the new revalidateTag profiles and updateTag semantics.
355
- if (NEXT_TEST_APP.includes('16.')) {
356
- describe('Next 16 caching APIs', () => {
357
- const cachedStaticPath = '/api/cached-static-fetch';
358
-
359
- async function assertCachedStaticFetchCleared() {
360
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
361
- const keys = await redisClient.keys(
362
- process.env.VERCEL_URL + cachedStaticPath,
363
- );
364
- expect(keys.length).toBe(0);
365
-
366
- const hashmap = await redisClient.hGet(
367
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
368
- cachedStaticPath,
369
- );
370
- expect(hashmap).toBeNull();
371
- }
372
-
373
- it('revalidateTag(tag, "max") should invalidate cached-static-fetch by tag', async () => {
374
- // Warm up cache and sharedTagsMap for cached-static-fetch
375
- await fetch(NEXT_START_URL + cachedStaticPath);
376
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
377
-
378
- // Use explicit tag for this route as set by Next.js
379
- const tag = '_N_T_/api/cached-static-fetch';
380
- const res = await fetch(
381
- `${NEXT_START_URL}/api/revalidateTag?tag=${encodeURIComponent(
382
- tag,
383
- )}&profile=max`,
384
- );
385
- const json: any = await res.json();
386
- expect(json.success).toBe(true);
387
-
388
- await assertCachedStaticFetchCleared();
389
- });
390
-
391
- it('revalidateTag(tag, { expire: 60 }) should also invalidate cached-static-fetch', async () => {
392
- // Warm up cache again
393
- await fetch(NEXT_START_URL + cachedStaticPath);
394
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
395
-
396
- const tag = '_N_T_/api/cached-static-fetch';
397
- const res = await fetch(
398
- `${NEXT_START_URL}/api/revalidateTag?tag=${encodeURIComponent(
399
- tag,
400
- )}&profile=expire`,
401
- );
402
- const json: any = await res.json();
403
- expect(json.success).toBe(true);
404
-
405
- await assertCachedStaticFetchCleared();
406
- });
407
- });
408
- }
409
-
410
- describe('should not cache uncached API routes in Redis', () => {
411
- let counter1: number;
412
-
413
- it('First request should increment counter', async () => {
414
- const res1 = await fetch(NEXT_START_URL + '/api/uncached-fetch');
415
- const data1: any = await res1.json();
416
- expect(data1.counter).toBe(1);
417
- counter1 = data1.counter;
418
- });
419
-
420
- it('Second request should hit cache (counter should not increment if cache works)', async () => {
421
- const res2 = await fetch(NEXT_START_URL + '/api/uncached-fetch');
422
- const data2: any = await res2.json();
423
-
424
- // If not caching it is working request 2 should be higher as request one
425
- expect(data2.counter).toBe(counter1 + 1);
426
- });
427
-
428
- it('The redis key should not be set', async () => {
429
- // check the content of redis key
430
- const value = await redisClient.get(
431
- process.env.VERCEL_URL + '/api/uncached-fetch',
432
- );
433
- expect(value).toBeNull();
434
- });
435
- });
436
-
437
- describe('should cache a nested fetch request inside a uncached API route', () => {
438
- describe('should cache the nested fetch request (but not the API route itself)', () => {
439
- let counter: number;
440
- let subCounter: number;
441
-
442
- it('should deduplicate requests to the sub-fetch-request, but not to the API route itself', async () => {
443
- // make two requests, both should return the same subFetchData but different counter
444
- const res1 = await fetch(
445
- NEXT_START_URL + '/api/nested-fetch-in-api-route/revalidated-fetch',
446
- );
447
- const res2 = await fetch(
448
- NEXT_START_URL + '/api/nested-fetch-in-api-route/revalidated-fetch',
449
- );
450
- const [data1, data2]: any[] = await Promise.all([
451
- res1.json(),
452
- res2.json(),
453
- ]);
454
-
455
- // API route counter itself increments for each request
456
- // But we do not know which request is first and which is second
457
- if (data1.counter < data2.counter) {
458
- expect(data2.counter).toBeGreaterThan(data1.counter);
459
- counter = data2.counter;
460
- } else {
461
- expect(data1.counter).toBeGreaterThan(data2.counter);
462
- counter = data1.counter;
463
- }
464
-
465
- // API route counter of revalidated sub-fetch-request should be the same (request deduplication of fetch requests)
466
- expect(data1.subFetchData.counter).toBe(data2.subFetchData.counter);
467
- subCounter = data1.subFetchData.counter;
468
- });
469
-
470
- if (process.env.SKIP_OPTIONAL_LONG_RUNNER_TESTS !== 'true') {
471
- it('should return the same subFetchData after 2 seconds (regular caching within revalidation interval (=3s) works)', async () => {
472
- // make another request after 2 seconds, it should return the same subFetchData
473
- await delay(2000); // 2s < 3s (revalidate interval)
474
- const res = await fetch(
475
- NEXT_START_URL +
476
- '/api/nested-fetch-in-api-route/revalidated-fetch',
477
- );
478
- const data: any = await res.json();
479
-
480
- expect(data.counter).toBe(counter + 1);
481
- expect(data.subFetchData.counter).toBe(subCounter);
482
- });
483
-
484
- it('should return the same subFetchData after 2 seconds and new data after another 2 seconds (caching while revalidation works)', async () => {
485
- // make another request after another 2 seconds, it should return the same subFetchData (caching while revalidation works)
486
- await delay(2000); // 2s+2s < 3s*2 (=TTL = revalidate=3s*2)
487
- const res1 = await fetch(
488
- NEXT_START_URL +
489
- '/api/nested-fetch-in-api-route/revalidated-fetch',
490
- );
491
- const data1: any = await res1.json();
492
- expect(data1.counter).toBe(counter + 2);
493
- expect(data1.subFetchData.counter).toBe(subCounter);
494
-
495
- // make another request directly after first request which was still in TTL, it should return new data (caching while revalidation works)
496
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
497
- const res2 = await fetch(
498
- NEXT_START_URL +
499
- '/api/nested-fetch-in-api-route/revalidated-fetch',
500
- );
501
- const data2: any = await res2.json();
502
- expect(data2.counter).toBe(counter + 3);
503
- expect(data2.subFetchData.counter).toBe(subCounter + 1);
504
- });
505
-
506
- it('A request to revalidatePage API should remove the route from redis (string and hashmap)', async () => {
507
- const revalidateRes = await fetch(
508
- NEXT_START_URL +
509
- '/api/revalidatePath?path=/api/nested-fetch-in-api-route/revalidated-fetch',
510
- );
511
- const revalidateResJson: any = await revalidateRes.json();
512
- expect(revalidateResJson.success).toBe(true);
513
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
514
-
515
- // check Redis keys
516
- const keys = await redisClient.keys(
517
- process.env.VERCEL_URL +
518
- '/api/nested-fetch-in-api-route/revalidated-fetch',
519
- );
520
- expect(keys.length).toBe(0);
521
-
522
- const hashmap = await redisClient.hGet(
523
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
524
- '/api/nested-fetch-in-api-route/revalidated-fetch',
525
- );
526
- expect(hashmap).toBeNull();
527
- });
528
-
529
- it('A new request after the revalidation should increment the counter (because the route was re-evaluated)', async () => {
530
- const res = await fetch(
531
- NEXT_START_URL +
532
- '/api/nested-fetch-in-api-route/revalidated-fetch',
533
- );
534
- const data: any = await res.json();
535
- expect(data.counter).toBe(counter + 4);
536
- expect(data.subFetchData.counter).toBe(subCounter + 2);
537
- });
538
-
539
- it('After the new request was made the redis key and hashmap should be set again', async () => {
540
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
541
-
542
- const cacheEntryKey = await findFetchCacheEntryKey(
543
- 'revalidated-fetch-revalidate3-nested-fetch-in-api-route',
544
- );
545
-
546
- // check Redis keys
547
- const keys = await redisClient.keys(
548
- process.env.VERCEL_URL + cacheEntryKey,
549
- );
550
- expect(keys.length).toBe(1);
551
-
552
- const hashmap = (await redisClient.hGet(
553
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
554
- cacheEntryKey,
555
- )) as string;
556
- expect(JSON.parse(hashmap)).toEqual([
557
- 'revalidated-fetch-revalidate3-nested-fetch-in-api-route',
558
- ]);
559
- });
560
-
561
- it('A request to revalidateTag API should remove the route from redis (string and hashmap)', async () => {
562
- const revalidateRes = await fetch(
563
- NEXT_START_URL +
564
- '/api/revalidateTag?tag=revalidated-fetch-revalidate3-nested-fetch-in-api-route',
565
- );
566
- const revalidateResJson: any = await revalidateRes.json();
567
- expect(revalidateResJson.success).toBe(true);
568
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
569
-
570
- // check Redis keys
571
- const keys = await redisClient.keys(
572
- process.env.VERCEL_URL +
573
- '/api/nested-fetch-in-api-route/revalidated-fetch',
574
- );
575
- expect(keys.length).toBe(0);
576
-
577
- const hashmap = await redisClient.hGet(
578
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
579
- '/api/nested-fetch-in-api-route/revalidated-fetch',
580
- );
581
- expect(hashmap).toBeNull();
582
- });
583
-
584
- it('Another new request after the revalidation should increment the counter (because the route was re-evaluated)', async () => {
585
- const res = await fetch(
586
- NEXT_START_URL +
587
- '/api/nested-fetch-in-api-route/revalidated-fetch',
588
- );
589
- const data: any = await res.json();
590
- expect(data.counter).toBe(counter + 5);
591
- expect(data.subFetchData.counter).toBe(subCounter + 3);
592
- });
593
-
594
- it('After the new request was made the redis key and hashmap should be set again', async () => {
595
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
596
- const cacheEntryKey = await findFetchCacheEntryKey(
597
- 'revalidated-fetch-revalidate3-nested-fetch-in-api-route',
598
- );
599
-
600
- // check Redis keys
601
- const keys = await redisClient.keys(
602
- process.env.VERCEL_URL + cacheEntryKey,
603
- );
604
- expect(keys.length).toBe(1);
605
-
606
- const hashmap = (await redisClient.hGet(
607
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
608
- cacheEntryKey,
609
- )) as string;
610
- expect(JSON.parse(hashmap)).toEqual([
611
- 'revalidated-fetch-revalidate3-nested-fetch-in-api-route',
612
- ]);
613
- });
614
- }
615
- });
616
- });
617
-
618
- // describe('With a API route that has a unstable_cacheTag', () => {
619
- // // TODO: implement API route for this test as well as the test itself
620
- // });
621
-
622
- // describe('With a API route that has a unstable_cacheLife', () => {
623
- // // TODO: implement API route for this test as well as the test itself
624
- // });
625
- });
626
-
627
- describe('should have the correct caching behavior for pages', () => {
628
- describe('Without any fetch requests inside the page', () => {
629
- describe('With default page configuration for revalidate and dynamic values', () => {
630
- let timestamp1: string | undefined;
631
-
632
- it('Two parallel requests should return the same timestamp (because requests are deduplicated)', async () => {
633
- // First request (should increment counter)
634
- const [pageRes1, pageRes2] = await Promise.all([
635
- fetch(NEXT_START_URL + '/pages/no-fetch/default-page'),
636
- fetch(NEXT_START_URL + '/pages/no-fetch/default-page'),
637
- ]);
638
-
639
- const pageText1 = await pageRes1.text();
640
- timestamp1 = pageText1.match(/Timestamp: <!-- -->(\d+)/)?.[1];
641
- expect(timestamp1).toBeDefined();
642
-
643
- const pageText2 = await pageRes2.text();
644
- const timestamp2 = pageText2.match(/Timestamp: <!-- -->(\d+)/)?.[1];
645
- expect(timestamp2).toBeDefined();
646
- expect(timestamp1).toBe(timestamp2);
647
- });
648
-
649
- it('Redis should have a key for the page which should have a TTL set to 28 days (2 * 14 days default revalidate time)', async () => {
650
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
651
- // check Redis keys
652
- const ttl = await redisClient.ttl(
653
- process.env.VERCEL_URL + '/pages/no-fetch/default-page',
654
- );
655
- // 14 days is default revalidate for pages -> expiration time is 2 * revalidate time -> -10 seconds for testing offset stability
656
- expect(ttl).toBeGreaterThan(2 * 14 * 24 * 60 * 60 - 30);
657
- expect(ttl).toBeLessThanOrEqual(2 * 14 * 24 * 60 * 60);
658
- });
659
-
660
- it('The data in the redis key should match the expected format', async () => {
661
- const data = (await redisClient.get(
662
- process.env.VERCEL_URL + '/pages/no-fetch/default-page',
663
- )) as string;
664
- expect(data).toBeDefined();
665
- const cacheEntry: CacheEntry = JSON.parse(data);
666
-
667
- // The format should be as expected. We intentionally do not assert on an optional status field here
668
- // so that different Next.js versions (which may include or omit it) are both supported.
669
- expect(cacheEntry).toMatchObject({
670
- value: {
671
- kind: 'APP_PAGE',
672
- html: expect.any(String),
673
- rscData: {
674
- $binary: expect.any(String),
675
- },
676
- headers: {
677
- 'x-nextjs-stale-time': expect.any(String),
678
- 'x-next-cache-tags':
679
- '_N_T_/layout,_N_T_/pages/layout,_N_T_/pages/no-fetch/layout,_N_T_/pages/no-fetch/default-page/layout,_N_T_/pages/no-fetch/default-page/page,_N_T_/pages/no-fetch/default-page',
680
- },
681
- },
682
- lastModified: expect.any(Number),
683
- tags: [
684
- '_N_T_/layout',
685
- '_N_T_/pages/layout',
686
- '_N_T_/pages/no-fetch/layout',
687
- '_N_T_/pages/no-fetch/default-page/layout',
688
- '_N_T_/pages/no-fetch/default-page/page',
689
- '_N_T_/pages/no-fetch/default-page',
690
- ],
691
- });
692
- });
693
-
694
- if (process.env.SKIP_OPTIONAL_LONG_RUNNER_TESTS !== 'true') {
695
- it('A new request after 3 seconds should return the same timestamp (because the page was cached in in-memory cache)', async () => {
696
- await delay(3_000);
697
- const pageRes3 = await fetch(
698
- NEXT_START_URL + '/pages/no-fetch/default-page',
699
- );
700
- const pageText3 = await pageRes3.text();
701
- const timestamp3 = pageText3.match(/Timestamp: <!-- -->(\d+)/)?.[1];
702
- expect(timestamp3).toBeDefined();
703
- expect(timestamp1).toBe(timestamp3);
704
- });
705
-
706
- it('A new request after 11 seconds should return the same timestamp (because the page was cached in redis cache)', async () => {
707
- await delay(11_000);
708
- const pageRes4 = await fetch(
709
- NEXT_START_URL + '/pages/no-fetch/default-page',
710
- );
711
- const pageText4 = await pageRes4.text();
712
- const timestamp4 = pageText4.match(/Timestamp: <!-- -->(\d+)/)?.[1];
713
- expect(timestamp4).toBeDefined();
714
- expect(timestamp1).toBe(timestamp4);
715
- }, 15_000);
716
- }
717
-
718
- it('A request to revalidatePage API should remove the page from redis (string and hashmap)', async () => {
719
- const revalidateRes = await fetch(
720
- NEXT_START_URL +
721
- '/api/revalidatePath?path=/pages/no-fetch/default-page',
722
- );
723
- const revalidateResJson: any = await revalidateRes.json();
724
- expect(revalidateResJson.success).toBe(true);
725
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
726
-
727
- // check Redis keys
728
- const keys = await redisClient.keys(
729
- process.env.VERCEL_URL + '/pages/no-fetch/default-page',
730
- );
731
- expect(keys.length).toBe(0);
732
-
733
- const hashmap = await redisClient.hGet(
734
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
735
- '/pages/no-fetch/default-page',
736
- );
737
- expect(hashmap).toBeNull();
738
- });
739
-
740
- it('A new request after the revalidation should return a new timestamp (because the page was recreated)', async () => {
741
- const pageRes4 = await fetch(
742
- NEXT_START_URL + '/pages/no-fetch/default-page',
743
- );
744
- const pageText4 = await pageRes4.text();
745
- const timestamp4 = pageText4.match(/Timestamp: <!-- -->(\d+)/)?.[1];
746
- expect(timestamp4).toBeDefined();
747
- expect(Number(timestamp4)).toBeGreaterThan(Number(timestamp1));
748
- });
749
-
750
- it('After the new request was made the redis key and hashmap should be set again', async () => {
751
- // check Redis keys
752
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
753
- const keys = await redisClient.keys(
754
- process.env.VERCEL_URL + '/pages/no-fetch/default-page',
755
- );
756
- expect(keys.length).toBe(1);
757
-
758
- const hashmap = (await redisClient.hGet(
759
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
760
- '/pages/no-fetch/default-page',
761
- )) as string;
762
- expect(JSON.parse(hashmap)).toEqual([
763
- '_N_T_/layout',
764
- '_N_T_/pages/layout',
765
- '_N_T_/pages/no-fetch/layout',
766
- '_N_T_/pages/no-fetch/default-page/layout',
767
- '_N_T_/pages/no-fetch/default-page/page',
768
- '_N_T_/pages/no-fetch/default-page',
769
- ]);
770
- });
771
- });
772
- });
773
-
774
- // describe('With a cached static fetch request inside a page', () => {
775
- // // TODO: implement test for `test/nextjs-test-projects/next-app/src/app/pages/cached-static-fetch`
776
- // });
777
-
778
- describe('With a cached revalidation fetch request inside a page', () => {
779
- let firstTimestamp: string;
780
- let firstCounter: string;
781
-
782
- it('should set all cache entries for this page after request is finished', async () => {
783
- const pageRes = await fetch(
784
- NEXT_START_URL +
785
- '/pages/revalidated-fetch/revalidate15--default-page',
786
- );
787
- const pageText = await pageRes.text();
788
- const timestamp = pageText.match(/Timestamp: <!-- -->(\d+)/)?.[1];
789
- const counter = pageText.match(/Counter: <!-- -->(\d+)/)?.[1];
790
- expect(timestamp).toBeDefined();
791
- expect(counter).toBeDefined();
792
- firstTimestamp = timestamp!;
793
- firstCounter = counter!;
794
-
795
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
796
-
797
- const nestedFetchCacheEntryKey = await findFetchCacheEntryKey(
798
- 'revalidated-fetch-revalidate15-default-page',
799
- );
800
-
801
- // test cache entry for 3 keys are set
802
- const keys1 = await redisClient.keys(
803
- process.env.VERCEL_URL +
804
- '/pages/revalidated-fetch/revalidate15--default-page',
805
- );
806
- expect(keys1.length).toBe(1);
807
- const keys2 = await redisClient.keys(
808
- process.env.VERCEL_URL + nestedFetchCacheEntryKey,
809
- );
810
- expect(keys2.length).toBe(1);
811
- const keys3 = await redisClient.keys(
812
- process.env.VERCEL_URL + '/api/revalidated-fetch',
813
- );
814
- expect(keys3.length).toBe(1);
815
-
816
- // test shared tag hashmap to be set for all keys
817
- const hashmap1 = (await redisClient.hGet(
818
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
819
- '/pages/revalidated-fetch/revalidate15--default-page',
820
- )) as string;
821
- expect(JSON.parse(hashmap1)).toEqual([
822
- '_N_T_/layout',
823
- '_N_T_/pages/layout',
824
- '_N_T_/pages/revalidated-fetch/layout',
825
- '_N_T_/pages/revalidated-fetch/revalidate15--default-page/layout',
826
- '_N_T_/pages/revalidated-fetch/revalidate15--default-page/page',
827
- '_N_T_/pages/revalidated-fetch/revalidate15--default-page',
828
- 'revalidated-fetch-revalidate15-default-page',
829
- ]);
830
- const hashmap2 = (await redisClient.hGet(
831
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
832
- nestedFetchCacheEntryKey,
833
- )) as string;
834
- expect(JSON.parse(hashmap2)).toEqual([
835
- 'revalidated-fetch-revalidate15-default-page',
836
- ]);
837
- const hashmap3 = (await redisClient.hGet(
838
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
839
- '/api/revalidated-fetch',
840
- )) as string;
841
- expect(JSON.parse(hashmap3)).toEqual([
842
- '_N_T_/layout',
843
- '_N_T_/api/layout',
844
- '_N_T_/api/revalidated-fetch/layout',
845
- '_N_T_/api/revalidated-fetch/route',
846
- '_N_T_/api/revalidated-fetch',
847
- ]);
848
- });
849
-
850
- it('a new request should return the same timestamp as the first request', async () => {
851
- const pageRes = await fetch(
852
- NEXT_START_URL +
853
- '/pages/revalidated-fetch/revalidate15--default-page',
854
- );
855
- const pageText = await pageRes.text();
856
- const timestamp = pageText.match(/Timestamp: <!-- -->(\d+)/)?.[1];
857
- expect(timestamp).toBeDefined();
858
- expect(timestamp).toBe(firstTimestamp);
859
- });
860
-
861
- it('A request to revalidatePath API should remove the page from redis (string and hashmap) but not the api route', async () => {
862
- const revalidateRes = await fetch(
863
- NEXT_START_URL +
864
- '/api/revalidatePath?path=/pages/revalidated-fetch/revalidate15--default-page',
865
- );
866
- const revalidateResJson: any = await revalidateRes.json();
867
- expect(revalidateResJson.success).toBe(true);
868
- await delay(REDIS_BACKGROUND_SYNC_DELAY);
869
-
870
- // test no cache entry for 2 keys
871
- const keys1 = await redisClient.keys(
872
- process.env.VERCEL_URL +
873
- '/pages/revalidated-fetch/revalidate15--default-page',
874
- );
875
- expect(keys1.length).toBe(0);
876
-
877
- const hashmap1 = await redisClient.hGet(
878
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
879
- '/pages/revalidated-fetch/revalidate15--default-page',
880
- );
881
- expect(hashmap1).toBeNull();
882
-
883
- // sub-fetch-request is not removed directly but will be removed on next get request
884
- const nestedFetchCacheEntryKey = await findFetchCacheEntryKey(
885
- 'revalidated-fetch-revalidate15-default-page',
886
- );
887
- const keys2 = await redisClient.keys(
888
- process.env.VERCEL_URL + nestedFetchCacheEntryKey,
889
- );
890
- expect(keys2.length).toBe(1);
891
- const hashmap2 = await redisClient.hGet(
892
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
893
- nestedFetchCacheEntryKey,
894
- );
895
- expect(hashmap2).toBeDefined();
896
-
897
- // the page should also be in revalidatedTagsMap so that the nested fetch requests knows that the page was invalidated
898
- const revalidationTimestamp = await redisClient.hGet(
899
- process.env.VERCEL_URL + '__revalidated_tags__',
900
- '_N_T_/pages/revalidated-fetch/revalidate15--default-page',
901
- );
902
- const ts = Number(revalidationTimestamp);
903
- expect(ts).toBeGreaterThan(1);
904
- expect(ts).toBeLessThan(Number(Date.now()));
905
-
906
- // API route should still be cached
907
- const keys3 = await redisClient.keys(
908
- process.env.VERCEL_URL + '/api/revalidated-fetch',
909
- );
910
- expect(keys3.length).toBe(1);
911
- const hashmap3 = (await redisClient.hGet(
912
- process.env.VERCEL_URL + SHARED_TAGS_KEY,
913
- '/api/revalidated-fetch',
914
- )) as string;
915
- expect(JSON.parse(hashmap3)).toEqual([
916
- '_N_T_/layout',
917
- '_N_T_/api/layout',
918
- '_N_T_/api/revalidated-fetch/layout',
919
- '_N_T_/api/revalidated-fetch/route',
920
- '_N_T_/api/revalidated-fetch',
921
- ]);
922
- });
923
-
924
- it('a new request should return a newer timestamp as the first request (which was invalidated by revalidatePath)', async () => {
925
- const pageRes = await fetch(
926
- NEXT_START_URL +
927
- '/pages/revalidated-fetch/revalidate15--default-page',
928
- );
929
- const pageText = await pageRes.text();
930
- const timestamp = pageText.match(/Timestamp: <!-- -->(\d+)/)?.[1];
931
- const secondCounter = pageText.match(/Counter: <!-- -->(\d+)/)?.[1];
932
- expect(timestamp).toBeDefined();
933
- expect(Number(timestamp)).toBeGreaterThan(Number(firstTimestamp));
934
-
935
- // Next.js 16.3 revalidates nested fetch entries when the parent page path
936
- // is revalidated; older versions keep the nested fetch cache intact.
937
- expect(secondCounter).toBeDefined();
938
- if (NEXT_TEST_APP === 'next-app-16-3-0') {
939
- expect(Number(secondCounter)).toBeGreaterThan(Number(firstCounter));
940
- } else {
941
- expect(secondCounter).toBe(firstCounter);
942
- }
943
- });
944
- });
945
-
946
- // describe('With a uncached fetch request inside a page', () => {
947
- // // TODO: implement test for `test/nextjs-test-projects/next-app/src/app/pages/uncached-fetch`
948
- //
949
- // });
950
-
951
- // describe('With a page that has a unstable_cacheTag', () => {
952
- // // TODO: implement page for this test as well as the test itself
953
- // });
954
-
955
- // describe('With a page that has a unstable_cacheLife', () => {
956
- // // TODO: implement page for this test as well as the test itself
957
- // });
958
- });
959
- });