@trieb.work/nextjs-turbo-redis-cache 1.17.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 (300) hide show
  1. package/README.md +87 -24
  2. package/dist/index.d.mts +40 -1
  3. package/dist/index.d.ts +40 -1
  4. package/dist/index.js +291 -116
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +288 -115
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +9 -6
  9. package/.cursor/skills/testing/SKILL.md +0 -121
  10. package/.github/workflows/ci.yml +0 -309
  11. package/.github/workflows/pages.yml +0 -38
  12. package/.github/workflows/release.yml +0 -207
  13. package/.prettierrc.json +0 -6
  14. package/.vscode/settings.json +0 -10
  15. package/ARCHITECTURE.md +0 -431
  16. package/CHANGELOG.md +0 -411
  17. package/commitlint.config.cjs +0 -4
  18. package/docker/redis.conf +0 -1
  19. package/docs/index.html +0 -140
  20. package/docs/robots.txt +0 -4
  21. package/docs/sitemap.xml +0 -8
  22. package/docs/styles.css +0 -141
  23. package/eslint.config.mjs +0 -26
  24. package/hooks/commit-msg +0 -10
  25. package/hooks/pre-commit +0 -11
  26. package/playwright.config.ts +0 -18
  27. package/release.config.cjs +0 -31
  28. package/scripts/prepare.sh +0 -7
  29. package/scripts/setup-git.sh +0 -8
  30. package/scripts/setup-repo-name.sh +0 -17
  31. package/scripts/vitest-run-staged.cjs +0 -44
  32. package/src/CacheComponentsHandler.ts +0 -567
  33. package/src/CachedHandler.ts +0 -53
  34. package/src/DeduplicatedRequestHandler.ts +0 -110
  35. package/src/RedisStringsHandler.ts +0 -937
  36. package/src/SyncedMap.ts +0 -482
  37. package/src/ZodHandler.ts +0 -45
  38. package/src/index.ts +0 -16
  39. package/src/serializer.ts +0 -59
  40. package/src/utils/debug.ts +0 -30
  41. package/src/utils/json.ts +0 -49
  42. package/src/utils/prefix.ts +0 -44
  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 -13
  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/revalidate-tag/route.ts +0 -19
  122. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  123. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  124. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/page.tsx +0 -90
  125. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  126. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  127. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  128. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  129. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/favicon.ico +0 -0
  130. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/globals.css +0 -26
  131. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/layout.tsx +0 -57
  132. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/page.tsx +0 -755
  133. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/revalidation-interface.tsx +0 -267
  134. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/update-tag-test/page.tsx +0 -22
  135. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/tsconfig.json +0 -34
  136. package/test/nextjs-test-projects/next-app-16-2-6/README.md +0 -36
  137. package/test/nextjs-test-projects/next-app-16-2-6/eslint.config.mjs +0 -18
  138. package/test/nextjs-test-projects/next-app-16-2-6/next.config.ts +0 -7
  139. package/test/nextjs-test-projects/next-app-16-2-6/package.json +0 -28
  140. package/test/nextjs-test-projects/next-app-16-2-6/pnpm-lock.yaml +0 -4165
  141. package/test/nextjs-test-projects/next-app-16-2-6/postcss.config.mjs +0 -7
  142. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/cached-static-fetch/route.ts +0 -18
  143. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  144. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidatePath/route.ts +0 -15
  145. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidateTag/route.ts +0 -20
  146. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidated-fetch/route.ts +0 -17
  147. package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/uncached-fetch/route.ts +0 -15
  148. package/test/nextjs-test-projects/next-app-16-2-6/src/app/favicon.ico +0 -0
  149. package/test/nextjs-test-projects/next-app-16-2-6/src/app/globals.css +0 -26
  150. package/test/nextjs-test-projects/next-app-16-2-6/src/app/layout.tsx +0 -59
  151. package/test/nextjs-test-projects/next-app-16-2-6/src/app/page.tsx +0 -755
  152. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  153. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  154. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  155. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  156. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  157. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  158. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  159. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  160. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  161. package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  162. package/test/nextjs-test-projects/next-app-16-2-6/src/app/revalidation-interface.tsx +0 -267
  163. package/test/nextjs-test-projects/next-app-16-2-6/src/app/update-tag-test/page.tsx +0 -25
  164. package/test/nextjs-test-projects/next-app-16-2-6/tsconfig.json +0 -34
  165. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/README.md +0 -36
  166. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/cache-handler.js +0 -3
  167. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/eslint.config.mjs +0 -18
  168. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/next.config.ts +0 -13
  169. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/package.json +0 -28
  170. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/pnpm-lock.yaml +0 -4165
  171. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/postcss.config.mjs +0 -7
  172. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/file.svg +0 -1
  173. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/globe.svg +0 -1
  174. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/next.svg +0 -1
  175. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/vercel.svg +0 -1
  176. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/window.svg +0 -1
  177. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
  178. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
  179. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
  180. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
  181. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  182. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  183. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/page.tsx +0 -90
  184. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  185. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  186. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  187. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  188. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/favicon.ico +0 -0
  189. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/globals.css +0 -26
  190. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/layout.tsx +0 -57
  191. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/page.tsx +0 -755
  192. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/revalidation-interface.tsx +0 -267
  193. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/update-tag-test/page.tsx +0 -22
  194. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/tsconfig.json +0 -34
  195. package/test/nextjs-test-projects/next-app-16-3-0/README.md +0 -36
  196. package/test/nextjs-test-projects/next-app-16-3-0/eslint.config.mjs +0 -18
  197. package/test/nextjs-test-projects/next-app-16-3-0/next.config.ts +0 -7
  198. package/test/nextjs-test-projects/next-app-16-3-0/package.json +0 -28
  199. package/test/nextjs-test-projects/next-app-16-3-0/pnpm-lock.yaml +0 -4284
  200. package/test/nextjs-test-projects/next-app-16-3-0/postcss.config.mjs +0 -7
  201. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/cached-static-fetch/route.ts +0 -18
  202. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  203. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidatePath/route.ts +0 -15
  204. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidateTag/route.ts +0 -20
  205. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidated-fetch/route.ts +0 -17
  206. package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/uncached-fetch/route.ts +0 -15
  207. package/test/nextjs-test-projects/next-app-16-3-0/src/app/favicon.ico +0 -0
  208. package/test/nextjs-test-projects/next-app-16-3-0/src/app/globals.css +0 -26
  209. package/test/nextjs-test-projects/next-app-16-3-0/src/app/layout.tsx +0 -59
  210. package/test/nextjs-test-projects/next-app-16-3-0/src/app/page.tsx +0 -755
  211. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  212. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  213. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  214. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  215. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  216. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  217. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  218. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  219. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  220. package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  221. package/test/nextjs-test-projects/next-app-16-3-0/src/app/revalidation-interface.tsx +0 -267
  222. package/test/nextjs-test-projects/next-app-16-3-0/src/app/update-tag-test/page.tsx +0 -25
  223. package/test/nextjs-test-projects/next-app-16-3-0/tsconfig.json +0 -34
  224. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/README.md +0 -36
  225. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/cache-handler.js +0 -3
  226. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/eslint.config.mjs +0 -18
  227. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/next.config.ts +0 -13
  228. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/package.json +0 -28
  229. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/pnpm-lock.yaml +0 -4284
  230. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/postcss.config.mjs +0 -7
  231. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/file.svg +0 -1
  232. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/globe.svg +0 -1
  233. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/next.svg +0 -1
  234. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/vercel.svg +0 -1
  235. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/window.svg +0 -1
  236. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
  237. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
  238. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
  239. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
  240. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
  241. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
  242. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/page.tsx +0 -90
  243. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
  244. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
  245. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
  246. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
  247. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/favicon.ico +0 -0
  248. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/globals.css +0 -26
  249. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/layout.tsx +0 -57
  250. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/page.tsx +0 -755
  251. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/revalidation-interface.tsx +0 -267
  252. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/update-tag-test/page.tsx +0 -22
  253. package/test/nextjs-test-projects/next-app-16-3-0-cache-components/tsconfig.json +0 -34
  254. package/test/nextjs-test-projects/next-app-customized/README.md +0 -36
  255. package/test/nextjs-test-projects/next-app-customized/customized-cache-handler.js +0 -34
  256. package/test/nextjs-test-projects/next-app-customized/eslint.config.mjs +0 -16
  257. package/test/nextjs-test-projects/next-app-customized/next.config.js +0 -6
  258. package/test/nextjs-test-projects/next-pages-16-2-6/README.md +0 -16
  259. package/test/nextjs-test-projects/next-pages-16-2-6/eslint.config.mjs +0 -18
  260. package/test/nextjs-test-projects/next-pages-16-2-6/next.config.ts +0 -7
  261. package/test/nextjs-test-projects/next-pages-16-2-6/package.json +0 -26
  262. package/test/nextjs-test-projects/next-pages-16-2-6/pnpm-lock.yaml +0 -3896
  263. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/api/revalidate.ts +0 -24
  264. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/index.tsx +0 -11
  265. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/isr/[slug].tsx +0 -49
  266. package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/static-forever.tsx +0 -20
  267. package/test/nextjs-test-projects/next-pages-16-2-6/tsconfig.json +0 -34
  268. package/test/nextjs-test-projects/next-pages-16-3-0/README.md +0 -16
  269. package/test/nextjs-test-projects/next-pages-16-3-0/eslint.config.mjs +0 -18
  270. package/test/nextjs-test-projects/next-pages-16-3-0/next.config.ts +0 -7
  271. package/test/nextjs-test-projects/next-pages-16-3-0/package.json +0 -26
  272. package/test/nextjs-test-projects/next-pages-16-3-0/pnpm-lock.yaml +0 -3939
  273. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/api/revalidate.ts +0 -24
  274. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/index.tsx +0 -11
  275. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/isr/[slug].tsx +0 -49
  276. package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/static-forever.tsx +0 -20
  277. package/test/nextjs-test-projects/next-pages-16-3-0/tsconfig.json +0 -34
  278. package/test/playwright/cache-lab.spec.ts +0 -157
  279. package/test/playwright/update-tag.spec.ts +0 -33
  280. package/test/vitest/integration/build-id-prefix.integration.test.ts +0 -102
  281. package/test/vitest/integration/cache-components/cache-components.integration.test.ts +0 -231
  282. package/test/vitest/integration/cache-components/redis-kill-reconnect.test.ts +0 -65
  283. package/test/vitest/integration/cache-components/redis-quit-vs-disconnect.test.ts +0 -59
  284. package/test/vitest/integration/cache-components/redis-subscriber-outage.test.ts +0 -100
  285. package/test/vitest/integration/cache-components/scripts/redis-kill-reconnect.ts +0 -243
  286. package/test/vitest/integration/cache-components/scripts/redis-quit-vs-disconnect.ts +0 -113
  287. package/test/vitest/integration/cache-components/scripts/redis-subscriber-outage.ts +0 -379
  288. package/test/vitest/integration/cache-components/scripts/redis-test-helpers.ts +0 -155
  289. package/test/vitest/integration/nextjs-cache-handler.integration.test.ts +0 -945
  290. package/test/vitest/integration/pages-router.integration.test.ts +0 -420
  291. package/test/vitest/unit/SyncedMap-reconnect-repro.test.ts +0 -154
  292. package/test/vitest/unit/index.test.ts +0 -173
  293. package/test/vitest/unit/pages-router-kinds.test.ts +0 -292
  294. package/test/vitest/unit/reconnect-socket-already-opened.test.ts +0 -117
  295. package/test/vitest/unit/serializer.test.ts +0 -182
  296. package/test/vitest/unit/utils/prefix.test.ts +0 -115
  297. package/tsconfig.json +0 -18
  298. package/tsup.config.ts +0 -14
  299. package/vite.config.ts +0 -34
  300. package/vitest.cache-components.config.ts +0 -16
