@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.js
CHANGED
|
@@ -36,7 +36,9 @@ __export(index_exports, {
|
|
|
36
36
|
default: () => index_default,
|
|
37
37
|
getRedisCacheComponentsHandler: () => getRedisCacheComponentsHandler,
|
|
38
38
|
jsonCacheValueSerializer: () => jsonCacheValueSerializer,
|
|
39
|
-
redisCacheHandler: () => redisCacheHandler
|
|
39
|
+
redisCacheHandler: () => redisCacheHandler,
|
|
40
|
+
resolveCacheEntryTtlSeconds: () => resolveCacheEntryTtlSeconds,
|
|
41
|
+
shouldDeferRedisConnection: () => shouldDeferRedisConnection
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(index_exports);
|
|
42
44
|
|
|
@@ -64,6 +66,12 @@ function debugVerbose(color, ...args) {
|
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
// src/utils/redisConnection.ts
|
|
70
|
+
var PHASE_PRODUCTION_BUILD = "phase-production-build";
|
|
71
|
+
function shouldDeferRedisConnection() {
|
|
72
|
+
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
// src/SyncedMap.ts
|
|
68
76
|
var SYNC_CHANNEL_SUFFIX = ":sync-channel:";
|
|
69
77
|
var SyncedMap = class {
|
|
@@ -89,6 +97,10 @@ var SyncedMap = class {
|
|
|
89
97
|
});
|
|
90
98
|
}
|
|
91
99
|
async setup() {
|
|
100
|
+
if (shouldDeferRedisConnection()) {
|
|
101
|
+
this.setupLockResolve();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
92
104
|
let setupPromises = [];
|
|
93
105
|
if (!this.customizedSync?.withoutRedisHashmap) {
|
|
94
106
|
setupPromises.push(this.initialSync());
|
|
@@ -99,45 +111,54 @@ var SyncedMap = class {
|
|
|
99
111
|
this.setupLockResolve();
|
|
100
112
|
}
|
|
101
113
|
async initialSync() {
|
|
102
|
-
let cursor = 0;
|
|
103
|
-
const hScanOptions = { COUNT: this.querySize };
|
|
114
|
+
let cursor = "0";
|
|
104
115
|
try {
|
|
105
116
|
do {
|
|
106
|
-
const
|
|
107
|
-
"SyncedMap.initialSync(), operation:
|
|
108
|
-
this.client.
|
|
117
|
+
const [nextCursor, tuples] = await redisErrorHandler(
|
|
118
|
+
"SyncedMap.initialSync(), operation: HSCAN " + this.keyPrefix + this.redisKey,
|
|
119
|
+
this.client.sendCommand([
|
|
120
|
+
"HSCAN",
|
|
109
121
|
this.keyPrefix + this.redisKey,
|
|
110
122
|
cursor,
|
|
111
|
-
|
|
112
|
-
|
|
123
|
+
"COUNT",
|
|
124
|
+
String(this.querySize)
|
|
125
|
+
])
|
|
113
126
|
);
|
|
114
|
-
for (
|
|
127
|
+
for (let i = 0; i < tuples.length; i += 2) {
|
|
128
|
+
const field = tuples[i];
|
|
115
129
|
if (this.filterKeys(field)) {
|
|
116
|
-
|
|
117
|
-
this.map.set(field, parsedValue);
|
|
130
|
+
this.map.set(field, JSON.parse(tuples[i + 1]));
|
|
118
131
|
}
|
|
119
132
|
}
|
|
120
|
-
cursor =
|
|
121
|
-
} while (cursor !== 0);
|
|
122
|
-
|
|
133
|
+
cursor = nextCursor;
|
|
134
|
+
} while (cursor !== "0");
|
|
135
|
+
if (!this.customizedSync?.withoutOrphanCleanup) {
|
|
136
|
+
await this.cleanupKeysNotInRedis();
|
|
137
|
+
}
|
|
123
138
|
} catch (error) {
|
|
124
139
|
console.error("Error during initial sync:", error);
|
|
125
140
|
throw error;
|
|
126
141
|
}
|
|
127
142
|
}
|
|
128
143
|
async cleanupKeysNotInRedis() {
|
|
129
|
-
let cursor = 0;
|
|
130
|
-
const scanOptions = { COUNT: this.querySize, MATCH: `${this.keyPrefix}*` };
|
|
144
|
+
let cursor = "0";
|
|
131
145
|
let remoteKeys = [];
|
|
132
146
|
try {
|
|
133
147
|
do {
|
|
134
|
-
const
|
|
135
|
-
"SyncedMap.cleanupKeysNotInRedis(), operation:
|
|
136
|
-
this.client.
|
|
148
|
+
const [nextCursor, keys] = await redisErrorHandler(
|
|
149
|
+
"SyncedMap.cleanupKeysNotInRedis(), operation: SCAN " + this.keyPrefix,
|
|
150
|
+
this.client.sendCommand([
|
|
151
|
+
"SCAN",
|
|
152
|
+
cursor,
|
|
153
|
+
"MATCH",
|
|
154
|
+
`${this.keyPrefix}*`,
|
|
155
|
+
"COUNT",
|
|
156
|
+
String(this.querySize)
|
|
157
|
+
])
|
|
137
158
|
);
|
|
138
|
-
remoteKeys = remoteKeys.concat(
|
|
139
|
-
cursor =
|
|
140
|
-
} while (cursor !== 0);
|
|
159
|
+
remoteKeys = remoteKeys.concat(keys);
|
|
160
|
+
cursor = nextCursor;
|
|
161
|
+
} while (cursor !== "0");
|
|
141
162
|
const remoteKeysSet = new Set(
|
|
142
163
|
remoteKeys.map((key) => key.substring(this.keyPrefix.length))
|
|
143
164
|
);
|
|
@@ -531,6 +552,37 @@ var jsonCacheValueSerializer = {
|
|
|
531
552
|
}
|
|
532
553
|
};
|
|
533
554
|
|
|
555
|
+
// src/utils/cacheTtl.ts
|
|
556
|
+
function resolveCacheEntryTtlSeconds(ctx, data, options) {
|
|
557
|
+
const expire = ctx.cacheControl?.expire;
|
|
558
|
+
if (Number.isFinite(expire) && expire > 0) {
|
|
559
|
+
return Math.max(1, Math.ceil(expire));
|
|
560
|
+
}
|
|
561
|
+
const revalidate = resolveRevalidateValue(ctx, data);
|
|
562
|
+
if (revalidate === false) {
|
|
563
|
+
return options.estimateExpireAge(options.defaultStaleAge);
|
|
564
|
+
}
|
|
565
|
+
if (revalidate && Number.isSafeInteger(revalidate) && revalidate > 0) {
|
|
566
|
+
return options.estimateExpireAge(revalidate);
|
|
567
|
+
}
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
function resolveRevalidateValue(ctx, data) {
|
|
571
|
+
if (data?.kind === "FETCH" && data.revalidate !== void 0) {
|
|
572
|
+
return data.revalidate;
|
|
573
|
+
}
|
|
574
|
+
if (ctx.revalidate !== void 0) {
|
|
575
|
+
return ctx.revalidate;
|
|
576
|
+
}
|
|
577
|
+
if (ctx.cacheControl?.revalidate !== void 0) {
|
|
578
|
+
return ctx.cacheControl.revalidate;
|
|
579
|
+
}
|
|
580
|
+
if (data?.revalidate !== void 0) {
|
|
581
|
+
return data.revalidate;
|
|
582
|
+
}
|
|
583
|
+
return void 0;
|
|
584
|
+
}
|
|
585
|
+
|
|
534
586
|
// src/RedisStringsHandler.ts
|
|
535
587
|
function redisErrorHandler(debugInfo, redisCommandResult) {
|
|
536
588
|
const beforeTimestamp = performance.now();
|
|
@@ -608,6 +660,7 @@ var RedisStringsHandler = class {
|
|
|
608
660
|
this.killContainerOnErrorThreshold = killContainerOnErrorThreshold;
|
|
609
661
|
this.getTimeoutMs = getTimeoutMs;
|
|
610
662
|
this.valueSerializer = valueSerializer;
|
|
663
|
+
this.redisConnectionDeferred = shouldDeferRedisConnection();
|
|
611
664
|
try {
|
|
612
665
|
this.client = (0, import_redis.createClient)({
|
|
613
666
|
url: redisUrl,
|
|
@@ -646,12 +699,14 @@ var RedisStringsHandler = class {
|
|
|
646
699
|
}, 500);
|
|
647
700
|
}
|
|
648
701
|
});
|
|
649
|
-
this.
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
702
|
+
if (!this.redisConnectionDeferred) {
|
|
703
|
+
this.client.connect().then(() => {
|
|
704
|
+
debug("green", "Redis client connected.");
|
|
705
|
+
}).catch((error) => {
|
|
706
|
+
console.error("Failed to connect Redis client:", error);
|
|
707
|
+
throw error;
|
|
708
|
+
});
|
|
709
|
+
}
|
|
655
710
|
} catch (error) {
|
|
656
711
|
console.error("Failed to initialize Redis client");
|
|
657
712
|
throw error;
|
|
@@ -673,6 +728,7 @@ var RedisStringsHandler = class {
|
|
|
673
728
|
database,
|
|
674
729
|
querySize: revalidateTagQuerySize,
|
|
675
730
|
filterKeys,
|
|
731
|
+
customizedSync: { withoutOrphanCleanup: true },
|
|
676
732
|
resyncIntervalMs: avgResyncIntervalMs + avgResyncIntervalMs / 10 + Math.random() * (avgResyncIntervalMs / 10)
|
|
677
733
|
});
|
|
678
734
|
this.inMemoryDeduplicationCache = new SyncedMap({
|
|
@@ -742,11 +798,17 @@ var RedisStringsHandler = class {
|
|
|
742
798
|
}
|
|
743
799
|
this.clientReadyCalls = 0;
|
|
744
800
|
if (!this.client.isReady) {
|
|
801
|
+
if (this.redisConnectionDeferred) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
745
804
|
throw new Error(
|
|
746
805
|
"assertClientIsReady: Redis client is not ready yet or connection is lost."
|
|
747
806
|
);
|
|
748
807
|
}
|
|
749
808
|
}
|
|
809
|
+
isClientUnavailable() {
|
|
810
|
+
return this.redisConnectionDeferred || !this.client.isReady;
|
|
811
|
+
}
|
|
750
812
|
async get(key, ctx) {
|
|
751
813
|
try {
|
|
752
814
|
if (!SUPPORTED_GET_KINDS.includes(ctx.kind)) {
|
|
@@ -760,6 +822,9 @@ var RedisStringsHandler = class {
|
|
|
760
822
|
}
|
|
761
823
|
debug("green", "RedisStringsHandler.get() called with", key, ctx);
|
|
762
824
|
await this.assertClientIsReady();
|
|
825
|
+
if (this.isClientUnavailable()) {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
763
828
|
const clientGet = this.redisGetDeduplication ? this.deduplicatedRedisGet(key) : this.redisGet;
|
|
764
829
|
const redisGetOperation = clientGet(
|
|
765
830
|
(0, import_redis.commandOptions)({ signal: AbortSignal.timeout(this.getTimeoutMs) }),
|
|
@@ -893,6 +958,9 @@ var RedisStringsHandler = class {
|
|
|
893
958
|
);
|
|
894
959
|
}
|
|
895
960
|
await this.assertClientIsReady();
|
|
961
|
+
if (this.isClientUnavailable()) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
896
964
|
if (data?.kind === "APP_PAGE" || data?.kind === "APP_ROUTE") {
|
|
897
965
|
const tags = data.headers["x-next-cache-tags"]?.split(",");
|
|
898
966
|
ctx.tags = [...ctx.tags || [], ...tags || []];
|
|
@@ -915,18 +983,14 @@ var RedisStringsHandler = class {
|
|
|
915
983
|
serializedCacheEntry
|
|
916
984
|
);
|
|
917
985
|
}
|
|
918
|
-
const
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
// matters for those older, non-discriminated shapes.
|
|
923
|
-
data?.revalidate
|
|
924
|
-
);
|
|
925
|
-
const expireAt = revalidate && Number.isSafeInteger(revalidate) && revalidate > 0 ? this.estimateExpireAge(revalidate) : this.estimateExpireAge(this.defaultStaleAge);
|
|
986
|
+
const expireAt = resolveCacheEntryTtlSeconds(ctx, data, {
|
|
987
|
+
estimateExpireAge: this.estimateExpireAge,
|
|
988
|
+
defaultStaleAge: this.defaultStaleAge
|
|
989
|
+
});
|
|
926
990
|
const setOperation = redisErrorHandler(
|
|
927
991
|
"RedisStringsHandler.set(), operation: set " + this.keyPrefix + " " + key,
|
|
928
992
|
this.client.set(this.keyPrefix + key, serializedCacheEntry, {
|
|
929
|
-
EX: expireAt
|
|
993
|
+
...expireAt ? { EX: expireAt } : {}
|
|
930
994
|
})
|
|
931
995
|
);
|
|
932
996
|
debug(
|
|
@@ -989,6 +1053,9 @@ var RedisStringsHandler = class {
|
|
|
989
1053
|
);
|
|
990
1054
|
const tags = new Set([tagOrTags || []].flat());
|
|
991
1055
|
await this.assertClientIsReady();
|
|
1056
|
+
if (this.isClientUnavailable()) {
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
992
1059
|
const keysToDelete = /* @__PURE__ */ new Set();
|
|
993
1060
|
for (const tag of tags) {
|
|
994
1061
|
if (tag.startsWith(NEXT_CACHE_IMPLICIT_TAG_ID)) {
|
|
@@ -1127,6 +1194,88 @@ var CachedHandler = class {
|
|
|
1127
1194
|
|
|
1128
1195
|
// src/CacheComponentsHandler.ts
|
|
1129
1196
|
var import_redis2 = require("redis");
|
|
1197
|
+
|
|
1198
|
+
// src/utils/compareAndUnlink.ts
|
|
1199
|
+
var COMPARE_AND_UNLINK = `
|
|
1200
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
|
1201
|
+
return redis.call('UNLINK', KEYS[1])
|
|
1202
|
+
end
|
|
1203
|
+
return 0
|
|
1204
|
+
`;
|
|
1205
|
+
async function compareAndUnlink(client, key, expected) {
|
|
1206
|
+
const deleted = await client.eval(COMPARE_AND_UNLINK, {
|
|
1207
|
+
keys: [key],
|
|
1208
|
+
arguments: [expected]
|
|
1209
|
+
});
|
|
1210
|
+
return deleted === 1 || deleted === 1n;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// src/utils/tagRevalidation.ts
|
|
1214
|
+
function normalizeTagManifest(stored, now = Date.now()) {
|
|
1215
|
+
if (typeof stored === "number" && Number.isFinite(stored)) {
|
|
1216
|
+
return { expired: Math.min(stored, now) };
|
|
1217
|
+
}
|
|
1218
|
+
if (stored && typeof stored === "object") {
|
|
1219
|
+
const rec = stored;
|
|
1220
|
+
const stale = typeof rec.stale === "number" && Number.isFinite(rec.stale) ? rec.stale : typeof rec.last === "number" && Number.isFinite(rec.last) ? rec.last : void 0;
|
|
1221
|
+
const expired = typeof rec.expired === "number" && Number.isFinite(rec.expired) ? rec.expired : typeof rec.pending === "number" && Number.isFinite(rec.pending) ? rec.pending : void 0;
|
|
1222
|
+
return {
|
|
1223
|
+
...stale !== void 0 ? { stale } : {},
|
|
1224
|
+
...expired !== void 0 ? { expired } : {}
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
return {};
|
|
1228
|
+
}
|
|
1229
|
+
function applyTagUpdate(existing, durations, now) {
|
|
1230
|
+
if (durations) {
|
|
1231
|
+
const updates = { ...existing };
|
|
1232
|
+
updates.stale = now;
|
|
1233
|
+
if (durations.expire !== void 0) {
|
|
1234
|
+
updates.expired = now + durations.expire * 1e3;
|
|
1235
|
+
}
|
|
1236
|
+
return updates;
|
|
1237
|
+
}
|
|
1238
|
+
return {
|
|
1239
|
+
...existing,
|
|
1240
|
+
expired: now
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
function persistableTagManifest(entry, now) {
|
|
1244
|
+
if (typeof entry.expired === "number" && entry.expired <= now && (entry.stale === void 0 || entry.stale <= entry.expired)) {
|
|
1245
|
+
return entry.expired;
|
|
1246
|
+
}
|
|
1247
|
+
return entry;
|
|
1248
|
+
}
|
|
1249
|
+
function areTagsExpired(tags, entryTimestamp, now, getEntry) {
|
|
1250
|
+
for (const tag of tags) {
|
|
1251
|
+
const expiredAt = getEntry(tag)?.expired;
|
|
1252
|
+
if (typeof expiredAt === "number" && expiredAt <= now && expiredAt > entryTimestamp) {
|
|
1253
|
+
return true;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return false;
|
|
1257
|
+
}
|
|
1258
|
+
function areTagsStale(tags, entryTimestamp, getEntry) {
|
|
1259
|
+
for (const tag of tags) {
|
|
1260
|
+
const staleAt = getEntry(tag)?.stale ?? 0;
|
|
1261
|
+
if (typeof staleAt === "number" && staleAt > entryTimestamp) {
|
|
1262
|
+
return true;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return false;
|
|
1266
|
+
}
|
|
1267
|
+
function maxExpiredTimestamp(tags, getEntry) {
|
|
1268
|
+
let max = 0;
|
|
1269
|
+
for (const tag of tags) {
|
|
1270
|
+
const expired = getEntry(tag)?.expired || 0;
|
|
1271
|
+
if (expired > max) {
|
|
1272
|
+
max = expired;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return max;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// src/CacheComponentsHandler.ts
|
|
1130
1279
|
var REVALIDATED_TAGS_KEY2 = "__cacheComponents_revalidated_tags__";
|
|
1131
1280
|
var SHARED_TAGS_KEY = "__cacheComponents_sharedTags__";
|
|
1132
1281
|
var killContainerOnErrorCount2 = 0;
|
|
@@ -1184,6 +1333,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1184
1333
|
this.getTimeoutMs = getTimeoutMs;
|
|
1185
1334
|
this.redisGetDeduplication = redisGetDeduplication;
|
|
1186
1335
|
this.inMemoryCachingTime = inMemoryCachingTime;
|
|
1336
|
+
this.redisConnectionDeferred = shouldDeferRedisConnection();
|
|
1187
1337
|
this.client = (0, import_redis2.createClient)({
|
|
1188
1338
|
url: redisUrl,
|
|
1189
1339
|
pingInterval: 1e4,
|
|
@@ -1219,18 +1369,20 @@ var RedisCacheComponentsHandler = class {
|
|
|
1219
1369
|
}, 500);
|
|
1220
1370
|
}
|
|
1221
1371
|
});
|
|
1222
|
-
this.
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1372
|
+
if (!this.redisConnectionDeferred) {
|
|
1373
|
+
this.client.connect().then(() => {
|
|
1374
|
+
debug("green", "RedisCacheComponentsHandler client connected.");
|
|
1375
|
+
}).catch(() => {
|
|
1376
|
+
this.client.connect().catch((error) => {
|
|
1377
|
+
console.error(
|
|
1378
|
+
"Failed to connect RedisCacheComponentsHandler client:",
|
|
1379
|
+
error
|
|
1380
|
+
);
|
|
1381
|
+
this.client.disconnect();
|
|
1382
|
+
throw error;
|
|
1383
|
+
});
|
|
1232
1384
|
});
|
|
1233
|
-
}
|
|
1385
|
+
}
|
|
1234
1386
|
const filterKeys = (key) => key !== REVALIDATED_TAGS_KEY2 && key !== SHARED_TAGS_KEY;
|
|
1235
1387
|
this.revalidatedTagsMap = new SyncedMap({
|
|
1236
1388
|
client: this.client,
|
|
@@ -1239,6 +1391,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1239
1391
|
database,
|
|
1240
1392
|
querySize: revalidateTagQuerySize,
|
|
1241
1393
|
filterKeys,
|
|
1394
|
+
customizedSync: { withoutOrphanCleanup: true },
|
|
1242
1395
|
resyncIntervalMs: avgResyncIntervalMs + avgResyncIntervalMs / 10 + Math.random() * (avgResyncIntervalMs / 10)
|
|
1243
1396
|
});
|
|
1244
1397
|
this.sharedTagsMap = new SyncedMap({
|
|
@@ -1276,6 +1429,13 @@ var RedisCacheComponentsHandler = class {
|
|
|
1276
1429
|
}
|
|
1277
1430
|
}
|
|
1278
1431
|
async assertClientIsReady() {
|
|
1432
|
+
if (this.redisConnectionDeferred) {
|
|
1433
|
+
await Promise.all([
|
|
1434
|
+
this.revalidatedTagsMap.waitUntilReady(),
|
|
1435
|
+
this.sharedTagsMap.waitUntilReady()
|
|
1436
|
+
]);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1279
1439
|
if (!this.client.isReady && !this.client.isOpen) {
|
|
1280
1440
|
await this.client.connect().catch((error) => {
|
|
1281
1441
|
console.error(
|
|
@@ -1290,57 +1450,76 @@ var RedisCacheComponentsHandler = class {
|
|
|
1290
1450
|
this.sharedTagsMap.waitUntilReady()
|
|
1291
1451
|
]);
|
|
1292
1452
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
max = ts;
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
return max;
|
|
1453
|
+
isClientUnavailable() {
|
|
1454
|
+
return this.redisConnectionDeferred || !this.client.isReady;
|
|
1455
|
+
}
|
|
1456
|
+
tagManifestFor(tag, now = Date.now()) {
|
|
1457
|
+
return normalizeTagManifest(this.revalidatedTagsMap.get(tag), now);
|
|
1302
1458
|
}
|
|
1303
|
-
async get(cacheKey,
|
|
1459
|
+
async get(cacheKey, _softTags) {
|
|
1460
|
+
void _softTags;
|
|
1304
1461
|
const redisKey = `${this.keyPrefix}${cacheKey}`;
|
|
1305
1462
|
try {
|
|
1306
1463
|
await this.assertClientIsReady();
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1464
|
+
if (this.isClientUnavailable()) {
|
|
1465
|
+
return void 0;
|
|
1466
|
+
}
|
|
1467
|
+
const readSerialized = (useDedup) => redisErrorHandler(
|
|
1468
|
+
"RedisCacheComponentsHandler.get(), operation: get" + (useDedup ? " deduplicated" : "") + " " + this.getTimeoutMs + "ms " + redisKey,
|
|
1469
|
+
(useDedup ? this.deduplicatedRedisGet(cacheKey) : this.redisGet)(
|
|
1311
1470
|
(0, import_redis2.commandOptions)({ signal: AbortSignal.timeout(this.getTimeoutMs) }),
|
|
1312
1471
|
redisKey
|
|
1313
1472
|
)
|
|
1314
1473
|
);
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1474
|
+
let usedDedup = this.redisGetDeduplication;
|
|
1475
|
+
let serialized = await readSerialized(usedDedup);
|
|
1476
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
1477
|
+
if (!serialized) {
|
|
1478
|
+
return void 0;
|
|
1479
|
+
}
|
|
1480
|
+
const stored = JSON.parse(serialized);
|
|
1481
|
+
const now = Date.now();
|
|
1482
|
+
const tags = stored.tags || [];
|
|
1483
|
+
const expiryTime = stored.timestamp + stored.expire * 1e3;
|
|
1484
|
+
const ttlExpired = Number.isFinite(stored.expire) && stored.expire > 0 && now > expiryTime;
|
|
1485
|
+
const tagsExpired = areTagsExpired(
|
|
1486
|
+
tags,
|
|
1487
|
+
stored.timestamp,
|
|
1488
|
+
now,
|
|
1489
|
+
(tag) => this.tagManifestFor(tag, now)
|
|
1490
|
+
);
|
|
1491
|
+
if (ttlExpired || tagsExpired) {
|
|
1492
|
+
if (usedDedup) {
|
|
1493
|
+
usedDedup = false;
|
|
1494
|
+
serialized = await readSerialized(false);
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
const dropped = await compareAndUnlink(
|
|
1498
|
+
this.client,
|
|
1499
|
+
redisKey,
|
|
1500
|
+
serialized
|
|
1501
|
+
);
|
|
1502
|
+
if (dropped) {
|
|
1503
|
+
await this.sharedTagsMap.delete(cacheKey).catch(() => {
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
return void 0;
|
|
1507
|
+
}
|
|
1508
|
+
const valueBuffer = typeof stored.value === "string" ? new Uint8Array(Buffer.from(stored.value, "base64")) : stored.value;
|
|
1509
|
+
const entry = {
|
|
1510
|
+
...stored,
|
|
1511
|
+
value: bufferToReadableStream(valueBuffer)
|
|
1512
|
+
};
|
|
1513
|
+
if (areTagsStale(
|
|
1514
|
+
tags,
|
|
1515
|
+
stored.timestamp,
|
|
1516
|
+
(tag) => this.tagManifestFor(tag, now)
|
|
1517
|
+
)) {
|
|
1518
|
+
entry.revalidate = -1;
|
|
1519
|
+
}
|
|
1520
|
+
return entry;
|
|
1338
1521
|
}
|
|
1339
|
-
|
|
1340
|
-
return {
|
|
1341
|
-
...stored,
|
|
1342
|
-
value: bufferToReadableStream(valueBuffer)
|
|
1343
|
-
};
|
|
1522
|
+
return void 0;
|
|
1344
1523
|
} catch (error) {
|
|
1345
1524
|
console.error(
|
|
1346
1525
|
"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:",
|
|
@@ -1353,6 +1532,9 @@ var RedisCacheComponentsHandler = class {
|
|
|
1353
1532
|
async set(cacheKey, pendingEntry) {
|
|
1354
1533
|
try {
|
|
1355
1534
|
await this.assertClientIsReady();
|
|
1535
|
+
if (this.isClientUnavailable()) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1356
1538
|
const entry = await pendingEntry;
|
|
1357
1539
|
const [storeStream] = entry.value.tee();
|
|
1358
1540
|
const buffer = await streamToBuffer(storeStream);
|
|
@@ -1416,7 +1598,7 @@ var RedisCacheComponentsHandler = class {
|
|
|
1416
1598
|
async getExpiration(tags) {
|
|
1417
1599
|
try {
|
|
1418
1600
|
await this.assertClientIsReady();
|
|
1419
|
-
return
|
|
1601
|
+
return maxExpiredTimestamp(tags || [], (tag) => this.tagManifestFor(tag));
|
|
1420
1602
|
} catch (error) {
|
|
1421
1603
|
console.error(
|
|
1422
1604
|
"RedisCacheComponentsHandler.getExpiration() Error occurred while getting expiration for tags. The original error was:",
|
|
@@ -1425,37 +1607,28 @@ var RedisCacheComponentsHandler = class {
|
|
|
1425
1607
|
return 0;
|
|
1426
1608
|
}
|
|
1427
1609
|
}
|
|
1428
|
-
async updateTags(tags,
|
|
1610
|
+
async updateTags(tags, durations) {
|
|
1429
1611
|
try {
|
|
1430
|
-
void _durations;
|
|
1431
1612
|
await this.assertClientIsReady();
|
|
1432
|
-
|
|
1433
|
-
const tagsSet = new Set(tags || []);
|
|
1434
|
-
for (const tag of tagsSet) {
|
|
1435
|
-
await this.revalidatedTagsMap.set(tag, now);
|
|
1436
|
-
}
|
|
1437
|
-
const keysToDelete = /* @__PURE__ */ new Set();
|
|
1438
|
-
for (const [key, storedTags] of this.sharedTagsMap.entries()) {
|
|
1439
|
-
if (storedTags.some((tag) => tagsSet.has(tag))) {
|
|
1440
|
-
keysToDelete.add(key);
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
if (keysToDelete.size === 0) {
|
|
1613
|
+
if (this.isClientUnavailable()) {
|
|
1444
1614
|
return;
|
|
1445
1615
|
}
|
|
1446
|
-
const
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
this.
|
|
1451
|
-
|
|
1616
|
+
const now = Date.now();
|
|
1617
|
+
const updated = new Set(tags || []);
|
|
1618
|
+
for (const tag of updated) {
|
|
1619
|
+
const next = applyTagUpdate(this.tagManifestFor(tag), durations, now);
|
|
1620
|
+
await this.revalidatedTagsMap.set(
|
|
1621
|
+
tag,
|
|
1622
|
+
persistableTagManifest(next, now)
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1452
1625
|
if (this.redisGetDeduplication && this.inMemoryCachingTime > 0) {
|
|
1453
|
-
for (const key of
|
|
1454
|
-
|
|
1626
|
+
for (const [key, sharedTags] of this.sharedTagsMap.entries()) {
|
|
1627
|
+
if (sharedTags.some((tag) => updated.has(tag))) {
|
|
1628
|
+
await this.inMemoryDeduplicationCache.delete(key, true);
|
|
1629
|
+
}
|
|
1455
1630
|
}
|
|
1456
1631
|
}
|
|
1457
|
-
const deleteTagsOperation = this.sharedTagsMap.delete(cacheKeys);
|
|
1458
|
-
await deleteTagsOperation;
|
|
1459
1632
|
} catch (error) {
|
|
1460
1633
|
console.error(
|
|
1461
1634
|
"RedisCacheComponentsHandler.updateTags() Error occurred while updating tags. The original error was:",
|
|
@@ -1499,6 +1672,8 @@ var index_default = CachedHandler;
|
|
|
1499
1672
|
bufferAndMapReviver,
|
|
1500
1673
|
getRedisCacheComponentsHandler,
|
|
1501
1674
|
jsonCacheValueSerializer,
|
|
1502
|
-
redisCacheHandler
|
|
1675
|
+
redisCacheHandler,
|
|
1676
|
+
resolveCacheEntryTtlSeconds,
|
|
1677
|
+
shouldDeferRedisConnection
|
|
1503
1678
|
});
|
|
1504
1679
|
//# sourceMappingURL=index.js.map
|