@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,567 +0,0 @@
1
- import { commandOptions, createClient } from 'redis';
2
- import type { RedisClientOptions } from 'redis';
3
- import {
4
- Client,
5
- CreateRedisStringsHandlerOptions,
6
- redisErrorHandler,
7
- } from './RedisStringsHandler';
8
- import { SyncedMap } from './SyncedMap';
9
- import { DeduplicatedRequestHandler } from './DeduplicatedRequestHandler';
10
- import { debug } from './utils/debug';
11
- import { resolveKeyPrefix } from './utils/prefix';
12
-
13
- export interface CacheComponentsEntry {
14
- value: ReadableStream<Uint8Array>;
15
- tags: string[];
16
- stale: number;
17
- timestamp: number;
18
- expire: number;
19
- revalidate: number;
20
- }
21
-
22
- export interface CacheComponentsHandler {
23
- get(
24
- cacheKey: string,
25
- softTags: string[],
26
- ): Promise<CacheComponentsEntry | undefined>;
27
- set(
28
- cacheKey: string,
29
- pendingEntry: Promise<CacheComponentsEntry>,
30
- ): Promise<void>;
31
- refreshTags(): Promise<void>;
32
- getExpiration(tags: string[]): Promise<number>;
33
- updateTags(tags: string[], durations?: { expire?: number }): Promise<void>;
34
- }
35
-
36
- type StoredCacheEntry = Omit<CacheComponentsEntry, 'value'> & {
37
- value: Uint8Array | string;
38
- };
39
-
40
- const REVALIDATED_TAGS_KEY = '__cacheComponents_revalidated_tags__';
41
- const SHARED_TAGS_KEY = '__cacheComponents_sharedTags__';
42
-
43
- let killContainerOnErrorCount = 0;
44
-
45
- export type CreateCacheComponentsHandlerOptions =
46
- CreateRedisStringsHandlerOptions & { serverDistDir?: string };
47
-
48
- async function streamToBuffer(
49
- stream: ReadableStream<Uint8Array>,
50
- ): Promise<Uint8Array> {
51
- const reader = stream.getReader();
52
- const chunks: Uint8Array[] = [];
53
-
54
- while (true) {
55
- const { value, done } = await reader.read();
56
- if (done) break;
57
- if (value) {
58
- chunks.push(value);
59
- }
60
- }
61
-
62
- if (chunks.length === 1) {
63
- return chunks[0];
64
- }
65
-
66
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
67
- const result = new Uint8Array(totalLength);
68
- let offset = 0;
69
- for (const chunk of chunks) {
70
- result.set(chunk, offset);
71
- offset += chunk.byteLength;
72
- }
73
- return result;
74
- }
75
-
76
- function bufferToReadableStream(
77
- buffer: Uint8Array,
78
- ): ReadableStream<Uint8Array> {
79
- return new ReadableStream<Uint8Array>({
80
- start(controller) {
81
- controller.enqueue(buffer);
82
- controller.close();
83
- },
84
- });
85
- }
86
-
87
- class RedisCacheComponentsHandler implements CacheComponentsHandler {
88
- private client: Client;
89
- private revalidatedTagsMap: SyncedMap<number>;
90
- private sharedTagsMap: SyncedMap<string[]>;
91
- private inMemoryDeduplicationCache: SyncedMap<
92
- Promise<ReturnType<Client['get']>>
93
- >;
94
- private keyPrefix: string;
95
- private getTimeoutMs: number;
96
- private redisGet: Client['get'];
97
- private redisDeduplicationHandler: DeduplicatedRequestHandler<
98
- Client['get'],
99
- string | Buffer | null
100
- >;
101
- private deduplicatedRedisGet: (key: string) => Client['get'];
102
- private redisGetDeduplication: boolean;
103
- private inMemoryCachingTime: number;
104
-
105
- constructor({
106
- redisUrl = process.env.REDIS_URL
107
- ? process.env.REDIS_URL
108
- : process.env.REDISHOST
109
- ? `redis://${process.env.REDISHOST}:${process.env.REDISPORT}`
110
- : 'redis://localhost:6379',
111
- database = process.env.VERCEL_ENV === 'production' ? 0 : 1,
112
- keyPrefix,
113
- getTimeoutMs = process.env.REDIS_COMMAND_TIMEOUT_MS
114
- ? (Number.parseInt(process.env.REDIS_COMMAND_TIMEOUT_MS) ?? 500)
115
- : 500,
116
- revalidateTagQuerySize = 250,
117
- avgResyncIntervalMs = 60 * 60 * 1_000,
118
- redisGetDeduplication = true,
119
- inMemoryCachingTime = 10_000,
120
- socketOptions,
121
- clientOptions,
122
- killContainerOnErrorThreshold = process.env
123
- .KILL_CONTAINER_ON_ERROR_THRESHOLD
124
- ? (Number.parseInt(process.env.KILL_CONTAINER_ON_ERROR_THRESHOLD) ?? 0)
125
- : 0,
126
- serverDistDir,
127
- }: CreateCacheComponentsHandlerOptions) {
128
- try {
129
- this.keyPrefix = resolveKeyPrefix({
130
- optionKeyPrefix: keyPrefix,
131
- serverDistDir,
132
- env: process.env,
133
- });
134
- this.getTimeoutMs = getTimeoutMs;
135
- this.redisGetDeduplication = redisGetDeduplication;
136
- this.inMemoryCachingTime = inMemoryCachingTime;
137
-
138
- this.client = createClient({
139
- url: redisUrl,
140
- pingInterval: 10_000,
141
- ...(database !== 0 ? { database } : {}),
142
- ...(socketOptions
143
- ? { socket: { ...socketOptions } as RedisClientOptions['socket'] }
144
- : {}),
145
- ...(clientOptions || {}),
146
- });
147
-
148
- this.client.on('error', (error) => {
149
- console.error(
150
- 'RedisCacheComponentsHandler client error',
151
- error,
152
- killContainerOnErrorCount++,
153
- );
154
- setTimeout(() => {
155
- // node-redis throws "Socket already opened" if connect() is called while a socket is already open.
156
- // When we get an error while isOpen=true (but isReady=false), we should *not* force an extra connect.
157
- if (this.client.isOpen) return;
158
-
159
- this.client.connect().catch((err) => {
160
- console.error(
161
- 'Failed to reconnect RedisCacheComponentsHandler client after connection loss:',
162
- err,
163
- );
164
- });
165
- }, 1000);
166
- if (
167
- killContainerOnErrorThreshold > 0 &&
168
- killContainerOnErrorCount >= killContainerOnErrorThreshold
169
- ) {
170
- console.error(
171
- 'RedisCacheComponentsHandler client error threshold reached, disconnecting and exiting (please implement a restart process/container watchdog to handle this error)',
172
- error,
173
- killContainerOnErrorCount++,
174
- );
175
- this.client.disconnect();
176
- this.client.quit();
177
- setTimeout(() => {
178
- process.exit(1);
179
- }, 500);
180
- }
181
- });
182
-
183
- this.client
184
- .connect()
185
- .then(() => {
186
- debug('green', 'RedisCacheComponentsHandler client connected.');
187
- })
188
- .catch(() => {
189
- this.client.connect().catch((error) => {
190
- console.error(
191
- 'Failed to connect RedisCacheComponentsHandler client:',
192
- error,
193
- );
194
- this.client.disconnect();
195
- throw error;
196
- });
197
- });
198
-
199
- const filterKeys = (key: string): boolean =>
200
- key !== REVALIDATED_TAGS_KEY && key !== SHARED_TAGS_KEY;
201
-
202
- this.revalidatedTagsMap = new SyncedMap<number>({
203
- client: this.client,
204
- keyPrefix: this.keyPrefix,
205
- redisKey: REVALIDATED_TAGS_KEY,
206
- database,
207
- querySize: revalidateTagQuerySize,
208
- filterKeys,
209
- resyncIntervalMs:
210
- avgResyncIntervalMs +
211
- avgResyncIntervalMs / 10 +
212
- Math.random() * (avgResyncIntervalMs / 10),
213
- });
214
-
215
- this.sharedTagsMap = new SyncedMap<string[]>({
216
- client: this.client,
217
- keyPrefix: this.keyPrefix,
218
- redisKey: SHARED_TAGS_KEY,
219
- database,
220
- querySize: revalidateTagQuerySize,
221
- filterKeys,
222
- resyncIntervalMs:
223
- avgResyncIntervalMs -
224
- avgResyncIntervalMs / 10 +
225
- Math.random() * (avgResyncIntervalMs / 10),
226
- });
227
-
228
- this.inMemoryDeduplicationCache = new SyncedMap({
229
- client: this.client,
230
- keyPrefix: this.keyPrefix,
231
- redisKey: '__cacheComponents_inMemoryDeduplicationCache__',
232
- database,
233
- querySize: revalidateTagQuerySize,
234
- filterKeys,
235
- customizedSync: {
236
- withoutRedisHashmap: true,
237
- withoutSetSync: true,
238
- },
239
- });
240
-
241
- const redisGet: Client['get'] = this.client.get.bind(this.client);
242
- this.redisDeduplicationHandler = new DeduplicatedRequestHandler(
243
- redisGet,
244
- inMemoryCachingTime,
245
- this.inMemoryDeduplicationCache,
246
- );
247
- this.redisGet = redisGet;
248
- this.deduplicatedRedisGet =
249
- this.redisDeduplicationHandler.deduplicatedFunction;
250
- } catch (error) {
251
- console.error('RedisCacheComponentsHandler constructor error', error);
252
- throw error;
253
- }
254
- }
255
-
256
- private async assertClientIsReady(): Promise<void> {
257
- if (!this.client.isReady && !this.client.isOpen) {
258
- await this.client.connect().catch((error) => {
259
- console.error(
260
- 'RedisCacheComponentsHandler assertClientIsReady reconnect error:',
261
- error,
262
- );
263
- throw error;
264
- });
265
- }
266
- await Promise.all([
267
- this.revalidatedTagsMap.waitUntilReady(),
268
- this.sharedTagsMap.waitUntilReady(),
269
- ]);
270
- }
271
-
272
- private async computeMaxRevalidation(tags: string[]): Promise<number> {
273
- let max = 0;
274
- for (const tag of tags) {
275
- const ts = this.revalidatedTagsMap.get(tag);
276
- if (ts && ts > max) {
277
- max = ts;
278
- }
279
- }
280
- return max;
281
- }
282
-
283
- async get(
284
- cacheKey: string,
285
- softTags: string[],
286
- ): Promise<CacheComponentsEntry | undefined> {
287
- // Construct the full Redis key
288
- // For cache components, Next.js provides the full key including environment prefix
289
- // We prepend our keyPrefix for multi-tenant isolation
290
- const redisKey = `${this.keyPrefix}${cacheKey}`;
291
-
292
- try {
293
- await this.assertClientIsReady();
294
-
295
- const clientGet = this.redisGetDeduplication
296
- ? this.deduplicatedRedisGet(cacheKey)
297
- : this.redisGet;
298
-
299
- const serialized = await redisErrorHandler(
300
- 'RedisCacheComponentsHandler.get(), operation: get' +
301
- (this.redisGetDeduplication ? ' deduplicated' : '') +
302
- ' ' +
303
- this.getTimeoutMs +
304
- 'ms ' +
305
- redisKey,
306
- clientGet(
307
- commandOptions({ signal: AbortSignal.timeout(this.getTimeoutMs) }),
308
- redisKey,
309
- ),
310
- );
311
-
312
- if (!serialized) {
313
- return undefined;
314
- }
315
-
316
- const stored: StoredCacheEntry = JSON.parse(serialized);
317
- const now = Date.now();
318
-
319
- // expire is a duration in seconds, calculate absolute expiry time
320
- const expiryTime = stored.timestamp + stored.expire * 1000;
321
- if (
322
- Number.isFinite(stored.expire) &&
323
- stored.expire > 0 &&
324
- now > expiryTime
325
- ) {
326
- await this.client.unlink(redisKey).catch(() => {});
327
- await this.sharedTagsMap.delete(cacheKey).catch(() => {});
328
- return undefined;
329
- }
330
-
331
- const maxRevalidation = await this.computeMaxRevalidation([
332
- ...(stored.tags || []),
333
- ...(softTags || []),
334
- ]);
335
-
336
- if (maxRevalidation > 0 && maxRevalidation > stored.timestamp) {
337
- await this.client.unlink(redisKey).catch(() => {});
338
- await this.sharedTagsMap.delete(cacheKey).catch(() => {});
339
- return undefined;
340
- }
341
-
342
- const valueBuffer =
343
- typeof stored.value === 'string'
344
- ? new Uint8Array(Buffer.from(stored.value, 'base64'))
345
- : stored.value;
346
-
347
- return {
348
- ...stored,
349
- value: bufferToReadableStream(valueBuffer),
350
- };
351
- } catch (error) {
352
- console.error(
353
- 'RedisCacheComponentsHandler.get() Error occurred while getting cache entry. Returning undefined so site can continue to serve content while cache is disabled. The original error was:',
354
- error,
355
- killContainerOnErrorCount++,
356
- );
357
- return undefined;
358
- }
359
- }
360
-
361
- async set(
362
- cacheKey: string,
363
- pendingEntry: Promise<CacheComponentsEntry>,
364
- ): Promise<void> {
365
- try {
366
- await this.assertClientIsReady();
367
-
368
- const entry = await pendingEntry;
369
-
370
- const [storeStream] = entry.value.tee();
371
-
372
- // Don't mutate entry.value as Next.js may still be using it internally
373
- // entry.value = forwardStream;
374
-
375
- const buffer = await streamToBuffer(storeStream);
376
-
377
- const stored: StoredCacheEntry = {
378
- value: Buffer.from(buffer).toString('base64'),
379
- tags: entry.tags || [],
380
- stale: entry.stale,
381
- timestamp: entry.timestamp,
382
- expire: entry.expire,
383
- revalidate: entry.revalidate,
384
- };
385
-
386
- let serialized: string;
387
- try {
388
- const cleanStored = {
389
- value: stored.value,
390
- tags: Array.isArray(stored.tags) ? [...stored.tags] : [],
391
- stale: Number(stored.stale),
392
- timestamp: Number(stored.timestamp),
393
- expire: Number(stored.expire),
394
- revalidate: Number(stored.revalidate),
395
- };
396
- serialized = JSON.stringify(cleanStored);
397
- } catch (jsonError) {
398
- console.error('JSON.stringify error:', jsonError);
399
- console.error('Stored object:', stored);
400
- throw jsonError;
401
- }
402
-
403
- if (this.redisGetDeduplication) {
404
- this.redisDeduplicationHandler.seedRequestReturn(cacheKey, serialized);
405
- }
406
-
407
- // expire is already a duration in seconds, use it directly
408
- const ttlSeconds =
409
- Number.isFinite(stored.expire) && stored.expire > 0
410
- ? Math.floor(stored.expire)
411
- : undefined;
412
-
413
- const redisKey = `${this.keyPrefix}${cacheKey}`;
414
-
415
- const setOperation = redisErrorHandler(
416
- 'RedisCacheComponentsHandler.set(), operation: set ' + redisKey,
417
- this.client.set(redisKey, serialized, {
418
- ...(ttlSeconds ? { EX: ttlSeconds } : {}),
419
- }),
420
- );
421
-
422
- let tagsOperation: Promise<void> | undefined;
423
- const tags = stored.tags || [];
424
- if (tags.length > 0) {
425
- const currentTags = this.sharedTagsMap.get(cacheKey);
426
- const currentIsSameAsNew =
427
- currentTags?.length === tags.length &&
428
- currentTags.every((v) => tags.includes(v)) &&
429
- tags.every((v) => currentTags!.includes(v));
430
-
431
- if (!currentIsSameAsNew) {
432
- tagsOperation = this.sharedTagsMap.set(cacheKey, [...tags]);
433
- }
434
- }
435
-
436
- await Promise.all([setOperation, tagsOperation]);
437
- } catch (error) {
438
- console.error(
439
- 'RedisCacheComponentsHandler.set() Error occurred while setting cache entry. The original error was:',
440
- error,
441
- killContainerOnErrorCount++,
442
- );
443
- throw error;
444
- }
445
- }
446
-
447
- async refreshTags(): Promise<void> {
448
- await this.assertClientIsReady();
449
- }
450
-
451
- async getExpiration(tags: string[]): Promise<number> {
452
- try {
453
- await this.assertClientIsReady();
454
- return this.computeMaxRevalidation(tags || []);
455
- } catch (error) {
456
- console.error(
457
- 'RedisCacheComponentsHandler.getExpiration() Error occurred while getting expiration for tags. The original error was:',
458
- error,
459
- );
460
- return 0;
461
- }
462
- }
463
-
464
- async updateTags(
465
- tags: string[],
466
- _durations?: { expire?: number },
467
- ): Promise<void> {
468
- try {
469
- // Mark optional argument as used to satisfy lint rules while keeping the signature
470
- void _durations;
471
- await this.assertClientIsReady();
472
- const now = Date.now();
473
-
474
- const tagsSet = new Set(tags || []);
475
-
476
- for (const tag of tagsSet) {
477
- await this.revalidatedTagsMap.set(tag, now);
478
- }
479
-
480
- const keysToDelete: Set<string> = new Set();
481
-
482
- for (const [key, storedTags] of this.sharedTagsMap.entries()) {
483
- if (storedTags.some((tag) => tagsSet.has(tag))) {
484
- keysToDelete.add(key);
485
- }
486
- }
487
-
488
- if (keysToDelete.size === 0) {
489
- return;
490
- }
491
-
492
- const cacheKeys = Array.from(keysToDelete);
493
-
494
- // Construct full Redis keys (same format as in get/set)
495
- const fullRedisKeys = cacheKeys.map((key) => `${this.keyPrefix}${key}`);
496
-
497
- await redisErrorHandler(
498
- 'RedisCacheComponentsHandler.updateTags(), operation: unlink',
499
- this.client.unlink(fullRedisKeys),
500
- );
501
-
502
- if (this.redisGetDeduplication && this.inMemoryCachingTime > 0) {
503
- for (const key of keysToDelete) {
504
- this.inMemoryDeduplicationCache.delete(key);
505
- }
506
- }
507
-
508
- // Delete from sharedTagsMap
509
- const deleteTagsOperation = this.sharedTagsMap.delete(cacheKeys);
510
- await deleteTagsOperation;
511
- } catch (error) {
512
- console.error(
513
- 'RedisCacheComponentsHandler.updateTags() Error occurred while updating tags. The original error was:',
514
- error,
515
- killContainerOnErrorCount++,
516
- );
517
- throw error;
518
- }
519
- }
520
- }
521
-
522
- let singletonHandler: CacheComponentsHandler | undefined;
523
-
524
- export function getRedisCacheComponentsHandler(
525
- options: CreateCacheComponentsHandlerOptions = {},
526
- ): CacheComponentsHandler {
527
- if (!singletonHandler) {
528
- singletonHandler = new RedisCacheComponentsHandler(options);
529
- }
530
- return singletonHandler;
531
- }
532
-
533
- // Lazily resolve the default Cache Components handler.
534
- //
535
- // Constructing a RedisCacheComponentsHandler opens a Redis connection in its
536
- // constructor. Building the singleton at module-eval time therefore means that simply
537
- // *importing this package* — e.g. only for `RedisStringsHandler` (the legacy
538
- // `cacheHandler`), with Cache Components never enabled — eagerly connects to Redis,
539
- // defaulting to `redis://localhost:6379` when neither `REDIS_URL` nor `REDISHOST` is
540
- // set. In a deployment whose Redis is not on localhost that yields a non-stop
541
- // `RedisCacheComponentsHandler client error ECONNREFUSED 127.0.0.1:6379` reconnect
542
- // loop, and it also makes a consumer's later `getRedisCacheComponentsHandler(options)`
543
- // a no-op, because the singleton was already built with defaults (see #84).
544
- //
545
- // Defer construction to first use via a Proxy: importing the package never connects, a
546
- // consumer that configures the handler via `getRedisCacheComponentsHandler(options)`
547
- // before it is first used has that configuration honored, and a consumer that never
548
- // touches Cache Components never opens a Redis connection at all.
549
- let resolvedHandler: CacheComponentsHandler | undefined;
550
-
551
- export const redisCacheHandler: CacheComponentsHandler = new Proxy(
552
- {} as CacheComponentsHandler,
553
- {
554
- get(_target, prop) {
555
- if (!resolvedHandler) {
556
- resolvedHandler = getRedisCacheComponentsHandler();
557
- }
558
- const value = resolvedHandler[prop as keyof CacheComponentsHandler];
559
- return typeof value === 'function'
560
- ? (value as (...args: unknown[]) => unknown).bind(resolvedHandler)
561
- : value;
562
- },
563
- has(_target, prop) {
564
- return prop in RedisCacheComponentsHandler.prototype;
565
- },
566
- },
567
- );
@@ -1,53 +0,0 @@
1
- import RedisStringsHandler, {
2
- CreateRedisStringsHandlerOptions,
3
- } from './RedisStringsHandler';
4
- import { debugVerbose } from './utils/debug';
5
- import { resolveKeyPrefix } from './utils/prefix';
6
-
7
- let cachedHandler: RedisStringsHandler;
8
-
9
- type NextCacheHandlerOptions = CreateRedisStringsHandlerOptions & {
10
- serverDistDir?: string;
11
- };
12
-
13
- export default class CachedHandler {
14
- constructor(options: NextCacheHandlerOptions) {
15
- if (!cachedHandler) {
16
- console.log('created cached handler');
17
- const keyPrefix = resolveKeyPrefix({
18
- optionKeyPrefix: options.keyPrefix,
19
- serverDistDir: options.serverDistDir,
20
- env: process.env,
21
- });
22
-
23
- cachedHandler = new RedisStringsHandler({
24
- ...options,
25
- keyPrefix,
26
- });
27
- }
28
- }
29
- get(
30
- ...args: Parameters<RedisStringsHandler['get']>
31
- ): ReturnType<RedisStringsHandler['get']> {
32
- debugVerbose('CachedHandler.get called with', args);
33
- return cachedHandler.get(...args);
34
- }
35
- set(
36
- ...args: Parameters<RedisStringsHandler['set']>
37
- ): ReturnType<RedisStringsHandler['set']> {
38
- debugVerbose('CachedHandler.set called with', args);
39
- return cachedHandler.set(...args);
40
- }
41
- revalidateTag(
42
- ...args: Parameters<RedisStringsHandler['revalidateTag']>
43
- ): ReturnType<RedisStringsHandler['revalidateTag']> {
44
- debugVerbose('CachedHandler.revalidateTag called with', args);
45
- return cachedHandler.revalidateTag(...args);
46
- }
47
- resetRequestCache(
48
- ...args: Parameters<RedisStringsHandler['resetRequestCache']>
49
- ): ReturnType<RedisStringsHandler['resetRequestCache']> {
50
- // debug("CachedHandler.resetRequestCache called with", args);
51
- return cachedHandler.resetRequestCache(...args);
52
- }
53
- }