@trieb.work/nextjs-turbo-redis-cache 1.15.0 → 1.15.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 (246) hide show
  1. package/.cursor/skills/testing/SKILL.md +121 -0
  2. package/.github/workflows/ci.yml +155 -70
  3. package/ARCHITECTURE.md +431 -0
  4. package/CHANGELOG.md +7 -0
  5. package/README.md +72 -47
  6. package/dist/index.js +78 -14
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +78 -14
  9. package/dist/index.mjs.map +1 -1
  10. package/eslint.config.mjs +1 -1
  11. package/package.json +14 -16
  12. package/playwright.config.ts +5 -3
  13. package/src/CacheComponentsHandler.ts +57 -2
  14. package/src/SyncedMap.ts +62 -13
  15. package/test/README.md +179 -0
  16. package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/package.json +6 -6
  17. package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-15-4-11}/pnpm-lock.yaml +89 -105
  18. package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11}/package.json +3 -3
  19. package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11}/pnpm-lock.yaml +53 -53
  20. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/package.json +28 -0
  21. package/test/nextjs-test-projects/next-app-16-0-11-cache-components/pnpm-lock.yaml +4206 -0
  22. package/test/nextjs-test-projects/next-app-16-2-6/eslint.config.mjs +18 -0
  23. package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6}/package.json +3 -3
  24. package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6}/pnpm-lock.yaml +54 -60
  25. package/test/nextjs-test-projects/next-app-16-2-6/postcss.config.mjs +7 -0
  26. package/test/nextjs-test-projects/next-app-16-2-6/src/app/favicon.ico +0 -0
  27. package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-2-6}/tsconfig.json +9 -2
  28. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/cache-handler.js +3 -0
  29. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/next.config.ts +13 -0
  30. package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6-cache-components}/package.json +3 -3
  31. package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6-cache-components}/pnpm-lock.yaml +54 -60
  32. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-static-fetch/route.ts +19 -0
  33. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-cachelife/route.ts +24 -0
  34. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-tag/route.ts +21 -0
  35. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidate-tag/route.ts +19 -0
  36. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidated-fetch/route.ts +19 -0
  37. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/cachelife-short/page.tsx +110 -0
  38. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/page.tsx +90 -0
  39. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +127 -0
  40. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +130 -0
  41. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +127 -0
  42. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +110 -0
  43. package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/src/app/layout.tsx +0 -2
  44. package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/update-tag-test/page.tsx +22 -0
  45. package/{tests → test/playwright}/update-tag.spec.ts +1 -1
  46. package/test/{integration → vitest/integration}/build-id-prefix.integration.test.ts +2 -2
  47. package/test/{cache-components/cache-components.integration.spec.ts → vitest/integration/cache-components/cache-components.integration.test.ts} +7 -3
  48. package/test/{cache-components/redis-kill-reconnect.spec.ts → vitest/integration/cache-components/redis-kill-reconnect.test.ts} +28 -7
  49. package/test/vitest/integration/cache-components/redis-quit-vs-disconnect.test.ts +59 -0
  50. package/test/vitest/integration/cache-components/redis-subscriber-outage.test.ts +100 -0
  51. package/test/{cache-components → vitest/integration/cache-components}/scripts/redis-kill-reconnect.ts +31 -8
  52. package/test/vitest/integration/cache-components/scripts/redis-quit-vs-disconnect.ts +113 -0
  53. package/test/vitest/integration/cache-components/scripts/redis-subscriber-outage.ts +379 -0
  54. package/test/vitest/integration/cache-components/scripts/redis-test-helpers.ts +155 -0
  55. package/test/{integration → vitest/integration}/nextjs-cache-handler.integration.test.ts +15 -9
  56. package/test/vitest/unit/SyncedMap-reconnect-repro.test.ts +154 -0
  57. package/{src → test/vitest/unit}/index.test.ts +3 -3
  58. package/test/{cache-components/reconnect-socket-already-opened.spec.ts → vitest/unit/reconnect-socket-already-opened.test.ts} +1 -1
  59. package/{src → test/vitest/unit}/serializer.test.ts +7 -3
  60. package/{src → test/vitest/unit}/utils/prefix.test.ts +1 -1
  61. package/vite.config.ts +4 -3
  62. package/vitest.cache-components.config.ts +1 -1
  63. package/test/browser/update-tag.browser.test.ts +0 -41
  64. package/test/integration/next-app-15-0-3/next.config.js +0 -6
  65. package/test/integration/next-app-15-0-3/package-lock.json +0 -5833
  66. package/test/integration/next-app-15-0-3/pnpm-lock.yaml +0 -3710
  67. package/test/integration/next-app-15-3-2/next.config.js +0 -6
  68. package/test/integration/next-app-15-3-2/package.json +0 -33
  69. package/test/integration/next-app-15-3-2/pnpm-lock.yaml +0 -3720
  70. package/test/integration/next-app-15-3-2/postcss.config.mjs +0 -5
  71. package/test/integration/next-app-15-3-2/src/app/api/revalidateTag/route.ts +0 -15
  72. package/test/integration/next-app-15-4-7/eslint.config.mjs +0 -16
  73. package/test/integration/next-app-15-4-7/package-lock.json +0 -5969
  74. package/test/integration/next-app-15-4-7/package.json +0 -33
  75. package/test/integration/next-app-15-4-7/postcss.config.mjs +0 -5
  76. package/test/integration/next-app-15-4-7/src/app/api/revalidateTag/route.ts +0 -15
  77. package/test/integration/next-app-15-4-7/tsconfig.json +0 -27
  78. package/test/integration/next-app-16-0-3/src/app/api/cached-static-fetch/route.ts +0 -18
  79. package/test/integration/next-app-16-0-3/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  80. package/test/integration/next-app-16-0-3/src/app/api/revalidatePath/route.ts +0 -15
  81. package/test/integration/next-app-16-0-3/src/app/api/revalidated-fetch/route.ts +0 -17
  82. package/test/integration/next-app-16-0-3/src/app/api/uncached-fetch/route.ts +0 -15
  83. package/test/integration/next-app-16-0-3/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  84. package/test/integration/next-app-16-0-3/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  85. package/test/integration/next-app-16-0-3/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  86. package/test/integration/next-app-16-0-3/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  87. package/test/integration/next-app-16-0-3/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  88. package/test/integration/next-app-16-0-3/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  89. package/test/integration/next-app-16-0-3/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  90. package/test/integration/next-app-16-0-3/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  91. package/test/integration/next-app-16-0-3/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  92. package/test/integration/next-app-16-0-3/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  93. package/test/integration/next-app-16-2-3/src/app/api/cached-static-fetch/route.ts +0 -18
  94. package/test/integration/next-app-16-2-3/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
  95. package/test/integration/next-app-16-2-3/src/app/api/revalidatePath/route.ts +0 -15
  96. package/test/integration/next-app-16-2-3/src/app/api/revalidated-fetch/route.ts +0 -17
  97. package/test/integration/next-app-16-2-3/src/app/api/uncached-fetch/route.ts +0 -15
  98. package/test/integration/next-app-16-2-3/src/app/globals.css +0 -26
  99. package/test/integration/next-app-16-2-3/src/app/layout.tsx +0 -59
  100. package/test/integration/next-app-16-2-3/src/app/page.tsx +0 -755
  101. package/test/integration/next-app-16-2-3/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
  102. package/test/integration/next-app-16-2-3/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
  103. package/test/integration/next-app-16-2-3/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  104. package/test/integration/next-app-16-2-3/src/app/pages/no-fetch/default-page/page.tsx +0 -55
  105. package/test/integration/next-app-16-2-3/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
  106. package/test/integration/next-app-16-2-3/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
  107. package/test/integration/next-app-16-2-3/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  108. package/test/integration/next-app-16-2-3/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
  109. package/test/integration/next-app-16-2-3/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
  110. package/test/integration/next-app-16-2-3/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
  111. package/test/integration/next-app-16-2-3/src/app/revalidation-interface.tsx +0 -267
  112. package/test/integration/next-app-16-2-3-cache-components/public/file.svg +0 -1
  113. package/test/integration/next-app-16-2-3-cache-components/public/globe.svg +0 -1
  114. package/test/integration/next-app-16-2-3-cache-components/public/next.svg +0 -1
  115. package/test/integration/next-app-16-2-3-cache-components/public/vercel.svg +0 -1
  116. package/test/integration/next-app-16-2-3-cache-components/public/window.svg +0 -1
  117. package/test/integration/next-app-customized/README.md +0 -36
  118. package/test/integration/next-app-customized/eslint.config.mjs +0 -16
  119. package/vitest.browser.config.ts +0 -10
  120. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/README.md +0 -0
  121. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/eslint.config.mjs +0 -0
  122. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-15-4-11}/next.config.js +0 -0
  123. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-15-4-11}/package-lock.json +0 -0
  124. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/postcss.config.mjs +0 -0
  125. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/public/file.svg +0 -0
  126. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/public/globe.svg +0 -0
  127. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/public/next.svg +0 -0
  128. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/public/vercel.svg +0 -0
  129. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/public/window.svg +0 -0
  130. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/cached-static-fetch/route.ts +0 -0
  131. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -0
  132. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/revalidatePath/route.ts +0 -0
  133. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/revalidateTag/route.ts +0 -0
  134. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/revalidated-fetch/route.ts +0 -0
  135. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/api/uncached-fetch/route.ts +0 -0
  136. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/globals.css +0 -0
  137. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/layout.tsx +0 -0
  138. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/page.tsx +0 -0
  139. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -0
  140. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -0
  141. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  142. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/no-fetch/default-page/page.tsx +0 -0
  143. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -0
  144. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -0
  145. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  146. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -0
  147. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -0
  148. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  149. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/src/app/revalidation-interface.tsx +0 -0
  150. /package/test/{integration/next-app-15-0-3 → nextjs-test-projects/next-app-15-4-11}/tsconfig.json +0 -0
  151. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-0-11}/README.md +0 -0
  152. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11}/eslint.config.mjs +0 -0
  153. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11}/next.config.ts +0 -0
  154. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11}/postcss.config.mjs +0 -0
  155. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/api/cached-static-fetch/route.ts +0 -0
  156. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -0
  157. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/api/revalidatePath/route.ts +0 -0
  158. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11}/src/app/api/revalidateTag/route.ts +0 -0
  159. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/api/revalidated-fetch/route.ts +0 -0
  160. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/api/uncached-fetch/route.ts +0 -0
  161. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11}/src/app/favicon.ico +0 -0
  162. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-0-11}/src/app/globals.css +0 -0
  163. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/layout.tsx +0 -0
  164. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-0-11}/src/app/page.tsx +0 -0
  165. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -0
  166. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -0
  167. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  168. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/no-fetch/default-page/page.tsx +0 -0
  169. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -0
  170. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -0
  171. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  172. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -0
  173. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -0
  174. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11}/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  175. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-0-11}/src/app/revalidation-interface.tsx +0 -0
  176. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11}/src/app/update-tag-test/page.tsx +0 -0
  177. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11}/tsconfig.json +0 -0
  178. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/README.md +0 -0
  179. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/cache-handler.js +0 -0
  180. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11-cache-components}/eslint.config.mjs +0 -0
  181. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/next.config.ts +0 -0
  182. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11-cache-components}/postcss.config.mjs +0 -0
  183. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/public/file.svg +0 -0
  184. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/public/globe.svg +0 -0
  185. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/public/next.svg +0 -0
  186. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/public/vercel.svg +0 -0
  187. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/public/window.svg +0 -0
  188. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/api/cached-static-fetch/route.ts +0 -0
  189. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/api/cached-with-cachelife/route.ts +0 -0
  190. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/api/cached-with-tag/route.ts +0 -0
  191. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/api/revalidate-tag/route.ts +0 -0
  192. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/api/revalidated-fetch/route.ts +0 -0
  193. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/cachelife-short/page.tsx +0 -0
  194. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/page.tsx +0 -0
  195. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -0
  196. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -0
  197. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/tag-invalidation/page.tsx +0 -0
  198. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -0
  199. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/favicon.ico +0 -0
  200. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/globals.css +0 -0
  201. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/layout.tsx +0 -0
  202. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/page.tsx +0 -0
  203. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/revalidation-interface.tsx +0 -0
  204. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-0-11-cache-components}/src/app/update-tag-test/page.tsx +0 -0
  205. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-0-11-cache-components}/tsconfig.json +0 -0
  206. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6}/README.md +0 -0
  207. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6}/next.config.ts +0 -0
  208. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/api/cached-static-fetch/route.ts +0 -0
  209. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -0
  210. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/api/revalidatePath/route.ts +0 -0
  211. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6}/src/app/api/revalidateTag/route.ts +0 -0
  212. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/api/revalidated-fetch/route.ts +0 -0
  213. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/api/uncached-fetch/route.ts +0 -0
  214. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6}/src/app/globals.css +0 -0
  215. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/layout.tsx +0 -0
  216. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6}/src/app/page.tsx +0 -0
  217. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -0
  218. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -0
  219. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  220. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/no-fetch/default-page/page.tsx +0 -0
  221. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -0
  222. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -0
  223. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  224. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -0
  225. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -0
  226. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6}/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -0
  227. /package/test/{integration/next-app-16-2-3-cache-components → nextjs-test-projects/next-app-16-2-6}/src/app/revalidation-interface.tsx +0 -0
  228. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6}/src/app/update-tag-test/page.tsx +0 -0
  229. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/README.md +0 -0
  230. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/eslint.config.mjs +0 -0
  231. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/postcss.config.mjs +0 -0
  232. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6-cache-components}/public/file.svg +0 -0
  233. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6-cache-components}/public/globe.svg +0 -0
  234. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6-cache-components}/public/next.svg +0 -0
  235. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6-cache-components}/public/vercel.svg +0 -0
  236. /package/test/{integration/next-app-15-4-7 → nextjs-test-projects/next-app-16-2-6-cache-components}/public/window.svg +0 -0
  237. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/src/app/favicon.ico +0 -0
  238. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/src/app/globals.css +0 -0
  239. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/src/app/page.tsx +0 -0
  240. /package/test/{integration/next-app-16-0-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/src/app/revalidation-interface.tsx +0 -0
  241. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-16-2-6-cache-components}/tsconfig.json +0 -0
  242. /package/test/{integration/next-app-16-2-3 → nextjs-test-projects/next-app-customized}/README.md +0 -0
  243. /package/test/{integration → nextjs-test-projects}/next-app-customized/customized-cache-handler.js +0 -0
  244. /package/test/{integration/next-app-15-3-2 → nextjs-test-projects/next-app-customized}/eslint.config.mjs +0 -0
  245. /package/test/{integration → nextjs-test-projects}/next-app-customized/next.config.js +0 -0
  246. /package/{tests → test/playwright}/cache-lab.spec.ts +0 -0