@@ -1,173 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
-
3
- import type { CreateRedisStringsHandlerOptions } from '../../../src/index';
4
- import RedisStringsHandler from '../../../src/RedisStringsHandler';
5
-
6
- vi.mock('redis', () => {
7
- const createClient = vi.fn(() => {
8
- return {
9
- isReady: true,
10
- on: vi.fn(),
11
- connect: vi.fn(async () => undefined),
12
- disconnect: vi.fn(),
13
- quit: vi.fn(),
14
- duplicate: vi.fn(() => ({
15
- connect: vi.fn(async () => undefined),
16
- subscribe: vi.fn(async () => undefined),
17
- on: vi.fn(),
18
- quit: vi.fn(async () => undefined),
19
- configGet: vi.fn(async () => ({ 'notify-keyspace-events': 'Exe' })),
20
- })),
21
- get: vi.fn(async () => {
22
- const err = new Error('timeout') as Error & { name: string };
23
- err.name = 'AbortError';
24
- throw err;
25
- }),
26
- hScan: vi.fn(async () => ({ cursor: 0, tuples: [] })),
27
- scan: vi.fn(async () => ({ cursor: 0, keys: [] })),
28
- hSet: vi.fn(async () => 1),
29
- hDel: vi.fn(async () => 1),
30
- publish: vi.fn(async () => 1),
31
- unlink: vi.fn(async () => 1),
32
- set: vi.fn(async () => 'OK'),
33
- };
34
- });
35
- return {
36
- createClient,
37
- commandOptions: vi.fn((opts) => opts),
38
- };
39
- });
40
-
41
- vi.mock('../../src/SyncedMap', () => {
42
- class SyncedMap {
43
- waitUntilReady = vi.fn(async () => undefined);
44
- get = vi.fn(() => undefined);
45
- set = vi.fn(async () => undefined);
46
- delete = vi.fn(async () => undefined);
47
- entries = vi.fn(function* () {
48
- return;
49
- });
50
-
51
- constructor() {}
52
- }
53
-
54
- return { SyncedMap };
55
- });
56
-
57
- describe('RedisStringsHandler', () => {
58
- beforeEach(() => {
59
- vi.restoreAllMocks();
60
- });
61
-
62
- afterEach(() => {
63
- vi.unstubAllEnvs();
64
- });
65
-
66
- it('treats aborted GET (timeout) as cache miss without console.error', async () => {
67
- const consoleErrorSpy = vi
68
- .spyOn(console, 'error')
69
- .mockImplementation(() => undefined);
70
-
71
- const handler = new RedisStringsHandler({
72
- redisUrl: 'redis://localhost:6379',
73
- keyPrefix: 'test:',
74
- database: 0,
75
- getTimeoutMs: 1,
76
- redisGetDeduplication: false,
77
- });
78
-
79
- const res = await handler.get('missing-key', {
80
- kind: 'APP_PAGE',
81
- isRoutePPREnabled: false,
82
- isFallback: false,
83
- });
84
-
85
- expect(res).toBeNull();
86
- expect(consoleErrorSpy).not.toHaveBeenCalled();
87
- });
88
-
89
- it('does not leave the readiness timeout timer pending after an operation', async () => {
90
- vi.useFakeTimers();
91
- try {
92
- const handler = new RedisStringsHandler({
93
- redisUrl: 'redis://localhost:6379',
94
- keyPrefix: 'test:',
95
- database: 0,
96
- getTimeoutMs: 1,
97
- redisGetDeduplication: false,
98
- });
99
-
100
- const timersBefore = vi.getTimerCount();
101
- await handler.get('missing-key', {
102
- kind: 'APP_PAGE',
103
- isRoutePPREnabled: false,
104
- isFallback: false,
105
- });
106
-
107
- // assertClientIsReady() races waitUntilReady() against a 30s timeout;
108
- // the timer must not stay pending once the race is settled, because
109
- // pending timers retain the ambient async context (and with it, in a
110
- // Next.js server, the whole per-request object graph).
111
- expect(vi.getTimerCount()).toBe(timersBefore);
112
- } finally {
113
- vi.useRealTimers();
114
- }
115
- });
116
- });
117
-
118
- describe('Public exports', () => {
119
- it('exports CreateRedisStringsHandlerOptions type', () => {
120
- const _typeCheck: CreateRedisStringsHandlerOptions = {
121
- keyPrefix: 'test',
122
- };
123
-
124
- expect(_typeCheck.keyPrefix).toBe('test');
125
- });
126
- });
127
-
128
- describe('redisCacheHandler lazy proxy', () => {
129
- it('does not construct a Redis connection on import', async () => {
130
- vi.resetModules();
131
- const { createClient } = await import('redis');
132
- vi.mocked(createClient).mockClear();
133
-
134
- // Importing the module should NOT trigger a Redis connection
135
- await import('../../../src');
136
-
137
- expect(vi.mocked(createClient)).not.toHaveBeenCalled();
138
- });
139
-
140
- it('has trap returns true for known methods without constructing the handler', async () => {
141
- vi.resetModules();
142
- const { createClient } = await import('redis');
143
- vi.mocked(createClient).mockClear();
144
-
145
- const { redisCacheHandler } = await import('../../../src');
146
-
147
- expect('getExpiration' in redisCacheHandler).toBe(true);
148
- expect('get' in redisCacheHandler).toBe(true);
149
- expect('set' in redisCacheHandler).toBe(true);
150
- expect('refreshTags' in redisCacheHandler).toBe(true);
151
- expect('updateTags' in redisCacheHandler).toBe(true);
152
-
153
- expect(vi.mocked(createClient)).not.toHaveBeenCalled();
154
- });
155
-
156
- it('method call delegates to the singleton and binds correctly', async () => {
157
- vi.resetModules();
158
- const { createClient } = await import('redis');
159
- vi.mocked(createClient).mockClear();
160
-
161
- const { redisCacheHandler } = await import('../../../src');
162
-
163
- // Accessing a method triggers construction and delegates to the real handler
164
- const getFn = redisCacheHandler.get;
165
- expect(typeof getFn).toBe('function');
166
- expect(vi.mocked(createClient)).toHaveBeenCalledTimes(1);
167
-
168
- // Subsequent accesses reuse the same singleton (no extra construction)
169
- const getFn2 = redisCacheHandler.get;
170
- expect(vi.mocked(createClient)).toHaveBeenCalledTimes(1);
171
- expect(typeof getFn2).toBe('function');
172
- });
173
- });
@@ -1,292 +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() derives the TTL from the legacy ctx.revalidate argument (Next.js 15.0.3)', async () => {
149
- const handler = createHandler();
150
- await handler.set('/blog/post-legacy', pagesData, {
151
- ...baseCtx,
152
- revalidate: 60,
153
- });
154
-
155
- const { ex } = storedEntry('/blog/post-legacy');
156
- expect(ex).toBe(expireAge(60));
157
- });
158
- });
159
-
160
- describe('REDIRECT entries (getStaticProps redirect)', () => {
161
- const redirectData = {
162
- kind: 'REDIRECT' as const,
163
- // Next.js nests the redirect directives under `pageProps`, matching the
164
- // real getStaticProps redirect payload asserted in the integration test.
165
- props: {
166
- pageProps: { __N_REDIRECT: '/target', __N_REDIRECT_STATUS: 307 },
167
- },
168
- };
169
-
170
- it('set() and get() round-trip a REDIRECT entry without warnings', async () => {
171
- const handler = createHandler();
172
- await handler.set('/old-location', redirectData, {
173
- ...baseCtx,
174
- cacheControl: { revalidate: 30, expire: undefined },
175
- });
176
-
177
- const { entry, ex } = storedEntry('/old-location');
178
- expect(entry).toEqual({
179
- value: redirectData,
180
- lastModified: expect.any(Number),
181
- tags: ['_N_T_/old-location'],
182
- });
183
- expect(ex).toBe(expireAge(30));
184
-
185
- const result = await handler.get('/old-location', {
186
- kind: 'PAGES',
187
- isFallback: false,
188
- });
189
- expect(result?.value).toEqual(redirectData);
190
- expect(warnSpy).not.toHaveBeenCalled();
191
- expect(errorSpy).not.toHaveBeenCalled();
192
- });
193
- });
194
-
195
- describe('notFound entries (data === null)', () => {
196
- it('set() stores a null-value entry without throwing or warning', async () => {
197
- const handler = createHandler();
198
- await handler.set('/missing-page', null, {
199
- ...baseCtx,
200
- cacheControl: { revalidate: 15, expire: undefined },
201
- });
202
-
203
- const { entry, ex } = storedEntry('/missing-page');
204
- expect(entry).toEqual({
205
- value: null,
206
- lastModified: expect.any(Number),
207
- tags: ['_N_T_/missing-page'],
208
- });
209
- expect(ex).toBe(expireAge(15));
210
- expect(warnSpy).not.toHaveBeenCalled();
211
- expect(errorSpy).not.toHaveBeenCalled();
212
- });
213
-
214
- it('get() returns the null-value entry without malformed warnings or errors', async () => {
215
- const handler = createHandler();
216
- await handler.set('/missing-page', null, {
217
- ...baseCtx,
218
- cacheControl: { revalidate: 15, expire: undefined },
219
- });
220
-
221
- const result = await handler.get('/missing-page', {
222
- kind: 'PAGES',
223
- isFallback: false,
224
- });
225
-
226
- expect(result).toEqual({
227
- value: null,
228
- lastModified: expect.any(Number),
229
- tags: ['_N_T_/missing-page'],
230
- });
231
- expect(warnSpy).not.toHaveBeenCalled();
232
- expect(errorSpy).not.toHaveBeenCalled();
233
- });
234
-
235
- it('get() still warns for a malformed entry with a missing (undefined) value', async () => {
236
- const handler = createHandler();
237
- hoisted.store.set(KEY_PREFIX + '/malformed', {
238
- value: JSON.stringify({ lastModified: Date.now(), tags: [] }),
239
- });
240
-
241
- await handler.get('/malformed', {
242
- kind: 'PAGES',
243
- isFallback: false,
244
- });
245
-
246
- expect(warnSpy).toHaveBeenCalledWith(
247
- 'RedisStringsHandler.get() called with',
248
- '/malformed',
249
- expect.anything(),
250
- 'cacheEntry is mall formed (missing value)',
251
- );
252
- });
253
- });
254
-
255
- describe('App Router entries are unaffected', () => {
256
- it('set() still extracts tags from the x-next-cache-tags header and adds no implicit tag', async () => {
257
- const handler = createHandler();
258
- await handler.set(
259
- '/app-page',
260
- {
261
- kind: 'APP_PAGE',
262
- html: '<html></html>',
263
- rscData: Buffer.from('rsc'),
264
- headers: {
265
- 'x-nextjs-stale-time': '1000',
266
- 'x-next-cache-tags': '_N_T_/layout,_N_T_/app-page',
267
- },
268
- segmentData: undefined,
269
- postboned: undefined,
270
- },
271
- { ...baseCtx, cacheControl: { revalidate: 60, expire: undefined } },
272
- );
273
-
274
- const { entry } = storedEntry('/app-page');
275
- expect(entry.tags).toEqual(['_N_T_/layout', '_N_T_/app-page']);
276
- expect(warnSpy).not.toHaveBeenCalled();
277
- });
278
-
279
- it('set() still warns for unsupported kinds (e.g. IMAGE)', async () => {
280
- const handler = createHandler();
281
- await handler.set(
282
- '/some-image',
283
- { kind: 'IMAGE' } as unknown as Parameters<
284
- RedisStringsHandler['set']
285
- >[1],
286
- baseCtx,
287
- );
288
-
289
- expect(warnSpy).toHaveBeenCalled();
290
- });
291
- });
292
- });
@@ -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
- });