@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.
- package/README.md +87 -24
- package/dist/index.d.mts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +291 -116
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +288 -115
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -6
- package/.cursor/skills/testing/SKILL.md +0 -121
- package/.github/workflows/ci.yml +0 -309
- package/.github/workflows/pages.yml +0 -38
- package/.github/workflows/release.yml +0 -207
- package/.prettierrc.json +0 -6
- package/.vscode/settings.json +0 -10
- package/ARCHITECTURE.md +0 -431
- package/CHANGELOG.md +0 -411
- package/commitlint.config.cjs +0 -4
- package/docker/redis.conf +0 -1
- package/docs/index.html +0 -140
- package/docs/robots.txt +0 -4
- package/docs/sitemap.xml +0 -8
- package/docs/styles.css +0 -141
- package/eslint.config.mjs +0 -26
- package/hooks/commit-msg +0 -10
- package/hooks/pre-commit +0 -11
- package/playwright.config.ts +0 -18
- package/release.config.cjs +0 -31
- package/scripts/prepare.sh +0 -7
- package/scripts/setup-git.sh +0 -8
- package/scripts/setup-repo-name.sh +0 -17
- package/scripts/vitest-run-staged.cjs +0 -44
- package/src/CacheComponentsHandler.ts +0 -567
- package/src/CachedHandler.ts +0 -53
- package/src/DeduplicatedRequestHandler.ts +0 -110
- package/src/RedisStringsHandler.ts +0 -937
- package/src/SyncedMap.ts +0 -482
- package/src/ZodHandler.ts +0 -45
- package/src/index.ts +0 -16
- package/src/serializer.ts +0 -59
- package/src/utils/debug.ts +0 -30
- package/src/utils/json.ts +0 -49
- package/src/utils/prefix.ts +0 -44
- package/test/README.md +0 -194
- package/test/nextjs-test-projects/next-app-15-4-11/README.md +0 -36
- package/test/nextjs-test-projects/next-app-15-4-11/eslint.config.mjs +0 -16
- package/test/nextjs-test-projects/next-app-15-4-11/next.config.js +0 -9
- package/test/nextjs-test-projects/next-app-15-4-11/package-lock.json +0 -5969
- package/test/nextjs-test-projects/next-app-15-4-11/package.json +0 -29
- package/test/nextjs-test-projects/next-app-15-4-11/pnpm-lock.yaml +0 -3726
- package/test/nextjs-test-projects/next-app-15-4-11/postcss.config.mjs +0 -5
- package/test/nextjs-test-projects/next-app-15-4-11/public/file.svg +0 -1
- package/test/nextjs-test-projects/next-app-15-4-11/public/globe.svg +0 -1
- package/test/nextjs-test-projects/next-app-15-4-11/public/next.svg +0 -1
- package/test/nextjs-test-projects/next-app-15-4-11/public/vercel.svg +0 -1
- package/test/nextjs-test-projects/next-app-15-4-11/public/window.svg +0 -1
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/cached-static-fetch/route.ts +0 -18
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidatePath/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidateTag/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/revalidated-fetch/route.ts +0 -17
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/api/uncached-fetch/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/layout.tsx +0 -59
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/no-fetch/default-page/page.tsx +0 -55
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-15-4-11/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-15-4-11/tsconfig.json +0 -27
- package/test/nextjs-test-projects/next-app-16-0-11/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-0-11/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-0-11/next.config.ts +0 -10
- package/test/nextjs-test-projects/next-app-16-0-11/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-0-11/pnpm-lock.yaml +0 -4163
- package/test/nextjs-test-projects/next-app-16-0-11/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/cached-static-fetch/route.ts +0 -18
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidatePath/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidateTag/route.ts +0 -20
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/revalidated-fetch/route.ts +0 -17
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/api/uncached-fetch/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/layout.tsx +0 -59
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/no-fetch/default-page/page.tsx +0 -55
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-0-11/src/app/update-tag-test/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-0-11/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/cache-handler.js +0 -3
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/next.config.ts +0 -13
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/pnpm-lock.yaml +0 -4206
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/file.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/globe.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/next.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/vercel.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/public/window.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/page.tsx +0 -90
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/layout.tsx +0 -57
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/update-tag-test/page.tsx +0 -22
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-16-2-6/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-2-6/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-2-6/next.config.ts +0 -7
- package/test/nextjs-test-projects/next-app-16-2-6/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-2-6/pnpm-lock.yaml +0 -4165
- package/test/nextjs-test-projects/next-app-16-2-6/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/cached-static-fetch/route.ts +0 -18
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidatePath/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidateTag/route.ts +0 -20
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/revalidated-fetch/route.ts +0 -17
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/api/uncached-fetch/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/layout.tsx +0 -59
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/no-fetch/default-page/page.tsx +0 -55
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-2-6/src/app/update-tag-test/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-2-6/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/cache-handler.js +0 -3
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/next.config.ts +0 -13
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/pnpm-lock.yaml +0 -4165
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/file.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/globe.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/next.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/vercel.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/public/window.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/page.tsx +0 -90
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/layout.tsx +0 -57
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/update-tag-test/page.tsx +0 -22
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-16-3-0/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-3-0/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-3-0/next.config.ts +0 -7
- package/test/nextjs-test-projects/next-app-16-3-0/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-3-0/pnpm-lock.yaml +0 -4284
- package/test/nextjs-test-projects/next-app-16-3-0/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/cached-static-fetch/route.ts +0 -18
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/nested-fetch-in-api-route/revalidated-fetch/route.ts +0 -27
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidatePath/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidateTag/route.ts +0 -20
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/revalidated-fetch/route.ts +0 -17
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/api/uncached-fetch/route.ts +0 -15
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/layout.tsx +0 -59
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--default-page/page.tsx +0 -34
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/cached-static-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/no-fetch/default-page/page.tsx +0 -55
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--default-page/page.tsx +0 -35
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/revalidated-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/default--force-dynamic-page/page.tsx +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--default-page/page.tsx +0 -32
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/pages/uncached-fetch/revalidate15--force-dynamic-page/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-3-0/src/app/update-tag-test/page.tsx +0 -25
- package/test/nextjs-test-projects/next-app-16-3-0/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/README.md +0 -36
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/cache-handler.js +0 -3
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/next.config.ts +0 -13
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/package.json +0 -28
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/pnpm-lock.yaml +0 -4284
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/postcss.config.mjs +0 -7
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/file.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/globe.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/next.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/vercel.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/public/window.svg +0 -1
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-static-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-cachelife/route.ts +0 -24
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/cached-with-tag/route.ts +0 -21
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidate-tag/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/revalidated-fetch/route.ts +0 -19
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/cachelife-short/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/page.tsx +0 -90
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/runtime-data-suspense/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/stale-while-revalidate/page.tsx +0 -130
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/tag-invalidation/page.tsx +0 -127
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/use-cache-nondeterministic/page.tsx +0 -110
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/favicon.ico +0 -0
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/globals.css +0 -26
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/layout.tsx +0 -57
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/page.tsx +0 -755
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/revalidation-interface.tsx +0 -267
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/update-tag-test/page.tsx +0 -22
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-app-customized/README.md +0 -36
- package/test/nextjs-test-projects/next-app-customized/customized-cache-handler.js +0 -34
- package/test/nextjs-test-projects/next-app-customized/eslint.config.mjs +0 -16
- package/test/nextjs-test-projects/next-app-customized/next.config.js +0 -6
- package/test/nextjs-test-projects/next-pages-16-2-6/README.md +0 -16
- package/test/nextjs-test-projects/next-pages-16-2-6/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-pages-16-2-6/next.config.ts +0 -7
- package/test/nextjs-test-projects/next-pages-16-2-6/package.json +0 -26
- package/test/nextjs-test-projects/next-pages-16-2-6/pnpm-lock.yaml +0 -3896
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/api/revalidate.ts +0 -24
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/index.tsx +0 -11
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/isr/[slug].tsx +0 -49
- package/test/nextjs-test-projects/next-pages-16-2-6/src/pages/static-forever.tsx +0 -20
- package/test/nextjs-test-projects/next-pages-16-2-6/tsconfig.json +0 -34
- package/test/nextjs-test-projects/next-pages-16-3-0/README.md +0 -16
- package/test/nextjs-test-projects/next-pages-16-3-0/eslint.config.mjs +0 -18
- package/test/nextjs-test-projects/next-pages-16-3-0/next.config.ts +0 -7
- package/test/nextjs-test-projects/next-pages-16-3-0/package.json +0 -26
- package/test/nextjs-test-projects/next-pages-16-3-0/pnpm-lock.yaml +0 -3939
- package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/api/revalidate.ts +0 -24
- package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/index.tsx +0 -11
- package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/isr/[slug].tsx +0 -49
- package/test/nextjs-test-projects/next-pages-16-3-0/src/pages/static-forever.tsx +0 -20
- package/test/nextjs-test-projects/next-pages-16-3-0/tsconfig.json +0 -34
- package/test/playwright/cache-lab.spec.ts +0 -157
- package/test/playwright/update-tag.spec.ts +0 -33
- package/test/vitest/integration/build-id-prefix.integration.test.ts +0 -102
- package/test/vitest/integration/cache-components/cache-components.integration.test.ts +0 -231
- package/test/vitest/integration/cache-components/redis-kill-reconnect.test.ts +0 -65
- package/test/vitest/integration/cache-components/redis-quit-vs-disconnect.test.ts +0 -59
- package/test/vitest/integration/cache-components/redis-subscriber-outage.test.ts +0 -100
- package/test/vitest/integration/cache-components/scripts/redis-kill-reconnect.ts +0 -243
- package/test/vitest/integration/cache-components/scripts/redis-quit-vs-disconnect.ts +0 -113
- package/test/vitest/integration/cache-components/scripts/redis-subscriber-outage.ts +0 -379
- package/test/vitest/integration/cache-components/scripts/redis-test-helpers.ts +0 -155
- package/test/vitest/integration/nextjs-cache-handler.integration.test.ts +0 -945
- package/test/vitest/integration/pages-router.integration.test.ts +0 -420
- package/test/vitest/unit/SyncedMap-reconnect-repro.test.ts +0 -154
- package/test/vitest/unit/index.test.ts +0 -173
- package/test/vitest/unit/pages-router-kinds.test.ts +0 -292
- package/test/vitest/unit/reconnect-socket-already-opened.test.ts +0 -117
- package/test/vitest/unit/serializer.test.ts +0 -182
- package/test/vitest/unit/utils/prefix.test.ts +0 -115
- package/tsconfig.json +0 -18
- package/tsup.config.ts +0 -14
- package/vite.config.ts +0 -34
- package/vitest.cache-components.config.ts +0 -16
package/dist/index.mjs
CHANGED
|
@@ -22,6 +22,12 @@ function debugVerbose(color, ...args) {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// src/utils/redisConnection.ts
|
|
26
|
+
var PHASE_PRODUCTION_BUILD = "phase-production-build";
|
|
27
|
+
function shouldDeferRedisConnection() {
|
|
28
|
+
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
// src/SyncedMap.ts
|
|
26
32
|
var SYNC_CHANNEL_SUFFIX = ":sync-channel:";
|
|
27
33
|
var SyncedMap = class {
|
|
@@ -47,6 +53,10 @@ var SyncedMap = class {
|
|
|
47
53
|
});
|
|
48
54
|
}
|
|
49
55
|
async setup() {
|
|
56
|
+
if (shouldDeferRedisConnection()) {
|
|
57
|
+
this.setupLockResolve();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
50
60
|
let setupPromises = [];
|
|
51
61
|
if (!this.customizedSync?.withoutRedisHashmap) {
|
|
52
62
|
setupPromises.push(this.initialSync());
|
|
@@ -57,45 +67,54 @@ var SyncedMap = class {
|
|
|
57
67
|
this.setupLockResolve();
|
|
58
68
|
}
|
|
59
69
|
async initialSync() {
|
|
60
|
-
let cursor = 0;
|
|
61
|
-
const hScanOptions = { COUNT: this.querySize };
|
|
70
|
+
let cursor = "0";
|
|
62
71
|
try {
|
|
63
72
|
do {
|
|
64
|
-
const
|
|
65
|
-
"SyncedMap.initialSync(), operation:
|
|
66
|
-
this.client.
|
|
73
|
+
const [nextCursor, tuples] = await redisErrorHandler(
|
|
74
|
+
"SyncedMap.initialSync(), operation: HSCAN " + this.keyPrefix + this.redisKey,
|
|
75
|
+
this.client.sendCommand([
|
|
76
|
+
"HSCAN",
|
|
67
77
|
this.keyPrefix + this.redisKey,
|
|
68
78
|
cursor,
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
"COUNT",
|
|
80
|
+
String(this.querySize)
|
|
81
|
+
])
|
|
71
82
|
);
|
|
72
|
-
for (
|
|
83
|
+
for (let i = 0; i < tuples.length; i += 2) {
|
|
84
|
+
const field = tuples[i];
|
|
73
85
|
if (this.filterKeys(field)) {
|
|
74
|
-
|
|
75
|
-
this.map.set(field, parsedValue);
|
|
86
|
+
this.map.set(field, JSON.parse(tuples[i + 1]));
|
|
76
87
|
}
|
|
77
88
|
}
|
|
78
|
-
cursor =
|
|
79
|
-
} while (cursor !== 0);
|
|
80
|
-
|
|
89
|
+
cursor = nextCursor;
|
|
90
|
+
} while (cursor !== "0");
|
|
91
|
+
if (!this.customizedSync?.withoutOrphanCleanup) {
|
|
92
|
+
await this.cleanupKeysNotInRedis();
|
|
93
|
+
}
|
|
81
94
|
} catch (error) {
|
|
82
95
|
console.error("Error during initial sync:", error);
|
|
83
96
|
throw error;
|
|
84
97
|
}
|
|
85
98
|
}
|
|
86
99
|
async cleanupKeysNotInRedis() {
|
|
87
|
-
let cursor = 0;
|
|
88
|
-
const scanOptions = { COUNT: this.querySize, MATCH: `${this.keyPrefix}*` };
|
|
100
|
+
let cursor = "0";
|
|
89
101
|
let remoteKeys = [];
|
|
90
102
|
try {
|
|
91
103
|
do {
|
|
92
|
-
const
|
|
93
|
-
"SyncedMap.cleanupKeysNotInRedis(), operation:
|
|
94
|
-
this.client.
|
|
104
|
+
const [nextCursor, keys] = await redisErrorHandler(
|
|
105
|
+
"SyncedMap.cleanupKeysNotInRedis(), operation: SCAN " + this.keyPrefix,
|
|
106
|
+
this.client.sendCommand([
|
|
107
|
+
"SCAN",
|
|
108
|
+
cursor,
|
|
109
|
+
"MATCH",
|
|
110
|
+
`${this.keyPrefix}*`,
|
|
111
|
+
"COUNT",
|
|
112
|
+
String(this.querySize)
|
|
113
|
+
])
|
|
95
114
|
);
|
|
96
|
-
remoteKeys = remoteKeys.concat(
|
|
97
|
-
cursor =
|
|
98
|
-
} while (cursor !== 0);
|
|
115
|
+
remoteKeys = remoteKeys.concat(keys);
|
|
116
|
+
cursor = nextCursor;
|
|
117
|
+
} while (cursor !== "0");
|
|
99
118
|
const remoteKeysSet = new Set(
|
|
100
119
|
remoteKeys.map((key) => key.substring(this.keyPrefix.length))
|
|
101
120
|
);
|
|
@@ -489,6 +508,37 @@ var jsonCacheValueSerializer = {
|
|
|
489
508
|
}
|
|
490
509
|
};
|
|
491
510
|
|
|
511
|
+
// src/utils/cacheTtl.ts
|
|
512
|
+
function resolveCacheEntryTtlSeconds(ctx, data, options) {
|
|
513
|
+
const expire = ctx.cacheControl?.expire;
|
|
514
|
+
if (Number.isFinite(expire) && expire > 0) {
|
|
515
|
+
return Math.max(1, Math.ceil(expire));
|
|
516
|
+
}
|
|
517
|
+
const revalidate = resolveRevalidateValue(ctx, data);
|
|
518
|
+
if (revalidate === false) {
|
|
519
|
+
return options.estimateExpireAge(options.defaultStaleAge);
|
|
520
|
+
}
|
|
521
|
+
if (revalidate && Number.isSafeInteger(revalidate) && revalidate > 0) {
|
|
522
|
+
return options.estimateExpireAge(revalidate);
|
|
523
|
+
}
|
|
524
|
+
return void 0;
|
|
525
|
+
}
|
|
526
|
+
function resolveRevalidateValue(ctx, data) {
|
|
527
|
+
if (data?.kind === "FETCH" && data.revalidate !== void 0) {
|
|
528
|
+
return data.revalidate;
|
|
529
|
+
}
|
|
530
|
+
if (ctx.revalidate !== void 0) {
|
|
531
|
+
return ctx.revalidate;
|
|
532
|
+
}
|
|
533
|
+
if (ctx.cacheControl?.revalidate !== void 0) {
|
|
534
|
+
return ctx.cacheControl.revalidate;
|
|
535
|
+
}
|
|
536
|
+
if (data?.revalidate !== void 0) {
|
|
537
|
+
return data.revalidate;
|
|
538
|
+
}
|
|
539
|
+
return void 0;
|
|
540
|
+
}
|
|
541
|
+
|
|
492
542
|
// src/RedisStringsHandler.ts
|
|
493
543
|
function redisErrorHandler(debugInfo, redisCommandResult) {
|
|
494
544
|
const beforeTimestamp = performance.now();
|
|
@@ -566,6 +616,7 @@ var RedisStringsHandler = class {
|
|
|
566
616
|
this.killContainerOnErrorThreshold = killContainerOnErrorThreshold;
|
|
567
617
|
this.getTimeoutMs = getTimeoutMs;
|
|
568
618
|
this.valueSerializer = valueSerializer;
|
|
619
|
+
this.redisConnectionDeferred = shouldDeferRedisConnection();
|
|
569
620
|
try {
|
|
570
621
|
this.client = createClient({
|
|
571
622
|
url: redisUrl,
|
|
@@ -604,12 +655,14 @@ var RedisStringsHandler = class {
|
|
|
604
655
|
}, 500);
|
|
605
656
|
}
|
|
606
657
|
});
|
|
607
|
-
this.
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
658
|
+
if (!this.redisConnectionDeferred) {
|
|
659
|
+
this.client.connect().then(() => {
|
|
660
|
+
debug("green", "Redis client connected.");
|
|
661
|
+
}).catch((error) => {
|
|
662
|
+
console.error("Failed to connect Redis client:", error);
|
|
663
|
+
throw error;
|
|
664
|
+
});
|
|
665
|
+
}
|
|
613
666
|
} catch (error) {
|
|
614
667
|
console.error("Failed to initialize Redis client");
|
|
615
668
|
throw error;
|
|
@@ -631,6 +684,7 @@ var RedisStringsHandler = class {
|
|
|
631
684
|
database,
|
|
632
685
|
querySize: revalidateTagQuerySize,
|
|
633
686
|
filterKeys,
|
|
687
|
+
customizedSync: { withoutOrphanCleanup: true },
|
|
634
688
|
resyncIntervalMs: avgResyncIntervalMs + avgResyncIntervalMs / 10 + Math.random() * (avgResyncIntervalMs / 10)
|
|
635
689
|
});
|
|
636
690
|
this.inMemoryDeduplicationCache = new SyncedMap({
|
|
@@ -700,11 +754,17 @@ var RedisStringsHandler = class {
|
|
|
700
754
|
}
|
|
701
755
|
this.clientReadyCalls = 0;
|
|
702
756
|
if (!this.client.isReady) {
|
|
757
|
+
if (this.redisConnectionDeferred) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
703
760
|
throw new Error(
|
|
704
761
|
"assertClientIsReady: Redis client is not ready yet or connection is lost."
|
|
705
762
|
);
|
|
706
763
|
}
|
|
707
764
|
}
|
|
765
|
+
isClientUnavailable() {
|
|
766
|
+
return this.redisConnectionDeferred || !this.client.isReady;
|
|
767
|
+
}
|
|
708
768
|
async get(key, ctx) {
|
|
709
769
|
try {
|
|
710
770
|
if (!SUPPORTED_GET_KINDS.includes(ctx.kind)) {
|
|
@@ -718,6 +778,9 @@ var RedisStringsHandler = class {
|
|
|
718
778
|
}
|
|
719
779
|
debug("green", "RedisStringsHandler.get() called with", key, ctx);
|
|
720
780
|
await this.assertClientIsReady();
|
|
781
|
+
if (this.isClientUnavailable()) {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
721
784
|
const clientGet = this.redisGetDeduplication ? this.deduplicatedRedisGet(key) : this.redisGet;
|
|
722
785
|
const redisGetOperation = clientGet(
|
|
723
786
|
commandOptions({ signal: AbortSignal.timeout(this.getTimeoutMs) }),
|
|
@@ -851,6 +914,9 @@ var RedisStringsHandler = class {
|
|
|
851
914
|
);
|
|
852
915
|
}
|
|
853
916
|
await this.assertClientIsReady();
|
|
917
|
+
if (this.isClientUnavailable()) {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
854
920
|
if (data?.kind === "APP_PAGE" || data?.kind === "APP_ROUTE") {
|
|
855
921
|
const tags = data.headers["x-next-cache-tags"]?.split(",");
|
|
856
922
|
ctx.tags = [...ctx.tags || [], ...tags || []];
|
|
@@ -873,18 +939,14 @@ var RedisStringsHandler = class {
|
|
|
873
939
|
serializedCacheEntry
|
|
874
940
|
);
|
|
875
941
|
}
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
// matters for those older, non-discriminated shapes.
|
|
881
|
-
data?.revalidate
|
|
882
|
-
);
|
|
883
|
-
const expireAt = revalidate && Number.isSafeInteger(revalidate) && revalidate > 0 ? this.estimateExpireAge(revalidate) : this.estimateExpireAge(this.defaultStaleAge);
|
|
942
|
+
const expireAt = resolveCacheEntryTtlSeconds(ctx, data, {
|
|
943
|
+
estimateExpireAge: this.estimateExpireAge,
|
|
944
|
+
defaultStaleAge: this.defaultStaleAge
|
|
945
|
+
});
|
|
884
946
|
const setOperation = redisErrorHandler(
|
|
885
947
|
"RedisStringsHandler.set(), operation: set " + this.keyPrefix + " " + key,
|
|
886
948
|
this.client.set(this.keyPrefix + key, serializedCacheEntry, {
|
|
887
|
-
EX: expireAt
|
|
949
|
+
...expireAt ? { EX: expireAt } : {}
|
|
888
950
|
})
|
|
889
951
|
);
|
|
890
952
|
debug(
|
|
@@ -947,6 +1009,9 @@ var RedisStringsHandler = class {
|
|
|
947
1009
|
);
|
|
948
1010
|
const tags = new Set([tagOrTags || []].flat());
|
|
949
1011
|
await this.assertClientIsReady();
|
|
1012
|
+
if (this.isClientUnavailable()) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
950
1015
|
const keysToDelete = /* @__PURE__ */ new Set();
|
|
951
1016
|
for (const tag of tags) {
|
|
952
1017
|
if (tag.startsWith(NEXT_CACHE_IMPLICIT_TAG_ID)) {
|
|
@@ -1085,6 +1150,88 @@ var CachedHandler = class {
|
|
|
1085
1150
|
|
|
1086
1151
|
// src/CacheComponentsHandler.ts
|
|
1087
1152
|
import { commandOptions as commandOptions2, createClient as createClient2 } from "redis";
|
|
1153
|
+
|
|
1154
|
+
// src/utils/compareAndUnlink.ts
|
|
1155
|
+
var COMPARE_AND_UNLINK = `
|
|
1156
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
|
1157
|
+
return redis.call('UNLINK', KEYS[1])
|
|
1158
|
+
end
|
|
1159
|
+
return 0
|
|
1160
|
+
`;
|
|
1161
|
+
async function compareAndUnlink(client, key, expected) {
|
|
1162
|
+
const deleted = await client.eval(COMPARE_AND_UNLINK, {
|
|
1163
|
+
keys: [key],
|
|
1164
|
+
arguments: [expected]
|
|
1165
|
+
});
|
|
1166
|
+
return deleted === 1 || deleted === 1n;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/utils/tagRevalidation.ts
|
|
1170
|
+
function normalizeTagManifest(stored, now = Date.now()) {
|
|
1171
|
+
if (typeof stored === "number" && Number.isFinite(stored)) {
|
|
1172
|
+
return { expired: Math.min(stored, now) };
|
|
1173
|
+
}
|
|
1174
|
+
if (stored && typeof stored === "object") {
|
|
1175
|
+
const rec = stored;
|
|
1176
|
+
const stale = typeof rec.stale === "number" && Number.isFinite(rec.stale) ? rec.stale : typeof rec.last === "number" && Number.isFinite(rec.last) ? rec.last : void 0;
|
|
1177
|
+
const expired = typeof rec.expired === "number" && Number.isFinite(rec.expired) ? rec.expired : typeof rec.pending === "number" && Number.isFinite(rec.pending) ? rec.pending : void 0;
|
|
1178
|
+
return {
|
|
1179
|
+
...stale !== void 0 ? { stale } : {},
|
|
1180
|
+
...expired !== void 0 ? { expired } : {}
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
return {};
|
|
1184
|
+
}
|
|
1185
|
+
function applyTagUpdate(existing, durations, now) {
|
|
1186
|
+
if (durations) {
|
|
1187
|
+
const updates = { ...existing };
|
|
1188
|
+
updates.stale = now;
|
|
1189
|
+
if (durations.expire !== void 0) {
|
|
1190
|
+
updates.expired = now + durations.expire * 1e3;
|
|
1191
|
+
}
|
|
1192
|
+
return updates;
|
|
1193
|
+
}
|
|
1194
|
+
return {
|
|
1195
|
+
...existing,
|
|
1196
|
+
expired: now
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
function persistableTagManifest(entry, now) {
|
|
1200
|
+
if (typeof entry.expired === "number" && entry.expired <= now && (entry.stale === void 0 || entry.stale <= entry.expired)) {
|
|
1201
|
+
return entry.expired;
|
|
1202
|
+
}
|
|
1203
|
+
return entry;
|
|
1204
|
+
}
|
|
1205
|
+
function areTagsExpired(tags, entryTimestamp, now, getEntry) {
|
|
1206
|
+
for (const tag of tags) {
|
|
1207
|
+
const expiredAt = getEntry(tag)?.expired;
|
|
1208
|
+
if (typeof expiredAt === "number" && expiredAt <= now && expiredAt > entryTimestamp) {
|
|
1209
|
+
return true;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
function areTagsStale(tags, entryTimestamp, getEntry) {
|
|
1215
|
+
for (const tag of tags) {
|
|
1216
|
+
const staleAt = getEntry(tag)?.stale ?? 0;
|
|
1217
|
+
if (typeof staleAt === "number" && staleAt > entryTimestamp) {
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
function maxExpiredTimestamp(tags, getEntry) {
|
|
1224
|
+
let max = 0;
|
|
1225
|
+
for (const tag of tags) {
|
|
1226
|
+
const expired = getEntry(tag)?.expired || 0;
|
|
1227
|
+
if (expired > max) {
|
|
1228
|
+
max = expired;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return max;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// src/CacheComponentsHandler.ts
|
|
1088
1235
|
var REVALIDATED_TAGS_KEY2 = "__cacheComponents_revalidated_tags__";
|
|
1089
1236
|
var SHARED_TAGS_KEY = "__cacheComponents_sharedTags__";
|
|
1090
1237
|
var killContainerOnErrorCount2 = 0;
|
|
@@ -1142,6 +1289,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1142
1289
|
this.getTimeoutMs = getTimeoutMs;
|
|
1143
1290
|
this.redisGetDeduplication = redisGetDeduplication;
|
|
1144
1291
|
this.inMemoryCachingTime = inMemoryCachingTime;
|
|
1292
|
+
this.redisConnectionDeferred = shouldDeferRedisConnection();
|
|
1145
1293
|
this.client = createClient2({
|
|
1146
1294
|
url: redisUrl,
|
|
1147
1295
|
pingInterval: 1e4,
|
|
@@ -1177,18 +1325,20 @@ var RedisCacheComponentsHandler = class {
|
|
|
1177
1325
|
}, 500);
|
|
1178
1326
|
}
|
|
1179
1327
|
});
|
|
1180
|
-
this.
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1328
|
+
if (!this.redisConnectionDeferred) {
|
|
1329
|
+
this.client.connect().then(() => {
|
|
1330
|
+
debug("green", "RedisCacheComponentsHandler client connected.");
|
|
1331
|
+
}).catch(() => {
|
|
1332
|
+
this.client.connect().catch((error) => {
|
|
1333
|
+
console.error(
|
|
1334
|
+
"Failed to connect RedisCacheComponentsHandler client:",
|
|
1335
|
+
error
|
|
1336
|
+
);
|
|
1337
|
+
this.client.disconnect();
|
|
1338
|
+
throw error;
|
|
1339
|
+
});
|
|
1190
1340
|
});
|
|
1191
|
-
}
|
|
1341
|
+
}
|
|
1192
1342
|
const filterKeys = (key) => key !== REVALIDATED_TAGS_KEY2 && key !== SHARED_TAGS_KEY;
|
|
1193
1343
|
this.revalidatedTagsMap = new SyncedMap({
|
|
1194
1344
|
client: this.client,
|
|
@@ -1197,6 +1347,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1197
1347
|
database,
|
|
1198
1348
|
querySize: revalidateTagQuerySize,
|
|
1199
1349
|
filterKeys,
|
|
1350
|
+
customizedSync: { withoutOrphanCleanup: true },
|
|
1200
1351
|
resyncIntervalMs: avgResyncIntervalMs + avgResyncIntervalMs / 10 + Math.random() * (avgResyncIntervalMs / 10)
|
|
1201
1352
|
});
|
|
1202
1353
|
this.sharedTagsMap = new SyncedMap({
|
|
@@ -1234,6 +1385,13 @@ var RedisCacheComponentsHandler = class {
|
|
|
1234
1385
|
}
|
|
1235
1386
|
}
|
|
1236
1387
|
async assertClientIsReady() {
|
|
1388
|
+
if (this.redisConnectionDeferred) {
|
|
1389
|
+
await Promise.all([
|
|
1390
|
+
this.revalidatedTagsMap.waitUntilReady(),
|
|
1391
|
+
this.sharedTagsMap.waitUntilReady()
|
|
1392
|
+
]);
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1237
1395
|
if (!this.client.isReady && !this.client.isOpen) {
|
|
1238
1396
|
await this.client.connect().catch((error) => {
|
|
1239
1397
|
console.error(
|
|
@@ -1248,57 +1406,76 @@ var RedisCacheComponentsHandler = class {
|
|
|
1248
1406
|
this.sharedTagsMap.waitUntilReady()
|
|
1249
1407
|
]);
|
|
1250
1408
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
max = ts;
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
return max;
|
|
1409
|
+
isClientUnavailable() {
|
|
1410
|
+
return this.redisConnectionDeferred || !this.client.isReady;
|
|
1411
|
+
}
|
|
1412
|
+
tagManifestFor(tag, now = Date.now()) {
|
|
1413
|
+
return normalizeTagManifest(this.revalidatedTagsMap.get(tag), now);
|
|
1260
1414
|
}
|
|
1261
|
-
async get(cacheKey,
|
|
1415
|
+
async get(cacheKey, _softTags) {
|
|
1416
|
+
void _softTags;
|
|
1262
1417
|
const redisKey = `${this.keyPrefix}${cacheKey}`;
|
|
1263
1418
|
try {
|
|
1264
1419
|
await this.assertClientIsReady();
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1420
|
+
if (this.isClientUnavailable()) {
|
|
1421
|
+
return void 0;
|
|
1422
|
+
}
|
|
1423
|
+
const readSerialized = (useDedup) => redisErrorHandler(
|
|
1424
|
+
"RedisCacheComponentsHandler.get(), operation: get" + (useDedup ? " deduplicated" : "") + " " + this.getTimeoutMs + "ms " + redisKey,
|
|
1425
|
+
(useDedup ? this.deduplicatedRedisGet(cacheKey) : this.redisGet)(
|
|
1269
1426
|
commandOptions2({ signal: AbortSignal.timeout(this.getTimeoutMs) }),
|
|
1270
1427
|
redisKey
|
|
1271
1428
|
)
|
|
1272
1429
|
);
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1430
|
+
let usedDedup = this.redisGetDeduplication;
|
|
1431
|
+
let serialized = await readSerialized(usedDedup);
|
|
1432
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
1433
|
+
if (!serialized) {
|
|
1434
|
+
return void 0;
|
|
1435
|
+
}
|
|
1436
|
+
const stored = JSON.parse(serialized);
|
|
1437
|
+
const now = Date.now();
|
|
1438
|
+
const tags = stored.tags || [];
|
|
1439
|
+
const expiryTime = stored.timestamp + stored.expire * 1e3;
|
|
1440
|
+
const ttlExpired = Number.isFinite(stored.expire) && stored.expire > 0 && now > expiryTime;
|
|
1441
|
+
const tagsExpired = areTagsExpired(
|
|
1442
|
+
tags,
|
|
1443
|
+
stored.timestamp,
|
|
1444
|
+
now,
|
|
1445
|
+
(tag) => this.tagManifestFor(tag, now)
|
|
1446
|
+
);
|
|
1447
|
+
if (ttlExpired || tagsExpired) {
|
|
1448
|
+
if (usedDedup) {
|
|
1449
|
+
usedDedup = false;
|
|
1450
|
+
serialized = await readSerialized(false);
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1453
|
+
const dropped = await compareAndUnlink(
|
|
1454
|
+
this.client,
|
|
1455
|
+
redisKey,
|
|
1456
|
+
serialized
|
|
1457
|
+
);
|
|
1458
|
+
if (dropped) {
|
|
1459
|
+
await this.sharedTagsMap.delete(cacheKey).catch(() => {
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
return void 0;
|
|
1463
|
+
}
|
|
1464
|
+
const valueBuffer = typeof stored.value === "string" ? new Uint8Array(Buffer.from(stored.value, "base64")) : stored.value;
|
|
1465
|
+
const entry = {
|
|
1466
|
+
...stored,
|
|
1467
|
+
value: bufferToReadableStream(valueBuffer)
|
|
1468
|
+
};
|
|
1469
|
+
if (areTagsStale(
|
|
1470
|
+
tags,
|
|
1471
|
+
stored.timestamp,
|
|
1472
|
+
(tag) => this.tagManifestFor(tag, now)
|
|
1473
|
+
)) {
|
|
1474
|
+
entry.revalidate = -1;
|
|
1475
|
+
}
|
|
1476
|
+
return entry;
|
|
1296
1477
|
}
|
|
1297
|
-
|
|
1298
|
-
return {
|
|
1299
|
-
...stored,
|
|
1300
|
-
value: bufferToReadableStream(valueBuffer)
|
|
1301
|
-
};
|
|
1478
|
+
return void 0;
|
|
1302
1479
|
} catch (error) {
|
|
1303
1480
|
console.error(
|
|
1304
1481
|
"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:",
|
|
@@ -1311,6 +1488,9 @@ var RedisCacheComponentsHandler = class {
|
|
|
1311
1488
|
async set(cacheKey, pendingEntry) {
|
|
1312
1489
|
try {
|
|
1313
1490
|
await this.assertClientIsReady();
|
|
1491
|
+
if (this.isClientUnavailable()) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1314
1494
|
const entry = await pendingEntry;
|
|
1315
1495
|
const [storeStream] = entry.value.tee();
|
|
1316
1496
|
const buffer = await streamToBuffer(storeStream);
|
|
@@ -1374,7 +1554,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1374
1554
|
async getExpiration(tags) {
|
|
1375
1555
|
try {
|
|
1376
1556
|
await this.assertClientIsReady();
|
|
1377
|
-
return
|
|
1557
|
+
return maxExpiredTimestamp(tags || [], (tag) => this.tagManifestFor(tag));
|
|
1378
1558
|
} catch (error) {
|
|
1379
1559
|
console.error(
|
|
1380
1560
|
"RedisCacheComponentsHandler.getExpiration() Error occurred while getting expiration for tags. The original error was:",
|
|
@@ -1383,37 +1563,28 @@ var RedisCacheComponentsHandler = class {
|
|
|
1383
1563
|
return 0;
|
|
1384
1564
|
}
|
|
1385
1565
|
}
|
|
1386
|
-
async updateTags(tags,
|
|
1566
|
+
async updateTags(tags, durations) {
|
|
1387
1567
|
try {
|
|
1388
|
-
void _durations;
|
|
1389
1568
|
await this.assertClientIsReady();
|
|
1390
|
-
|
|
1391
|
-
const tagsSet = new Set(tags || []);
|
|
1392
|
-
for (const tag of tagsSet) {
|
|
1393
|
-
await this.revalidatedTagsMap.set(tag, now);
|
|
1394
|
-
}
|
|
1395
|
-
const keysToDelete = /* @__PURE__ */ new Set();
|
|
1396
|
-
for (const [key, storedTags] of this.sharedTagsMap.entries()) {
|
|
1397
|
-
if (storedTags.some((tag) => tagsSet.has(tag))) {
|
|
1398
|
-
keysToDelete.add(key);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
if (keysToDelete.size === 0) {
|
|
1569
|
+
if (this.isClientUnavailable()) {
|
|
1402
1570
|
return;
|
|
1403
1571
|
}
|
|
1404
|
-
const
|
|
1405
|
-
const
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
this.
|
|
1409
|
-
|
|
1572
|
+
const now = Date.now();
|
|
1573
|
+
const updated = new Set(tags || []);
|
|
1574
|
+
for (const tag of updated) {
|
|
1575
|
+
const next = applyTagUpdate(this.tagManifestFor(tag), durations, now);
|
|
1576
|
+
await this.revalidatedTagsMap.set(
|
|
1577
|
+
tag,
|
|
1578
|
+
persistableTagManifest(next, now)
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1410
1581
|
if (this.redisGetDeduplication && this.inMemoryCachingTime > 0) {
|
|
1411
|
-
for (const key of
|
|
1412
|
-
|
|
1582
|
+
for (const [key, sharedTags] of this.sharedTagsMap.entries()) {
|
|
1583
|
+
if (sharedTags.some((tag) => updated.has(tag))) {
|
|
1584
|
+
await this.inMemoryDeduplicationCache.delete(key, true);
|
|
1585
|
+
}
|
|
1413
1586
|
}
|
|
1414
1587
|
}
|
|
1415
|
-
const deleteTagsOperation = this.sharedTagsMap.delete(cacheKeys);
|
|
1416
|
-
await deleteTagsOperation;
|
|
1417
1588
|
} catch (error) {
|
|
1418
1589
|
console.error(
|
|
1419
1590
|
"RedisCacheComponentsHandler.updateTags() Error occurred while updating tags. The original error was:",
|
|
@@ -1457,6 +1628,8 @@ export {
|
|
|
1457
1628
|
index_default as default,
|
|
1458
1629
|
getRedisCacheComponentsHandler,
|
|
1459
1630
|
jsonCacheValueSerializer,
|
|
1460
|
-
redisCacheHandler
|
|
1631
|
+
redisCacheHandler,
|
|
1632
|
+
resolveCacheEntryTtlSeconds,
|
|
1633
|
+
shouldDeferRedisConnection
|
|
1461
1634
|
};
|
|
1462
1635
|
//# sourceMappingURL=index.mjs.map
|