@wular/pnext 0.0.4 → 0.0.6
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 +11 -11
- package/bin/pnext +1 -1
- package/config/lint/base.js +7 -7
- package/config/ts/base.json +2 -4
- package/config/ts/react.json +2 -6
- package/package.json +23 -2
- package/reference/compat.md +1 -1
- package/reference/config.md +2 -2
- package/reference/css.md +13 -9
- package/reference/dev.md +1 -1
- package/reference/metadata.md +7 -7
- package/reference/navigation.md +35 -28
- package/reference/performance.md +70 -70
- package/reference/rendering.md +17 -17
- package/reference/routing.md +17 -17
- package/reference/typegen.md +12 -8
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +113 -109
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +49 -52
- package/src/api/navigation.ts +59 -58
- package/src/api/server.ts +152 -144
- package/src/api/suspense.ts +4 -4
- package/src/cli/adapters/vercel-warm.ts +126 -121
- package/src/cli/adapters/vercel.ts +437 -443
- package/src/cli/analyze.ts +333 -144
- package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
- package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
- package/src/cli/build.ts +976 -978
- package/src/cli/create.ts +71 -63
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +88 -85
- package/src/cli/migrate/package-json.ts +73 -71
- package/src/cli/migrate/report.ts +32 -33
- package/src/cli/migrate/{index.ts → run.ts} +48 -49
- package/src/cli/migrate/scan.ts +46 -46
- package/src/cli/migrate/spinner.ts +9 -9
- package/src/cli/migrate/tsconfig.ts +35 -35
- package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
- package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
- package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
- package/src/cli/start.ts +65 -66
- package/src/{typegen.ts → cli/typegen.ts} +59 -59
- package/src/client/build.ts +794 -768
- package/src/client/chunk-fold.ts +245 -240
- package/src/client/{paths.ts → chunk-name.ts} +6 -6
- package/src/client/entry.ts +162 -147
- package/src/client/prebuilt.ts +231 -223
- package/src/client/profile.ts +29 -29
- package/src/client/react-compiler.ts +20 -15
- package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
- package/src/client/reference-stub.ts +51 -51
- package/src/client/reference.ts +19 -19
- package/src/{api → client}/router/events.ts +17 -17
- package/src/{api → client}/router/history.ts +16 -16
- package/src/{api → client}/router/hub.ts +52 -53
- package/src/{api/router.ts → client/router/index.ts} +61 -60
- package/src/{api → client}/router/policies.ts +24 -24
- package/src/{api → client}/router/runtime.ts +1988 -1992
- package/src/{api → client}/router/types.ts +93 -98
- package/src/compat/actions/client-plugin.ts +42 -43
- package/src/compat/actions/client-stub.ts +14 -14
- package/src/compat/actions/{action-client.ts → client.ts} +194 -193
- package/src/compat/actions/config.ts +63 -64
- package/src/compat/actions/detect.ts +68 -68
- package/src/compat/actions/discovery.ts +105 -105
- package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
- package/src/compat/actions/early-submit.ts +1 -1
- package/src/compat/actions/endpoint.ts +198 -198
- package/src/compat/actions/extensions.ts +811 -0
- package/src/compat/actions/flight.ts +23 -23
- package/src/compat/actions/form-state.ts +34 -34
- package/src/compat/actions/hoist.ts +382 -236
- package/src/compat/actions/ids.ts +7 -12
- package/src/compat/actions/index.ts +8 -8
- package/src/compat/actions/instances.ts +46 -46
- package/src/compat/actions/origin.ts +47 -48
- package/src/compat/actions/protocol.ts +22 -22
- package/src/compat/actions/registry.ts +19 -19
- package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
- package/src/compat/actions/rewrite.ts +125 -125
- package/src/compat/actions/{action-router.ts → router.ts} +10 -10
- package/src/compat/actions/serve.ts +132 -136
- package/src/compat/actions/server-tag.ts +4 -4
- package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
- package/src/compat/actions/unrecognized-error.ts +4 -4
- package/src/compat/{index.ts → aliases.ts} +112 -109
- package/src/compat/bundler/bun-externals.ts +18 -18
- package/src/compat/bundler/cjs-exports.ts +271 -223
- package/src/compat/bundler/config.ts +116 -111
- package/src/compat/bundler/externals.ts +12 -12
- package/src/compat/bundler/import-meta-url.ts +19 -19
- package/src/compat/bundler/modularize-imports.ts +36 -33
- package/src/compat/bundler/new-url-asset.ts +22 -24
- package/src/compat/bundler/optimize-package-imports.ts +111 -107
- package/src/compat/bundler/polyfill.ts +28 -28
- package/src/compat/bundler/react-compiler.ts +35 -29
- package/src/compat/bundler/react-profiler.tsx +11 -11
- package/src/compat/bundler/relay-transform.ts +48 -47
- package/src/compat/bundler/require-context.ts +119 -113
- package/src/compat/bundler/resolve-extensions.ts +19 -19
- package/src/compat/bundler/source-cache.ts +25 -25
- package/src/compat/bundler/static-imports.ts +7 -7
- package/src/compat/bundler/symlink-imports.ts +46 -46
- package/src/compat/bundler/tsconfig-paths.ts +13 -15
- package/src/compat/bundler/wasm.ts +58 -60
- package/src/compat/bundler/webpack-loaders.ts +254 -241
- package/src/compat/bundler/worker.ts +101 -104
- package/src/compat/cache/build-flags.ts +29 -29
- package/src/compat/cache/build-prerender-errors.ts +40 -44
- package/src/compat/cache/custom-handler.ts +60 -53
- package/src/compat/cache/fetch-patch.ts +240 -240
- package/src/compat/cache/handler.ts +27 -31
- package/src/compat/cache/modern-handler.ts +148 -126
- package/src/compat/cache/resume-data-cache.ts +47 -45
- package/src/compat/cache/revalidate.ts +233 -232
- package/src/compat/cache/runtime-error.ts +35 -35
- package/src/compat/cache/use-cache-transform.ts +442 -417
- package/src/compat/cache/use-cache.ts +650 -614
- package/src/compat/cache-control.ts +140 -142
- package/src/compat/client/base-path.ts +21 -20
- package/src/compat/client/css-order.ts +18 -18
- package/src/compat/client/errors/bare-boundary.ts +11 -11
- package/src/compat/client/errors/control-flow.ts +23 -23
- package/src/compat/client/errors/error-boundary.ts +61 -61
- package/src/compat/client/errors/global-error.ts +101 -91
- package/src/compat/client/errors/install.ts +71 -72
- package/src/compat/client/errors/lazy.ts +23 -23
- package/src/compat/client/errors/primitive-throw.ts +47 -45
- package/src/compat/client/errors/soft-refresh.ts +4 -4
- package/src/compat/client/link-status.ts +33 -33
- package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
- package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
- package/src/compat/client/navigation-scroll.ts +63 -63
- package/src/compat/client/optimistic-routing.ts +93 -88
- package/src/compat/client/prefetch-cache.ts +23 -24
- package/src/compat/client/route-announcer.ts +35 -35
- package/src/compat/client/segment-cache-policy.ts +20 -20
- package/src/compat/client/segment-cache.ts +309 -315
- package/src/compat/client/segment-prefetch.ts +127 -132
- package/src/compat/client/trailing-slash.ts +5 -4
- package/src/compat/css/chunking.ts +113 -116
- package/src/compat/css/inline-css.ts +21 -21
- package/src/compat/css/lightningcss.ts +37 -38
- package/src/compat/css/modules.ts +161 -175
- package/src/compat/css/nonce.ts +7 -7
- package/src/compat/css/sass-plugin.ts +18 -21
- package/src/compat/css/sass.ts +150 -152
- package/src/compat/css/styled-jsx-runtime.ts +27 -27
- package/src/compat/css/styled-jsx.ts +21 -21
- package/src/compat/edge-runtime.ts +27 -27
- package/src/compat/{adapter → export}/build-complete.ts +72 -75
- package/src/compat/export/client.ts +29 -31
- package/src/compat/export/{index.ts → emit.ts} +111 -110
- package/src/compat/export/standalone.ts +62 -54
- package/src/compat/image-optimizer/cache.ts +51 -49
- package/src/compat/image-optimizer/detect.ts +52 -52
- package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
- package/src/compat/image-optimizer/source.ts +77 -80
- package/src/compat/lifecycle/after-scope.ts +26 -26
- package/src/compat/lifecycle/after.ts +48 -45
- package/src/compat/lifecycle/error-funnel.ts +98 -102
- package/src/compat/lifecycle/error-serialize.ts +30 -26
- package/src/compat/lifecycle/error-ui.ts +67 -32
- package/src/compat/lifecycle/instrumentation-client.ts +36 -38
- package/src/compat/lifecycle/instrumentation.ts +85 -85
- package/src/compat/lifecycle/node-console.ts +11 -11
- package/src/compat/lifecycle/testmode.ts +160 -132
- package/src/compat/mdx/compile.ts +60 -57
- package/src/compat/mdx/plugin.ts +11 -11
- package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
- package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
- package/src/compat/metadata.ts +75 -81
- package/src/compat/next/cache.ts +68 -69
- package/src/compat/next/canonical-url.ts +9 -9
- package/src/compat/next/client-cache.ts +19 -19
- package/src/compat/next/client-navigation.ts +112 -116
- package/src/compat/next/client-only.ts +1 -1
- package/src/compat/next/client-script.tsx +99 -93
- package/src/compat/next/client-server.ts +10 -10
- package/src/compat/next/config-loader.ts +176 -173
- package/src/compat/next/config.ts +7 -7
- package/src/compat/next/constants.cjs +6 -6
- package/src/compat/next/constants.ts +6 -6
- package/src/compat/next/custom-server.ts +26 -24
- package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
- package/src/compat/next/dynamic.tsx +21 -18
- package/src/compat/next/error.tsx +52 -52
- package/src/compat/next/font/cache.ts +74 -74
- package/src/compat/next/font/google.ts +2 -2
- package/src/compat/next/font/index.ts +1 -1
- package/src/compat/next/font/local.ts +3 -3
- package/src/compat/next/font/runtime-client.ts +17 -15
- package/src/compat/next/font/runtime.ts +443 -408
- package/src/compat/next/font/shared.ts +120 -108
- package/src/compat/next/form.tsx +63 -63
- package/src/compat/next/head.tsx +2 -2
- package/src/compat/next/headers.ts +103 -95
- package/src/compat/next/image/client.tsx +220 -0
- package/src/compat/next/image/config.ts +56 -58
- package/src/compat/next/image/optimizer.ts +40 -36
- package/src/compat/next/image/patterns.ts +37 -40
- package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
- package/src/compat/next/image/shared.ts +65 -57
- package/src/compat/next/image/static-metadata.ts +98 -107
- package/src/compat/next/image/validate.ts +79 -88
- package/src/compat/next/image.tsx +19 -23
- package/src/compat/next/index.ts +1 -1
- package/src/compat/next/legacy-image.tsx +59 -60
- package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
- package/src/compat/next/link.tsx +158 -158
- package/src/compat/next/navigation.cjs +12 -3
- package/src/compat/next/navigation.ts +48 -50
- package/src/compat/next/offline.ts +27 -27
- package/src/compat/next/og.ts +121 -124
- package/src/compat/next/preferred-region.ts +13 -14
- package/src/compat/next/redirects.ts +58 -56
- package/src/compat/next/resource-hints.ts +73 -76
- package/src/compat/next/rewrites.ts +130 -133
- package/src/compat/next/root-params.ts +45 -45
- package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
- package/src/compat/next/router.cjs +4 -2
- package/src/compat/next/router.ts +58 -61
- package/src/compat/next/script.tsx +108 -108
- package/src/compat/next/server-only.ts +1 -1
- package/src/compat/next/server.ts +19 -19
- package/src/compat/next/svgr.ts +18 -17
- package/src/compat/next/telemetry.ts +24 -24
- package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
- package/src/compat/next/user-agent.ts +53 -49
- package/src/compat/next/web-vitals.ts +22 -24
- package/src/compat/otel/api.ts +41 -41
- package/src/compat/otel/client-trace-metadata.ts +25 -27
- package/src/compat/otel/fetch-span.ts +29 -29
- package/src/compat/otel/tracer.ts +331 -331
- package/src/compat/pages/api.ts +456 -0
- package/src/compat/pages/client-plugin.ts +36 -36
- package/src/compat/pages/router-state.ts +34 -34
- package/src/compat/pages/{index.ts → router.ts} +130 -135
- package/src/compat/ppr/io.ts +12 -12
- package/src/compat/ppr/missing-root-params.ts +34 -38
- package/src/compat/ppr/root-params-scan.ts +66 -66
- package/src/compat/ppr/root-params-transform.ts +24 -26
- package/src/compat/ppr/root-params.ts +30 -30
- package/src/compat/ppr/segment-config-incompat.ts +6 -7
- package/src/compat/protocol.ts +71 -70
- package/src/compat/react/action-state.ts +47 -48
- package/src/compat/react/client-lite.ts +15 -15
- package/src/compat/react/client.ts +4 -4
- package/src/compat/react/compiler-runtime.ts +11 -11
- package/src/compat/react/dom-client.ts +44 -44
- package/src/compat/react/dom-react-server.ts +10 -16
- package/src/compat/react/dom-server.ts +10 -10
- package/src/compat/react/dom.ts +52 -52
- package/src/compat/react/hooks-extra.ts +34 -35
- package/src/compat/react/parity.ts +64 -61
- package/src/compat/react/preact.ts +81 -82
- package/src/compat/react/react-server.ts +28 -28
- package/src/compat/react/router-shim.ts +1 -1
- package/src/compat/react/server-component-use.ts +8 -8
- package/src/compat/react/server-inserted-html.ts +30 -31
- package/src/compat/react/server.ts +53 -55
- package/src/compat/react/use.ts +32 -32
- package/src/compat/react/view-transition.ts +20 -20
- package/src/compat/register/actions.ts +35 -824
- package/src/compat/register/boot.ts +41 -41
- package/src/compat/register/build-tier.ts +5 -5
- package/src/compat/register/build.ts +74 -70
- package/src/compat/register/bundler.ts +161 -156
- package/src/compat/register/cache.ts +20 -20
- package/src/compat/register/client-errors.ts +3 -3
- package/src/compat/register/config.ts +6 -6
- package/src/compat/register/css-extras.ts +30 -34
- package/src/compat/register/edge-runtime.ts +3 -3
- package/src/compat/register/errors.ts +10 -12
- package/src/compat/register/export.ts +16 -16
- package/src/compat/register/font.ts +11 -11
- package/src/compat/register/hooks.ts +2 -2
- package/src/compat/register/image.ts +40 -40
- package/src/compat/register/index.ts +59 -62
- package/src/compat/register/instrumentation-client.ts +10 -10
- package/src/compat/register/lifecycle.ts +25 -28
- package/src/compat/register/mdx.ts +10 -10
- package/src/compat/register/middleware.ts +226 -16
- package/src/compat/register/otel.ts +80 -88
- package/src/compat/register/pages-api.ts +10 -463
- package/src/compat/register/ppr.ts +16 -16
- package/src/compat/register/protocol.ts +17 -18
- package/src/compat/register/proxy.ts +49 -51
- package/src/compat/register/render.ts +79 -76
- package/src/compat/register/routing.ts +162 -159
- package/src/compat/register/segment.ts +24 -1897
- package/src/compat/register/static-image.ts +3 -3
- package/src/compat/register/{misc.ts → taint.ts} +9 -9
- package/src/compat/register/typed-routes.ts +14 -14
- package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
- package/src/compat/register/validation.ts +18 -18
- package/src/compat/segment/loading-boundary.ts +43 -45
- package/src/compat/segment/page-slot.ts +69 -69
- package/src/compat/segment/serve.ts +1884 -0
- package/src/compat/segment/tree.ts +113 -112
- package/src/compat/segment/vary-key.ts +38 -38
- package/src/compat/segment/vary-params.ts +138 -142
- package/src/compat/static-params.ts +14 -12
- package/src/compat/tsconfig-defaults.ts +87 -91
- package/src/compat/typecheck/{index.ts → check.ts} +234 -212
- package/src/compat/typecheck/worker.ts +15 -12
- package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
- package/src/compat/typed-routes/manifest.ts +174 -170
- package/src/compat/typed-routes/typegen.ts +127 -110
- package/src/compat/validation/errors.ts +16 -19
- package/src/compat/validation/prerender-diagnostics.ts +521 -504
- package/src/compat/validation/{index.ts → validate.ts} +647 -648
- package/src/compat-bootstrap.ts +16 -16
- package/src/config.ts +69 -69
- package/src/css/build.ts +230 -227
- package/src/css/postcss.ts +79 -80
- package/src/css/worker.ts +14 -15
- package/src/dev/client-actions.ts +10 -10
- package/src/dev/client-chunk-store.ts +27 -27
- package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
- package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
- package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
- package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
- package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
- package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
- package/src/dev/server.ts +804 -820
- package/src/env.ts +46 -43
- package/src/extensions.ts +491 -478
- package/src/index.ts +8 -8
- package/src/internal.ts +20 -23
- package/src/{islands → render}/boundary-error.ts +3 -3
- package/src/render/hooks.ts +71 -71
- package/src/render/island-context.ts +14 -14
- package/src/render/metadata.ts +310 -310
- package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
- package/src/{ppr.ts → render/ppr.ts} +244 -245
- package/src/render/renderer.ts +2076 -2082
- package/src/render/resource-hints.ts +16 -17
- package/src/render/slots.tsx +224 -235
- package/src/{islands → render}/static-children.ts +9 -12
- package/src/{islands → render}/static-slots.ts +37 -37
- package/src/{cache/context.ts → request/cache.ts} +20 -20
- package/src/request/context.ts +107 -107
- package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
- package/src/resolve/engine.ts +90 -77
- package/src/resolve/imports.ts +475 -463
- package/src/resolve/scan-facts.ts +318 -296
- package/src/resolve/source-text.ts +37 -37
- package/src/{dynamic → resolve}/tree-shake.ts +132 -128
- package/src/routing/forwarded.ts +19 -19
- package/src/routing/handler.ts +84 -91
- package/src/routing/href.ts +69 -70
- package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
- package/src/{proxy.ts → routing/proxy.ts} +306 -312
- package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
- package/src/routing/routes.ts +827 -815
- package/src/routing/slots.ts +164 -160
- package/src/runtime/loader.ts +952 -0
- package/src/{dev → runtime}/module-cache.ts +309 -287
- package/src/{dev → runtime}/module-generations.ts +9 -9
- package/src/{dev → runtime}/module-transform.ts +81 -72
- package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
- package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
- package/src/runtime/vendor.ts +425 -404
- package/src/styles.d.ts +9 -0
- package/src/types.ts +320 -335
- package/src/utils/ansi.ts +5 -5
- package/src/utils/{source.ts → code.ts} +15 -12
- package/src/utils/content-type.ts +3 -3
- package/src/utils/decode.ts +2 -2
- package/src/utils/dev-profile.ts +13 -13
- package/src/utils/error-log.ts +6 -6
- package/src/utils/esbuild.ts +18 -18
- package/src/utils/fs-cache.ts +13 -13
- package/src/utils/fs.ts +57 -49
- package/src/utils/html.ts +20 -24
- package/src/utils/native-require.ts +8 -8
- package/src/utils/serialize.ts +139 -146
- package/src/utils/verbose.ts +18 -18
- package/src/cli/analyze-print.ts +0 -181
- package/src/compat/middleware/manifest.ts +0 -210
- package/src/compat/next/image-client.tsx +0 -215
- package/src/compat/next/link-usage.ts +0 -29
- package/src/css/index.ts +0 -2
- package/src/render/index.ts +0 -1
- package/src/style-modules.d.ts +0 -9
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
* Installed once per process by `pnext build` / `pnext start` when Next
|
|
8
8
|
* compat is enabled; plain fetches outside a render scope pass through.
|
|
9
9
|
*/
|
|
10
|
-
import { currentCacheScope } from '../../cache
|
|
10
|
+
import { currentCacheScope } from '../../request/cache'
|
|
11
11
|
import {
|
|
12
12
|
cacheComponents,
|
|
13
13
|
hangingPromise,
|
|
14
14
|
isPrerendering,
|
|
15
15
|
realNow,
|
|
16
16
|
trackPrerenderCacheFill,
|
|
17
|
-
} from '../../ppr'
|
|
18
|
-
import { cacheHandlerGet, cacheHandlerSet, hasCacheHandler } from './handler'
|
|
17
|
+
} from '../../render/ppr'
|
|
18
|
+
import { cacheHandlerGet, cacheHandlerSet, hasCacheHandler } from './handler'
|
|
19
19
|
import {
|
|
20
20
|
currentRenderCacheMeta,
|
|
21
21
|
currentRenderIsStaticGeneration,
|
|
@@ -31,116 +31,116 @@ import {
|
|
|
31
31
|
pathScopeRevalidated,
|
|
32
32
|
tagsRevalidatedAfterSeq,
|
|
33
33
|
tagsStaleSince,
|
|
34
|
-
} from './revalidate'
|
|
35
|
-
import { insideUseCacheProducer } from './use-cache'
|
|
34
|
+
} from './revalidate'
|
|
35
|
+
import { insideUseCacheProducer } from './use-cache'
|
|
36
36
|
|
|
37
|
-
const MAX_TAGS = 128
|
|
37
|
+
const MAX_TAGS = 128
|
|
38
38
|
|
|
39
39
|
interface NextFetchOptions {
|
|
40
|
-
revalidate?: number | false
|
|
41
|
-
tags?: string[]
|
|
40
|
+
revalidate?: number | false
|
|
41
|
+
tags?: string[]
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
interface FetchSnapshot {
|
|
45
|
-
status: number
|
|
46
|
-
statusText: string
|
|
47
|
-
headers: [string, string][]
|
|
48
|
-
body: Uint8Array
|
|
49
|
-
url: string
|
|
45
|
+
status: number
|
|
46
|
+
statusText: string
|
|
47
|
+
headers: [string, string][]
|
|
48
|
+
body: Uint8Array
|
|
49
|
+
url: string
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
interface FetchCacheEntry {
|
|
53
|
-
value: Promise<FetchSnapshot
|
|
54
|
-
storedAt: number
|
|
55
|
-
tags: readonly string[]
|
|
56
|
-
revalidateSeconds?: number
|
|
53
|
+
value: Promise<FetchSnapshot>
|
|
54
|
+
storedAt: number
|
|
55
|
+
tags: readonly string[]
|
|
56
|
+
revalidateSeconds?: number
|
|
57
57
|
/** A background stale-while-revalidate refresh is already in flight. */
|
|
58
|
-
refreshing?: boolean
|
|
58
|
+
refreshing?: boolean
|
|
59
59
|
/** Pathname of the render that produced this entry (path-revalidation scope). */
|
|
60
|
-
route?: string
|
|
60
|
+
route?: string
|
|
61
61
|
/**
|
|
62
62
|
* Other routes that have SERVED this entry. One fetch cache entry is shared by every route issuing the
|
|
63
63
|
* same request, and Next widens its implicit `_N_T_/<route>` soft tag on each read - so
|
|
64
64
|
* revalidatePath('/b') expires an entry that /a produced and /b reused.
|
|
65
65
|
*/
|
|
66
|
-
readRoutes?: string[]
|
|
66
|
+
readRoutes?: string[]
|
|
67
67
|
/** Hard-tag-revalidation sequence sampled when this entry was produced. */
|
|
68
|
-
tagSeq: number
|
|
68
|
+
tagSeq: number
|
|
69
69
|
/**
|
|
70
70
|
* The render cache-meta this entry was produced under: an on-demand
|
|
71
71
|
* regeneration (refreshFetches) refetches each entry once per render, then
|
|
72
72
|
* repeated reads dedupe against it.
|
|
73
73
|
*/
|
|
74
|
-
refreshedIn?: object
|
|
74
|
+
refreshedIn?: object
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export interface FetchRdcRecord {
|
|
78
|
-
key: string
|
|
78
|
+
key: string
|
|
79
79
|
snapshot: {
|
|
80
|
-
status: number
|
|
81
|
-
statusText: string
|
|
82
|
-
headers: [string, string][]
|
|
83
|
-
body: string
|
|
84
|
-
url: string
|
|
85
|
-
}
|
|
86
|
-
tags: string[]
|
|
87
|
-
storedAt: number
|
|
88
|
-
tagSeq: number
|
|
80
|
+
status: number
|
|
81
|
+
statusText: string
|
|
82
|
+
headers: [string, string][]
|
|
83
|
+
body: string
|
|
84
|
+
url: string
|
|
85
|
+
}
|
|
86
|
+
tags: string[]
|
|
87
|
+
storedAt: number
|
|
88
|
+
tagSeq: number
|
|
89
89
|
/** Process that produced this record — `tagSeq` only means anything there. */
|
|
90
|
-
pid?: string
|
|
91
|
-
revalidateSeconds?: number
|
|
92
|
-
route?: string
|
|
90
|
+
pid?: string
|
|
91
|
+
revalidateSeconds?: number
|
|
92
|
+
route?: string
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
const FETCH_CACHE = Symbol.for('pnext.compat.fetchCache')
|
|
96
|
-
const FETCH_CACHE_INSTALLED = Symbol.for('pnext.compat.fetchCacheInstalled')
|
|
95
|
+
const FETCH_CACHE = Symbol.for('pnext.compat.fetchCache')
|
|
96
|
+
const FETCH_CACHE_INSTALLED = Symbol.for('pnext.compat.fetchCacheInstalled')
|
|
97
97
|
|
|
98
98
|
function fetchCacheStore(): Map<string, FetchCacheEntry> {
|
|
99
|
-
const state = globalThis as Record<PropertyKey, unknown
|
|
100
|
-
return (state[FETCH_CACHE] ??= new Map<string, FetchCacheEntry>()) as Map<string, FetchCacheEntry
|
|
99
|
+
const state = globalThis as Record<PropertyKey, unknown>
|
|
100
|
+
return (state[FETCH_CACHE] ??= new Map<string, FetchCacheEntry>()) as Map<string, FetchCacheEntry>
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
function fetchCacheInstalled(): boolean {
|
|
104
|
-
return (globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] === true
|
|
104
|
+
return (globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] === true
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function markFetchCacheInstalled(): void {
|
|
108
|
-
(globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] = true
|
|
108
|
+
;(globalThis as Record<PropertyKey, unknown>)[FETCH_CACHE_INSTALLED] = true
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const fetchCache = fetchCacheStore()
|
|
112
|
-
const fetchCacheLimit = 2048
|
|
113
|
-
const FETCH_RDC_CAPTURE = Symbol.for('pnext.compat.fetchRdcCapture')
|
|
114
|
-
const FETCH_RDC_RECORDS = Symbol.for('pnext.compat.fetchRdcRecords')
|
|
111
|
+
const fetchCache = fetchCacheStore()
|
|
112
|
+
const fetchCacheLimit = 2048
|
|
113
|
+
const FETCH_RDC_CAPTURE = Symbol.for('pnext.compat.fetchRdcCapture')
|
|
114
|
+
const FETCH_RDC_RECORDS = Symbol.for('pnext.compat.fetchRdcRecords')
|
|
115
115
|
|
|
116
116
|
function fetchRdcRecords(): Map<string, FetchCacheEntry> {
|
|
117
|
-
const state = globalThis as Record<PropertyKey, unknown
|
|
117
|
+
const state = globalThis as Record<PropertyKey, unknown>
|
|
118
118
|
return (state[FETCH_RDC_RECORDS] ??= new Map<string, FetchCacheEntry>()) as Map<
|
|
119
119
|
string,
|
|
120
120
|
FetchCacheEntry
|
|
121
|
-
|
|
121
|
+
>
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function fetchRdcCapture(): Set<string> | undefined {
|
|
125
|
-
return (globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] as Set<string> | undefined
|
|
125
|
+
return (globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] as Set<string> | undefined
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
function captureFetchRdcEntry(key: string) {
|
|
129
|
-
fetchRdcCapture()?.add(key)
|
|
129
|
+
fetchRdcCapture()?.add(key)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
export function beginFetchRdcCapture() {
|
|
133
|
-
(globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] = new Set<string>()
|
|
133
|
+
;(globalThis as Record<PropertyKey, unknown>)[FETCH_RDC_CAPTURE] = new Set<string>()
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
export async function collectFetchRdcRecords(): Promise<FetchRdcRecord[]> {
|
|
137
|
-
const capture = fetchRdcCapture()
|
|
138
|
-
if (!capture) return []
|
|
139
|
-
const records: FetchRdcRecord[] = []
|
|
137
|
+
const capture = fetchRdcCapture()
|
|
138
|
+
if (!capture) return []
|
|
139
|
+
const records: FetchRdcRecord[] = []
|
|
140
140
|
for (const key of capture) {
|
|
141
|
-
const entry = fetchCache.get(key)
|
|
142
|
-
if (!entry) continue
|
|
143
|
-
const snapshot = await entry.value
|
|
141
|
+
const entry = fetchCache.get(key)
|
|
142
|
+
if (!entry) continue
|
|
143
|
+
const snapshot = await entry.value
|
|
144
144
|
records.push({
|
|
145
145
|
key,
|
|
146
146
|
snapshot: {
|
|
@@ -154,11 +154,13 @@ export async function collectFetchRdcRecords(): Promise<FetchRdcRecord[]> {
|
|
|
154
154
|
storedAt: entry.storedAt,
|
|
155
155
|
tagSeq: entry.tagSeq,
|
|
156
156
|
pid: rdcProcessId(),
|
|
157
|
-
...(entry.revalidateSeconds !== undefined
|
|
157
|
+
...(entry.revalidateSeconds !== undefined
|
|
158
|
+
? { revalidateSeconds: entry.revalidateSeconds }
|
|
159
|
+
: {}),
|
|
158
160
|
...(entry.route !== undefined ? { route: entry.route } : {}),
|
|
159
|
-
})
|
|
161
|
+
})
|
|
160
162
|
}
|
|
161
|
-
return records
|
|
163
|
+
return records
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
export function seedFetchRdcRecords(
|
|
@@ -167,11 +169,11 @@ export function seedFetchRdcRecords(
|
|
|
167
169
|
routeTags: readonly string[] = [],
|
|
168
170
|
) {
|
|
169
171
|
for (const record of records) {
|
|
170
|
-
if (!isFetchRdcRecord(record)) continue
|
|
172
|
+
if (!isFetchRdcRecord(record)) continue
|
|
171
173
|
// An RDC artifact is a snapshot: seeding it must never regress a live
|
|
172
174
|
// entry filled more recently (each regen seeds the stale .rdc first).
|
|
173
|
-
const live = fetchCache.get(record.key)
|
|
174
|
-
if (live !== undefined && live.storedAt > record.storedAt) continue
|
|
175
|
+
const live = fetchCache.get(record.key)
|
|
176
|
+
if (live !== undefined && live.storedAt > record.storedAt) continue
|
|
175
177
|
const entry: FetchCacheEntry = {
|
|
176
178
|
value: Promise.resolve({
|
|
177
179
|
status: record.snapshot.status,
|
|
@@ -191,33 +193,37 @@ export function seedFetchRdcRecords(
|
|
|
191
193
|
...(record.revalidateSeconds !== undefined
|
|
192
194
|
? { revalidateSeconds: record.revalidateSeconds }
|
|
193
195
|
: {}),
|
|
194
|
-
...(route !== undefined
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
...(route !== undefined
|
|
197
|
+
? { route }
|
|
198
|
+
: record.route !== undefined
|
|
199
|
+
? { route: record.route }
|
|
200
|
+
: {}),
|
|
201
|
+
}
|
|
202
|
+
fetchRdcRecords().set(record.key, entry)
|
|
203
|
+
fetchCache.set(record.key, entry)
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
/** Widen an entry's path-revalidation scope with the route now reading it. */
|
|
202
208
|
function noteFetchEntryRoute(entry: FetchCacheEntry, route: string | undefined): void {
|
|
203
|
-
if (route === undefined || route === entry.route) return
|
|
204
|
-
const routes = (entry.readRoutes ??= [])
|
|
205
|
-
if (routes.includes(route)) return
|
|
206
|
-
routes.push(route)
|
|
209
|
+
if (route === undefined || route === entry.route) return
|
|
210
|
+
const routes = (entry.readRoutes ??= [])
|
|
211
|
+
if (routes.includes(route)) return
|
|
212
|
+
routes.push(route)
|
|
207
213
|
// A single entry read from an unbounded set of routes (dynamic pathnames)
|
|
208
214
|
// must not grow without limit; the oldest reader's scope is dropped first.
|
|
209
|
-
if (routes.length > 32) routes.shift()
|
|
215
|
+
if (routes.length > 32) routes.shift()
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
/** True when this entry's producing OR any reading route was revalidated. */
|
|
213
219
|
function fetchEntryPathRevalidated(entry: FetchCacheEntry): boolean {
|
|
214
|
-
if (pathScopeRevalidated(entry.route, entry.storedAt)) return true
|
|
215
|
-
return (entry.readRoutes ?? []).some(route => pathScopeRevalidated(route, entry.storedAt))
|
|
220
|
+
if (pathScopeRevalidated(entry.route, entry.storedAt)) return true
|
|
221
|
+
return (entry.readRoutes ?? []).some(route => pathScopeRevalidated(route, entry.storedAt))
|
|
216
222
|
}
|
|
217
223
|
|
|
218
224
|
function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
|
|
219
|
-
if (!value || typeof value !== 'object') return false
|
|
220
|
-
const record = value as Partial<FetchRdcRecord
|
|
225
|
+
if (!value || typeof value !== 'object') return false
|
|
226
|
+
const record = value as Partial<FetchRdcRecord>
|
|
221
227
|
return (
|
|
222
228
|
typeof record.key === 'string' &&
|
|
223
229
|
!!record.snapshot &&
|
|
@@ -225,7 +231,10 @@ function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
|
|
|
225
231
|
typeof record.snapshot.statusText === 'string' &&
|
|
226
232
|
Array.isArray(record.snapshot.headers) &&
|
|
227
233
|
record.snapshot.headers.every(
|
|
228
|
-
header =>
|
|
234
|
+
header =>
|
|
235
|
+
Array.isArray(header) &&
|
|
236
|
+
header.length === 2 &&
|
|
237
|
+
header.every(part => typeof part === 'string'),
|
|
229
238
|
) &&
|
|
230
239
|
typeof record.snapshot.body === 'string' &&
|
|
231
240
|
typeof record.snapshot.url === 'string' &&
|
|
@@ -235,36 +244,36 @@ function isFetchRdcRecord(value: unknown): value is FetchRdcRecord {
|
|
|
235
244
|
Number.isFinite(record.storedAt) &&
|
|
236
245
|
typeof record.tagSeq === 'number' &&
|
|
237
246
|
Number.isInteger(record.tagSeq)
|
|
238
|
-
)
|
|
247
|
+
)
|
|
239
248
|
}
|
|
240
249
|
|
|
241
250
|
export function installCompatFetchCache() {
|
|
242
|
-
if (fetchCacheInstalled()) return
|
|
243
|
-
markFetchCacheInstalled()
|
|
244
|
-
registerDataCacheInvalidator(clearFetchCache)
|
|
245
|
-
const original = globalThis.fetch.bind(globalThis)
|
|
251
|
+
if (fetchCacheInstalled()) return
|
|
252
|
+
markFetchCacheInstalled()
|
|
253
|
+
registerDataCacheInvalidator(clearFetchCache)
|
|
254
|
+
const original = globalThis.fetch.bind(globalThis)
|
|
246
255
|
|
|
247
256
|
const patched = async function fetch(
|
|
248
257
|
input: Parameters<typeof globalThis.fetch>[0],
|
|
249
258
|
init?: RequestInit & { next?: NextFetchOptions },
|
|
250
259
|
): Promise<Response> {
|
|
251
|
-
const normalized = await normalizeFetchArgs(input, init)
|
|
252
|
-
if (!normalized) return original(input, init)
|
|
253
|
-
const { request } = normalized
|
|
260
|
+
const normalized = await normalizeFetchArgs(input, init)
|
|
261
|
+
if (!normalized) return original(input, init)
|
|
262
|
+
const { request } = normalized
|
|
254
263
|
// A consumed stream body was buffered for the cache key; forward the bytes.
|
|
255
|
-
if (normalized.replacementInit) init = { ...init, ...normalized.replacementInit }
|
|
264
|
+
if (normalized.replacementInit) init = { ...init, ...normalized.replacementInit }
|
|
256
265
|
|
|
257
|
-
const nextOptions = init?.next ?? requestNextOptions(input)
|
|
258
|
-
let tags = nextOptions?.tags ?? []
|
|
266
|
+
const nextOptions = init?.next ?? requestNextOptions(input)
|
|
267
|
+
let tags = nextOptions?.tags ?? []
|
|
259
268
|
if (tags.length > MAX_TAGS) {
|
|
260
269
|
console.warn(
|
|
261
270
|
`Warning: exceeded max tag count for ${request.url}, dropped tags: ${tags
|
|
262
271
|
.slice(MAX_TAGS)
|
|
263
272
|
.join(', ')}`,
|
|
264
|
-
)
|
|
265
|
-
tags = tags.slice(0, MAX_TAGS)
|
|
273
|
+
)
|
|
274
|
+
tags = tags.slice(0, MAX_TAGS)
|
|
266
275
|
}
|
|
267
|
-
const revalidate = nextOptions?.revalidate
|
|
276
|
+
const revalidate = nextOptions?.revalidate
|
|
268
277
|
if (
|
|
269
278
|
revalidate !== undefined &&
|
|
270
279
|
revalidate !== false &&
|
|
@@ -274,12 +283,12 @@ export function installCompatFetchCache() {
|
|
|
274
283
|
`Invalid revalidate value "${String(revalidate)}" on "${
|
|
275
284
|
currentRenderCacheMeta()?.route ?? request.url
|
|
276
285
|
}", must be a non-negative number or false`,
|
|
277
|
-
)
|
|
286
|
+
)
|
|
278
287
|
}
|
|
279
|
-
recordCacheTags(tags)
|
|
280
|
-
if (typeof revalidate === 'number' && revalidate > 0) recordCacheRevalidate(revalidate)
|
|
288
|
+
recordCacheTags(tags)
|
|
289
|
+
if (typeof revalidate === 'number' && revalidate > 0) recordCacheRevalidate(revalidate)
|
|
281
290
|
|
|
282
|
-
const cacheOption = init?.cache ?? requestCacheOption(input)
|
|
291
|
+
const cacheOption = init?.cache ?? requestCacheOption(input)
|
|
283
292
|
if (
|
|
284
293
|
insideDataCacheProducer() &&
|
|
285
294
|
cacheOption === undefined &&
|
|
@@ -292,12 +301,12 @@ export function installCompatFetchCache() {
|
|
|
292
301
|
// across entries whose keys differ.
|
|
293
302
|
(!currentRenderIsStaticGeneration() || insideUseCacheProducer())
|
|
294
303
|
) {
|
|
295
|
-
return original(input, init)
|
|
304
|
+
return original(input, init)
|
|
296
305
|
}
|
|
297
306
|
|
|
298
|
-
const segmentFetchCache = currentRenderCacheMeta()?.fetchCache
|
|
307
|
+
const segmentFetchCache = currentRenderCacheMeta()?.fetchCache
|
|
299
308
|
const segmentForcesCache =
|
|
300
|
-
segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache'
|
|
309
|
+
segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache'
|
|
301
310
|
// Explicit no-store signals opt the surrounding route out of prebuilt
|
|
302
311
|
// static output (Next renders it dynamically per request) — unless the
|
|
303
312
|
// segment's fetchCache forces caching, which supersedes them.
|
|
@@ -305,7 +314,7 @@ export function installCompatFetchCache() {
|
|
|
305
314
|
!segmentForcesCache &&
|
|
306
315
|
(cacheOption === 'no-store' || cacheOption === 'no-cache' || revalidate === 0)
|
|
307
316
|
) {
|
|
308
|
-
recordCacheNoStore()
|
|
317
|
+
recordCacheNoStore()
|
|
309
318
|
}
|
|
310
319
|
// Route handlers never auto-cache an implicit/default fetch (Next treats
|
|
311
320
|
// both forms as uncached), and it keeps the handler out of prebuilt static
|
|
@@ -313,8 +322,8 @@ export function installCompatFetchCache() {
|
|
|
313
322
|
// prerender time.
|
|
314
323
|
const handlerDefaultFetch =
|
|
315
324
|
(cacheOption === undefined || cacheOption === 'default') &&
|
|
316
|
-
currentRenderCacheMeta()?.handler === true
|
|
317
|
-
if (handlerDefaultFetch && !segmentForcesCache) recordCacheNoStore()
|
|
325
|
+
currentRenderCacheMeta()?.handler === true
|
|
326
|
+
if (handlerDefaultFetch && !segmentForcesCache) recordCacheNoStore()
|
|
318
327
|
|
|
319
328
|
const mode = cacheModeFor(
|
|
320
329
|
cacheOption,
|
|
@@ -322,34 +331,26 @@ export function installCompatFetchCache() {
|
|
|
322
331
|
segmentFetchCache,
|
|
323
332
|
request.method,
|
|
324
333
|
currentRenderIsStaticGeneration() && !handlerDefaultFetch,
|
|
325
|
-
)
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
cacheComponents() &&
|
|
329
|
-
isPrerendering() &&
|
|
330
|
-
!insideDataCacheProducer()
|
|
331
|
-
) {
|
|
332
|
-
return hangingPromise<Response>('fetch()');
|
|
334
|
+
)
|
|
335
|
+
if (mode !== 'cache' && cacheComponents() && isPrerendering() && !insideDataCacheProducer()) {
|
|
336
|
+
return hangingPromise<Response>('fetch()')
|
|
333
337
|
}
|
|
334
|
-
if (mode === 'bypass') return original(input, init)
|
|
338
|
+
if (mode === 'bypass') return original(input, init)
|
|
335
339
|
|
|
336
|
-
const key = fetchCacheKey(request)
|
|
340
|
+
const key = fetchCacheKey(request)
|
|
337
341
|
|
|
338
342
|
if (mode === 'cache' && !draftModeBypassActive()) {
|
|
339
|
-
const meta = currentRenderCacheMeta()
|
|
340
|
-
const resumeEntry = fetchRdcRecords().get(key)
|
|
343
|
+
const meta = currentRenderCacheMeta()
|
|
344
|
+
const resumeEntry = fetchRdcRecords().get(key)
|
|
341
345
|
if (
|
|
342
346
|
resumeEntry &&
|
|
343
|
-
!tagsRevalidatedAfterSeq(
|
|
344
|
-
[...resumeEntry.tags, ...tags],
|
|
345
|
-
resumeEntry.tagSeq,
|
|
346
|
-
) &&
|
|
347
|
+
!tagsRevalidatedAfterSeq([...resumeEntry.tags, ...tags], resumeEntry.tagSeq) &&
|
|
347
348
|
!fetchEntryPathRevalidated(resumeEntry) &&
|
|
348
349
|
(fetchCache.get(key)?.storedAt ?? -1) <= resumeEntry.storedAt
|
|
349
350
|
) {
|
|
350
|
-
fetchCache.set(key, resumeEntry)
|
|
351
|
+
fetchCache.set(key, resumeEntry)
|
|
351
352
|
}
|
|
352
|
-
const preRefreshEntry = fetchCache.get(key)
|
|
353
|
+
const preRefreshEntry = fetchCache.get(key)
|
|
353
354
|
// On-demand revalidation refetches each entry ONCE per render (Next skips the cache read entirely
|
|
354
355
|
// under isOnDemandRevalidate), then dedupes via refreshedIn - but only entries the revalidation
|
|
355
356
|
// actually reached. See the matching gate in use-cache.ts: a still-marked route re-renders many
|
|
@@ -358,23 +359,20 @@ export function installCompatFetchCache() {
|
|
|
358
359
|
meta?.refreshFetches === true &&
|
|
359
360
|
preRefreshEntry?.refreshedIn !== meta &&
|
|
360
361
|
(preRefreshEntry === undefined ||
|
|
361
|
-
tagsRevalidatedAfterSeq(
|
|
362
|
-
[...preRefreshEntry.tags, ...tags],
|
|
363
|
-
preRefreshEntry.tagSeq,
|
|
364
|
-
) ||
|
|
362
|
+
tagsRevalidatedAfterSeq([...preRefreshEntry.tags, ...tags], preRefreshEntry.tagSeq) ||
|
|
365
363
|
fetchEntryPathRevalidated(preRefreshEntry) ||
|
|
366
364
|
tagsStaleSince(preRefreshEntry.tags, preRefreshEntry.storedAt) ||
|
|
367
|
-
fetchEntryExpired(preRefreshEntry))
|
|
365
|
+
fetchEntryExpired(preRefreshEntry))
|
|
368
366
|
const revalidateSeconds =
|
|
369
|
-
typeof revalidate === 'number' && revalidate > 0 ? revalidate : undefined
|
|
370
|
-
const blockingStale = currentRenderCacheMeta()?.blockingStaleFetches === true
|
|
367
|
+
typeof revalidate === 'number' && revalidate > 0 ? revalidate : undefined
|
|
368
|
+
const blockingStale = currentRenderCacheMeta()?.blockingStaleFetches === true
|
|
371
369
|
// Seed the in-memory entry from the configured cache handler on a miss,
|
|
372
370
|
// so the handler observes every read (its get() logs are asserted) and
|
|
373
371
|
// persists entries across the SWR window / restarts.
|
|
374
|
-
let entry = fetchCache.get(key)
|
|
372
|
+
let entry = fetchCache.get(key)
|
|
375
373
|
if (!entry && !refresh && hasCacheHandler()) {
|
|
376
|
-
const persisted = await cacheHandlerGet(key, { tags })
|
|
377
|
-
const snapshot = persistedSnapshot(persisted?.value)
|
|
374
|
+
const persisted = await cacheHandlerGet(key, { tags })
|
|
375
|
+
const snapshot = persistedSnapshot(persisted?.value)
|
|
378
376
|
if (snapshot) {
|
|
379
377
|
entry = {
|
|
380
378
|
value: Promise.resolve(snapshot),
|
|
@@ -385,21 +383,21 @@ export function installCompatFetchCache() {
|
|
|
385
383
|
...(currentRenderCacheMeta()?.route !== undefined
|
|
386
384
|
? { route: currentRenderCacheMeta()?.route }
|
|
387
385
|
: {}),
|
|
388
|
-
}
|
|
389
|
-
fetchCache.set(key, entry)
|
|
386
|
+
}
|
|
387
|
+
fetchCache.set(key, entry)
|
|
390
388
|
}
|
|
391
389
|
}
|
|
392
390
|
// This render's route joins the entry's path-revalidation scope before
|
|
393
391
|
// the freshness check, so revalidatePath() of a route that only REUSES a
|
|
394
392
|
// shared entry expires it too.
|
|
395
|
-
if (entry) noteFetchEntryRoute(entry, meta?.route)
|
|
393
|
+
if (entry) noteFetchEntryRoute(entry, meta?.route)
|
|
396
394
|
if (
|
|
397
395
|
entry &&
|
|
398
396
|
!refresh &&
|
|
399
397
|
!tagsRevalidatedAfterSeq([...entry.tags, ...tags], entry.tagSeq) &&
|
|
400
398
|
!fetchEntryPathRevalidated(entry)
|
|
401
399
|
) {
|
|
402
|
-
const tagStale = tagsStaleSince(entry.tags, entry.storedAt)
|
|
400
|
+
const tagStale = tagsStaleSince(entry.tags, entry.storedAt)
|
|
403
401
|
// Staleness honours THIS call's revalidate, not only the value baked
|
|
404
402
|
// into the stored entry. The data cache is shared by URL across routes,
|
|
405
403
|
// so a shorter-lived reader (e.g. a `revalidate: 9` fetch) can find an
|
|
@@ -408,52 +406,56 @@ export function installCompatFetchCache() {
|
|
|
408
406
|
// expires). Without folding the current revalidate into the check, that
|
|
409
407
|
// reader's window would be silently ignored and its page would never
|
|
410
408
|
// refresh (app-static variable-config-revalidate under a full suite).
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
|
|
409
|
+
if (
|
|
410
|
+
!tagStale &&
|
|
411
|
+
!fetchEntryExpired(entry) &&
|
|
412
|
+
!currentRequestExpired(entry, revalidateSeconds)
|
|
413
|
+
) {
|
|
414
|
+
captureFetchRdcEntry(key)
|
|
415
|
+
return snapshotResponse(await entry.value)
|
|
414
416
|
}
|
|
415
417
|
// TTL expiry: serve stale, refresh in the background (Next's SWR
|
|
416
418
|
// data-cache semantics) — except inside an ISR regeneration render,
|
|
417
419
|
// which refetches inline. On-demand invalidation above blocks too.
|
|
418
420
|
if (!blockingStale) {
|
|
419
421
|
if (!entry.refreshing) {
|
|
420
|
-
entry.refreshing = true
|
|
421
|
-
void storeFetchEntry(key, original, input, init, tags, revalidateSeconds, entry)
|
|
422
|
+
entry.refreshing = true
|
|
423
|
+
void storeFetchEntry(key, original, input, init, tags, revalidateSeconds, entry)
|
|
422
424
|
}
|
|
423
|
-
captureFetchRdcEntry(key)
|
|
424
|
-
return snapshotResponse(await entry.value)
|
|
425
|
+
captureFetchRdcEntry(key)
|
|
426
|
+
return snapshotResponse(await entry.value)
|
|
425
427
|
}
|
|
426
428
|
}
|
|
427
|
-
const value = storeFetchEntry(key, original, input, init, tags, revalidateSeconds)
|
|
428
|
-
return snapshotResponse(await value)
|
|
429
|
+
const value = storeFetchEntry(key, original, input, init, tags, revalidateSeconds)
|
|
430
|
+
return snapshotResponse(await value)
|
|
429
431
|
}
|
|
430
432
|
|
|
431
433
|
// Uncached, but dedupe identical GETs within the render pass.
|
|
432
|
-
const scope = currentCacheScope()
|
|
433
|
-
if (!scope) return original(input, init)
|
|
434
|
-
scope.fetches ??= new Map()
|
|
435
|
-
let pending = scope.fetches.get(key) as Promise<FetchSnapshot> | undefined
|
|
434
|
+
const scope = currentCacheScope()
|
|
435
|
+
if (!scope) return original(input, init)
|
|
436
|
+
scope.fetches ??= new Map()
|
|
437
|
+
let pending = scope.fetches.get(key) as Promise<FetchSnapshot> | undefined
|
|
436
438
|
if (!pending) {
|
|
437
|
-
pending = snapshotFetch(original, input, init)
|
|
438
|
-
scope.fetches.set(key, pending)
|
|
439
|
+
pending = snapshotFetch(original, input, init)
|
|
440
|
+
scope.fetches.set(key, pending)
|
|
439
441
|
}
|
|
440
|
-
return snapshotResponse(await pending)
|
|
441
|
-
}
|
|
442
|
+
return snapshotResponse(await pending)
|
|
443
|
+
}
|
|
442
444
|
|
|
443
|
-
globalThis.fetch = patched as typeof globalThis.fetch
|
|
445
|
+
globalThis.fetch = patched as typeof globalThis.fetch
|
|
444
446
|
}
|
|
445
447
|
|
|
446
448
|
interface NormalizedFetchRequest {
|
|
447
|
-
url: string
|
|
448
|
-
method: string
|
|
449
|
-
headers: [string, string][]
|
|
450
|
-
body?: string
|
|
449
|
+
url: string
|
|
450
|
+
method: string
|
|
451
|
+
headers: [string, string][]
|
|
452
|
+
body?: string
|
|
451
453
|
}
|
|
452
454
|
|
|
453
455
|
interface NormalizedFetchArgs {
|
|
454
|
-
request: NormalizedFetchRequest
|
|
456
|
+
request: NormalizedFetchRequest
|
|
455
457
|
/** Set when a one-shot body (stream) was buffered and must be re-sent as bytes. */
|
|
456
|
-
replacementInit?: { body: BodyInit }
|
|
458
|
+
replacementInit?: { body: BodyInit }
|
|
457
459
|
}
|
|
458
460
|
|
|
459
461
|
async function normalizeFetchArgs(
|
|
@@ -461,34 +463,34 @@ async function normalizeFetchArgs(
|
|
|
461
463
|
init?: RequestInit,
|
|
462
464
|
): Promise<NormalizedFetchArgs | null> {
|
|
463
465
|
try {
|
|
464
|
-
let url: string
|
|
465
|
-
let method = 'GET'
|
|
466
|
-
let headers: Headers
|
|
466
|
+
let url: string
|
|
467
|
+
let method = 'GET'
|
|
468
|
+
let headers: Headers
|
|
467
469
|
|
|
468
470
|
if (typeof input === 'string' || input instanceof URL) {
|
|
469
|
-
url = String(input)
|
|
470
|
-
method = (init?.method ?? 'GET').toUpperCase()
|
|
471
|
-
headers = new Headers(init?.headers)
|
|
471
|
+
url = String(input)
|
|
472
|
+
method = (init?.method ?? 'GET').toUpperCase()
|
|
473
|
+
headers = new Headers(init?.headers)
|
|
472
474
|
} else if (input instanceof Request) {
|
|
473
|
-
if (input.body != null) return null
|
|
474
|
-
url = input.url
|
|
475
|
-
method = (init?.method ?? input.method).toUpperCase()
|
|
476
|
-
headers = new Headers(init?.headers ?? input.headers)
|
|
475
|
+
if (input.body != null) return null
|
|
476
|
+
url = input.url
|
|
477
|
+
method = (init?.method ?? input.method).toUpperCase()
|
|
478
|
+
headers = new Headers(init?.headers ?? input.headers)
|
|
477
479
|
} else {
|
|
478
|
-
return null
|
|
480
|
+
return null
|
|
479
481
|
}
|
|
480
|
-
if (!/^https?:/.test(url)) return null
|
|
482
|
+
if (!/^https?:/.test(url)) return null
|
|
481
483
|
|
|
482
|
-
const normalizedBody = await normalizeFetchBody(init?.body)
|
|
483
|
-
if (normalizedBody === null) return null
|
|
484
|
+
const normalizedBody = await normalizeFetchBody(init?.body)
|
|
485
|
+
if (normalizedBody === null) return null
|
|
484
486
|
return {
|
|
485
487
|
request: { url, method, headers: [...headers.entries()], body: normalizedBody?.key },
|
|
486
488
|
...(normalizedBody?.replacement !== undefined
|
|
487
489
|
? { replacementInit: { body: normalizedBody.replacement } }
|
|
488
490
|
: {}),
|
|
489
|
-
}
|
|
491
|
+
}
|
|
490
492
|
} catch {
|
|
491
|
-
return null
|
|
493
|
+
return null
|
|
492
494
|
}
|
|
493
495
|
}
|
|
494
496
|
|
|
@@ -500,42 +502,42 @@ async function normalizeFetchArgs(
|
|
|
500
502
|
async function normalizeFetchBody(
|
|
501
503
|
body: BodyInit | null | undefined,
|
|
502
504
|
): Promise<{ key: string; replacement?: BodyInit } | undefined | null> {
|
|
503
|
-
if (body == null) return undefined
|
|
504
|
-
if (typeof body === 'string') return { key: body }
|
|
505
|
-
if (body instanceof URLSearchParams) return { key: body.toString() }
|
|
506
|
-
if (body instanceof ArrayBuffer) return { key: bytesKey(new Uint8Array(body)) }
|
|
505
|
+
if (body == null) return undefined
|
|
506
|
+
if (typeof body === 'string') return { key: body }
|
|
507
|
+
if (body instanceof URLSearchParams) return { key: body.toString() }
|
|
508
|
+
if (body instanceof ArrayBuffer) return { key: bytesKey(new Uint8Array(body)) }
|
|
507
509
|
if (ArrayBuffer.isView(body)) {
|
|
508
|
-
return { key: bytesKey(new Uint8Array(body.buffer, body.byteOffset, body.byteLength)) }
|
|
510
|
+
return { key: bytesKey(new Uint8Array(body.buffer, body.byteOffset, body.byteLength)) }
|
|
509
511
|
}
|
|
510
512
|
if (body instanceof ReadableStream) {
|
|
511
|
-
const bytes = new Uint8Array(await new Response(body).arrayBuffer())
|
|
512
|
-
return { key: bytesKey(bytes), replacement: bytes as BodyInit }
|
|
513
|
+
const bytes = new Uint8Array(await new Response(body).arrayBuffer())
|
|
514
|
+
return { key: bytesKey(bytes), replacement: bytes as BodyInit }
|
|
513
515
|
}
|
|
514
516
|
if (body instanceof FormData) {
|
|
515
517
|
// Reading entries does not consume the body; fetch re-serializes it.
|
|
516
|
-
const parts: string[] = []
|
|
518
|
+
const parts: string[] = []
|
|
517
519
|
for (const [name, value] of body.entries()) {
|
|
518
|
-
parts.push(name, typeof value === 'string' ? value : await (value as Blob).text())
|
|
520
|
+
parts.push(name, typeof value === 'string' ? value : await (value as Blob).text())
|
|
519
521
|
}
|
|
520
|
-
return { key: parts.join(' ') }
|
|
522
|
+
return { key: parts.join(' ') }
|
|
521
523
|
}
|
|
522
|
-
return null
|
|
524
|
+
return null
|
|
523
525
|
}
|
|
524
526
|
|
|
525
527
|
function bytesKey(bytes: Uint8Array) {
|
|
526
|
-
return Buffer.from(bytes).toString('base64')
|
|
528
|
+
return Buffer.from(bytes).toString('base64')
|
|
527
529
|
}
|
|
528
530
|
|
|
529
531
|
function requestNextOptions(input: unknown): NextFetchOptions | undefined {
|
|
530
|
-
return (input as { next?: NextFetchOptions } | null | undefined)?.next
|
|
532
|
+
return (input as { next?: NextFetchOptions } | null | undefined)?.next
|
|
531
533
|
}
|
|
532
534
|
|
|
533
535
|
function requestCacheOption(input: unknown): RequestCache | undefined {
|
|
534
|
-
if (input instanceof Request) return input.cache
|
|
535
|
-
return undefined
|
|
536
|
+
if (input instanceof Request) return input.cache
|
|
537
|
+
return undefined
|
|
536
538
|
}
|
|
537
539
|
|
|
538
|
-
type CacheMode = 'cache' | 'dedupe' | 'bypass'
|
|
540
|
+
type CacheMode = 'cache' | 'dedupe' | 'bypass'
|
|
539
541
|
|
|
540
542
|
function cacheModeFor(
|
|
541
543
|
cacheOption: RequestCache | undefined,
|
|
@@ -545,21 +547,21 @@ function cacheModeFor(
|
|
|
545
547
|
staticGeneration: boolean,
|
|
546
548
|
): CacheMode {
|
|
547
549
|
if (segmentFetchCache === 'force-no-store' || segmentFetchCache === 'only-no-store') {
|
|
548
|
-
return 'dedupe'
|
|
550
|
+
return 'dedupe'
|
|
549
551
|
}
|
|
550
552
|
// Segment-level force-cache supersedes even explicit no-store fetch options.
|
|
551
553
|
if (segmentFetchCache === 'force-cache' || segmentFetchCache === 'only-cache') {
|
|
552
|
-
return revalidate === 0 ? 'dedupe' : 'cache'
|
|
554
|
+
return revalidate === 0 ? 'dedupe' : 'cache'
|
|
553
555
|
}
|
|
554
556
|
if (cacheOption === 'no-store' || cacheOption === 'no-cache' || revalidate === 0) {
|
|
555
|
-
return 'dedupe'
|
|
557
|
+
return 'dedupe'
|
|
556
558
|
}
|
|
557
559
|
if (
|
|
558
560
|
cacheOption === 'force-cache' ||
|
|
559
561
|
revalidate === false ||
|
|
560
562
|
(typeof revalidate === 'number' && revalidate > 0)
|
|
561
563
|
) {
|
|
562
|
-
return 'cache'
|
|
564
|
+
return 'cache'
|
|
563
565
|
}
|
|
564
566
|
// Auto (no explicit option): uncached per-request at runtime, but during
|
|
565
567
|
// static generation a plain GET defaults to force-cache (Next semantics).
|
|
@@ -569,22 +571,22 @@ function cacheModeFor(
|
|
|
569
571
|
// data, so a prerender postpones the boundary around it instead of baking the
|
|
570
572
|
// response in (cache-components-errors dynamic-boundary expects the prerender
|
|
571
573
|
// to keep its `<Suspense>` fallbacks).
|
|
572
|
-
if (staticGeneration && method === 'GET' && !cacheComponents()) return 'cache'
|
|
573
|
-
return 'dedupe'
|
|
574
|
+
if (staticGeneration && method === 'GET' && !cacheComponents()) return 'cache'
|
|
575
|
+
return 'dedupe'
|
|
574
576
|
}
|
|
575
577
|
|
|
576
578
|
function fetchCacheKey(request: NormalizedFetchRequest): string {
|
|
577
579
|
const headers = request.headers
|
|
578
580
|
.filter(([name]) => name !== 'traceparent' && name !== 'tracestate')
|
|
579
|
-
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
580
|
-
return JSON.stringify([request.method, request.url, headers, request.body ?? null])
|
|
581
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
582
|
+
return JSON.stringify([request.method, request.url, headers, request.body ?? null])
|
|
581
583
|
}
|
|
582
584
|
|
|
583
585
|
function fetchEntryExpired(entry: FetchCacheEntry) {
|
|
584
586
|
return (
|
|
585
587
|
entry.revalidateSeconds !== undefined &&
|
|
586
588
|
realNow() - entry.storedAt >= entry.revalidateSeconds * 1000
|
|
587
|
-
)
|
|
589
|
+
)
|
|
588
590
|
}
|
|
589
591
|
|
|
590
592
|
// Staleness as seen by the CURRENT fetch call: its own `revalidate` window,
|
|
@@ -592,9 +594,7 @@ function fetchEntryExpired(entry: FetchCacheEntry) {
|
|
|
592
594
|
// which only knows the window baked in when the entry was stored — a later
|
|
593
595
|
// reader with a shorter revalidate must still see its own expiry.
|
|
594
596
|
function currentRequestExpired(entry: FetchCacheEntry, revalidateSeconds: number | undefined) {
|
|
595
|
-
return (
|
|
596
|
-
revalidateSeconds !== undefined && realNow() - entry.storedAt >= revalidateSeconds * 1000
|
|
597
|
-
);
|
|
597
|
+
return revalidateSeconds !== undefined && realNow() - entry.storedAt >= revalidateSeconds * 1000
|
|
598
598
|
}
|
|
599
599
|
|
|
600
600
|
function storeFetchEntry(
|
|
@@ -606,13 +606,13 @@ function storeFetchEntry(
|
|
|
606
606
|
revalidateSeconds: number | undefined,
|
|
607
607
|
serveStale?: FetchCacheEntry,
|
|
608
608
|
): Promise<FetchSnapshot> {
|
|
609
|
-
const value = snapshotFetch(original, input, init)
|
|
609
|
+
const value = snapshotFetch(original, input, init)
|
|
610
610
|
// Same contract as the 'use cache' / data-cache fills: a build prerender's
|
|
611
611
|
// task boundary waits for an in-flight CACHED fetch rather than cutting it
|
|
612
612
|
// short, so its result still lands in the static shell (core ppr).
|
|
613
|
-
void trackPrerenderCacheFill(value)
|
|
614
|
-
const producingMeta = currentRenderCacheMeta()
|
|
615
|
-
const route = serveStale?.route ?? producingMeta?.route
|
|
613
|
+
void trackPrerenderCacheFill(value)
|
|
614
|
+
const producingMeta = currentRenderCacheMeta()
|
|
615
|
+
const route = serveStale?.route ?? producingMeta?.route
|
|
616
616
|
const stored: FetchCacheEntry = {
|
|
617
617
|
value,
|
|
618
618
|
// realNow: a build prerender freezes Date.now() to 0 (prerender
|
|
@@ -627,60 +627,60 @@ function storeFetchEntry(
|
|
|
627
627
|
// A background refresh replaces the entry: the routes that had joined its
|
|
628
628
|
// revalidation scope keep it (they still read this key).
|
|
629
629
|
...(serveStale?.readRoutes?.length ? { readRoutes: [...serveStale.readRoutes] } : {}),
|
|
630
|
-
}
|
|
630
|
+
}
|
|
631
631
|
if (serveStale) {
|
|
632
632
|
value.then(
|
|
633
633
|
snapshot => {
|
|
634
634
|
if (snapshot.status === 200) {
|
|
635
|
-
fetchCache.set(key, stored)
|
|
636
|
-
void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
|
|
637
|
-
} else serveStale.refreshing = false
|
|
635
|
+
fetchCache.set(key, stored)
|
|
636
|
+
void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
|
|
637
|
+
} else serveStale.refreshing = false
|
|
638
638
|
},
|
|
639
639
|
() => {
|
|
640
|
-
serveStale.refreshing = false
|
|
640
|
+
serveStale.refreshing = false
|
|
641
641
|
},
|
|
642
|
-
)
|
|
643
|
-
return value
|
|
642
|
+
)
|
|
643
|
+
return value
|
|
644
644
|
}
|
|
645
645
|
if (fetchCache.size >= fetchCacheLimit) {
|
|
646
|
-
const oldest = fetchCache.keys().next().value
|
|
647
|
-
if (oldest !== undefined) fetchCache.delete(oldest)
|
|
646
|
+
const oldest = fetchCache.keys().next().value
|
|
647
|
+
if (oldest !== undefined) fetchCache.delete(oldest)
|
|
648
648
|
}
|
|
649
|
-
fetchCache.set(key, stored)
|
|
650
|
-
captureFetchRdcEntry(key)
|
|
649
|
+
fetchCache.set(key, stored)
|
|
650
|
+
captureFetchRdcEntry(key)
|
|
651
651
|
value.then(
|
|
652
652
|
snapshot => {
|
|
653
653
|
// Only 200s are cached (Next does not cache error statuses).
|
|
654
|
-
if (snapshot.status !== 200 && fetchCache.get(key) === stored) fetchCache.delete(key)
|
|
655
|
-
else void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
|
|
654
|
+
if (snapshot.status !== 200 && fetchCache.get(key) === stored) fetchCache.delete(key)
|
|
655
|
+
else void persistFetchEntry(key, snapshot, tags, revalidateSeconds)
|
|
656
656
|
},
|
|
657
657
|
() => {
|
|
658
|
-
if (fetchCache.get(key) === stored) fetchCache.delete(key)
|
|
658
|
+
if (fetchCache.get(key) === stored) fetchCache.delete(key)
|
|
659
659
|
},
|
|
660
|
-
)
|
|
661
|
-
return value
|
|
660
|
+
)
|
|
661
|
+
return value
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
/** Snapshot <-> serializable value stored through the custom cache handler. */
|
|
665
665
|
interface PersistedFetch {
|
|
666
|
-
status: number
|
|
667
|
-
statusText: string
|
|
668
|
-
headers: [string, string][]
|
|
669
|
-
body: string
|
|
670
|
-
url: string
|
|
666
|
+
status: number
|
|
667
|
+
statusText: string
|
|
668
|
+
headers: [string, string][]
|
|
669
|
+
body: string
|
|
670
|
+
url: string
|
|
671
671
|
}
|
|
672
672
|
|
|
673
673
|
function persistedSnapshot(value: unknown): FetchSnapshot | undefined {
|
|
674
|
-
if (!value || typeof value !== 'object') return undefined
|
|
675
|
-
const v = value as Partial<PersistedFetch
|
|
676
|
-
if (typeof v.status !== 'number' || typeof v.body !== 'string') return undefined
|
|
674
|
+
if (!value || typeof value !== 'object') return undefined
|
|
675
|
+
const v = value as Partial<PersistedFetch>
|
|
676
|
+
if (typeof v.status !== 'number' || typeof v.body !== 'string') return undefined
|
|
677
677
|
return {
|
|
678
678
|
status: v.status,
|
|
679
679
|
statusText: v.statusText ?? '',
|
|
680
680
|
headers: v.headers ?? [],
|
|
681
681
|
body: new Uint8Array(Buffer.from(v.body, 'base64')),
|
|
682
682
|
url: v.url ?? '',
|
|
683
|
-
}
|
|
683
|
+
}
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
async function persistFetchEntry(
|
|
@@ -689,14 +689,14 @@ async function persistFetchEntry(
|
|
|
689
689
|
tags: readonly string[],
|
|
690
690
|
revalidateSeconds: number | undefined,
|
|
691
691
|
): Promise<void> {
|
|
692
|
-
if (!hasCacheHandler()) return
|
|
692
|
+
if (!hasCacheHandler()) return
|
|
693
693
|
const value: PersistedFetch = {
|
|
694
694
|
status: snapshot.status,
|
|
695
695
|
statusText: snapshot.statusText,
|
|
696
696
|
headers: snapshot.headers,
|
|
697
697
|
body: Buffer.from(snapshot.body).toString('base64'),
|
|
698
698
|
url: snapshot.url,
|
|
699
|
-
}
|
|
699
|
+
}
|
|
700
700
|
// fetchCache/fetchUrl mirror Next's incremental-cache ctx for fetch writes;
|
|
701
701
|
// custom handlers key their logging/persistence off them.
|
|
702
702
|
await cacheHandlerSet(key, value, {
|
|
@@ -704,7 +704,7 @@ async function persistFetchEntry(
|
|
|
704
704
|
revalidate: revalidateSeconds ?? false,
|
|
705
705
|
fetchCache: true,
|
|
706
706
|
fetchUrl: snapshot.url || undefined,
|
|
707
|
-
})
|
|
707
|
+
})
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
async function snapshotFetch(
|
|
@@ -712,18 +712,18 @@ async function snapshotFetch(
|
|
|
712
712
|
input: Parameters<typeof globalThis.fetch>[0],
|
|
713
713
|
init?: RequestInit,
|
|
714
714
|
): Promise<FetchSnapshot> {
|
|
715
|
-
const response = await original(input, init)
|
|
716
|
-
const body = new Uint8Array(await response.arrayBuffer())
|
|
715
|
+
const response = await original(input, init)
|
|
716
|
+
const body = new Uint8Array(await response.arrayBuffer())
|
|
717
717
|
const headers = [...response.headers.entries()].filter(
|
|
718
718
|
([name]) => !['content-encoding', 'content-length', 'transfer-encoding'].includes(name),
|
|
719
|
-
)
|
|
719
|
+
)
|
|
720
720
|
return {
|
|
721
721
|
status: response.status,
|
|
722
722
|
statusText: response.statusText,
|
|
723
723
|
headers,
|
|
724
724
|
body,
|
|
725
725
|
url: response.url,
|
|
726
|
-
}
|
|
726
|
+
}
|
|
727
727
|
}
|
|
728
728
|
|
|
729
729
|
function snapshotResponse(snapshot: FetchSnapshot): Response {
|
|
@@ -731,15 +731,15 @@ function snapshotResponse(snapshot: FetchSnapshot): Response {
|
|
|
731
731
|
status: snapshot.status,
|
|
732
732
|
statusText: snapshot.statusText,
|
|
733
733
|
headers: snapshot.headers,
|
|
734
|
-
})
|
|
734
|
+
})
|
|
735
735
|
// Response.url is read-only and lost through the constructor; restore it.
|
|
736
736
|
if (snapshot.url) {
|
|
737
|
-
Object.defineProperty(response, 'url', { value: snapshot.url, configurable: true })
|
|
737
|
+
Object.defineProperty(response, 'url', { value: snapshot.url, configurable: true })
|
|
738
738
|
}
|
|
739
|
-
return response
|
|
739
|
+
return response
|
|
740
740
|
}
|
|
741
741
|
|
|
742
742
|
/** Test hook: drop all cached fetch entries. */
|
|
743
743
|
export function clearFetchCache() {
|
|
744
|
-
fetchCache.clear()
|
|
744
|
+
fetchCache.clear()
|
|
745
745
|
}
|