@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,303 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
-
3
- import RedisStringsHandler, {
4
- CacheEntry,
5
- } from '../../../src/RedisStringsHandler';
6
-
7
- // In-memory Redis string store shared between the mocked client and the tests
8
- const hoisted = vi.hoisted(() => {
9
- const store = new Map<string, { value: string; ex?: number }>();
10
- return { store };
11
- });
12
-
13
- vi.mock('redis', () => {
14
- const createClient = () => {
15
- return {
16
- isReady: true,
17
- on: vi.fn(),
18
- connect: vi.fn(async () => undefined),
19
- disconnect: vi.fn(),
20
- quit: vi.fn(),
21
- duplicate: vi.fn(() => ({
22
- connect: vi.fn(async () => undefined),
23
- subscribe: vi.fn(async () => undefined),
24
- on: vi.fn(),
25
- quit: vi.fn(async () => undefined),
26
- configGet: vi.fn(async () => ({ 'notify-keyspace-events': 'Exe' })),
27
- })),
28
- get: vi.fn(
29
- async (_opts: unknown, key: string) =>
30
- hoisted.store.get(key)?.value ?? null,
31
- ),
32
- hScan: vi.fn(async () => ({ cursor: 0, tuples: [] })),
33
- scan: vi.fn(async () => ({ cursor: 0, keys: [] })),
34
- hSet: vi.fn(async () => 1),
35
- hDel: vi.fn(async () => 1),
36
- publish: vi.fn(async () => 1),
37
- unlink: vi.fn(async () => 1),
38
- set: vi.fn(async (key: string, value: string, opts?: { EX?: number }) => {
39
- hoisted.store.set(key, { value, ex: opts?.EX });
40
- return 'OK';
41
- }),
42
- };
43
- };
44
- return {
45
- createClient,
46
- commandOptions: vi.fn((opts) => opts),
47
- };
48
- });
49
-
50
- const KEY_PREFIX = 'test:';
51
- const DEFAULT_STALE_AGE = 60 * 60 * 24 * 14;
52
- // Default estimateExpireAge outside production is staleAge * 1.2
53
- const expireAge = (staleAge: number) => staleAge * 1.2;
54
-
55
- function createHandler() {
56
- return new RedisStringsHandler({
57
- redisUrl: 'redis://localhost:6379',
58
- keyPrefix: KEY_PREFIX,
59
- database: 0,
60
- getTimeoutMs: 100,
61
- redisGetDeduplication: false,
62
- inMemoryCachingTime: 0,
63
- });
64
- }
65
-
66
- function storedEntry(key: string): { entry: CacheEntry; ex?: number } {
67
- const raw = hoisted.store.get(KEY_PREFIX + key);
68
- expect(raw).toBeDefined();
69
- return { entry: JSON.parse(raw!.value), ex: raw!.ex };
70
- }
71
-
72
- const baseCtx = { isRoutePPREnabled: false, isFallback: false };
73
-
74
- describe('RedisStringsHandler Pages Router kinds', () => {
75
- let warnSpy: ReturnType<typeof vi.spyOn>;
76
- let errorSpy: ReturnType<typeof vi.spyOn>;
77
-
78
- beforeEach(() => {
79
- hoisted.store.clear();
80
- warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
81
- errorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
82
- });
83
-
84
- afterEach(() => {
85
- vi.restoreAllMocks();
86
- });
87
-
88
- describe('PAGES entries', () => {
89
- const pagesData = {
90
- kind: 'PAGES' as const,
91
- html: '<html><body>hello</body></html>',
92
- pageData: { pageProps: { title: 'hello' }, __N_SSG: true },
93
- headers: undefined,
94
- status: 200,
95
- };
96
-
97
- it('set() stores a PAGES entry without warnings and with the implicit path tag', async () => {
98
- const handler = createHandler();
99
- await handler.set('/blog/post-1', pagesData, {
100
- ...baseCtx,
101
- cacheControl: { revalidate: 60, expire: undefined },
102
- });
103
-
104
- const { entry, ex } = storedEntry('/blog/post-1');
105
- expect(entry).toEqual({
106
- value: pagesData,
107
- lastModified: expect.any(Number),
108
- tags: ['_N_T_/blog/post-1'],
109
- });
110
- // TTL is derived from cacheControl.revalidate (getStaticProps revalidate)
111
- expect(ex).toBe(expireAge(60));
112
- expect(warnSpy).not.toHaveBeenCalled();
113
- expect(errorSpy).not.toHaveBeenCalled();
114
- });
115
-
116
- it('get() returns a PAGES entry without warnings', async () => {
117
- const handler = createHandler();
118
- await handler.set('/blog/post-1', pagesData, {
119
- ...baseCtx,
120
- cacheControl: { revalidate: 60, expire: undefined },
121
- });
122
-
123
- const result = await handler.get('/blog/post-1', {
124
- kind: 'PAGES',
125
- isFallback: false,
126
- });
127
-
128
- expect(result).toEqual({
129
- value: pagesData,
130
- lastModified: expect.any(Number),
131
- tags: ['_N_T_/blog/post-1'],
132
- });
133
- expect(warnSpy).not.toHaveBeenCalled();
134
- expect(errorSpy).not.toHaveBeenCalled();
135
- });
136
-
137
- it('set() with revalidate: false falls back to defaultStaleAge for the TTL', async () => {
138
- const handler = createHandler();
139
- await handler.set('/static-forever', pagesData, {
140
- ...baseCtx,
141
- cacheControl: { revalidate: false, expire: undefined },
142
- });
143
-
144
- const { ex } = storedEntry('/static-forever');
145
- expect(ex).toBe(expireAge(DEFAULT_STALE_AGE));
146
- });
147
-
148
- it('set() prefers cacheControl.expire over revalidate for the Redis TTL', async () => {
149
- const handler = createHandler();
150
- await handler.set('/blog/post-swr', pagesData, {
151
- ...baseCtx,
152
- cacheControl: { revalidate: 60, expire: 3600 },
153
- });
154
-
155
- const { ex } = storedEntry('/blog/post-swr');
156
- expect(ex).toBe(3600);
157
- });
158
-
159
- it('set() derives the TTL from the legacy ctx.revalidate argument (Next.js 15.0.3)', async () => {
160
- const handler = createHandler();
161
- await handler.set('/blog/post-legacy', pagesData, {
162
- ...baseCtx,
163
- revalidate: 60,
164
- });
165
-
166
- const { ex } = storedEntry('/blog/post-legacy');
167
- expect(ex).toBe(expireAge(60));
168
- });
169
- });
170
-
171
- describe('REDIRECT entries (getStaticProps redirect)', () => {
172
- const redirectData = {
173
- kind: 'REDIRECT' as const,
174
- // Next.js nests the redirect directives under `pageProps`, matching the
175
- // real getStaticProps redirect payload asserted in the integration test.
176
- props: {
177
- pageProps: { __N_REDIRECT: '/target', __N_REDIRECT_STATUS: 307 },
178
- },
179
- };
180
-
181
- it('set() and get() round-trip a REDIRECT entry without warnings', async () => {
182
- const handler = createHandler();
183
- await handler.set('/old-location', redirectData, {
184
- ...baseCtx,
185
- cacheControl: { revalidate: 30, expire: undefined },
186
- });
187
-
188
- const { entry, ex } = storedEntry('/old-location');
189
- expect(entry).toEqual({
190
- value: redirectData,
191
- lastModified: expect.any(Number),
192
- tags: ['_N_T_/old-location'],
193
- });
194
- expect(ex).toBe(expireAge(30));
195
-
196
- const result = await handler.get('/old-location', {
197
- kind: 'PAGES',
198
- isFallback: false,
199
- });
200
- expect(result?.value).toEqual(redirectData);
201
- expect(warnSpy).not.toHaveBeenCalled();
202
- expect(errorSpy).not.toHaveBeenCalled();
203
- });
204
- });
205
-
206
- describe('notFound entries (data === null)', () => {
207
- it('set() stores a null-value entry without throwing or warning', async () => {
208
- const handler = createHandler();
209
- await handler.set('/missing-page', null, {
210
- ...baseCtx,
211
- cacheControl: { revalidate: 15, expire: undefined },
212
- });
213
-
214
- const { entry, ex } = storedEntry('/missing-page');
215
- expect(entry).toEqual({
216
- value: null,
217
- lastModified: expect.any(Number),
218
- tags: ['_N_T_/missing-page'],
219
- });
220
- expect(ex).toBe(expireAge(15));
221
- expect(warnSpy).not.toHaveBeenCalled();
222
- expect(errorSpy).not.toHaveBeenCalled();
223
- });
224
-
225
- it('get() returns the null-value entry without malformed warnings or errors', async () => {
226
- const handler = createHandler();
227
- await handler.set('/missing-page', null, {
228
- ...baseCtx,
229
- cacheControl: { revalidate: 15, expire: undefined },
230
- });
231
-
232
- const result = await handler.get('/missing-page', {
233
- kind: 'PAGES',
234
- isFallback: false,
235
- });
236
-
237
- expect(result).toEqual({
238
- value: null,
239
- lastModified: expect.any(Number),
240
- tags: ['_N_T_/missing-page'],
241
- });
242
- expect(warnSpy).not.toHaveBeenCalled();
243
- expect(errorSpy).not.toHaveBeenCalled();
244
- });
245
-
246
- it('get() still warns for a malformed entry with a missing (undefined) value', async () => {
247
- const handler = createHandler();
248
- hoisted.store.set(KEY_PREFIX + '/malformed', {
249
- value: JSON.stringify({ lastModified: Date.now(), tags: [] }),
250
- });
251
-
252
- await handler.get('/malformed', {
253
- kind: 'PAGES',
254
- isFallback: false,
255
- });
256
-
257
- expect(warnSpy).toHaveBeenCalledWith(
258
- 'RedisStringsHandler.get() called with',
259
- '/malformed',
260
- expect.anything(),
261
- 'cacheEntry is mall formed (missing value)',
262
- );
263
- });
264
- });
265
-
266
- describe('App Router entries are unaffected', () => {
267
- it('set() still extracts tags from the x-next-cache-tags header and adds no implicit tag', async () => {
268
- const handler = createHandler();
269
- await handler.set(
270
- '/app-page',
271
- {
272
- kind: 'APP_PAGE',
273
- html: '<html></html>',
274
- rscData: Buffer.from('rsc'),
275
- headers: {
276
- 'x-nextjs-stale-time': '1000',
277
- 'x-next-cache-tags': '_N_T_/layout,_N_T_/app-page',
278
- },
279
- segmentData: undefined,
280
- postboned: undefined,
281
- },
282
- { ...baseCtx, cacheControl: { revalidate: 60, expire: undefined } },
283
- );
284
-
285
- const { entry } = storedEntry('/app-page');
286
- expect(entry.tags).toEqual(['_N_T_/layout', '_N_T_/app-page']);
287
- expect(warnSpy).not.toHaveBeenCalled();
288
- });
289
-
290
- it('set() still warns for unsupported kinds (e.g. IMAGE)', async () => {
291
- const handler = createHandler();
292
- await handler.set(
293
- '/some-image',
294
- { kind: 'IMAGE' } as unknown as Parameters<
295
- RedisStringsHandler['set']
296
- >[1],
297
- baseCtx,
298
- );
299
-
300
- expect(warnSpy).toHaveBeenCalled();
301
- });
302
- });
303
- });
@@ -1,117 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest';
2
-
3
- vi.mock('redis', () => ({
4
- createClient: vi.fn(() => {
5
- const listeners = new Map<string, Function[]>();
6
- const client = {
7
- isOpen: false,
8
- isReady: false,
9
- on: vi.fn((event: string, cb: Function) => {
10
- if (!listeners.has(event)) listeners.set(event, []);
11
- listeners.get(event)!.push(cb);
12
- }),
13
- emit: vi.fn((event: string, ...args: unknown[]) => {
14
- (listeners.get(event) ?? []).forEach((cb) => cb(...args));
15
- }),
16
- connect: vi.fn(async () => undefined),
17
- disconnect: vi.fn(),
18
- quit: vi.fn(async () => undefined),
19
- duplicate: vi.fn(() => ({
20
- connect: vi.fn(async () => undefined),
21
- subscribe: vi.fn(async () => undefined),
22
- on: vi.fn(),
23
- quit: vi.fn(async () => undefined),
24
- configGet: vi.fn(async () => ({ 'notify-keyspace-events': 'Exe' })),
25
- })),
26
- get: vi.fn(async () => null),
27
- hScan: vi.fn(async () => ({ cursor: 0, tuples: [] })),
28
- scan: vi.fn(async () => ({ cursor: 0, keys: [] })),
29
- hSet: vi.fn(async () => 1),
30
- hDel: vi.fn(async () => 1),
31
- publish: vi.fn(async () => 1),
32
- unlink: vi.fn(async () => 1),
33
- set: vi.fn(async () => 'OK'),
34
- };
35
- return client;
36
- }),
37
- commandOptions: vi.fn((opts) => opts),
38
- }));
39
-
40
- vi.mock('../../../src/SyncedMap', () => {
41
- class SyncedMap {
42
- waitUntilReady = vi.fn(async () => undefined);
43
- get = vi.fn(() => undefined);
44
- set = vi.fn(async () => undefined);
45
- delete = vi.fn(async () => undefined);
46
- entries = vi.fn(function* () {
47
- return;
48
- });
49
-
50
- constructor() {}
51
- }
52
-
53
- return { SyncedMap };
54
- });
55
-
56
- /**
57
- * Deterministic regression test for:
58
- * "Failed to reconnect RedisCacheComponentsHandler client after connection loss: Error: Socket already opened"
59
- *
60
- * We simulate the node-redis client emitting an error while its socket is still considered open,
61
- * and we stub connect() to reject with "Socket already opened".
62
- */
63
-
64
- describe('RedisCacheComponentsHandler reconnect logic', () => {
65
- afterEach(() => {
66
- vi.useRealTimers();
67
- vi.restoreAllMocks();
68
- });
69
-
70
- it('does not call connect() when an error occurs but the socket is already open (prevents "Socket already opened")', async () => {
71
- vi.useFakeTimers();
72
- vi.resetModules();
73
-
74
- const consoleError = vi
75
- .spyOn(console, 'error')
76
- .mockImplementation(() => {});
77
-
78
- const { getRedisCacheComponentsHandler } = await import('../../../src');
79
-
80
- const handler = getRedisCacheComponentsHandler({
81
- redisUrl: 'redis://127.0.0.1:6399',
82
- clientOptions: {
83
- // Avoid queueing commands in tests.
84
- disableOfflineQueue: true,
85
- } as any,
86
- });
87
-
88
- const client = (handler as any).client;
89
-
90
- // Clear the initial connect() call from the constructor.
91
- vi.mocked(client.connect).mockClear();
92
-
93
- // Simulate a connection-loss situation where the socket is still open.
94
- Object.defineProperty(client, 'isOpen', { value: true });
95
- Object.defineProperty(client, 'isReady', { value: false });
96
-
97
- // Stub connect() so we can assert it is NOT called.
98
- const connectSpy = vi.spyOn(client, 'connect');
99
-
100
- // Trigger the handler's on('error') callback.
101
- client.emit('error', new Error('ECONNREFUSED 127.0.0.1:6379'));
102
-
103
- // Reconnect is scheduled after 1000ms.
104
- await vi.advanceTimersByTimeAsync(1100);
105
-
106
- expect(connectSpy).not.toHaveBeenCalled();
107
-
108
- const msgs = consoleError.mock.calls
109
- .map((c) => c.map(String).join(' '))
110
- .join('\n');
111
-
112
- expect(msgs).not.toContain(
113
- 'Failed to reconnect RedisCacheComponentsHandler client after connection loss:',
114
- );
115
- expect(msgs).not.toContain('Socket already opened');
116
- });
117
- });
@@ -1,39 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import {
3
- PHASE_PRODUCTION_BUILD,
4
- shouldDeferRedisConnection,
5
- } from '../../../src/utils/redisConnection';
6
-
7
- describe('shouldDeferRedisConnection', () => {
8
- const originalPhase = process.env.NEXT_PHASE;
9
-
10
- beforeEach(() => {
11
- delete process.env.NEXT_PHASE;
12
- });
13
-
14
- afterEach(() => {
15
- if (originalPhase === undefined) {
16
- delete process.env.NEXT_PHASE;
17
- } else {
18
- process.env.NEXT_PHASE = originalPhase;
19
- }
20
- });
21
-
22
- it('returns false when NEXT_PHASE is not set', () => {
23
- expect(shouldDeferRedisConnection()).toBe(false);
24
- });
25
-
26
- it('returns true when NEXT_PHASE is phase-production-build', () => {
27
- process.env.NEXT_PHASE = 'phase-production-build';
28
- expect(shouldDeferRedisConnection()).toBe(true);
29
- });
30
-
31
- it('returns false for other Next.js phases', () => {
32
- process.env.NEXT_PHASE = 'phase-production-server';
33
- expect(shouldDeferRedisConnection()).toBe(false);
34
- });
35
-
36
- it('uses the Next.js PHASE_PRODUCTION_BUILD string', () => {
37
- expect(PHASE_PRODUCTION_BUILD).toBe('phase-production-build');
38
- });
39
- });
@@ -1,182 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
-
3
- import {
4
- CacheValueSerializer,
5
- jsonCacheValueSerializer,
6
- } from '../../../src/serializer';
7
- import type { CacheEntry } from '../../../src/RedisStringsHandler';
8
-
9
- function makeEntry(value: unknown): CacheEntry {
10
- return {
11
- value,
12
- lastModified: 1700000000000,
13
- tags: ['tag-a', 'tag-b'],
14
- };
15
- }
16
-
17
- describe('jsonCacheValueSerializer (default)', () => {
18
- it('round-trips a CacheEntry with a top-level Buffer value (Buffer + Map encoding preserved)', async () => {
19
- const original = makeEntry(Buffer.from('hello world', 'utf8'));
20
-
21
- const serialized = await jsonCacheValueSerializer.serialize(original);
22
- expect(typeof serialized).toBe('string');
23
-
24
- const restored = await jsonCacheValueSerializer.deserialize(serialized);
25
- expect(restored).not.toBeNull();
26
- expect(Buffer.isBuffer(restored!.value)).toBe(true);
27
- expect((restored!.value as Buffer).toString('utf8')).toBe('hello world');
28
- expect(restored!.lastModified).toBe(original.lastModified);
29
- expect(restored!.tags).toEqual(original.tags);
30
- });
31
-
32
- it('round-trips a Buffer nested inside a CacheEntry value object', async () => {
33
- const original = makeEntry({
34
- kind: 'APP_ROUTE',
35
- body: Buffer.from([0x01, 0x02, 0x03, 0x04]),
36
- });
37
-
38
- const serialized = await jsonCacheValueSerializer.serialize(original);
39
- const restored = await jsonCacheValueSerializer.deserialize(serialized);
40
-
41
- const nested = (restored!.value as { body: Buffer }).body;
42
- expect(Buffer.isBuffer(nested)).toBe(true);
43
- expect(Array.from(nested)).toEqual([0x01, 0x02, 0x03, 0x04]);
44
- });
45
-
46
- it('round-trips a Map value back to a native Map instance', async () => {
47
- const map = new Map<string, string>([
48
- ['k1', 'v1'],
49
- ['k2', 'v2'],
50
- ]);
51
- const original = makeEntry(map);
52
-
53
- const serialized = await jsonCacheValueSerializer.serialize(original);
54
- const restored = await jsonCacheValueSerializer.deserialize(serialized);
55
-
56
- expect(restored!.value).toBeInstanceOf(Map);
57
- const restoredMap = restored!.value as Map<string, string>;
58
- expect(restoredMap.size).toBe(2);
59
- expect(restoredMap.get('k1')).toBe('v1');
60
- expect(restoredMap.get('k2')).toBe('v2');
61
- });
62
-
63
- it('is referentially stable so consumers can detect default usage', async () => {
64
- // Importing twice should yield the same singleton; this guards against
65
- // accidental "factory" refactors that would break reference equality.
66
- const reimport = (await import('../../../src/serializer'))
67
- .jsonCacheValueSerializer;
68
- expect(reimport).toBe(jsonCacheValueSerializer);
69
- });
70
- });
71
-
72
- describe('CacheValueSerializer custom implementations', () => {
73
- it('invokes a synchronous custom serializer exactly once per call', async () => {
74
- const serialize = vi.fn(
75
- (value: CacheEntry) => `sync:${JSON.stringify(value)}`,
76
- );
77
- const deserialize = vi.fn(
78
- (stored: string) =>
79
- JSON.parse(stored.replace(/^sync:/, '')) as CacheEntry,
80
- );
81
- const custom: CacheValueSerializer = { serialize, deserialize };
82
-
83
- const entry = makeEntry({ kind: 'FETCH', payload: 42 });
84
-
85
- const out = await custom.serialize(entry);
86
- expect(serialize).toHaveBeenCalledTimes(1);
87
- expect(out.startsWith('sync:')).toBe(true);
88
-
89
- const restored = await custom.deserialize(out);
90
- expect(deserialize).toHaveBeenCalledTimes(1);
91
- expect(restored).toEqual(entry);
92
- });
93
-
94
- it('awaits an asynchronous custom serializer (Promise-returning serialize/deserialize)', async () => {
95
- const custom: CacheValueSerializer = {
96
- async serialize(value) {
97
- // Simulate async work (e.g. zlib.brotliCompress promisified).
98
- await new Promise((r) => setTimeout(r, 0));
99
- return `async:${JSON.stringify(value)}`;
100
- },
101
- async deserialize(stored) {
102
- await new Promise((r) => setTimeout(r, 0));
103
- return JSON.parse(stored.replace(/^async:/, '')) as CacheEntry;
104
- },
105
- };
106
-
107
- const entry = makeEntry({ kind: 'FETCH', payload: 'async-value' });
108
-
109
- const out = await custom.serialize(entry);
110
- expect(typeof out).toBe('string');
111
- expect(out.startsWith('async:')).toBe(true);
112
-
113
- const restored = await custom.deserialize(out);
114
- expect(restored).toEqual(entry);
115
- });
116
-
117
- it('treats a deserializer returning null as a cache miss (sync and async)', async () => {
118
- const syncMiss: CacheValueSerializer = {
119
- serialize: () => 'ignored',
120
- deserialize: () => null,
121
- };
122
- const asyncMiss: CacheValueSerializer = {
123
- serialize: async () => 'ignored',
124
- deserialize: async () => null,
125
- };
126
-
127
- expect(await syncMiss.deserialize('whatever')).toBeNull();
128
- expect(await asyncMiss.deserialize('whatever')).toBeNull();
129
- });
130
-
131
- it('propagates synchronous serializer throws and asynchronous rejections to the caller', async () => {
132
- const syncThrowing: CacheValueSerializer = {
133
- serialize() {
134
- throw new Error('sync serialize boom');
135
- },
136
- deserialize() {
137
- throw new Error('sync deserialize boom');
138
- },
139
- };
140
- const asyncRejecting: CacheValueSerializer = {
141
- async serialize() {
142
- throw new Error('async serialize boom');
143
- },
144
- async deserialize() {
145
- throw new Error('async deserialize boom');
146
- },
147
- };
148
-
149
- const entry = makeEntry({ kind: 'FETCH', payload: 'x' });
150
-
151
- expect(() => syncThrowing.serialize(entry)).toThrow('sync serialize boom');
152
- expect(() => syncThrowing.deserialize('x')).toThrow(
153
- 'sync deserialize boom',
154
- );
155
- await expect(asyncRejecting.serialize(entry)).rejects.toThrow(
156
- 'async serialize boom',
157
- );
158
- await expect(asyncRejecting.deserialize('x')).rejects.toThrow(
159
- 'async deserialize boom',
160
- );
161
- });
162
-
163
- it('passes the exact stored string to deserialize (no pre-parsing by the caller)', async () => {
164
- const serialize = (value: CacheEntry) =>
165
- `wrapped(${JSON.stringify(value)})`;
166
- const deserialize = vi.fn((stored: string) => {
167
- // If the caller mutated the wire format, this would explode.
168
- const m = /^wrapped\((.+)\)$/.exec(stored);
169
- if (!m) return null;
170
- return JSON.parse(m[1]) as CacheEntry;
171
- });
172
- const custom: CacheValueSerializer = { serialize, deserialize };
173
-
174
- const entry = makeEntry({ kind: 'APP_PAGE', html: '<p>hi</p>' });
175
-
176
- const wire = await custom.serialize(entry);
177
- const restored = await custom.deserialize(wire);
178
-
179
- expect(deserialize).toHaveBeenCalledWith(wire);
180
- expect(restored).toEqual(entry);
181
- });
182
- });