@@ -0,0 +1,154 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { SyncedMap } from '../../../src/SyncedMap';
3
+
4
+ // Module-level knobs for the subscribe() mock so that behaviour persists
5
+ // across the duplicate() clients created inside SyncedMap.
6
+ let globalSubscribeCalls = 0;
7
+ let globalSubscribeFailUntil = 0;
8
+
9
+ class MockClient {
10
+ static nextId = 1;
11
+ id = MockClient.nextId++;
12
+ private errorHandlers: Set<(err: Error) => void | Promise<void>> = new Set();
13
+ quitShouldThrow = true;
14
+
15
+ isOpen = true;
16
+ isReady = true;
17
+
18
+ on(event: string, handler: (err: Error) => void | Promise<void>) {
19
+ if (event === 'error') this.errorHandlers.add(handler);
20
+ return this as any;
21
+ }
22
+
23
+ emit(event: string, err: Error) {
24
+ if (event === 'error') {
25
+ for (const h of this.errorHandlers) {
26
+ void h(err);
27
+ }
28
+ }
29
+ return true;
30
+ }
31
+
32
+ removeAllListeners(event?: string) {
33
+ if (!event || event === 'error') this.errorHandlers.clear();
34
+ return this as any;
35
+ }
36
+
37
+ async connect() {
38
+ this.isOpen = true;
39
+ this.isReady = true;
40
+ }
41
+
42
+ async configGet() {
43
+ return { 'notify-keyspace-events': 'Exe' };
44
+ }
45
+
46
+ async subscribe() {
47
+ const attempt = globalSubscribeCalls++;
48
+ if (attempt < globalSubscribeFailUntil) {
49
+ throw new Error(`Mock subscribe failure ${attempt}`);
50
+ }
51
+ }
52
+
53
+ async quit() {
54
+ if (this.quitShouldThrow)
55
+ throw new Error('Mock quit failure (disconnected)');
56
+ }
57
+
58
+ async disconnect() {
59
+ this.isOpen = false;
60
+ this.isReady = false;
61
+ this.errorHandlers.clear();
62
+ }
63
+
64
+ duplicate() {
65
+ return new MockClient();
66
+ }
67
+
68
+ hScan() {
69
+ return { cursor: 0, tuples: [] };
70
+ }
71
+
72
+ scan() {
73
+ return { cursor: 0, keys: [] };
74
+ }
75
+ }
76
+
77
+ function createMap(rootClient = new MockClient()) {
78
+ return new SyncedMap<string>({
79
+ client: rootClient as any,
80
+ keyPrefix: 'repro:',
81
+ redisKey: '__sharedTags__',
82
+ database: 0,
83
+ querySize: 250,
84
+ filterKeys: () => true,
85
+ customizedSync: {
86
+ withoutRedisHashmap: true,
87
+ withoutSetSync: true,
88
+ },
89
+ });
90
+ }
91
+
92
+ describe('SyncedMap.reconnectSubscriber() repro tests', () => {
93
+ let originalSetTimeout: typeof global.setTimeout;
94
+
95
+ beforeEach(() => {
96
+ globalSubscribeCalls = 0;
97
+ globalSubscribeFailUntil = 0;
98
+ originalSetTimeout = global.setTimeout;
99
+ });
100
+
101
+ afterEach(() => {
102
+ global.setTimeout = originalSetTimeout;
103
+ });
104
+
105
+ it('Issue 2: first backoff delay should be 500ms, not 1000ms', async () => {
106
+ const root = new MockClient();
107
+ const map = createMap(root);
108
+ // wait for initial setup to succeed (attempt 0)
109
+ await (map as any).waitUntilReady().catch(() => undefined);
110
+
111
+ const capturedDelays: number[] = [];
112
+ global.setTimeout = ((callback: () => void, delay?: number) => {
113
+ capturedDelays.push(Number(delay ?? 0));
114
+ return originalSetTimeout(callback, 0) as any;
115
+ }) as any;
116
+
117
+ // initial subscribe consumed attempt 0; force the next 3 reconnection
118
+ // attempts to fail, then succeed on the 4th
119
+ globalSubscribeFailUntil = 4;
120
+
121
+ await (map as any).reconnectSubscriber();
122
+
123
+ expect(capturedDelays.length).toBeGreaterThanOrEqual(1);
124
+ // Bug: delay is computed with attempt already incremented, so the first
125
+ // retry waits 500 * 2^1 = 1000 ms. After the fix it should be 500 ms.
126
+ expect(capturedDelays[0]).toBe(500);
127
+ });
128
+
129
+ it('Issue 1: stale error on old subscriber must not kill the healthy new subscriber', async () => {
130
+ const root = new MockClient();
131
+ const map = createMap(root);
132
+ await (map as any).waitUntilReady().catch(() => undefined);
133
+
134
+ const oldSubscriber = (map as any).subscriberClient as MockClient;
135
+ expect(oldSubscriber).toBeDefined();
136
+
137
+ await (map as any).reconnectSubscriber();
138
+
139
+ const newSubscriber = (map as any).subscriberClient as MockClient;
140
+ expect(newSubscriber.id).not.toBe(oldSubscriber.id);
141
+
142
+ // Simulate a delayed error from the old (now replaced) subscriber.
143
+ // With the current code the old 'error' listener is still attached,
144
+ // so it triggers reconnectSubscriber() and tears down the healthy client.
145
+ oldSubscriber.emit('error', new Error('delayed zombie error'));
146
+
147
+ // Give the async error handler a chance to run.
148
+ await new Promise((r) => originalSetTimeout(r, 50));
149
+
150
+ const afterStaleError = (map as any).subscriberClient as MockClient;
151
+
152
+ expect(afterStaleError.id).toBe(newSubscriber.id);
153
+ });
154
+ });
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
2
 
