@trieb.work/nextjs-turbo-redis-cache 1.18.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/dist/index.js +27 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +27 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -1
- 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 -58
- package/.prettierrc.json +0 -6
- package/.vscode/settings.json +0 -10
- package/ARCHITECTURE.md +0 -470
- 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 -12
- 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 -597
- package/src/CachedHandler.ts +0 -53
- package/src/DeduplicatedRequestHandler.ts +0 -110
- package/src/RedisStringsHandler.ts +0 -949
- package/src/SyncedMap.ts +0 -496
- package/src/ZodHandler.ts +0 -45
- package/src/index.ts +0 -23
- package/src/serializer.ts +0 -59
- package/src/utils/cacheTtl.ts +0 -71
- package/src/utils/compareAndUnlink.ts +0 -29
- package/src/utils/debug.ts +0 -30
- package/src/utils/json.ts +0 -49
- package/src/utils/prefix.ts +0 -44
- package/src/utils/redisConnection.ts +0 -17
- package/src/utils/tagRevalidation.ts +0 -162
- 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 -15
- 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/expire-matrix/revalidate/route.ts +0 -34
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/api/expire-matrix/route.ts +0 -23
- 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 -112
- package/test/nextjs-test-projects/next-app-16-0-11-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
- 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/cache-lab/use-cache-remote/page.tsx +0 -85
- 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 -15
- 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/expire-matrix/revalidate/route.ts +0 -34
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/api/expire-matrix/route.ts +0 -23
- 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 -112
- package/test/nextjs-test-projects/next-app-16-2-6-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
- 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/cache-lab/use-cache-remote/page.tsx +0 -85
- 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 -15
- 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/expire-matrix/revalidate/route.ts +0 -34
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/api/expire-matrix/route.ts +0 -23
- 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 -112
- package/test/nextjs-test-projects/next-app-16-3-0-cache-components/src/app/cache-lab/revalidate-durations/page.tsx +0 -106
- 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/cache-lab/use-cache-remote/page.tsx +0 -85
- 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 -232
- 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 -389
- 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 -959
- package/test/vitest/integration/pages-router.integration.test.ts +0 -430
- package/test/vitest/unit/SyncedMap-orphan-cleanup.test.ts +0 -111
- package/test/vitest/unit/SyncedMap-reconnect-repro.test.ts +0 -154
- package/test/vitest/unit/cache-components-update-tags.test.ts +0 -350
- package/test/vitest/unit/cache-ttl.test.ts +0 -67
- package/test/vitest/unit/compare-and-unlink.test.ts +0 -22
- package/test/vitest/unit/index.test.ts +0 -190
- package/test/vitest/unit/pages-router-kinds.test.ts +0 -303
- package/test/vitest/unit/reconnect-socket-already-opened.test.ts +0 -117
- package/test/vitest/unit/redis-connection.test.ts +0 -39
- package/test/vitest/unit/serializer.test.ts +0 -182
- package/test/vitest/unit/tag-revalidation.test.ts +0 -178
- 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
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Atomically delete `key` only if its current value still equals `expected`.
|
|
3
|
-
* GET then UNLINK would race: another instance can SET a replacement in between.
|
|
4
|
-
*/
|
|
5
|
-
const COMPARE_AND_UNLINK = `
|
|
6
|
-
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
|
7
|
-
return redis.call('UNLINK', KEYS[1])
|
|
8
|
-
end
|
|
9
|
-
return 0
|
|
10
|
-
`;
|
|
11
|
-
|
|
12
|
-
type EvalClient = {
|
|
13
|
-
eval(
|
|
14
|
-
script: string,
|
|
15
|
-
options: { keys: string[]; arguments: string[] },
|
|
16
|
-
): Promise<unknown>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export async function compareAndUnlink(
|
|
20
|
-
client: EvalClient,
|
|
21
|
-
key: string,
|
|
22
|
-
expected: string,
|
|
23
|
-
): Promise<boolean> {
|
|
24
|
-
const deleted = await client.eval(COMPARE_AND_UNLINK, {
|
|
25
|
-
keys: [key],
|
|
26
|
-
arguments: [expected],
|
|
27
|
-
});
|
|
28
|
-
return deleted === 1 || deleted === 1n;
|
|
29
|
-
}
|
package/src/utils/debug.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export function debug(
|
|
2
|
-
color:
|
|
3
|
-
| 'red'
|
|
4
|
-
| 'blue'
|
|
5
|
-
| 'green'
|
|
6
|
-
| 'yellow'
|
|
7
|
-
| 'cyan'
|
|
8
|
-
| 'white'
|
|
9
|
-
| 'none' = 'none',
|
|
10
|
-
...args: unknown[]
|
|
11
|
-
): void {
|
|
12
|
-
const colorCode = {
|
|
13
|
-
red: '\x1b[31m',
|
|
14
|
-
blue: '\x1b[34m',
|
|
15
|
-
green: '\x1b[32m',
|
|
16
|
-
yellow: '\x1b[33m',
|
|
17
|
-
cyan: '\x1b[36m',
|
|
18
|
-
white: '\x1b[37m',
|
|
19
|
-
none: '',
|
|
20
|
-
};
|
|
21
|
-
if (process.env.DEBUG_CACHE_HANDLER) {
|
|
22
|
-
console.log(colorCode[color], 'DEBUG CACHE HANDLER: ', ...args);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function debugVerbose(color: string, ...args: unknown[]) {
|
|
27
|
-
if (process.env.DEBUG_CACHE_HANDLER_VERBOSE_VERBOSE) {
|
|
28
|
-
console.log('\x1b[35m', 'DEBUG SYNCED MAP: ', ...args);
|
|
29
|
-
}
|
|
30
|
-
}
|
package/src/utils/json.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
-
export function bufferAndMapReviver(_: string, value: any): any {
|
|
3
|
-
if (value && typeof value === 'object' && typeof value.$binary === 'string') {
|
|
4
|
-
return Buffer.from(value.$binary, 'base64');
|
|
5
|
-
}
|
|
6
|
-
if (
|
|
7
|
-
value &&
|
|
8
|
-
typeof value === 'object' &&
|
|
9
|
-
typeof value.$map === 'object' &&
|
|
10
|
-
!!value.$map
|
|
11
|
-
) {
|
|
12
|
-
return new Map(
|
|
13
|
-
Object.entries(value.$map).map(([key, value]) => {
|
|
14
|
-
const revivedValue = bufferAndMapReviver('', value);
|
|
15
|
-
return [key, revivedValue];
|
|
16
|
-
}),
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
export function bufferAndMapReplacer(_: string, value: any): any {
|
|
23
|
-
if (Buffer.isBuffer(value)) {
|
|
24
|
-
return {
|
|
25
|
-
$binary: value.toString('base64'),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
if (
|
|
29
|
-
value &&
|
|
30
|
-
typeof value === 'object' &&
|
|
31
|
-
value?.type === 'Buffer' &&
|
|
32
|
-
Array.isArray(value.data)
|
|
33
|
-
) {
|
|
34
|
-
return {
|
|
35
|
-
$binary: Buffer.from(value.data).toString('base64'),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
if (value && typeof value === 'object' && value instanceof Map) {
|
|
39
|
-
return {
|
|
40
|
-
$map: Object.fromEntries(
|
|
41
|
-
Array.from(value.entries()).map(([key, value]) => {
|
|
42
|
-
const replacedValue = bufferAndMapReplacer('', value);
|
|
43
|
-
return [key, replacedValue];
|
|
44
|
-
}),
|
|
45
|
-
),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return value;
|
|
49
|
-
}
|
package/src/utils/prefix.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
export function readBuildId(serverDistDir?: string): string | undefined {
|
|
5
|
-
try {
|
|
6
|
-
if (serverDistDir) {
|
|
7
|
-
const buildIdPath = path.join(serverDistDir, '..', 'BUILD_ID');
|
|
8
|
-
const buildId = fs.readFileSync(buildIdPath, 'utf8').trim();
|
|
9
|
-
return buildId || undefined;
|
|
10
|
-
}
|
|
11
|
-
} catch {
|
|
12
|
-
// fall through to cwd-based read
|
|
13
|
-
}
|
|
14
|
-
try {
|
|
15
|
-
const fromCwd = path.join(process.cwd(), '.next', 'BUILD_ID');
|
|
16
|
-
const buildId = fs.readFileSync(fromCwd, 'utf8').trim();
|
|
17
|
-
return buildId || undefined;
|
|
18
|
-
} catch {
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function resolveKeyPrefix({
|
|
24
|
-
optionKeyPrefix,
|
|
25
|
-
serverDistDir,
|
|
26
|
-
env,
|
|
27
|
-
}: {
|
|
28
|
-
optionKeyPrefix?: string;
|
|
29
|
-
serverDistDir?: string;
|
|
30
|
-
env: NodeJS.ProcessEnv;
|
|
31
|
-
}): string {
|
|
32
|
-
// If the option is explicitly provided, honor it even if it's an empty string
|
|
33
|
-
if (optionKeyPrefix !== undefined) {
|
|
34
|
-
return optionKeyPrefix;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const keyPrefixEnv =
|
|
38
|
-
env.KEY_PREFIX && env.KEY_PREFIX.length > 0 ? env.KEY_PREFIX : undefined;
|
|
39
|
-
const vercelUrl =
|
|
40
|
-
env.VERCEL_URL && env.VERCEL_URL.length > 0 ? env.VERCEL_URL : undefined;
|
|
41
|
-
const buildId = readBuildId(serverDistDir);
|
|
42
|
-
|
|
43
|
-
return keyPrefixEnv ?? vercelUrl ?? buildId ?? 'UNDEFINED_URL_';
|
|
44
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Matches `PHASE_PRODUCTION_BUILD` from `next/constants`.
|
|
3
|
-
*
|
|
4
|
-
* Hardcoded so ESM builds (tsup `shims: false`) never call `require()`.
|
|
5
|
-
* A dynamic `require('next/constants')` throws in ESM, and catching that used
|
|
6
|
-
* to cache `undefined` for the process lifetime — disabling the build-phase
|
|
7
|
-
* Redis skip entirely.
|
|
8
|
-
*/
|
|
9
|
-
export const PHASE_PRODUCTION_BUILD = 'phase-production-build';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Returns true during `next build` so handlers can skip opening Redis
|
|
13
|
-
* connections. Matches the official Next.js cache-handler-redis example.
|
|
14
|
-
*/
|
|
15
|
-
export function shouldDeferRedisConnection(): boolean {
|
|
16
|
-
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
|
|
17
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tag manifest matching Next.js 16.0–16.3
|
|
3
|
-
* `next/dist/server/lib/cache-handlers/default.js` `updateTags`
|
|
4
|
-
* and `next/dist/server/lib/incremental-cache/tags-manifest.external.js`.
|
|
5
|
-
*
|
|
6
|
-
* `revalidateTag(tag, profile)` resolves `cacheLife[profile].expire` (seconds)
|
|
7
|
-
* and calls `updateTags(tags, { expire })`. `updateTag` / no profile calls
|
|
8
|
-
* `updateTags(tags)` with no durations (immediate hard expire).
|
|
9
|
-
*/
|
|
10
|
-
export type TagManifestEntry = {
|
|
11
|
-
stale?: number;
|
|
12
|
-
expired?: number;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Read a tag-manifest field from Redis.
|
|
17
|
-
*
|
|
18
|
-
* Next.js 16.0–16.3 never persists plain numbers here — `updateTags` always
|
|
19
|
-
* writes `{ stale, expired }` via `applyTagUpdate()`. A plain number can only
|
|
20
|
-
* appear from older releases of this package that stored `Date.now()` directly
|
|
21
|
-
* (before the `{ stale, expired }` manifest). ISR uses a separate Redis hash
|
|
22
|
-
* (`__revalidated_tags__`) and is unaffected.
|
|
23
|
-
*
|
|
24
|
-
* A future-looking plain number is not produced by Next.js and is not the same
|
|
25
|
-
* as intentional SWR (`{ stale: now, expired: now + N }`). It can only happen
|
|
26
|
-
* when another instance wrote the timestamp with a faster clock (NTP skew).
|
|
27
|
-
* Clamp to `now` on read so the revalidation is not delayed on slower instances.
|
|
28
|
-
*/
|
|
29
|
-
export function normalizeTagManifest(
|
|
30
|
-
stored: unknown,
|
|
31
|
-
now: number = Date.now(),
|
|
32
|
-
): TagManifestEntry {
|
|
33
|
-
if (typeof stored === 'number' && Number.isFinite(stored)) {
|
|
34
|
-
return { expired: Math.min(stored, now) };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (stored && typeof stored === 'object') {
|
|
38
|
-
const rec = stored as {
|
|
39
|
-
stale?: unknown;
|
|
40
|
-
expired?: unknown;
|
|
41
|
-
last?: unknown;
|
|
42
|
-
pending?: unknown;
|
|
43
|
-
};
|
|
44
|
-
const stale =
|
|
45
|
-
typeof rec.stale === 'number' && Number.isFinite(rec.stale)
|
|
46
|
-
? rec.stale
|
|
47
|
-
: typeof rec.last === 'number' && Number.isFinite(rec.last)
|
|
48
|
-
? rec.last
|
|
49
|
-
: undefined;
|
|
50
|
-
const expired =
|
|
51
|
-
typeof rec.expired === 'number' && Number.isFinite(rec.expired)
|
|
52
|
-
? rec.expired
|
|
53
|
-
: typeof rec.pending === 'number' && Number.isFinite(rec.pending)
|
|
54
|
-
? rec.pending
|
|
55
|
-
: undefined;
|
|
56
|
-
return {
|
|
57
|
-
...(stale !== undefined ? { stale } : {}),
|
|
58
|
-
...(expired !== undefined ? { expired } : {}),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Mirrors Next.js DefaultCacheHandler.updateTags().
|
|
67
|
-
*/
|
|
68
|
-
export function applyTagUpdate(
|
|
69
|
-
existing: TagManifestEntry,
|
|
70
|
-
durations: { expire?: number } | undefined,
|
|
71
|
-
now: number,
|
|
72
|
-
): TagManifestEntry {
|
|
73
|
-
if (durations) {
|
|
74
|
-
const updates = { ...existing };
|
|
75
|
-
updates.stale = now;
|
|
76
|
-
if (durations.expire !== undefined) {
|
|
77
|
-
updates.expired = now + durations.expire * 1000;
|
|
78
|
-
}
|
|
79
|
-
return updates;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
...existing,
|
|
84
|
-
expired: now,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Immediate hard-expires (`expired <= now`) are stored as a plain number so
|
|
90
|
-
* older package versions that JSON.parse + numeric-compare the hash field still
|
|
91
|
-
* see the invalidation during a rolling deploy. SWR windows stay objects.
|
|
92
|
-
*/
|
|
93
|
-
export function persistableTagManifest(
|
|
94
|
-
entry: TagManifestEntry,
|
|
95
|
-
now: number,
|
|
96
|
-
): TagManifestEntry | number {
|
|
97
|
-
if (
|
|
98
|
-
typeof entry.expired === 'number' &&
|
|
99
|
-
entry.expired <= now &&
|
|
100
|
-
(entry.stale === undefined || entry.stale <= entry.expired)
|
|
101
|
-
) {
|
|
102
|
-
return entry.expired;
|
|
103
|
-
}
|
|
104
|
-
return entry;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Mirrors Next.js `areTagsExpired`: hard miss once `expired` has elapsed
|
|
109
|
-
* and is newer than the entry timestamp.
|
|
110
|
-
*/
|
|
111
|
-
export function areTagsExpired(
|
|
112
|
-
tags: string[],
|
|
113
|
-
entryTimestamp: number,
|
|
114
|
-
now: number,
|
|
115
|
-
getEntry: (tag: string) => TagManifestEntry | undefined,
|
|
116
|
-
): boolean {
|
|
117
|
-
for (const tag of tags) {
|
|
118
|
-
const expiredAt = getEntry(tag)?.expired;
|
|
119
|
-
if (
|
|
120
|
-
typeof expiredAt === 'number' &&
|
|
121
|
-
expiredAt <= now &&
|
|
122
|
-
expiredAt > entryTimestamp
|
|
123
|
-
) {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Mirrors Next.js `areTagsStale`: SWR when `stale` is newer than the entry.
|
|
132
|
-
*/
|
|
133
|
-
export function areTagsStale(
|
|
134
|
-
tags: string[],
|
|
135
|
-
entryTimestamp: number,
|
|
136
|
-
getEntry: (tag: string) => TagManifestEntry | undefined,
|
|
137
|
-
): boolean {
|
|
138
|
-
for (const tag of tags) {
|
|
139
|
-
const staleAt = getEntry(tag)?.stale ?? 0;
|
|
140
|
-
if (typeof staleAt === 'number' && staleAt > entryTimestamp) {
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Mirrors Next.js DefaultCacheHandler.getExpiration(): max `expired` or 0.
|
|
149
|
-
*/
|
|
150
|
-
export function maxExpiredTimestamp(
|
|
151
|
-
tags: string[],
|
|
152
|
-
getEntry: (tag: string) => TagManifestEntry | undefined,
|
|
153
|
-
): number {
|
|
154
|
-
let max = 0;
|
|
155
|
-
for (const tag of tags) {
|
|
156
|
-
const expired = getEntry(tag)?.expired || 0;
|
|
157
|
-
if (expired > max) {
|
|
158
|
-
max = expired;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return max;
|
|
162
|
-
}
|
package/test/README.md
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# Test Structure
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
test/
|
|
5
|
-
├── playwright/ # E2E tests — browser automation (Playwright)
|
|
6
|
-
├── vitest/ # Unit + Integration tests (Vitest)
|
|
7
|
-
│ ├── unit/ # Pure unit tests (no external deps)
|
|
8
|
-
│ └── integration/ # Integration tests (Redis + Next.js server)
|
|
9
|
-
│ └── cache-components/ # Cache Components integration (Next.js 16+)
|
|
10
|
-
└── nextjs-test-projects/ # Next.js app fixtures (shared across test types)
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Overview
|
|
14
|
-
|
|
15
|
-
| Layer | Runner | What it validates | Needs Redis? | Needs Next.js app? |
|
|
16
|
-
| --------------- | ---------- | ----------------------------------------------------------------------- | ------------ | ------------------ |
|
|
17
|
-
| **Unit** | Vitest | Logic in isolation (serializer, prefix resolution, reconnect handling) | No | No |
|
|
18
|
-
| **Integration** | Vitest | Cache handler ↔ Redis ↔ Next.js HTTP responses (server-side plumbing) | Yes | Yes |
|
|
19
|
-
| **E2E** | Playwright | User-facing behavior in a real browser (Cache Components / `use cache`) | Yes | Yes |
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Unit Tests (`test/vitest/unit/`)
|
|
24
|
-
|
|
25
|
-
**Runner:** Vitest
|
|
26
|
-
**Command:** `pnpm test:unit`
|
|
27
|
-
**Config:** `vite.config.ts`
|
|
28
|
-
|
|
29
|
-
Fast tests with no external dependencies. Mocks are used where needed.
|
|
30
|
-
|
|
31
|
-
| File | What it tests |
|
|
32
|
-
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
33
|
-
| `serializer.test.ts` | `CacheValueSerializer` interface, JSON round-trips, singleton stability |
|
|
34
|
-
| `index.test.ts` | `RedisStringsHandler` constructor options, default behaviors |
|
|
35
|
-
| `utils/prefix.test.ts` | `resolveKeyPrefix` logic (BUILD_ID fallback, env var precedence) |
|
|
36
|
-
| `reconnect-socket-already-opened.test.ts` | Regression: reconnect logic doesn't call `connect()` when socket is already open |
|
|
37
|
-
| `pages-router-kinds.test.ts` | Pages Router cache kinds (`PAGES`, `REDIRECT`, `null`/notFound), implicit tags, TTL derivation |
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
pnpm test:unit # single run
|
|
41
|
-
pnpm test:unit:watch # watch mode
|
|
42
|
-
pnpm test:unit:coverage # with coverage report (used in CI)
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Integration Tests (`test/vitest/integration/`)
|
|
48
|
-
|
|
49
|
-
**Runner:** Vitest
|
|
50
|
-
**Command:** `pnpm test:integration`
|
|
51
|
-
**Config:** `vite.config.ts`
|
|
52
|
-
**Requires:** Redis on localhost:6379, pre-built Next.js test app
|
|
53
|
-
|
|
54
|
-
These tests spawn a real Next.js server as a child process, make `fetch()` requests against it, and verify both HTTP responses and Redis state directly.
|
|
55
|
-
|
|
56
|
-
### Standard Integration (`nextjs-cache-handler.integration.test.ts`)
|
|
57
|
-
|
|
58
|
-
Full cache lifecycle: static pages, fetch caching, revalidation, tag invalidation, TTL behavior. In CI this runs against Next.js 15.4, 16.0, 16.2, and 16.3. Nested fetch entries are resolved from their explicit cache tag in Redis's shared-tags map rather than Next.js's internal fetch-key hash, which changed in Next.js 16.3.
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
pnpm test:integration
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Pages Router (`pages-router.integration.test.ts`)
|
|
65
|
-
|
|
66
|
-
Pages Router cache lifecycle against the `next-pages-16-2-6` and `next-pages-16-3-0` apps: `PAGES` entry format, TTL derivation from `getStaticProps` `revalidate`, `fallback: 'blocking'` first hits, `notFound: true` (null cache entries), `redirect:` results, and `revalidate: false` TTL fallback.
|
|
67
|
-
|
|
68
|
-
Starts **two** `next start` instances of the same build sharing one Redis and proves that on-demand revalidation (`res.revalidate(path)`) triggered on instance A is served fresh by instance B (HTML and `/_next/data` pageData JSON) — the multi-instance ISR scenario behind a load balancer.
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
pnpm test:integration:pages
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### BUILD_ID Prefix (`build-id-prefix.integration.test.ts`)
|
|
75
|
-
|
|
76
|
-
Verifies that when neither `KEY_PREFIX` nor `VERCEL_URL` is set, the handler falls back to `.next/BUILD_ID` as the Redis key prefix. Runs in its own CI job because it needs a clean environment without those env vars.
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
pnpm test:integration:build-id-prefix
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Cache Components (`cache-components/`)
|
|
83
|
-
|
|
84
|
-
Integration tests specific to Next.js 16 Cache Components (`use cache`). CI runs them against the 16.0, 16.2, and 16.3 Cache Components test apps.
|
|
85
|
-
|
|
86
|
-
| File | What it tests |
|
|
87
|
-
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
88
|
-
| `cache-components.integration.test.ts` | `use cache` lifecycle: store, retrieve, tag invalidation, `cacheLife` expiry, and every `revalidateTag` expire setting (`max`/`default`/`seconds`/`minutes`/`hours`/`days`/`weeks`, `{ expire: N }`, `{ expire: 0 }`, omitted profile) against `next start` + Redis |
|
|
89
|
-
| `redis-kill-reconnect.test.ts` | Graceful recovery when Redis drops and reconnects (main client ping only) |
|
|
90
|
-
| `redis-subscriber-outage.test.ts` | Issue #86: subscriber PubSub does not recover after Redis outage (expected to fail until bug is fixed) |
|
|
91
|
-
| `redis-quit-vs-disconnect.test.ts` | `quit()` does not reliably close a subscriber during an outage; `disconnect()` does |
|
|
92
|
-
|
|
93
|
-
`redis-kill-reconnect.test.ts` uses a container runtime and auto-detects `podman` first, then `docker`. You can force runtime selection with `CONTAINER_RUNTIME=podman` or `CONTAINER_RUNTIME=docker`.
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
pnpm test:integration:cache-components
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**Prerequisites for all integration tests:**
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
cd test/nextjs-test-projects/<app-name>
|
|
103
|
-
pnpm install && pnpm build
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## E2E Tests (`test/playwright/`)
|
|
109
|
-
|
|
110
|
-
**Runner:** Playwright
|
|
111
|
-
**Command:** `pnpm test:e2e`
|
|
112
|
-
**Config:** `playwright.config.ts`
|
|
113
|
-
**Requires:** Redis on localhost:6379 (Playwright auto-starts `next-app-16-2-6-cache-components` via `webServer`)
|
|
114
|
-
|
|
115
|
-
Browser-based tests that validate Cache Components behavior from the user's perspective. Playwright was introduced because the Cache Components (`use cache`) feature in Next.js 16 relies on interactions that `fetch()` alone cannot reproduce:
|
|
116
|
-
|
|
117
|
-
- **Server Actions** are triggered by form submissions / button clicks — requires a real browser context
|
|
118
|
-
- `**updateTag`\*\* must be called from within a Server Action — needs actual UI interaction to verify
|
|
119
|
-
- **Cookie-based cache keys** depend on the browser sending cookies during navigation
|
|
120
|
-
- **Stale-while-revalidate** effects are only observable through page reloads and DOM diffing
|
|
121
|
-
|
|
122
|
-
The Vitest cache-components integration tests verify the server-side plumbing (Redis state, HTTP responses). Playwright closes the gap by testing the full user-facing flow.
|
|
123
|
-
|
|
124
|
-
| File | What it tests |
|
|
125
|
-
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
126
|
-
| `cache-lab.spec.ts` | `use cache` / `use cache: remote` stability, tag invalidation (`updateTag`/`revalidateTag`), `revalidateTag` durations (SWR stale window), runtime cookie-based cache keys, SWR behavior |
|
|
127
|
-
| `update-tag.spec.ts` | `updateTag` via Server Actions (button click → action → UI update) |
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
pnpm test:e2e
|
|
131
|
-
|
|
132
|
-
# Test against a specific Next.js version:
|
|
133
|
-
PLAYWRIGHT_TEST_APP=next-app-16-0-11-cache-components pnpm test:e2e
|
|
134
|
-
|
|
135
|
-
# Or point at an already-running server:
|
|
136
|
-
PLAYWRIGHT_BASE_URL=http://localhost:3001 pnpm test:e2e
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Next.js Test Projects (`test/nextjs-test-projects/`)
|
|
142
|
-
|
|
143
|
-
Minimal Next.js applications used as fixtures. They are not test runners — they provide the server that tests run against.
|
|
144
|
-
|
|
145
|
-
| App | Next.js | Used by |
|
|
146
|
-
| ----------------------------------- | ------- | -------------------------------------------------------------- |
|
|
147
|
-
| `next-app-15-4-11` | 15.4.11 | Integration (matrix, default for local), build-id-prefix |
|
|
148
|
-
| `next-app-16-0-11` | 16.0.11 | Integration (matrix) |
|
|
149
|
-
| `next-app-16-2-6` | 16.2.6 | Integration (matrix) |
|
|
150
|
-
| `next-pages-16-2-6` | 16.2.6 | Integration (Pages Router, two-instance revalidation) |
|
|
151
|
-
| `next-app-16-0-11-cache-components` | 16.0.11 | Integration (cache-components matrix), E2E (Playwright matrix) |
|
|
152
|
-
| `next-app-16-2-6-cache-components` | 16.2.6 | Integration (cache-components matrix), E2E (Playwright matrix) |
|
|
153
|
-
| `next-app-customized` | — | Example of custom config (referenced in project README) |
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## CI Jobs
|
|
158
|
-
|
|
159
|
-
The CI workflow (`.github/workflows/ci.yml`) is structured as:
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
lint-and-unit → Lint + Unit Tests + Coverage
|
|
163
|
-
├── integration → Matrix: 3 Next.js versions (15.4–16.2)
|
|
164
|
-
├── integration-pages → Pages Router (two-instance revalidation)
|
|
165
|
-
├── integration-build-id-prefix → Isolated BUILD_ID prefix test
|
|
166
|
-
├── integration-cache-components → Matrix: 16.0.11 + 16.2.6 cache-components
|
|
167
|
-
└── e2e → Matrix: Playwright against 16.0.11 + 16.2.6
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
`lint-and-unit` runs first as a gate. All other jobs run in parallel after it passes.
|
|
171
|
-
|
|
172
|
-
| CI Job | Test App(s) | What runs |
|
|
173
|
-
| ------------------------------ | --------------------------------------------------------- | --------------------------------------------------------------- |
|
|
174
|
-
| `lint-and-unit` | — | `pnpm lint` + `pnpm test:unit:coverage` |
|
|
175
|
-
| `integration` | `next-app-15-4-11`, `next-app-16-0-11`, `next-app-16-2-6` | `pnpm test:integration` (per matrix entry) |
|
|
176
|
-
| `integration-pages` | `next-pages-16-2-6` | `pnpm test:integration:pages` |
|
|
177
|
-
| `integration-build-id-prefix` | `next-app-15-4-11` | `pnpm test:integration:build-id-prefix` |
|
|
178
|
-
| `integration-cache-components` | `next-app-16-{0-3,2-3}-cache-components` | `pnpm test:integration:cache-components` + Redis kill/reconnect |
|
|
179
|
-
| `e2e` | `next-app-16-{0-3,2-3}-cache-components` | `pnpm test:e2e` (Playwright) |
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Environment Variables
|
|
184
|
-
|
|
185
|
-
| Variable | Used by | Description |
|
|
186
|
-
| ----------------------- | ------------------------------ | ------------------------------------------------------------------------- |
|
|
187
|
-
| `NEXT_TEST_APP` | Integration | Which test app to use (default: `next-app-15-4-11`) |
|
|
188
|
-
| `NEXT_PAGES_TEST_APP` | Integration (Pages Router) | Which Pages Router test app to use (default: `next-pages-16-2-6`) |
|
|
189
|
-
| `CACHE_COMPONENTS_APP` | Integration (cache-components) | Which cache-components app (default: `next-app-16-2-6-cache-components`) |
|
|
190
|
-
| `PLAYWRIGHT_TEST_APP` | E2E | Which app Playwright starts (default: `next-app-16-2-6-cache-components`) |
|
|
191
|
-
| `PLAYWRIGHT_BASE_URL` | E2E | Override base URL (skips `webServer` auto-start) |
|
|
192
|
-
| `SKIP_BUILD` | Integration | Skip Next.js build if app is pre-built |
|
|
193
|
-
| `DEBUG_INTEGRATION` | Integration | Print child process stdout/stderr |
|
|
194
|
-
| `CACHE_COMPONENTS_PORT` | Integration (cache-components) | Port for the server (default: 3065) |
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
|
2
|
-
|
|
3
|
-
## Getting Started
|
|
4
|
-
|
|
5
|
-
First, run the development server:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run dev
|
|
9
|
-
# or
|
|
10
|
-
yarn dev
|
|
11
|
-
# or
|
|
12
|
-
pnpm dev
|
|
13
|
-
# or
|
|
14
|
-
bun dev
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
-
|
|
19
|
-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
|
20
|
-
|
|
21
|
-
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
22
|
-
|
|
23
|
-
## Learn More
|
|
24
|
-
|
|
25
|
-
To learn more about Next.js, take a look at the following resources:
|
|
26
|
-
|
|
27
|
-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
28
|
-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
29
|
-
|
|
30
|
-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
31
|
-
|
|
32
|
-
## Deploy on Vercel
|
|
33
|
-
|
|
34
|
-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
35
|
-
|
|
36
|
-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { dirname } from "path";
|
|
2
|
-
import { fileURLToPath } from "url";
|
|
3
|
-
import { FlatCompat } from "@eslint/eslintrc";
|
|
4
|
-
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = dirname(__filename);
|
|
7
|
-
|
|
8
|
-
const compat = new FlatCompat({
|
|
9
|
-
baseDirectory: __dirname,
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const eslintConfig = [
|
|
13
|
-
...compat.extends("next/core-web-vitals", "next/typescript"),
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
export default eslintConfig;
|