vinext 0.0.30 → 0.0.32
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 +15 -7
- package/dist/build/prerender.d.ts +188 -0
- package/dist/build/prerender.js +675 -0
- package/dist/build/prerender.js.map +1 -0
- package/dist/build/report.d.ts +45 -46
- package/dist/build/report.js +581 -276
- package/dist/build/report.js.map +1 -1
- package/dist/build/run-prerender.d.ts +62 -0
- package/dist/build/run-prerender.js +183 -0
- package/dist/build/run-prerender.js.map +1 -0
- package/dist/build/server-manifest.d.ts +19 -0
- package/dist/build/server-manifest.js +29 -0
- package/dist/build/server-manifest.js.map +1 -0
- package/dist/build/static-export.d.ts +51 -66
- package/dist/build/static-export.js +51 -545
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.d.ts +26 -24
- package/dist/check.js +681 -571
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +1 -15
- package/dist/cli.js +432 -491
- package/dist/cli.js.map +1 -1
- package/dist/client/entry.d.ts +1 -2
- package/dist/client/entry.js +49 -62
- package/dist/client/entry.js.map +1 -1
- package/dist/client/validate-module-path.d.ts +4 -1
- package/dist/client/validate-module-path.js +23 -28
- package/dist/client/validate-module-path.js.map +1 -1
- package/dist/client/vinext-next-data.d.ts +15 -20
- package/dist/client/vinext-next-data.js +0 -1
- package/dist/cloudflare/index.d.ts +3 -8
- package/dist/cloudflare/index.js +3 -8
- package/dist/cloudflare/kv-cache-handler.d.ts +95 -105
- package/dist/cloudflare/kv-cache-handler.js +354 -380
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +36 -34
- package/dist/cloudflare/tpr.js +460 -603
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.d.ts +31 -40
- package/dist/config/config-matchers.js +727 -936
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.d.ts +18 -11
- package/dist/config/dotenv.js +79 -84
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +156 -146
- package/dist/config/next-config.js +376 -464
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts +87 -96
- package/dist/deploy.js +490 -628
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +4 -1
- package/dist/entries/app-browser-entry.js +12 -8
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +33 -20
- package/dist/entries/app-rsc-entry.js +444 -212
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-ssr-entry.d.ts +9 -1
- package/dist/entries/app-ssr-entry.js +61 -28
- package/dist/entries/app-ssr-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +6 -2
- package/dist/entries/pages-client-entry.js +30 -33
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-entry-helpers.d.ts +5 -1
- package/dist/entries/pages-entry-helpers.js +17 -14
- package/dist/entries/pages-entry-helpers.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts +6 -2
- package/dist/entries/pages-server-entry.js +86 -114
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +92 -60
- package/dist/index.js +2151 -3133
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +40 -37
- package/dist/init.js +201 -258
- package/dist/init.js.map +1 -1
- package/dist/plugins/async-hooks-stub.d.ts +7 -3
- package/dist/plugins/async-hooks-stub.js +39 -42
- package/dist/plugins/async-hooks-stub.js.map +1 -1
- package/dist/plugins/client-reference-dedup.d.ts +7 -3
- package/dist/plugins/client-reference-dedup.js +63 -88
- package/dist/plugins/client-reference-dedup.js.map +1 -1
- package/dist/routing/app-router.d.ts +100 -96
- package/dist/routing/app-router.js +560 -670
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +18 -15
- package/dist/routing/file-matcher.js +65 -65
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +23 -24
- package/dist/routing/pages-router.js +147 -172
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.d.ts +23 -20
- package/dist/routing/route-trie.js +131 -151
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/route-validation.d.ts +5 -2
- package/dist/routing/route-validation.js +98 -130
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +10 -7
- package/dist/routing/utils.js +75 -111
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts +8 -13
- package/dist/server/api-handler.js +160 -193
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.d.ts +6 -16
- package/dist/server/app-router-entry.js +26 -54
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts +11 -64
- package/dist/server/dev-module-runner.js +89 -101
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/dev-origin-check.d.ts +12 -10
- package/dist/server/dev-origin-check.js +98 -108
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-server.d.ts +19 -15
- package/dist/server/dev-server.js +543 -871
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +4 -1
- package/dist/server/html.js +25 -26
- package/dist/server/html.js.map +1 -1
- package/dist/server/image-optimization.d.ts +31 -28
- package/dist/server/image-optimization.js +181 -210
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.d.ts +34 -59
- package/dist/server/instrumentation.js +112 -125
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +16 -26
- package/dist/server/isr-cache.js +106 -128
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts +85 -88
- package/dist/server/metadata-routes.js +270 -317
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +7 -4
- package/dist/server/middleware-codegen.js +61 -61
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware-request-headers.d.ts +8 -6
- package/dist/server/middleware-request-headers.js +47 -65
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware.d.ts +32 -47
- package/dist/server/middleware.js +261 -409
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/normalize-path.d.ts +4 -1
- package/dist/server/normalize-path.js +33 -47
- package/dist/server/normalize-path.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +38 -30
- package/dist/server/pages-i18n.js +112 -139
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/prod-server.d.ts +19 -31
- package/dist/server/prod-server.js +715 -945
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-log.d.ts +18 -12
- package/dist/server/request-log.js +45 -52
- package/dist/server/request-log.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +9 -17
- package/dist/server/request-pipeline.js +133 -184
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/worker-utils.d.ts +4 -1
- package/dist/server/worker-utils.js +31 -37
- package/dist/server/worker-utils.js.map +1 -1
- package/dist/shims/amp.d.ts +5 -2
- package/dist/shims/amp.js +19 -15
- package/dist/shims/amp.js.map +1 -1
- package/dist/shims/app.d.ts +8 -10
- package/dist/shims/app.js +0 -1
- package/dist/shims/cache-runtime.d.ts +20 -45
- package/dist/shims/cache-runtime.js +271 -422
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +130 -121
- package/dist/shims/cache.js +339 -427
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/client-only.d.ts +1 -18
- package/dist/shims/client-only.js +0 -17
- package/dist/shims/compat-router.d.ts +6 -1
- package/dist/shims/compat-router.js +23 -19
- package/dist/shims/compat-router.js.map +1 -1
- package/dist/shims/config.d.ts +7 -5
- package/dist/shims/config.js +16 -23
- package/dist/shims/config.js.map +1 -1
- package/dist/shims/constants.d.ts +119 -118
- package/dist/shims/constants.js +159 -164
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/document.d.ts +20 -16
- package/dist/shims/document.js +41 -22
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/dynamic.d.ts +13 -22
- package/dist/shims/dynamic.js +122 -136
- package/dist/shims/dynamic.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +22 -15
- package/dist/shims/error-boundary.js +81 -79
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.d.ts +11 -12
- package/dist/shims/error.js +35 -39
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +16 -14
- package/dist/shims/fetch-cache.js +439 -645
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +28 -26
- package/dist/shims/font-google-base.js +238 -325
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/font-google.d.ts +3 -3
- package/dist/shims/font-google.generated.d.ts +1928 -1924
- package/dist/shims/font-google.generated.js +1928 -2133
- package/dist/shims/font-google.generated.js.map +1 -1
- package/dist/shims/font-google.js +3 -3
- package/dist/shims/font-local.d.ts +28 -26
- package/dist/shims/font-local.js +204 -260
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/form.d.ts +13 -27
- package/dist/shims/form.js +128 -180
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/head-state.d.ts +8 -13
- package/dist/shims/head-state.js +25 -42
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +17 -20
- package/dist/shims/head.js +194 -250
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +84 -78
- package/dist/shims/headers.js +447 -575
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +16 -20
- package/dist/shims/i18n-context.js +35 -48
- package/dist/shims/i18n-context.js.map +1 -1
- package/dist/shims/i18n-state.d.ts +8 -14
- package/dist/shims/i18n-state.js +34 -42
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/image-config.d.ts +11 -8
- package/dist/shims/image-config.js +50 -83
- package/dist/shims/image-config.js.map +1 -1
- package/dist/shims/image.d.ts +37 -46
- package/dist/shims/image.js +283 -308
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/api-utils.d.ts +7 -4
- package/dist/shims/internal/api-utils.js +0 -6
- package/dist/shims/internal/app-router-context.d.ts +22 -17
- package/dist/shims/internal/app-router-context.js +17 -13
- package/dist/shims/internal/app-router-context.js.map +1 -1
- package/dist/shims/internal/cookies.d.ts +2 -9
- package/dist/shims/internal/cookies.js +2 -9
- package/dist/shims/internal/parse-cookie-header.d.ts +4 -1
- package/dist/shims/internal/parse-cookie-header.js +29 -29
- package/dist/shims/internal/parse-cookie-header.js.map +1 -1
- package/dist/shims/internal/router-context.d.ts +7 -1
- package/dist/shims/internal/router-context.js +11 -7
- package/dist/shims/internal/router-context.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +40 -37
- package/dist/shims/internal/utils.js +24 -30
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/internal/work-unit-async-storage.d.ts +6 -10
- package/dist/shims/internal/work-unit-async-storage.js +14 -11
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/layout-segment-context.d.ts +11 -14
- package/dist/shims/layout-segment-context.js +24 -23
- package/dist/shims/layout-segment-context.js.map +1 -1
- package/dist/shims/legacy-image.d.ts +39 -46
- package/dist/shims/legacy-image.js +47 -42
- package/dist/shims/legacy-image.js.map +1 -1
- package/dist/shims/link.d.ts +32 -36
- package/dist/shims/link.js +255 -391
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +210 -202
- package/dist/shims/metadata.js +545 -546
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +10 -18
- package/dist/shims/navigation-state.js +66 -74
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +59 -63
- package/dist/shims/navigation.js +505 -704
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/og.d.ts +2 -20
- package/dist/shims/og.js +2 -19
- package/dist/shims/readonly-url-search-params.d.ts +8 -5
- package/dist/shims/readonly-url-search-params.js +26 -22
- package/dist/shims/readonly-url-search-params.js.map +1 -1
- package/dist/shims/request-context.d.ts +8 -5
- package/dist/shims/request-context.js +50 -60
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -11
- package/dist/shims/request-state-types.js +0 -1
- package/dist/shims/router-state.d.ts +13 -10
- package/dist/shims/router-state.js +34 -43
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +81 -85
- package/dist/shims/router.js +506 -628
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +39 -48
- package/dist/shims/script.js +107 -160
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server-only.d.ts +1 -19
- package/dist/shims/server-only.js +0 -18
- package/dist/shims/server.d.ts +213 -164
- package/dist/shims/server.js +545 -478
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +20 -20
- package/dist/shims/unified-request-context.js +81 -99
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.d.ts +4 -1
- package/dist/shims/url-safety.js +15 -11
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/shims/url-utils.d.ts +8 -5
- package/dist/shims/url-utils.js +62 -93
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/shims/web-vitals.d.ts +10 -8
- package/dist/shims/web-vitals.js +9 -15
- package/dist/shims/web-vitals.js.map +1 -1
- package/dist/utils/base-path.d.ts +5 -2
- package/dist/utils/base-path.js +21 -19
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +17 -9
- package/dist/utils/domain-locale.js +36 -56
- package/dist/utils/domain-locale.js.map +1 -1
- package/dist/utils/hash.d.ts +4 -1
- package/dist/utils/hash.js +19 -17
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/manifest-paths.d.ts +6 -3
- package/dist/utils/manifest-paths.js +15 -16
- package/dist/utils/manifest-paths.js.map +1 -1
- package/dist/utils/project.d.ts +13 -11
- package/dist/utils/project.js +169 -216
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/query.d.ts +8 -6
- package/dist/utils/query.js +57 -67
- package/dist/utils/query.js.map +1 -1
- package/package.json +10 -9
- package/dist/build/report.d.ts.map +0 -1
- package/dist/build/static-export.d.ts.map +0 -1
- package/dist/check.d.ts.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/client/entry.d.ts.map +0 -1
- package/dist/client/validate-module-path.d.ts.map +0 -1
- package/dist/client/vinext-next-data.d.ts.map +0 -1
- package/dist/client/vinext-next-data.js.map +0 -1
- package/dist/cloudflare/index.d.ts.map +0 -1
- package/dist/cloudflare/index.js.map +0 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +0 -1
- package/dist/cloudflare/tpr.d.ts.map +0 -1
- package/dist/config/config-matchers.d.ts.map +0 -1
- package/dist/config/dotenv.d.ts.map +0 -1
- package/dist/config/next-config.d.ts.map +0 -1
- package/dist/deploy.d.ts.map +0 -1
- package/dist/entries/app-browser-entry.d.ts.map +0 -1
- package/dist/entries/app-rsc-entry.d.ts.map +0 -1
- package/dist/entries/app-ssr-entry.d.ts.map +0 -1
- package/dist/entries/pages-client-entry.d.ts.map +0 -1
- package/dist/entries/pages-entry-helpers.d.ts.map +0 -1
- package/dist/entries/pages-server-entry.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/plugins/async-hooks-stub.d.ts.map +0 -1
- package/dist/plugins/client-reference-dedup.d.ts.map +0 -1
- package/dist/routing/app-router.d.ts.map +0 -1
- package/dist/routing/file-matcher.d.ts.map +0 -1
- package/dist/routing/pages-router.d.ts.map +0 -1
- package/dist/routing/route-trie.d.ts.map +0 -1
- package/dist/routing/route-validation.d.ts.map +0 -1
- package/dist/routing/utils.d.ts.map +0 -1
- package/dist/server/api-handler.d.ts.map +0 -1
- package/dist/server/app-router-entry.d.ts.map +0 -1
- package/dist/server/dev-module-runner.d.ts.map +0 -1
- package/dist/server/dev-origin-check.d.ts.map +0 -1
- package/dist/server/dev-server.d.ts.map +0 -1
- package/dist/server/html.d.ts.map +0 -1
- package/dist/server/image-optimization.d.ts.map +0 -1
- package/dist/server/instrumentation.d.ts.map +0 -1
- package/dist/server/isr-cache.d.ts.map +0 -1
- package/dist/server/metadata-routes.d.ts.map +0 -1
- package/dist/server/middleware-codegen.d.ts.map +0 -1
- package/dist/server/middleware-request-headers.d.ts.map +0 -1
- package/dist/server/middleware.d.ts.map +0 -1
- package/dist/server/normalize-path.d.ts.map +0 -1
- package/dist/server/pages-i18n.d.ts.map +0 -1
- package/dist/server/prod-server.d.ts.map +0 -1
- package/dist/server/request-log.d.ts.map +0 -1
- package/dist/server/request-pipeline.d.ts.map +0 -1
- package/dist/server/worker-utils.d.ts.map +0 -1
- package/dist/shims/amp.d.ts.map +0 -1
- package/dist/shims/app.d.ts.map +0 -1
- package/dist/shims/app.js.map +0 -1
- package/dist/shims/cache-runtime.d.ts.map +0 -1
- package/dist/shims/cache.d.ts.map +0 -1
- package/dist/shims/client-only.d.ts.map +0 -1
- package/dist/shims/client-only.js.map +0 -1
- package/dist/shims/compat-router.d.ts.map +0 -1
- package/dist/shims/config.d.ts.map +0 -1
- package/dist/shims/constants.d.ts.map +0 -1
- package/dist/shims/document.d.ts.map +0 -1
- package/dist/shims/dynamic.d.ts.map +0 -1
- package/dist/shims/error-boundary.d.ts.map +0 -1
- package/dist/shims/error.d.ts.map +0 -1
- package/dist/shims/fetch-cache.d.ts.map +0 -1
- package/dist/shims/font-google-base.d.ts.map +0 -1
- package/dist/shims/font-google.d.ts.map +0 -1
- package/dist/shims/font-google.generated.d.ts.map +0 -1
- package/dist/shims/font-google.js.map +0 -1
- package/dist/shims/font-local.d.ts.map +0 -1
- package/dist/shims/form.d.ts.map +0 -1
- package/dist/shims/head-state.d.ts.map +0 -1
- package/dist/shims/head.d.ts.map +0 -1
- package/dist/shims/headers.d.ts.map +0 -1
- package/dist/shims/i18n-context.d.ts.map +0 -1
- package/dist/shims/i18n-state.d.ts.map +0 -1
- package/dist/shims/image-config.d.ts.map +0 -1
- package/dist/shims/image.d.ts.map +0 -1
- package/dist/shims/internal/api-utils.d.ts.map +0 -1
- package/dist/shims/internal/api-utils.js.map +0 -1
- package/dist/shims/internal/app-router-context.d.ts.map +0 -1
- package/dist/shims/internal/cookies.d.ts.map +0 -1
- package/dist/shims/internal/cookies.js.map +0 -1
- package/dist/shims/internal/parse-cookie-header.d.ts.map +0 -1
- package/dist/shims/internal/router-context.d.ts.map +0 -1
- package/dist/shims/internal/utils.d.ts.map +0 -1
- package/dist/shims/internal/work-unit-async-storage.d.ts.map +0 -1
- package/dist/shims/layout-segment-context.d.ts.map +0 -1
- package/dist/shims/legacy-image.d.ts.map +0 -1
- package/dist/shims/link.d.ts.map +0 -1
- package/dist/shims/metadata.d.ts.map +0 -1
- package/dist/shims/navigation-state.d.ts.map +0 -1
- package/dist/shims/navigation.d.ts.map +0 -1
- package/dist/shims/og.d.ts.map +0 -1
- package/dist/shims/og.js.map +0 -1
- package/dist/shims/readonly-url-search-params.d.ts.map +0 -1
- package/dist/shims/request-context.d.ts.map +0 -1
- package/dist/shims/request-state-types.d.ts.map +0 -1
- package/dist/shims/request-state-types.js.map +0 -1
- package/dist/shims/router-state.d.ts.map +0 -1
- package/dist/shims/router.d.ts.map +0 -1
- package/dist/shims/script.d.ts.map +0 -1
- package/dist/shims/server-only.d.ts.map +0 -1
- package/dist/shims/server-only.js.map +0 -1
- package/dist/shims/server.d.ts.map +0 -1
- package/dist/shims/unified-request-context.d.ts.map +0 -1
- package/dist/shims/url-safety.d.ts.map +0 -1
- package/dist/shims/url-utils.d.ts.map +0 -1
- package/dist/shims/web-vitals.d.ts.map +0 -1
- package/dist/utils/base-path.d.ts.map +0 -1
- package/dist/utils/domain-locale.d.ts.map +0 -1
- package/dist/utils/hash.d.ts.map +0 -1
- package/dist/utils/manifest-paths.d.ts.map +0 -1
- package/dist/utils/project.d.ts.map +0 -1
- package/dist/utils/query.d.ts.map +0 -1
|
@@ -1,704 +1,498 @@
|
|
|
1
|
-
|
|
2
|
-
* Extended fetch() with Next.js caching semantics.
|
|
3
|
-
*
|
|
4
|
-
* Patches `globalThis.fetch` during server rendering to support:
|
|
5
|
-
*
|
|
6
|
-
* fetch(url, { next: { revalidate: 60, tags: ['posts'] } })
|
|
7
|
-
* fetch(url, { cache: 'force-cache' })
|
|
8
|
-
* fetch(url, { cache: 'no-store' })
|
|
9
|
-
*
|
|
10
|
-
* Cached responses are stored via the pluggable CacheHandler, so
|
|
11
|
-
* revalidateTag() and revalidatePath() invalidate fetch-level caches.
|
|
12
|
-
*
|
|
13
|
-
* Usage (in server entry):
|
|
14
|
-
* import { withFetchCache, cleanupFetchCache } from './fetch-cache';
|
|
15
|
-
* const cleanup = withFetchCache();
|
|
16
|
-
* try { ... render ... } finally { cleanup(); }
|
|
17
|
-
*
|
|
18
|
-
* Or use the async helper:
|
|
19
|
-
* await runWithFetchCache(async () => { ... render ... });
|
|
20
|
-
*/
|
|
21
|
-
import { getCacheHandler } from "./cache.js";
|
|
1
|
+
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
22
2
|
import { getRequestExecutionContext } from "./request-context.js";
|
|
3
|
+
import { getCacheHandler } from "./cache.js";
|
|
23
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
24
|
-
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Cache key generation
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
5
|
+
//#region src/shims/fetch-cache.ts
|
|
28
6
|
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
7
|
+
* Extended fetch() with Next.js caching semantics.
|
|
8
|
+
*
|
|
9
|
+
* Patches `globalThis.fetch` during server rendering to support:
|
|
10
|
+
*
|
|
11
|
+
* fetch(url, { next: { revalidate: 60, tags: ['posts'] } })
|
|
12
|
+
* fetch(url, { cache: 'force-cache' })
|
|
13
|
+
* fetch(url, { cache: 'no-store' })
|
|
14
|
+
*
|
|
15
|
+
* Cached responses are stored via the pluggable CacheHandler, so
|
|
16
|
+
* revalidateTag() and revalidatePath() invalidate fetch-level caches.
|
|
17
|
+
*
|
|
18
|
+
* Usage (in server entry):
|
|
19
|
+
* import { withFetchCache, cleanupFetchCache } from './fetch-cache';
|
|
20
|
+
* const cleanup = withFetchCache();
|
|
21
|
+
* try { ... render ... } finally { cleanup(); }
|
|
22
|
+
*
|
|
23
|
+
* Or use the async helper:
|
|
24
|
+
* await runWithFetchCache(async () => { ... render ... });
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Headers excluded from the cache key. These are W3C trace context headers
|
|
28
|
+
* that can break request caching and deduplication.
|
|
29
|
+
* All other headers ARE included in the cache key, matching Next.js behavior.
|
|
30
|
+
*/
|
|
33
31
|
const HEADER_BLOCKLIST = ["traceparent", "tracestate"];
|
|
34
|
-
// Cache key version — bump when changing the key format to bust stale entries
|
|
35
32
|
const CACHE_KEY_PREFIX = "v3";
|
|
36
|
-
const MAX_CACHE_KEY_BODY_BYTES = 1024 * 1024;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
33
|
+
const MAX_CACHE_KEY_BODY_BYTES = 1024 * 1024;
|
|
34
|
+
var BodyTooLargeForCacheKeyError = class extends Error {
|
|
35
|
+
constructor() {
|
|
36
|
+
super("Fetch body too large for cache key generation");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var SkipCacheKeyGenerationError = class extends Error {
|
|
40
|
+
constructor() {
|
|
41
|
+
super("Fetch body could not be serialized for cache key generation");
|
|
42
|
+
}
|
|
43
|
+
};
|
|
47
44
|
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
* Collect all headers from the request, excluding the blocklist.
|
|
46
|
+
* Merges headers from both the Request object and the init object,
|
|
47
|
+
* with init taking precedence (matching fetch() spec behavior).
|
|
48
|
+
*/
|
|
52
49
|
function collectHeaders(input, init) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
63
|
-
headers.forEach((v, k) => {
|
|
64
|
-
merged[k] = v;
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
// Remove blocklisted headers
|
|
68
|
-
for (const blocked of HEADER_BLOCKLIST) {
|
|
69
|
-
delete merged[blocked];
|
|
70
|
-
}
|
|
71
|
-
return merged;
|
|
50
|
+
const merged = {};
|
|
51
|
+
if (input instanceof Request && input.headers) input.headers.forEach((v, k) => {
|
|
52
|
+
merged[k] = v;
|
|
53
|
+
});
|
|
54
|
+
if (init?.headers) (init.headers instanceof Headers ? init.headers : new Headers(init.headers)).forEach((v, k) => {
|
|
55
|
+
merged[k] = v;
|
|
56
|
+
});
|
|
57
|
+
for (const blocked of HEADER_BLOCKLIST) delete merged[blocked];
|
|
58
|
+
return merged;
|
|
72
59
|
}
|
|
73
60
|
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const AUTH_HEADERS = [
|
|
61
|
+
* Check whether a fetch request carries any per-user auth headers.
|
|
62
|
+
* Used for the safety bypass (skip caching when auth headers are present
|
|
63
|
+
* without an explicit cache opt-in).
|
|
64
|
+
*/
|
|
65
|
+
const AUTH_HEADERS = [
|
|
66
|
+
"authorization",
|
|
67
|
+
"cookie",
|
|
68
|
+
"x-api-key"
|
|
69
|
+
];
|
|
79
70
|
function hasAuthHeaders(input, init) {
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
const headers = collectHeaders(input, init);
|
|
72
|
+
return AUTH_HEADERS.some((name) => name in headers);
|
|
82
73
|
}
|
|
83
74
|
async function serializeFormData(formData, pushBodyChunk, getTotalBodyBytes) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
},
|
|
101
|
-
]));
|
|
102
|
-
}
|
|
75
|
+
for (const [key, val] of formData.entries()) {
|
|
76
|
+
if (typeof val === "string") {
|
|
77
|
+
pushBodyChunk(JSON.stringify([key, {
|
|
78
|
+
kind: "string",
|
|
79
|
+
value: val
|
|
80
|
+
}]));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (val.size > MAX_CACHE_KEY_BODY_BYTES || getTotalBodyBytes() + val.size > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
84
|
+
pushBodyChunk(JSON.stringify([key, {
|
|
85
|
+
kind: "file",
|
|
86
|
+
name: val.name,
|
|
87
|
+
type: val.type,
|
|
88
|
+
value: await val.text()
|
|
89
|
+
}]));
|
|
90
|
+
}
|
|
103
91
|
}
|
|
104
92
|
function getParsedFormContentType(contentType) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return mediaType;
|
|
108
|
-
}
|
|
109
|
-
return undefined;
|
|
93
|
+
const mediaType = contentType?.split(";")[0]?.trim().toLowerCase();
|
|
94
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") return mediaType;
|
|
110
95
|
}
|
|
111
96
|
function stripMultipartBoundary(contentType) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
.filter((param) => !/^boundary\s*=/i.test(param));
|
|
117
|
-
const normalizedType = type.trim().toLowerCase();
|
|
118
|
-
return keptParams.length > 0 ? `${normalizedType}; ${keptParams.join("; ")}` : normalizedType;
|
|
97
|
+
const [type, ...params] = contentType.split(";");
|
|
98
|
+
const keptParams = params.map((param) => param.trim()).filter(Boolean).filter((param) => !/^boundary\s*=/i.test(param));
|
|
99
|
+
const normalizedType = type.trim().toLowerCase();
|
|
100
|
+
return keptParams.length > 0 ? `${normalizedType}; ${keptParams.join("; ")}` : normalizedType;
|
|
119
101
|
}
|
|
120
102
|
async function readRequestBodyChunksWithinLimit(request) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
return { chunks, contentType };
|
|
103
|
+
const contentLengthHeader = request.headers.get("content-length");
|
|
104
|
+
if (contentLengthHeader) {
|
|
105
|
+
const contentLength = Number(contentLengthHeader);
|
|
106
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
107
|
+
}
|
|
108
|
+
const requestClone = request.clone();
|
|
109
|
+
const contentType = requestClone.headers.get("content-type") ?? void 0;
|
|
110
|
+
const reader = requestClone.body?.getReader();
|
|
111
|
+
if (!reader) return {
|
|
112
|
+
chunks: [],
|
|
113
|
+
contentType
|
|
114
|
+
};
|
|
115
|
+
const chunks = [];
|
|
116
|
+
let totalBodyBytes = 0;
|
|
117
|
+
try {
|
|
118
|
+
while (true) {
|
|
119
|
+
const { done, value } = await reader.read();
|
|
120
|
+
if (done) break;
|
|
121
|
+
totalBodyBytes += value.byteLength;
|
|
122
|
+
if (totalBodyBytes > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
123
|
+
chunks.push(value);
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
reader.cancel().catch(() => {});
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
chunks,
|
|
131
|
+
contentType
|
|
132
|
+
};
|
|
153
133
|
}
|
|
154
134
|
/**
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
135
|
+
* Serialize request body into string chunks for cache key inclusion.
|
|
136
|
+
* Handles all body types: string, Uint8Array, ReadableStream, FormData, Blob,
|
|
137
|
+
* and Request object bodies.
|
|
138
|
+
* Returns the serialized body chunks and optionally stashes the original body
|
|
139
|
+
* on init as `_ogBody` so it can still be used after stream consumption.
|
|
140
|
+
*/
|
|
161
141
|
async function serializeBody(input, init) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
pushBodyChunk(init.body);
|
|
251
|
-
init._ogBody = init.body;
|
|
252
|
-
}
|
|
253
|
-
else if (input instanceof Request && input.body) {
|
|
254
|
-
let chunks;
|
|
255
|
-
let contentType;
|
|
256
|
-
try {
|
|
257
|
-
({ chunks, contentType } = await readRequestBodyChunksWithinLimit(input));
|
|
258
|
-
}
|
|
259
|
-
catch (err) {
|
|
260
|
-
if (err instanceof BodyTooLargeForCacheKeyError) {
|
|
261
|
-
throw err;
|
|
262
|
-
}
|
|
263
|
-
throw new SkipCacheKeyGenerationError();
|
|
264
|
-
}
|
|
265
|
-
const formContentType = getParsedFormContentType(contentType);
|
|
266
|
-
if (formContentType) {
|
|
267
|
-
try {
|
|
268
|
-
const boundedRequest = new Request(input.url, {
|
|
269
|
-
method: input.method,
|
|
270
|
-
headers: contentType ? { "content-type": contentType } : undefined,
|
|
271
|
-
body: new Blob(chunks),
|
|
272
|
-
});
|
|
273
|
-
const formData = await boundedRequest.formData();
|
|
274
|
-
await serializeFormData(formData, pushBodyChunk, getTotalBodyBytes);
|
|
275
|
-
canonicalizedContentType =
|
|
276
|
-
formContentType === "multipart/form-data" && contentType
|
|
277
|
-
? stripMultipartBoundary(contentType)
|
|
278
|
-
: undefined;
|
|
279
|
-
return { bodyChunks, canonicalizedContentType };
|
|
280
|
-
}
|
|
281
|
-
catch (err) {
|
|
282
|
-
if (err instanceof BodyTooLargeForCacheKeyError) {
|
|
283
|
-
throw err;
|
|
284
|
-
}
|
|
285
|
-
throw new SkipCacheKeyGenerationError();
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
for (const chunk of chunks) {
|
|
289
|
-
pushBodyChunk(decoder.decode(chunk, { stream: true }));
|
|
290
|
-
}
|
|
291
|
-
const finalChunk = decoder.decode();
|
|
292
|
-
if (finalChunk) {
|
|
293
|
-
pushBodyChunk(finalChunk);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return { bodyChunks, canonicalizedContentType };
|
|
142
|
+
if (!init?.body && !(input instanceof Request && input.body)) return { bodyChunks: [] };
|
|
143
|
+
const bodyChunks = [];
|
|
144
|
+
const encoder = new TextEncoder();
|
|
145
|
+
const decoder = new TextDecoder();
|
|
146
|
+
let totalBodyBytes = 0;
|
|
147
|
+
let canonicalizedContentType;
|
|
148
|
+
const pushBodyChunk = (chunk) => {
|
|
149
|
+
totalBodyBytes += encoder.encode(chunk).byteLength;
|
|
150
|
+
if (totalBodyBytes > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
151
|
+
bodyChunks.push(chunk);
|
|
152
|
+
};
|
|
153
|
+
const getTotalBodyBytes = () => totalBodyBytes;
|
|
154
|
+
if (init?.body instanceof Uint8Array) {
|
|
155
|
+
if (init.body.byteLength > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
156
|
+
pushBodyChunk(decoder.decode(init.body));
|
|
157
|
+
init._ogBody = init.body;
|
|
158
|
+
} else if (init?.body && typeof init.body.getReader === "function") {
|
|
159
|
+
const [bodyForHashing, bodyForFetch] = init.body.tee();
|
|
160
|
+
init._ogBody = bodyForFetch;
|
|
161
|
+
const reader = bodyForHashing.getReader();
|
|
162
|
+
try {
|
|
163
|
+
while (true) {
|
|
164
|
+
const { done, value } = await reader.read();
|
|
165
|
+
if (done) break;
|
|
166
|
+
if (typeof value === "string") pushBodyChunk(value);
|
|
167
|
+
else {
|
|
168
|
+
totalBodyBytes += value.byteLength;
|
|
169
|
+
if (totalBodyBytes > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
170
|
+
bodyChunks.push(decoder.decode(value, { stream: true }));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const finalChunk = decoder.decode();
|
|
174
|
+
if (finalChunk) pushBodyChunk(finalChunk);
|
|
175
|
+
} catch (err) {
|
|
176
|
+
await reader.cancel();
|
|
177
|
+
if (err instanceof BodyTooLargeForCacheKeyError) throw err;
|
|
178
|
+
throw new SkipCacheKeyGenerationError();
|
|
179
|
+
}
|
|
180
|
+
} else if (init?.body instanceof URLSearchParams) {
|
|
181
|
+
init._ogBody = init.body;
|
|
182
|
+
pushBodyChunk(init.body.toString());
|
|
183
|
+
} else if (init?.body && typeof init.body.keys === "function") {
|
|
184
|
+
const formData = init.body;
|
|
185
|
+
init._ogBody = init.body;
|
|
186
|
+
await serializeFormData(formData, pushBodyChunk, getTotalBodyBytes);
|
|
187
|
+
} else if (init?.body && typeof init.body.arrayBuffer === "function") {
|
|
188
|
+
const blob = init.body;
|
|
189
|
+
if (blob.size > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
190
|
+
pushBodyChunk(await blob.text());
|
|
191
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
192
|
+
init._ogBody = new Blob([arrayBuffer], { type: blob.type });
|
|
193
|
+
} else if (typeof init?.body === "string") {
|
|
194
|
+
if (init.body.length > MAX_CACHE_KEY_BODY_BYTES) throw new BodyTooLargeForCacheKeyError();
|
|
195
|
+
pushBodyChunk(init.body);
|
|
196
|
+
init._ogBody = init.body;
|
|
197
|
+
} else if (input instanceof Request && input.body) {
|
|
198
|
+
let chunks;
|
|
199
|
+
let contentType;
|
|
200
|
+
try {
|
|
201
|
+
({chunks, contentType} = await readRequestBodyChunksWithinLimit(input));
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (err instanceof BodyTooLargeForCacheKeyError) throw err;
|
|
204
|
+
throw new SkipCacheKeyGenerationError();
|
|
205
|
+
}
|
|
206
|
+
const formContentType = getParsedFormContentType(contentType);
|
|
207
|
+
if (formContentType) try {
|
|
208
|
+
await serializeFormData(await new Request(input.url, {
|
|
209
|
+
method: input.method,
|
|
210
|
+
headers: contentType ? { "content-type": contentType } : void 0,
|
|
211
|
+
body: new Blob(chunks)
|
|
212
|
+
}).formData(), pushBodyChunk, getTotalBodyBytes);
|
|
213
|
+
canonicalizedContentType = formContentType === "multipart/form-data" && contentType ? stripMultipartBoundary(contentType) : void 0;
|
|
214
|
+
return {
|
|
215
|
+
bodyChunks,
|
|
216
|
+
canonicalizedContentType
|
|
217
|
+
};
|
|
218
|
+
} catch (err) {
|
|
219
|
+
if (err instanceof BodyTooLargeForCacheKeyError) throw err;
|
|
220
|
+
throw new SkipCacheKeyGenerationError();
|
|
221
|
+
}
|
|
222
|
+
for (const chunk of chunks) pushBodyChunk(decoder.decode(chunk, { stream: true }));
|
|
223
|
+
const finalChunk = decoder.decode();
|
|
224
|
+
if (finalChunk) pushBodyChunk(finalChunk);
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
bodyChunks,
|
|
228
|
+
canonicalizedContentType
|
|
229
|
+
};
|
|
297
230
|
}
|
|
298
231
|
/**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
232
|
+
* Generate a deterministic cache key from a fetch request.
|
|
233
|
+
*
|
|
234
|
+
* Matches Next.js behavior: the key is a SHA-256 hash of a JSON array
|
|
235
|
+
* containing URL, method, all headers (minus blocklist), all RequestInit
|
|
236
|
+
* options, and the serialized body.
|
|
237
|
+
*/
|
|
305
238
|
async function buildFetchCacheKey(input, init) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
init?.referrerPolicy,
|
|
336
|
-
init?.integrity,
|
|
337
|
-
init?.cache,
|
|
338
|
-
bodyChunks,
|
|
339
|
-
]);
|
|
340
|
-
const encoder = new TextEncoder();
|
|
341
|
-
const buffer = encoder.encode(cacheString);
|
|
342
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
343
|
-
return Array.prototype.map
|
|
344
|
-
.call(new Uint8Array(hashBuffer), (b) => b.toString(16).padStart(2, "0"))
|
|
345
|
-
.join("");
|
|
239
|
+
let url;
|
|
240
|
+
let method = "GET";
|
|
241
|
+
if (typeof input === "string") url = input;
|
|
242
|
+
else if (input instanceof URL) url = input.toString();
|
|
243
|
+
else {
|
|
244
|
+
url = input.url;
|
|
245
|
+
method = input.method || "GET";
|
|
246
|
+
}
|
|
247
|
+
if (init?.method) method = init.method;
|
|
248
|
+
const headers = collectHeaders(input, init);
|
|
249
|
+
const { bodyChunks, canonicalizedContentType } = await serializeBody(input, init);
|
|
250
|
+
if (canonicalizedContentType) headers["content-type"] = canonicalizedContentType;
|
|
251
|
+
const cacheString = JSON.stringify([
|
|
252
|
+
CACHE_KEY_PREFIX,
|
|
253
|
+
url,
|
|
254
|
+
method,
|
|
255
|
+
headers,
|
|
256
|
+
init?.mode,
|
|
257
|
+
init?.redirect,
|
|
258
|
+
init?.credentials,
|
|
259
|
+
init?.referrer,
|
|
260
|
+
init?.referrerPolicy,
|
|
261
|
+
init?.integrity,
|
|
262
|
+
init?.cache,
|
|
263
|
+
bodyChunks
|
|
264
|
+
]);
|
|
265
|
+
const buffer = new TextEncoder().encode(cacheString);
|
|
266
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
267
|
+
return Array.prototype.map.call(new Uint8Array(hashBuffer), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
346
268
|
}
|
|
347
|
-
// ---------------------------------------------------------------------------
|
|
348
|
-
// Background revalidation dedup — one in-flight refetch per cache key.
|
|
349
|
-
// Uses Symbol.for() on globalThis so the map is shared across Vite's
|
|
350
|
-
// separate RSC and SSR module instances.
|
|
351
|
-
// ---------------------------------------------------------------------------
|
|
352
269
|
const _PENDING_KEY = Symbol.for("vinext.fetchCache.pendingRefetches");
|
|
353
270
|
const _gPending = globalThis;
|
|
354
|
-
const pendingRefetches =
|
|
355
|
-
|
|
356
|
-
// Guards against hung upstream fetches that never settle, which would
|
|
357
|
-
// permanently suppress background refetches for that cache key.
|
|
358
|
-
const DEDUP_TIMEOUT_MS = 60_000;
|
|
271
|
+
const pendingRefetches = _gPending[_PENDING_KEY] ??= /* @__PURE__ */ new Map();
|
|
272
|
+
const DEDUP_TIMEOUT_MS = 6e4;
|
|
359
273
|
/** @internal Reset dedup state — exposed for test isolation only. */
|
|
360
|
-
|
|
361
|
-
|
|
274
|
+
function _resetPendingRefetches() {
|
|
275
|
+
pendingRefetches.clear();
|
|
362
276
|
}
|
|
363
|
-
// ---------------------------------------------------------------------------
|
|
364
|
-
// Patching
|
|
365
|
-
// ---------------------------------------------------------------------------
|
|
366
|
-
// Capture the real (unpatched) fetch once, shared across Vite's
|
|
367
|
-
// multi-environment module instances via Symbol.for().
|
|
368
277
|
const _ORIG_FETCH_KEY = Symbol.for("vinext.fetchCache.originalFetch");
|
|
369
278
|
const _gFetch = globalThis;
|
|
370
|
-
const originalFetch =
|
|
371
|
-
globalThis.fetch);
|
|
279
|
+
const originalFetch = _gFetch[_ORIG_FETCH_KEY] ??= globalThis.fetch;
|
|
372
280
|
const _ALS_KEY = Symbol.for("vinext.fetchCache.als");
|
|
373
281
|
const _FALLBACK_KEY = Symbol.for("vinext.fetchCache.fallback");
|
|
374
282
|
const _g = globalThis;
|
|
375
|
-
const _als =
|
|
376
|
-
|
|
377
|
-
const _fallbackState = (_g[_FALLBACK_KEY] ??= {
|
|
378
|
-
currentRequestTags: [],
|
|
379
|
-
});
|
|
283
|
+
const _als = _g[_ALS_KEY] ??= new AsyncLocalStorage();
|
|
284
|
+
const _fallbackState = _g[_FALLBACK_KEY] ??= { currentRequestTags: [] };
|
|
380
285
|
function _getState() {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
return _als.getStore() ?? _fallbackState;
|
|
286
|
+
if (isInsideUnifiedScope()) return getRequestContext();
|
|
287
|
+
return _als.getStore() ?? _fallbackState;
|
|
385
288
|
}
|
|
386
289
|
/**
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
290
|
+
* Reset the fallback state for a new request. Used by `withFetchCache()`
|
|
291
|
+
* in single-threaded contexts where ALS.run() isn't used.
|
|
292
|
+
*/
|
|
390
293
|
function _resetFallbackState() {
|
|
391
|
-
|
|
294
|
+
_fallbackState.currentRequestTags = [];
|
|
392
295
|
}
|
|
393
296
|
/**
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
297
|
+
* Get tags collected during the current render pass.
|
|
298
|
+
* Useful for associating page-level cache entries with all the
|
|
299
|
+
* fetch tags used during rendering.
|
|
300
|
+
*/
|
|
301
|
+
function getCollectedFetchTags() {
|
|
302
|
+
return [..._getState().currentRequestTags];
|
|
400
303
|
}
|
|
401
304
|
/**
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
305
|
+
* Create a patched fetch function with Next.js caching semantics.
|
|
306
|
+
*
|
|
307
|
+
* The patched fetch:
|
|
308
|
+
* 1. Checks `cache` and `next` options to determine caching behavior
|
|
309
|
+
* 2. On cache hit, returns the cached response without hitting the network
|
|
310
|
+
* 3. On cache miss, fetches from network, stores in cache, returns response
|
|
311
|
+
* 4. Respects `next.revalidate` for TTL-based revalidation
|
|
312
|
+
* 5. Respects `next.tags` for tag-based invalidation via revalidateTag()
|
|
313
|
+
*/
|
|
411
314
|
function createPatchedFetch() {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
kind: "FETCH",
|
|
527
|
-
data: {
|
|
528
|
-
headers: freshHeaders,
|
|
529
|
-
body: freshBody,
|
|
530
|
-
url: typeof input === "string"
|
|
531
|
-
? input
|
|
532
|
-
: input instanceof URL
|
|
533
|
-
? input.toString()
|
|
534
|
-
: input.url,
|
|
535
|
-
status: freshResp.status,
|
|
536
|
-
},
|
|
537
|
-
tags,
|
|
538
|
-
revalidate: revalidateSeconds,
|
|
539
|
-
};
|
|
540
|
-
await handler.set(cacheKey, freshValue, {
|
|
541
|
-
fetchCache: true,
|
|
542
|
-
tags,
|
|
543
|
-
revalidate: revalidateSeconds,
|
|
544
|
-
});
|
|
545
|
-
})
|
|
546
|
-
.catch((err) => {
|
|
547
|
-
const url = typeof input === "string"
|
|
548
|
-
? input
|
|
549
|
-
: input instanceof URL
|
|
550
|
-
? input.toString()
|
|
551
|
-
: input.url;
|
|
552
|
-
console.error(`[vinext] fetch cache background revalidation failed for ${url} (key=${cacheKey.slice(0, 12)}...):`, err);
|
|
553
|
-
})
|
|
554
|
-
.finally(() => {
|
|
555
|
-
// Only clear if we still own the slot — the timeout may have
|
|
556
|
-
// already replaced it with a newer refetch promise.
|
|
557
|
-
if (pendingRefetches.get(cacheKey) === refetchPromise) {
|
|
558
|
-
pendingRefetches.delete(cacheKey);
|
|
559
|
-
}
|
|
560
|
-
clearTimeout(timeoutId);
|
|
561
|
-
});
|
|
562
|
-
pendingRefetches.set(cacheKey, refetchPromise);
|
|
563
|
-
// Safety net: if the upstream fetch hangs forever, force-clean the
|
|
564
|
-
// dedup entry so future stale hits can retry instead of being
|
|
565
|
-
// permanently suppressed.
|
|
566
|
-
const timeoutId = setTimeout(() => {
|
|
567
|
-
if (pendingRefetches.get(cacheKey) === refetchPromise) {
|
|
568
|
-
pendingRefetches.delete(cacheKey);
|
|
569
|
-
}
|
|
570
|
-
}, DEDUP_TIMEOUT_MS);
|
|
571
|
-
getRequestExecutionContext()?.waitUntil(refetchPromise);
|
|
572
|
-
}
|
|
573
|
-
// Return stale data immediately
|
|
574
|
-
return new Response(staleData.body, {
|
|
575
|
-
status: staleData.status ?? 200,
|
|
576
|
-
headers: staleData.headers,
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
catch (cacheErr) {
|
|
581
|
-
// Cache read failed — fall through to network
|
|
582
|
-
console.error("[vinext] fetch cache read error:", cacheErr);
|
|
583
|
-
}
|
|
584
|
-
// Cache miss — fetch from network
|
|
585
|
-
const cleanInit = stripNextFromInit(init);
|
|
586
|
-
const response = await originalFetch(input, cleanInit);
|
|
587
|
-
// Only cache 200 responses
|
|
588
|
-
if (response.status === 200) {
|
|
589
|
-
// Clone before reading body
|
|
590
|
-
const cloned = response.clone();
|
|
591
|
-
const body = await cloned.text();
|
|
592
|
-
const headers = {};
|
|
593
|
-
cloned.headers.forEach((v, k) => {
|
|
594
|
-
headers[k] = v;
|
|
595
|
-
});
|
|
596
|
-
const cacheValue = {
|
|
597
|
-
kind: "FETCH",
|
|
598
|
-
data: {
|
|
599
|
-
headers,
|
|
600
|
-
body,
|
|
601
|
-
url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
|
|
602
|
-
status: cloned.status,
|
|
603
|
-
},
|
|
604
|
-
tags,
|
|
605
|
-
revalidate: revalidateSeconds,
|
|
606
|
-
};
|
|
607
|
-
// Store in cache (fire-and-forget)
|
|
608
|
-
handler
|
|
609
|
-
.set(cacheKey, cacheValue, {
|
|
610
|
-
fetchCache: true,
|
|
611
|
-
tags,
|
|
612
|
-
revalidate: revalidateSeconds,
|
|
613
|
-
})
|
|
614
|
-
.catch((err) => {
|
|
615
|
-
console.error("[vinext] fetch cache write error:", err);
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
return response;
|
|
619
|
-
};
|
|
315
|
+
return async function patchedFetch(input, init) {
|
|
316
|
+
const nextOpts = init?.next;
|
|
317
|
+
const cacheDirective = init?.cache;
|
|
318
|
+
if (!nextOpts && !cacheDirective) return originalFetch(input, init);
|
|
319
|
+
if (cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === false || nextOpts?.revalidate === 0) return originalFetch(input, stripNextFromInit(init));
|
|
320
|
+
if (!(cacheDirective === "force-cache" || typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) && hasAuthHeaders(input, init)) return originalFetch(input, stripNextFromInit(init));
|
|
321
|
+
let revalidateSeconds;
|
|
322
|
+
if (cacheDirective === "force-cache") revalidateSeconds = nextOpts?.revalidate && typeof nextOpts.revalidate === "number" ? nextOpts.revalidate : 31536e3;
|
|
323
|
+
else if (typeof nextOpts?.revalidate === "number" && nextOpts.revalidate > 0) revalidateSeconds = nextOpts.revalidate;
|
|
324
|
+
else if (nextOpts?.tags && nextOpts.tags.length > 0) revalidateSeconds = 31536e3;
|
|
325
|
+
else return originalFetch(input, stripNextFromInit(init));
|
|
326
|
+
const tags = nextOpts?.tags ?? [];
|
|
327
|
+
let cacheKey;
|
|
328
|
+
try {
|
|
329
|
+
cacheKey = await buildFetchCacheKey(input, init);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
if (err instanceof BodyTooLargeForCacheKeyError || err instanceof SkipCacheKeyGenerationError) return originalFetch(input, stripNextFromInit(init));
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
const handler = getCacheHandler();
|
|
335
|
+
const reqTags = _getState().currentRequestTags;
|
|
336
|
+
if (tags.length > 0) {
|
|
337
|
+
for (const tag of tags) if (!reqTags.includes(tag)) reqTags.push(tag);
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const cached = await handler.get(cacheKey, {
|
|
341
|
+
kind: "FETCH",
|
|
342
|
+
tags
|
|
343
|
+
});
|
|
344
|
+
if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState !== "stale") {
|
|
345
|
+
const cachedData = cached.value.data;
|
|
346
|
+
return new Response(cachedData.body, {
|
|
347
|
+
status: cachedData.status ?? 200,
|
|
348
|
+
headers: cachedData.headers
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState === "stale") {
|
|
352
|
+
const staleData = cached.value.data;
|
|
353
|
+
if (!pendingRefetches.has(cacheKey)) {
|
|
354
|
+
const refetchPromise = originalFetch(input, stripNextFromInit(init)).then(async (freshResp) => {
|
|
355
|
+
if (freshResp.status !== 200) return;
|
|
356
|
+
const freshBody = await freshResp.text();
|
|
357
|
+
const freshHeaders = {};
|
|
358
|
+
freshResp.headers.forEach((v, k) => {
|
|
359
|
+
if (k.toLowerCase() === "set-cookie") return;
|
|
360
|
+
freshHeaders[k] = v;
|
|
361
|
+
});
|
|
362
|
+
const freshValue = {
|
|
363
|
+
kind: "FETCH",
|
|
364
|
+
data: {
|
|
365
|
+
headers: freshHeaders,
|
|
366
|
+
body: freshBody,
|
|
367
|
+
url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
|
|
368
|
+
status: freshResp.status
|
|
369
|
+
},
|
|
370
|
+
tags,
|
|
371
|
+
revalidate: revalidateSeconds
|
|
372
|
+
};
|
|
373
|
+
await handler.set(cacheKey, freshValue, {
|
|
374
|
+
fetchCache: true,
|
|
375
|
+
tags,
|
|
376
|
+
revalidate: revalidateSeconds
|
|
377
|
+
});
|
|
378
|
+
}).catch((err) => {
|
|
379
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
380
|
+
console.error(`[vinext] fetch cache background revalidation failed for ${url} (key=${cacheKey.slice(0, 12)}...):`, err);
|
|
381
|
+
}).finally(() => {
|
|
382
|
+
if (pendingRefetches.get(cacheKey) === refetchPromise) pendingRefetches.delete(cacheKey);
|
|
383
|
+
clearTimeout(timeoutId);
|
|
384
|
+
});
|
|
385
|
+
pendingRefetches.set(cacheKey, refetchPromise);
|
|
386
|
+
const timeoutId = setTimeout(() => {
|
|
387
|
+
if (pendingRefetches.get(cacheKey) === refetchPromise) pendingRefetches.delete(cacheKey);
|
|
388
|
+
}, DEDUP_TIMEOUT_MS);
|
|
389
|
+
getRequestExecutionContext()?.waitUntil(refetchPromise);
|
|
390
|
+
}
|
|
391
|
+
return new Response(staleData.body, {
|
|
392
|
+
status: staleData.status ?? 200,
|
|
393
|
+
headers: staleData.headers
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
} catch (cacheErr) {
|
|
397
|
+
console.error("[vinext] fetch cache read error:", cacheErr);
|
|
398
|
+
}
|
|
399
|
+
const response = await originalFetch(input, stripNextFromInit(init));
|
|
400
|
+
if (response.status === 200) {
|
|
401
|
+
const cloned = response.clone();
|
|
402
|
+
const body = await cloned.text();
|
|
403
|
+
const headers = {};
|
|
404
|
+
cloned.headers.forEach((v, k) => {
|
|
405
|
+
if (k.toLowerCase() === "set-cookie") return;
|
|
406
|
+
headers[k] = v;
|
|
407
|
+
});
|
|
408
|
+
const cacheValue = {
|
|
409
|
+
kind: "FETCH",
|
|
410
|
+
data: {
|
|
411
|
+
headers,
|
|
412
|
+
body,
|
|
413
|
+
url: typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url,
|
|
414
|
+
status: cloned.status
|
|
415
|
+
},
|
|
416
|
+
tags,
|
|
417
|
+
revalidate: revalidateSeconds
|
|
418
|
+
};
|
|
419
|
+
handler.set(cacheKey, cacheValue, {
|
|
420
|
+
fetchCache: true,
|
|
421
|
+
tags,
|
|
422
|
+
revalidate: revalidateSeconds
|
|
423
|
+
}).catch((err) => {
|
|
424
|
+
console.error("[vinext] fetch cache write error:", err);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
return response;
|
|
428
|
+
};
|
|
620
429
|
}
|
|
621
430
|
/**
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
431
|
+
* Strip the `next` property from RequestInit before passing to real fetch.
|
|
432
|
+
* The `next` property is not a standard fetch option and would cause warnings
|
|
433
|
+
* in some environments.
|
|
434
|
+
*/
|
|
626
435
|
function stripNextFromInit(init) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
// Restore the original body if it was stashed by serializeBody (e.g. after
|
|
632
|
-
// consuming a ReadableStream for cache key generation).
|
|
633
|
-
if (_ogBody !== undefined) {
|
|
634
|
-
rest.body = _ogBody;
|
|
635
|
-
}
|
|
636
|
-
return Object.keys(rest).length > 0 ? rest : undefined;
|
|
436
|
+
if (!init) return init;
|
|
437
|
+
const { next: _next, _ogBody, ...rest } = init;
|
|
438
|
+
if (_ogBody !== void 0) rest.body = _ogBody;
|
|
439
|
+
return Object.keys(rest).length > 0 ? rest : void 0;
|
|
637
440
|
}
|
|
638
|
-
// ---------------------------------------------------------------------------
|
|
639
|
-
// Public API
|
|
640
|
-
// ---------------------------------------------------------------------------
|
|
641
|
-
// ---------------------------------------------------------------------------
|
|
642
|
-
// Fetch patching — install once, not per-request.
|
|
643
|
-
// The patched fetch uses _getState() internally, which reads from ALS
|
|
644
|
-
// (concurrent) or _fallbackState (single-threaded), so per-request
|
|
645
|
-
// isolation is handled at the state level, not by swapping globalThis.fetch.
|
|
646
|
-
// ---------------------------------------------------------------------------
|
|
647
441
|
const _PATCH_KEY = Symbol.for("vinext.fetchCache.patchInstalled");
|
|
648
442
|
function _ensurePatchInstalled() {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
globalThis.fetch = createPatchedFetch();
|
|
443
|
+
if (_g[_PATCH_KEY]) return;
|
|
444
|
+
_g[_PATCH_KEY] = true;
|
|
445
|
+
globalThis.fetch = createPatchedFetch();
|
|
653
446
|
}
|
|
654
447
|
/**
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
448
|
+
* Install the patched fetch and reset per-request tag state.
|
|
449
|
+
* Returns a cleanup function that clears tags.
|
|
450
|
+
*
|
|
451
|
+
* @deprecated Prefer `runWithFetchCache()` which uses `AsyncLocalStorage.run()`
|
|
452
|
+
* for proper per-request isolation in concurrent environments.
|
|
453
|
+
*
|
|
454
|
+
* Usage:
|
|
455
|
+
* const cleanup = withFetchCache();
|
|
456
|
+
* try { await render(); } finally { cleanup(); }
|
|
457
|
+
*/
|
|
458
|
+
function withFetchCache() {
|
|
459
|
+
_ensurePatchInstalled();
|
|
460
|
+
_resetFallbackState();
|
|
461
|
+
return () => {
|
|
462
|
+
_resetFallbackState();
|
|
463
|
+
};
|
|
671
464
|
}
|
|
672
465
|
/**
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
return _als.run({ currentRequestTags: [] }, fn);
|
|
466
|
+
* Run an async function with patched fetch caching enabled.
|
|
467
|
+
* Uses `AsyncLocalStorage.run()` for proper per-request isolation
|
|
468
|
+
* of collected fetch tags in concurrent server environments.
|
|
469
|
+
*/
|
|
470
|
+
async function runWithFetchCache(fn) {
|
|
471
|
+
_ensurePatchInstalled();
|
|
472
|
+
if (isInsideUnifiedScope()) return await runWithUnifiedStateMutation((uCtx) => {
|
|
473
|
+
uCtx.currentRequestTags = [];
|
|
474
|
+
}, fn);
|
|
475
|
+
return _als.run({ currentRequestTags: [] }, fn);
|
|
685
476
|
}
|
|
686
477
|
/**
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
478
|
+
* Install the patched fetch without creating a standalone ALS scope.
|
|
479
|
+
*
|
|
480
|
+
* `runWithFetchCache()` is the standalone helper: it installs the patch and
|
|
481
|
+
* creates an isolated per-request tag store. The unified request context owns
|
|
482
|
+
* that isolation itself via `currentRequestTags`, so callers inside
|
|
483
|
+
* `runWithRequestContext()` only need the process-global fetch monkey-patch.
|
|
484
|
+
*/
|
|
485
|
+
function ensureFetchPatch() {
|
|
486
|
+
_ensurePatchInstalled();
|
|
696
487
|
}
|
|
697
488
|
/**
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
489
|
+
* Get the original (unpatched) fetch function.
|
|
490
|
+
* Useful for internal code that should bypass caching.
|
|
491
|
+
*/
|
|
492
|
+
function getOriginalFetch() {
|
|
493
|
+
return originalFetch;
|
|
703
494
|
}
|
|
495
|
+
//#endregion
|
|
496
|
+
export { _resetPendingRefetches, ensureFetchPatch, getCollectedFetchTags, getOriginalFetch, runWithFetchCache, withFetchCache };
|
|
497
|
+
|
|
704
498
|
//# sourceMappingURL=fetch-cache.js.map
|