3
- import type { CreateRedisStringsHandlerOptions } from './index';
4
- import RedisStringsHandler from './RedisStringsHandler';
3
+ import type { CreateRedisStringsHandlerOptions } from '../../../src/index';
4
+ import RedisStringsHandler from '../../../src/RedisStringsHandler';
5
5
 
6
6
  vi.mock('redis', () => {
7
7
  const createClient = () => {
@@ -38,7 +38,7 @@ vi.mock('redis', () => {
38
38
  };
39
39
  });
40
40
 
41
- vi.mock('./SyncedMap', () => {
41
+ vi.mock('../../src/SyncedMap', () => {
42
42
  class SyncedMap {
43
43
  waitUntilReady = vi.fn(async () => undefined);
44
44
  get = vi.fn(() => undefined);
@@ -22,7 +22,7 @@ describe('RedisCacheComponentsHandler reconnect logic', () => {
22
22
  .spyOn(console, 'error')
23
23
  .mockImplementation(() => {});
24
24
 
25
- const { getRedisCacheComponentsHandler } = await import('../../src');
25
+ const { getRedisCacheComponentsHandler } = await import('../../../src');
26
26
 
27
27
  const handler = getRedisCacheComponentsHandler({
28
28
  redisUrl: 'redis://127.0.0.1:6399',
@@ -1,7 +1,10 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
2
 
3
- import { CacheValueSerializer, jsonCacheValueSerializer } from './serializer';
4
- import type { CacheEntry } from './RedisStringsHandler';
3
+ import {
4
+ CacheValueSerializer,
5
+ jsonCacheValueSerializer,
6
+ } from '../../../src/serializer';
7
+ import type { CacheEntry } from '../../../src/RedisStringsHandler';
5
8
 
6
9
  function makeEntry(value: unknown): CacheEntry {
7
10
  return {
@@ -60,7 +63,8 @@ describe('jsonCacheValueSerializer (default)', () => {
60
63
  it('is referentially stable so consumers can detect default usage', async () => {
61
64
  // Importing twice should yield the same singleton; this guards against
62
65
  // accidental "factory" refactors that would break reference equality.
63
- const reimport = (await import('./serializer')).jsonCacheValueSerializer;
66
+ const reimport = (await import('../../../src/serializer'))
67
+ .jsonCacheValueSerializer;
64
68
  expect(reimport).toBe(jsonCacheValueSerializer);
65
69
  });
66
70
  });
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach } from 'vitest';
2
2
  import os from 'node:os';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
- import { resolveKeyPrefix } from './prefix';
5
+ import { resolveKeyPrefix } from '../../../../src/utils/prefix';
6
6
 
7
7
  function withEnv<T>(env: Partial<NodeJS.ProcessEnv>, fn: () => T): T {
8
8
  const original: NodeJS.ProcessEnv = { ...process.env };
package/vite.config.ts CHANGED
@@ -5,9 +5,9 @@ export default defineConfig({
5
5
  globals: true,
6
6
  environment: 'node',
7
7
  include: [
8
- 'src/**/*.test.ts',
9
- 'src/**/*.test.tsx',
10
- 'test/integration/**/*.test.ts',
8
+ 'test/vitest/unit/**/*.test.ts',
9
+ 'test/vitest/unit/**/*.test.tsx',
10
+ 'test/vitest/integration/**/*.test.ts',
11
11
  ],
12
12
  exclude: [
13
13
  'node_modules',
@@ -15,6 +15,7 @@ export default defineConfig({
15
15
  '.git',
16
16
  '**/node_modules/**',
17
17
  '**/node_modules',
18
+ 'test/vitest/integration/cache-components/**',
18
19
  ],
19
20
  coverage: {
20
21
  provider: 'v8',
@@ -4,7 +4,7 @@ export default defineConfig({
4
4
  test: {
5
5
  globals: true,
6
6
  environment: 'node',
7
- include: ['test/cache-components/**/*.spec.ts'],
7
+ include: ['test/vitest/integration/cache-components/**/*.test.ts'],
8
8
  exclude: [
9
9
  'node_modules',
10
10
  'dist',
@@ -1,41 +0,0 @@
1
- import { test, expect } from 'vitest';
2
-
3
- // Base URL of the running Next 16 app.
4
- // Start it separately, e.g.:
5
- // cd test/integration/next-app-16-0-3 && pnpm dev
6
- // and ensure it listens on the same origin as below.
7
- const BASE_URL =
8
- (globalThis as any).NEXT_BROWSER_BASE_URL || 'http://localhost:3000';
9
-
10
- // This test exercises a real Server Action that calls updateTag.
11
- // It does not assert Redis state, but it verifies that calling the
12
- // server action endpoint does not trigger the "Server Action only" error.
13
-
14
- test('Server Action calling updateTag responds without server-action-only error', async () => {
15
- // 1) Fetch the SSR HTML for the page containing the Server Action form
16
- const res = await fetch(`${BASE_URL}/update-tag-test`);
17
- expect(res.status).toBeLessThan(500);
18
- const html = await res.text();
19
-
20
- // 2) Parse the HTML to find the form action URL that Next generated
21
- const parser = new DOMParser();
22
- const doc = parser.parseFromString(html, 'text/html');
23
- const form = doc.querySelector('form');
24
- expect(form).not.toBeNull();
25
-
26
- const actionAttr = form!.getAttribute('action');
27
- expect(actionAttr).toBeTruthy();
28
-
29
- const actionUrl = new URL(actionAttr!, BASE_URL).toString();
30
-
31
- // 3) Call the Server Action endpoint directly.
32
- // If updateTag were not allowed here, Next.js would respond with
33
- // an error page that contains the specific error message.
34
- const actionRes = await fetch(actionUrl, { method: 'POST' });
35
- const actionText = await actionRes.text();
36
-
37
- expect(actionRes.status).toBeLessThan(500);
38
- expect(actionText).not.toContain(
39
- 'updateTag can only be called from within a Server Action',
40
- );
41
- });
@@ -1,6 +0,0 @@
1
- /** @type {import('next').NextConfig} */
2
- const nextConfig = {
3
- cacheHandler: require.resolve('@trieb.work/nextjs-turbo-redis-cache'),
4
- };
5
-
6
- module.exports = nextConfig;