@wular/pnext 0.0.4 → 0.0.7
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 +22 -16
- package/bin/pnext +6 -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 +87 -22
- package/reference/config.md +40 -93
- package/reference/css.md +42 -33
- package/reference/dev.md +26 -33
- package/reference/env.md +18 -20
- package/reference/getting-started.md +132 -0
- package/reference/metadata.md +31 -46
- package/reference/navigation.md +65 -105
- package/reference/performance.md +21 -142
- package/reference/rendering.md +78 -75
- package/reference/routing.md +97 -107
- package/reference/typegen.md +27 -29
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +121 -114
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +52 -53
- 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 +72 -64
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +94 -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 +802 -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 +32 -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 +2022 -1995
- package/src/{api → client}/router/types.ts +98 -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 +86 -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 +2087 -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 +87 -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 +954 -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 +428 -406
- package/src/styles.d.ts +9 -0
- package/src/types.ts +324 -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/reference/overview.md +0 -35
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
2
|
|
|
3
3
|
// Partial Prerendering (Next.js-compatible "mixed" model).
|
|
4
4
|
//
|
|
@@ -21,68 +21,68 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
21
21
|
// so client control-flow code can import isPostpone without pulling this module
|
|
22
22
|
// (and its AsyncLocalStorage) into the browser bundle. Re-exported here so
|
|
23
23
|
// every server caller keeps importing them from ppr.
|
|
24
|
-
export { PostponeError, isPostpone } from './
|
|
25
|
-
import { isPostpone as isPostponeError, PostponeError } from './
|
|
24
|
+
export { PostponeError, isPostpone } from './postpone'
|
|
25
|
+
import { isPostpone as isPostponeError, PostponeError } from './postpone'
|
|
26
26
|
|
|
27
27
|
// The prerender scope carries an AbortController so a hanging promise whose
|
|
28
28
|
// settlement microtask has not yet run stays pending once the prerender has
|
|
29
29
|
// produced its shell (see hangingPromise's `scope.signal.aborted` guard).
|
|
30
30
|
interface PrerenderScope {
|
|
31
31
|
/** Fires when the prerender pass has produced its shell. */
|
|
32
|
-
readonly signal: AbortSignal
|
|
33
|
-
abort: () => void
|
|
32
|
+
readonly signal: AbortSignal
|
|
33
|
+
abort: () => void
|
|
34
34
|
/**
|
|
35
35
|
* A RUNTIME-PREFETCH prerender (`unstable_instant` full prefetch): the render runs against a real sampled
|
|
36
36
|
* request, so request APIs RESOLVE from it instead of hanging - only connection()-gated content stays
|
|
37
37
|
* dynamic, its promise hanging so the boundary records a hole. Nothing this request-sampled render
|
|
38
38
|
* produces may be persisted into build artifacts.
|
|
39
39
|
*/
|
|
40
|
-
readonly runtimePrefetch?: boolean
|
|
40
|
+
readonly runtimePrefetch?: boolean
|
|
41
41
|
/**
|
|
42
42
|
* Runtime-prefetch prerenders only: a runtime API (cookies/headers/params/searchParams, or a `use cache`
|
|
43
43
|
* read) has been AWAITED somewhere in this render. From that point on, synchronous platform IO aborts its
|
|
44
44
|
* boundary - see runWithRuntimePrefetchSyncIoAbort.
|
|
45
45
|
*/
|
|
46
|
-
awaitedRuntimeApi?: boolean
|
|
46
|
+
awaitedRuntimeApi?: boolean
|
|
47
47
|
/**
|
|
48
48
|
* A prerender whose output becomes a PREFETCH shell (the body segment the client's segment cache stores),
|
|
49
49
|
* NOT the document served for a direct request. Short-lived `use cache` scopes are omitted from it exactly
|
|
50
50
|
* as they are from a runtime prefetch - the client's stale window for the prefetch would otherwise be
|
|
51
51
|
* governed by a cache that expires before it.
|
|
52
52
|
*/
|
|
53
|
-
readonly prefetchShell?: boolean
|
|
53
|
+
readonly prefetchShell?: boolean
|
|
54
54
|
/**
|
|
55
55
|
* A BUILD prerender running under Next's task-boundary semantics (see
|
|
56
56
|
* awaitAtTaskBoundary). Only set for a cacheComponents build shell render.
|
|
57
57
|
*/
|
|
58
|
-
readonly taskBoundary?: boolean
|
|
58
|
+
readonly taskBoundary?: boolean
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Anchored on globalThis (like requestStorage in request/context.ts) so a
|
|
62
62
|
// compiled compat copy of this module shares the same prerender-scope ALS —
|
|
63
63
|
// unanchored, a second module instance splits prerender detection.
|
|
64
|
-
const PRERENDER_STORAGE = Symbol.for('pnext.prerenderStorage')
|
|
64
|
+
const PRERENDER_STORAGE = Symbol.for('pnext.prerenderStorage')
|
|
65
65
|
const prerenderStorage = ((globalThis as Record<PropertyKey, unknown>)[PRERENDER_STORAGE] ??=
|
|
66
|
-
new AsyncLocalStorage<PrerenderScope>()) as AsyncLocalStorage<PrerenderScope
|
|
66
|
+
new AsyncLocalStorage<PrerenderScope>()) as AsyncLocalStorage<PrerenderScope>
|
|
67
67
|
|
|
68
68
|
interface PrerenderDynamicTracker {
|
|
69
|
-
dynamic: boolean
|
|
69
|
+
dynamic: boolean
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
const prerenderDynamicTrackerStorage = new AsyncLocalStorage<PrerenderDynamicTracker>()
|
|
72
|
+
const prerenderDynamicTrackerStorage = new AsyncLocalStorage<PrerenderDynamicTracker>()
|
|
73
73
|
|
|
74
74
|
export async function trackPrerenderDynamic<T>(callback: () => Promise<T>): Promise<{
|
|
75
|
-
value: T
|
|
76
|
-
dynamic: boolean
|
|
75
|
+
value: T
|
|
76
|
+
dynamic: boolean
|
|
77
77
|
}> {
|
|
78
|
-
const tracker: PrerenderDynamicTracker = { dynamic: false }
|
|
79
|
-
const value = await prerenderDynamicTrackerStorage.run(tracker, callback)
|
|
80
|
-
return { value, dynamic: tracker.dynamic }
|
|
78
|
+
const tracker: PrerenderDynamicTracker = { dynamic: false }
|
|
79
|
+
const value = await prerenderDynamicTrackerStorage.run(tracker, callback)
|
|
80
|
+
return { value, dynamic: tracker.dynamic }
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
function markPrerenderDynamic(): void {
|
|
84
|
-
const tracker = prerenderDynamicTrackerStorage.getStore()
|
|
85
|
-
if (tracker) tracker.dynamic = true
|
|
84
|
+
const tracker = prerenderDynamicTrackerStorage.getStore()
|
|
85
|
+
if (tracker) tracker.dynamic = true
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// ---------------------------------------------------------------------------
|
|
@@ -101,47 +101,47 @@ function markPrerenderDynamic(): void {
|
|
|
101
101
|
// copy of this module (same reason revalidate.ts / cache-fill state anchor
|
|
102
102
|
// there): the cache runtime recording a fill lives in a different module copy
|
|
103
103
|
// from the build driver that begins/reads the window.
|
|
104
|
-
const SHELL_SOURCES = Symbol.for('pnext.shellDynamicSources')
|
|
104
|
+
const SHELL_SOURCES = Symbol.for('pnext.shellDynamicSources')
|
|
105
105
|
interface ShellSourceState {
|
|
106
|
-
active: boolean
|
|
107
|
-
cacheIO: boolean
|
|
108
|
-
nonParamsRequest: boolean
|
|
106
|
+
active: boolean
|
|
107
|
+
cacheIO: boolean
|
|
108
|
+
nonParamsRequest: boolean
|
|
109
109
|
}
|
|
110
110
|
function shellSourceState(): ShellSourceState {
|
|
111
|
-
const root = globalThis as Record<PropertyKey, unknown
|
|
111
|
+
const root = globalThis as Record<PropertyKey, unknown>
|
|
112
112
|
return (root[SHELL_SOURCES] ??= {
|
|
113
113
|
active: false,
|
|
114
114
|
cacheIO: false,
|
|
115
115
|
nonParamsRequest: false,
|
|
116
|
-
}) as ShellSourceState
|
|
116
|
+
}) as ShellSourceState
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
/** Arm shell-source tracking for one partial-shell prerender (resets counters). */
|
|
120
120
|
export function beginShellSourceTracking(): void {
|
|
121
|
-
const state = shellSourceState()
|
|
122
|
-
state.active = true
|
|
123
|
-
state.cacheIO = false
|
|
124
|
-
state.nonParamsRequest = false
|
|
121
|
+
const state = shellSourceState()
|
|
122
|
+
state.active = true
|
|
123
|
+
state.cacheIO = false
|
|
124
|
+
state.nonParamsRequest = false
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/** Read + disarm the dynamic sources observed during the last shell prerender. */
|
|
128
128
|
export function endShellSourceTracking(): { cacheIO: boolean; nonParamsRequest: boolean } {
|
|
129
|
-
const state = shellSourceState()
|
|
130
|
-
const result = { cacheIO: state.cacheIO, nonParamsRequest: state.nonParamsRequest }
|
|
131
|
-
state.active = false
|
|
132
|
-
return result
|
|
129
|
+
const state = shellSourceState()
|
|
130
|
+
const result = { cacheIO: state.cacheIO, nonParamsRequest: state.nonParamsRequest }
|
|
131
|
+
state.active = false
|
|
132
|
+
return result
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/** Record a request-API postpone by name (params is URL-derived, everything else is real request IO). */
|
|
136
136
|
function recordShellRequestApi(api: string): void {
|
|
137
|
-
const state = shellSourceState()
|
|
138
|
-
if (state.active && api !== 'params') state.nonParamsRequest = true
|
|
137
|
+
const state = shellSourceState()
|
|
138
|
+
if (state.active && api !== 'params') state.nonParamsRequest = true
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/** Record that cached IO (a `use cache`/fetch/unstable_cache fill) ran during the shell. */
|
|
142
142
|
function recordShellCacheIO(): void {
|
|
143
|
-
const state = shellSourceState()
|
|
144
|
-
if (state.active) state.cacheIO = true
|
|
143
|
+
const state = shellSourceState()
|
|
144
|
+
if (state.active) state.cacheIO = true
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/** Render `callback` in prerender mode so request APIs postpone instead of throwing. */
|
|
@@ -149,16 +149,16 @@ export function runInPrerender<T>(
|
|
|
149
149
|
callback: () => T,
|
|
150
150
|
options: { runtimePrefetch?: boolean; prefetchShell?: boolean; taskBoundary?: boolean } = {},
|
|
151
151
|
): T {
|
|
152
|
-
const controller = new AbortController()
|
|
153
|
-
activePrerenderControllers().add(controller)
|
|
152
|
+
const controller = new AbortController()
|
|
153
|
+
activePrerenderControllers().add(controller)
|
|
154
154
|
const scope: PrerenderScope = {
|
|
155
155
|
signal: controller.signal,
|
|
156
156
|
abort: () => controller.abort(),
|
|
157
157
|
...(options.runtimePrefetch ? { runtimePrefetch: true, awaitedRuntimeApi: false } : {}),
|
|
158
158
|
...(options.prefetchShell ? { prefetchShell: true } : {}),
|
|
159
159
|
...(options.taskBoundary ? { taskBoundary: true } : {}),
|
|
160
|
-
}
|
|
161
|
-
return prerenderStorage.run(scope, callback)
|
|
160
|
+
}
|
|
161
|
+
return prerenderStorage.run(scope, callback)
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// The build process force-aborts every prerender AbortController created since
|
|
@@ -168,10 +168,10 @@ export function runInPrerender<T>(
|
|
|
168
168
|
// React.cacheSignal() })`) and then escaped in a way that skipped its abort would
|
|
169
169
|
// keep the event loop alive and hang the whole build. Anchored on globalThis for
|
|
170
170
|
// the usual dual-module-copy reason (build driver vs built compat-server bundle).
|
|
171
|
-
const ACTIVE_PRERENDER_CONTROLLERS = Symbol.for('pnext.activePrerenderControllers')
|
|
171
|
+
const ACTIVE_PRERENDER_CONTROLLERS = Symbol.for('pnext.activePrerenderControllers')
|
|
172
172
|
function activePrerenderControllers(): Set<AbortController> {
|
|
173
|
-
const root = globalThis as Record<PropertyKey, unknown
|
|
174
|
-
return (root[ACTIVE_PRERENDER_CONTROLLERS] ??= new Set<AbortController>()) as Set<AbortController
|
|
173
|
+
const root = globalThis as Record<PropertyKey, unknown>
|
|
174
|
+
return (root[ACTIVE_PRERENDER_CONTROLLERS] ??= new Set<AbortController>()) as Set<AbortController>
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
/**
|
|
@@ -180,28 +180,28 @@ function activePrerenderControllers(): Set<AbortController> {
|
|
|
180
180
|
* stray cacheSignal-bound timer can outlive its render and hang the build.
|
|
181
181
|
*/
|
|
182
182
|
export function abortActivePrerenderScopes(): void {
|
|
183
|
-
const controllers = activePrerenderControllers()
|
|
184
|
-
for (const controller of controllers) controller.abort()
|
|
185
|
-
controllers.clear()
|
|
183
|
+
const controllers = activePrerenderControllers()
|
|
184
|
+
for (const controller of controllers) controller.abort()
|
|
185
|
+
controllers.clear()
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
export function isPrerendering() {
|
|
189
|
-
return prerenderStorage.getStore() !== undefined
|
|
189
|
+
return prerenderStorage.getStore() !== undefined
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/** True inside a runtime-prefetch prerender (see PrerenderScope.runtimePrefetch). */
|
|
193
193
|
export function isRuntimePrefetchPrerender(): boolean {
|
|
194
|
-
return prerenderStorage.getStore()?.runtimePrefetch === true
|
|
194
|
+
return prerenderStorage.getStore()?.runtimePrefetch === true
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
/** True inside a prefetch-shell prerender (see PrerenderScope.prefetchShell). */
|
|
198
198
|
export function isPrefetchShellPrerender(): boolean {
|
|
199
|
-
return prerenderStorage.getStore()?.prefetchShell === true
|
|
199
|
+
return prerenderStorage.getStore()?.prefetchShell === true
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/** The active prerender scope (undefined outside a prerender). */
|
|
203
203
|
export function currentPrerenderScope(): PrerenderScope | undefined {
|
|
204
|
-
return prerenderStorage.getStore()
|
|
204
|
+
return prerenderStorage.getStore()
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
/**
|
|
@@ -211,8 +211,8 @@ export function currentPrerenderScope(): PrerenderScope | undefined {
|
|
|
211
211
|
* rejecting post-shell. Idempotent.
|
|
212
212
|
*/
|
|
213
213
|
export function completePrerender(scope: PrerenderScope | undefined): void {
|
|
214
|
-
if (!scope) return
|
|
215
|
-
scope.abort()
|
|
214
|
+
if (!scope) return
|
|
215
|
+
scope.abort()
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
// Task-boundary prerender (cacheComponents build parity).
|
|
@@ -237,7 +237,7 @@ export function completePrerender(scope: PrerenderScope | undefined): void {
|
|
|
237
237
|
// subtree renderable after another subtree hit the boundary - the parallel-routes case, where the `@slot`
|
|
238
238
|
// becomes a hole but `children` must still bake into the shell.
|
|
239
239
|
|
|
240
|
-
const taskPostponeSymbol = Symbol.for('pnext.taskPostpone')
|
|
240
|
+
const taskPostponeSymbol = Symbol.for('pnext.taskPostpone')
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
243
|
* A postpone raised by the task boundary rather than by a request API. Escaping
|
|
@@ -245,22 +245,22 @@ const taskPostponeSymbol = Symbol.for('pnext.taskPostpone');
|
|
|
245
245
|
* all, which Next reports as a blocking-prerender build error.
|
|
246
246
|
*/
|
|
247
247
|
export function isTaskPostpone(error: unknown): boolean {
|
|
248
|
-
return isPostponeError(error) && taskPostponeSymbol in error
|
|
248
|
+
return isPostponeError(error) && taskPostponeSymbol in error
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
function taskPostponeError(): PostponeError {
|
|
252
|
-
const error = new PostponeError('task')
|
|
253
|
-
Object.defineProperty(error, taskPostponeSymbol, { value: true })
|
|
254
|
-
return error
|
|
252
|
+
const error = new PostponeError('task')
|
|
253
|
+
Object.defineProperty(error, taskPostponeSymbol, { value: true })
|
|
254
|
+
return error
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
/** True inside a build prerender running under task-boundary semantics. */
|
|
258
258
|
export function isTaskBoundaryPrerender(): boolean {
|
|
259
|
-
return prerenderStorage.getStore()?.taskBoundary === true
|
|
259
|
+
return prerenderStorage.getStore()?.taskBoundary === true
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
const taskBoundaryArmedStorage = new AsyncLocalStorage<true>()
|
|
263
|
-
const taskBoundarySuspendedStorage = new AsyncLocalStorage<true>()
|
|
262
|
+
const taskBoundaryArmedStorage = new AsyncLocalStorage<true>()
|
|
263
|
+
const taskBoundarySuspendedStorage = new AsyncLocalStorage<true>()
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
266
|
* Render `callback` with the task boundary ARMED. The renderer arms it only while resolving a <Suspense>
|
|
@@ -269,7 +269,7 @@ const taskBoundarySuspendedStorage = new AsyncLocalStorage<true>();
|
|
|
269
269
|
* shell, matching Next, where such work escaping the root is a separate blocking-prerender concern.
|
|
270
270
|
*/
|
|
271
271
|
export function runWithTaskBoundaryArmed<T>(callback: () => T): T {
|
|
272
|
-
return taskBoundaryArmedStorage.run(true, callback)
|
|
272
|
+
return taskBoundaryArmedStorage.run(true, callback)
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
/**
|
|
@@ -279,20 +279,20 @@ export function runWithTaskBoundaryArmed<T>(callback: () => T): T {
|
|
|
279
279
|
* returns immediately and its children do the IO.
|
|
280
280
|
*/
|
|
281
281
|
export function runWithTaskBoundarySuspended<T>(callback: () => T): T {
|
|
282
|
-
return taskBoundarySuspendedStorage.run(true, callback)
|
|
282
|
+
return taskBoundarySuspendedStorage.run(true, callback)
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// compat/cache/use-cache tags both shapes of "renders inside a cache scope" with globally-registered
|
|
286
286
|
// symbols, so reading them keeps core free of a compat import: the `'use cache'` wrapper itself, and the
|
|
287
287
|
// render-once memo wrapper it puts on every server component inside a produced (cached) tree.
|
|
288
|
-
const useCacheWrapperSymbol = Symbol.for('pnext.compat.useCacheWrapper')
|
|
289
|
-
const useCacheMemoWrappedSymbol = Symbol.for('pnext.compat.useCacheMemoWrapped')
|
|
288
|
+
const useCacheWrapperSymbol = Symbol.for('pnext.compat.useCacheWrapper')
|
|
289
|
+
const useCacheMemoWrappedSymbol = Symbol.for('pnext.compat.useCacheMemoWrapped')
|
|
290
290
|
|
|
291
291
|
/** Whether `component` renders inside a compat `'use cache'` scope. */
|
|
292
292
|
export function isCachedComponent(component: unknown): boolean {
|
|
293
|
-
if (typeof component !== 'function') return false
|
|
294
|
-
const tagged = component as unknown as Record<symbol, unknown
|
|
295
|
-
return tagged[useCacheWrapperSymbol] === true || tagged[useCacheMemoWrappedSymbol] === true
|
|
293
|
+
if (typeof component !== 'function') return false
|
|
294
|
+
const tagged = component as unknown as Record<symbol, unknown>
|
|
295
|
+
return tagged[useCacheWrapperSymbol] === true || tagged[useCacheMemoWrappedSymbol] === true
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
/**
|
|
@@ -301,18 +301,18 @@ export function isCachedComponent(component: unknown): boolean {
|
|
|
301
301
|
* value is returned untouched, so this is a no-op on every serving path.
|
|
302
302
|
*/
|
|
303
303
|
export function awaitAtTaskBoundary<T>(value: T): T {
|
|
304
|
-
if (!isTaskBoundaryPrerender()) return value
|
|
304
|
+
if (!isTaskBoundaryPrerender()) return value
|
|
305
305
|
// Only armed inside a <Suspense> subtree (see runWithTaskBoundaryArmed), and
|
|
306
306
|
// never inside a `'use cache'` subtree (runWithTaskBoundarySuspended).
|
|
307
|
-
if (taskBoundaryArmedStorage.getStore() !== true) return value
|
|
308
|
-
if (taskBoundarySuspendedStorage.getStore() === true) return value
|
|
309
|
-
if (typeof (value as { then?: unknown } | null)?.then !== 'function') return value
|
|
310
|
-
const deadline = taskDeadline()
|
|
307
|
+
if (taskBoundaryArmedStorage.getStore() !== true) return value
|
|
308
|
+
if (taskBoundarySuspendedStorage.getStore() === true) return value
|
|
309
|
+
if (typeof (value as { then?: unknown } | null)?.then !== 'function') return value
|
|
310
|
+
const deadline = taskDeadline()
|
|
311
311
|
// Cancel on settle so a component that wins the race does not leave its
|
|
312
312
|
// deadline burning through the rest of its microtask budget.
|
|
313
313
|
return Promise.race([value as PromiseLike<unknown>, deadline.promise]).finally(
|
|
314
314
|
deadline.cancel,
|
|
315
|
-
) as T
|
|
315
|
+
) as T
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
// Cache fills are the one kind of task-queue work a build prerender must WAIT for rather than cut off.
|
|
@@ -325,11 +325,11 @@ export function awaitAtTaskBoundary<T>(value: T): T {
|
|
|
325
325
|
// A fill that never settles must not hang the build (the E236 fill-timeout guard covers 'use cache', but
|
|
326
326
|
// nothing bounds an unstable_cache producer), so the deadline only ever defers to fills a bounded number of
|
|
327
327
|
// times before firing anyway.
|
|
328
|
-
const MAX_CACHE_FILL_DEFERRALS = 50
|
|
328
|
+
const MAX_CACHE_FILL_DEFERRALS = 50
|
|
329
329
|
|
|
330
330
|
interface CacheFillState {
|
|
331
|
-
pending: number
|
|
332
|
-
waiters: (() => void)[]
|
|
331
|
+
pending: number
|
|
332
|
+
waiters: (() => void)[]
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
// The build process and the built compat-server bundle load their own copies of
|
|
@@ -337,11 +337,11 @@ interface CacheFillState {
|
|
|
337
337
|
// their state), and the cache runtime registering a fill lives in the other
|
|
338
338
|
// copy from the renderer arming the deadline. Anchor the counter on globalThis
|
|
339
339
|
// so both copies share one window.
|
|
340
|
-
const CACHE_FILL_STATE = Symbol.for('pnext.prerenderCacheFills')
|
|
340
|
+
const CACHE_FILL_STATE = Symbol.for('pnext.prerenderCacheFills')
|
|
341
341
|
|
|
342
342
|
function cacheFillState(): CacheFillState {
|
|
343
|
-
const root = globalThis as Record<PropertyKey, unknown
|
|
344
|
-
return (root[CACHE_FILL_STATE] ??= { pending: 0, waiters: [] }) as CacheFillState
|
|
343
|
+
const root = globalThis as Record<PropertyKey, unknown>
|
|
344
|
+
return (root[CACHE_FILL_STATE] ??= { pending: 0, waiters: [] }) as CacheFillState
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
/**
|
|
@@ -351,18 +351,18 @@ function cacheFillState(): CacheFillState {
|
|
|
351
351
|
* Returns `fill` for chaining.
|
|
352
352
|
*/
|
|
353
353
|
export function trackPrerenderCacheFill<T>(fill: Promise<T>): Promise<T> {
|
|
354
|
-
recordShellCacheIO()
|
|
355
|
-
const state = cacheFillState()
|
|
356
|
-
state.pending += 1
|
|
354
|
+
recordShellCacheIO()
|
|
355
|
+
const state = cacheFillState()
|
|
356
|
+
state.pending += 1
|
|
357
357
|
const settled = () => {
|
|
358
|
-
state.pending -= 1
|
|
359
|
-
if (state.pending > 0) return
|
|
360
|
-
const waiters = state.waiters
|
|
361
|
-
state.waiters = []
|
|
362
|
-
for (const waiter of waiters) waiter()
|
|
363
|
-
}
|
|
364
|
-
fill.then(settled, settled)
|
|
365
|
-
return fill
|
|
358
|
+
state.pending -= 1
|
|
359
|
+
if (state.pending > 0) return
|
|
360
|
+
const waiters = state.waiters
|
|
361
|
+
state.waiters = []
|
|
362
|
+
for (const waiter of waiters) waiter()
|
|
363
|
+
}
|
|
364
|
+
fill.then(settled, settled)
|
|
365
|
+
return fill
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
// How many microtask turns count as "the queue drained". Generous enough that no
|
|
@@ -370,46 +370,46 @@ export function trackPrerenderCacheFill<T>(fill: Promise<T>): Promise<T> {
|
|
|
370
370
|
// siblings interleaving with it) runs out of budget, and still free: the whole
|
|
371
371
|
// drain happens inside one event-loop turn, and it is cancelled the moment the
|
|
372
372
|
// component it guards settles.
|
|
373
|
-
const MICROTASK_DRAIN_TURNS = 1000
|
|
373
|
+
const MICROTASK_DRAIN_TURNS = 1000
|
|
374
374
|
|
|
375
375
|
function taskDeadline(): { promise: Promise<never>; cancel: () => void } {
|
|
376
|
-
let cancelled = false
|
|
376
|
+
let cancelled = false
|
|
377
377
|
const promise = new Promise<never>((_resolve, reject) => {
|
|
378
|
-
let deferrals = 0
|
|
378
|
+
let deferrals = 0
|
|
379
379
|
const drain = (remaining: number) => {
|
|
380
|
-
if (cancelled) return
|
|
380
|
+
if (cancelled) return
|
|
381
381
|
if (remaining === 0) {
|
|
382
|
-
const state = cacheFillState()
|
|
382
|
+
const state = cacheFillState()
|
|
383
383
|
if (state.pending > 0 && deferrals < MAX_CACHE_FILL_DEFERRALS) {
|
|
384
384
|
// Cache fills are the one kind of task work the boundary waits for:
|
|
385
385
|
// yield until the last one settles, then drain again.
|
|
386
|
-
deferrals += 1
|
|
387
|
-
state.waiters.push(() => drain(MICROTASK_DRAIN_TURNS))
|
|
388
|
-
return
|
|
386
|
+
deferrals += 1
|
|
387
|
+
state.waiters.push(() => drain(MICROTASK_DRAIN_TURNS))
|
|
388
|
+
return
|
|
389
389
|
}
|
|
390
|
-
reject(taskPostponeError())
|
|
391
|
-
return
|
|
390
|
+
reject(taskPostponeError())
|
|
391
|
+
return
|
|
392
392
|
}
|
|
393
393
|
// Yield through BOTH pre-macrotask queues each turn: the nextTick queue
|
|
394
394
|
// ahead of us runs first (a component awaiting `process.nextTick` must
|
|
395
395
|
// still land in the shell), then a microtask hop. Neither queue can be
|
|
396
396
|
// preempted by a timer or an I/O callback, which is what makes the verdict
|
|
397
397
|
// load-independent.
|
|
398
|
-
const next = () => void Promise.resolve().then(() => drain(remaining - 1))
|
|
399
|
-
if (typeof process?.nextTick === 'function') process.nextTick(next)
|
|
400
|
-
else next()
|
|
401
|
-
}
|
|
402
|
-
drain(MICROTASK_DRAIN_TURNS)
|
|
403
|
-
})
|
|
398
|
+
const next = () => void Promise.resolve().then(() => drain(remaining - 1))
|
|
399
|
+
if (typeof process?.nextTick === 'function') process.nextTick(next)
|
|
400
|
+
else next()
|
|
401
|
+
}
|
|
402
|
+
drain(MICROTASK_DRAIN_TURNS)
|
|
403
|
+
})
|
|
404
404
|
// The losing copy of a raced deadline must never reach the unhandled-rejection
|
|
405
405
|
// channel (the race attaches its own handler to the winning one).
|
|
406
|
-
promise.catch(() => undefined)
|
|
406
|
+
promise.catch(() => undefined)
|
|
407
407
|
return {
|
|
408
408
|
promise,
|
|
409
409
|
cancel: () => {
|
|
410
|
-
cancelled = true
|
|
410
|
+
cancelled = true
|
|
411
411
|
},
|
|
412
|
-
}
|
|
412
|
+
}
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
/**
|
|
@@ -429,17 +429,17 @@ function taskDeadline(): { promise: Promise<never>; cancel: () => void } {
|
|
|
429
429
|
* hook returns the canonical form - the request-apis e2e suite substring-matches exactly that.
|
|
430
430
|
*/
|
|
431
431
|
function prerenderCompleteError(api: string): Error {
|
|
432
|
-
const message = `During prerendering, \`${api}\` rejects when the prerender is complete
|
|
433
|
-
const error = new Error(message)
|
|
432
|
+
const message = `During prerendering, \`${api}\` rejects when the prerender is complete.`
|
|
433
|
+
const error = new Error(message)
|
|
434
434
|
Object.defineProperty(error, Symbol.for('nodejs.util.inspect.custom'), {
|
|
435
435
|
value: () => {
|
|
436
|
-
const stackTail = (error.stack ?? '').split('\n').slice(1).join('\n')
|
|
437
|
-
return stackTail ? `Error: ${message}\n${stackTail}` : `Error: ${message}
|
|
436
|
+
const stackTail = (error.stack ?? '').split('\n').slice(1).join('\n')
|
|
437
|
+
return stackTail ? `Error: ${message}\n${stackTail}` : `Error: ${message}`
|
|
438
438
|
},
|
|
439
439
|
enumerable: false,
|
|
440
440
|
configurable: true,
|
|
441
|
-
})
|
|
442
|
-
return error
|
|
441
|
+
})
|
|
442
|
+
return error
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
/**
|
|
@@ -447,7 +447,7 @@ function prerenderCompleteError(api: string): Error {
|
|
|
447
447
|
* request-API promise, rather than consume its value, must be able to ask without marking the prerender
|
|
448
448
|
* dynamic - so the tag arm sits ahead of the then/catch/finally arms in the `get` trap.
|
|
449
449
|
*/
|
|
450
|
-
const HANGING_PROMISE = Symbol.for('pnext.hangingPromise')
|
|
450
|
+
const HANGING_PROMISE = Symbol.for('pnext.hangingPromise')
|
|
451
451
|
|
|
452
452
|
/**
|
|
453
453
|
* True for the promise `hangingPromise` returns. Used by the island-props
|
|
@@ -461,17 +461,17 @@ export function isHangingPromise(value: unknown): boolean {
|
|
|
461
461
|
typeof value === 'object' &&
|
|
462
462
|
value !== null &&
|
|
463
463
|
(value as Record<symbol, unknown>)[HANGING_PROMISE] === true
|
|
464
|
-
)
|
|
464
|
+
)
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
export function hangingPromise<T = never>(api: string): Promise<T> {
|
|
468
|
-
const scope = prerenderStorage.getStore()
|
|
468
|
+
const scope = prerenderStorage.getStore()
|
|
469
469
|
// Outside a prerender scope this should not be called; return a caught
|
|
470
470
|
// rejection defensively so a stray await surfaces rather than hangs forever.
|
|
471
471
|
if (!scope) {
|
|
472
|
-
const stray = Promise.reject<T>(new PostponeError(api))
|
|
473
|
-
stray.catch(() => undefined)
|
|
474
|
-
return stray
|
|
472
|
+
const stray = Promise.reject<T>(new PostponeError(api))
|
|
473
|
+
stray.catch(() => undefined)
|
|
474
|
+
return stray
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
// The promise settles exactly once, via whichever observation happens first: a consumer awaiting it (a
|
|
@@ -479,54 +479,54 @@ export function hangingPromise<T = never>(api: string): Promise<T> {
|
|
|
479
479
|
// records a hole; the prerender completing (scope abort) rejects with the "rejects when the prerender is
|
|
480
480
|
// complete" Error so stashed-promise subscribers observe it. It must stay PENDING until one of those
|
|
481
481
|
// happens - settling on a timer or microtask races late awaiters into the wrong rejection.
|
|
482
|
-
let settle: ((error: Error) => void) | undefined
|
|
482
|
+
let settle: ((error: Error) => void) | undefined
|
|
483
483
|
const promise = new Promise<T>((_resolve, reject) => {
|
|
484
|
-
settle = (error: Error) => reject(error)
|
|
485
|
-
})
|
|
486
|
-
const rejectAwaited = () => settle?.(new PostponeError(api))
|
|
484
|
+
settle = (error: Error) => reject(error)
|
|
485
|
+
})
|
|
486
|
+
const rejectAwaited = () => settle?.(new PostponeError(api))
|
|
487
487
|
if (scope.signal.aborted) {
|
|
488
|
-
settle?.(prerenderCompleteError(api))
|
|
488
|
+
settle?.(prerenderCompleteError(api))
|
|
489
489
|
} else {
|
|
490
490
|
scope.signal.addEventListener('abort', () => settle?.(prerenderCompleteError(api)), {
|
|
491
491
|
once: true,
|
|
492
|
-
})
|
|
492
|
+
})
|
|
493
493
|
}
|
|
494
494
|
// Swallow the rejection for the un-subscribed copy so a hanging promise nobody
|
|
495
495
|
// observed never surfaces as an unhandled rejection; an actual awaiter/handler
|
|
496
496
|
// still observes the throw (it subscribes to the same promise).
|
|
497
|
-
promise.catch(() => undefined)
|
|
497
|
+
promise.catch(() => undefined)
|
|
498
498
|
return new Proxy(promise, {
|
|
499
499
|
get(target, property) {
|
|
500
500
|
// Before every observation arm: reading the tag must not mark dynamic.
|
|
501
|
-
if (property === HANGING_PROMISE) return true
|
|
501
|
+
if (property === HANGING_PROMISE) return true
|
|
502
502
|
if (property === 'then') {
|
|
503
503
|
return (...args: Parameters<typeof target.then>) => {
|
|
504
504
|
// A fulfillment handler means the value is being consumed (an await or
|
|
505
505
|
// value-taking `.then`): mark the boundary dynamic and postpone.
|
|
506
|
-
if (typeof args[0] === 'function') rejectAwaited()
|
|
507
|
-
markPrerenderDynamic()
|
|
508
|
-
recordShellRequestApi(api)
|
|
509
|
-
return target.then(...args)
|
|
510
|
-
}
|
|
506
|
+
if (typeof args[0] === 'function') rejectAwaited()
|
|
507
|
+
markPrerenderDynamic()
|
|
508
|
+
recordShellRequestApi(api)
|
|
509
|
+
return target.then(...args)
|
|
510
|
+
}
|
|
511
511
|
}
|
|
512
512
|
if (property === 'catch') {
|
|
513
513
|
return (...args: Parameters<typeof target.catch>) => {
|
|
514
|
-
markPrerenderDynamic()
|
|
515
|
-
recordShellRequestApi(api)
|
|
516
|
-
return target.catch(...args)
|
|
517
|
-
}
|
|
514
|
+
markPrerenderDynamic()
|
|
515
|
+
recordShellRequestApi(api)
|
|
516
|
+
return target.catch(...args)
|
|
517
|
+
}
|
|
518
518
|
}
|
|
519
519
|
if (property === 'finally') {
|
|
520
520
|
return (...args: Parameters<typeof target.finally>) => {
|
|
521
|
-
markPrerenderDynamic()
|
|
522
|
-
recordShellRequestApi(api)
|
|
523
|
-
return target.finally(...args)
|
|
524
|
-
}
|
|
521
|
+
markPrerenderDynamic()
|
|
522
|
+
recordShellRequestApi(api)
|
|
523
|
+
return target.finally(...args)
|
|
524
|
+
}
|
|
525
525
|
}
|
|
526
|
-
const value: unknown = Reflect.get(target, property, target)
|
|
527
|
-
return value
|
|
526
|
+
const value: unknown = Reflect.get(target, property, target)
|
|
527
|
+
return value
|
|
528
528
|
},
|
|
529
|
-
})
|
|
529
|
+
})
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
// ---------------------------------------------------------------------------
|
|
@@ -540,14 +540,14 @@ export function hangingPromise<T = never>(api: string): Promise<T> {
|
|
|
540
540
|
// ---------------------------------------------------------------------------
|
|
541
541
|
|
|
542
542
|
// globalThis-anchored: the prebundled server entry inlines its own copy of this module.
|
|
543
|
-
const CACHE_COMPONENTS = Symbol.for('pnext.cacheComponents')
|
|
543
|
+
const CACHE_COMPONENTS = Symbol.for('pnext.cacheComponents')
|
|
544
544
|
|
|
545
545
|
export function setCacheComponents(enabled: boolean): void {
|
|
546
|
-
(globalThis as Record<PropertyKey, unknown>)[CACHE_COMPONENTS] = enabled
|
|
546
|
+
;(globalThis as Record<PropertyKey, unknown>)[CACHE_COMPONENTS] = enabled
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
export function cacheComponents(): boolean {
|
|
550
|
-
return (globalThis as Record<PropertyKey, unknown>)[CACHE_COMPONENTS] === true
|
|
550
|
+
return (globalThis as Record<PropertyKey, unknown>)[CACHE_COMPONENTS] === true
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
// ---------------------------------------------------------------------------
|
|
@@ -564,52 +564,51 @@ export function cacheComponents(): boolean {
|
|
|
564
564
|
// Real wall-clock that survives the determinism patch below. Cache bookkeeping
|
|
565
565
|
// (use-cache storedAt) must never be stamped with the frozen build clock — a
|
|
566
566
|
// `storedAt: 0` entry reads as perpetually expired at runtime.
|
|
567
|
-
const REAL_NOW = Symbol.for('pnext.realNow')
|
|
567
|
+
const REAL_NOW = Symbol.for('pnext.realNow')
|
|
568
568
|
export function realNow(): number {
|
|
569
|
-
const stored = (globalThis as Record<PropertyKey, unknown>)[REAL_NOW]
|
|
570
|
-
return typeof stored === 'function' ? (stored as () => number)() : Date.now()
|
|
569
|
+
const stored = (globalThis as Record<PropertyKey, unknown>)[REAL_NOW]
|
|
570
|
+
return typeof stored === 'function' ? (stored as () => number)() : Date.now()
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
// A `use cache` body is allowed to be non-deterministic - its output is what gets cached, and Next's
|
|
574
574
|
// work-unit store inside a cache scope is `cache`, not `prerender-runtime`, so
|
|
575
575
|
// abortOnSynchronousPlatformIOAccess never applies there. The scope ALS is read off its globalThis symbol
|
|
576
576
|
// rather than imported: ppr.ts is core and must not depend on compat/cache.
|
|
577
|
-
const USE_CACHE_SCOPE_STORAGE = Symbol.for('pnext.compat.useCacheScopeStorage')
|
|
577
|
+
const USE_CACHE_SCOPE_STORAGE = Symbol.for('pnext.compat.useCacheScopeStorage')
|
|
578
578
|
|
|
579
579
|
function insideUseCacheScope(): boolean {
|
|
580
580
|
const storage = (globalThis as Record<PropertyKey, unknown>)[USE_CACHE_SCOPE_STORAGE] as
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
return storage?.getStore() !== undefined;
|
|
581
|
+
{ getStore(): unknown } | undefined
|
|
582
|
+
return storage?.getStore() !== undefined
|
|
584
583
|
}
|
|
585
584
|
|
|
586
585
|
export async function runWithPrerenderDeterminism<T>(fn: () => Promise<T>): Promise<T> {
|
|
587
|
-
if (!cacheComponents()) return fn()
|
|
588
|
-
const deterministicTime = 1
|
|
589
|
-
const realRandom = Math.random
|
|
590
|
-
const RealDate = Date
|
|
591
|
-
(globalThis as Record<PropertyKey, unknown>)[REAL_NOW] = RealDate.now.bind(RealDate)
|
|
592
|
-
let counter = 0
|
|
586
|
+
if (!cacheComponents()) return fn()
|
|
587
|
+
const deterministicTime = 1
|
|
588
|
+
const realRandom = Math.random
|
|
589
|
+
const RealDate = Date
|
|
590
|
+
;(globalThis as Record<PropertyKey, unknown>)[REAL_NOW] = RealDate.now.bind(RealDate)
|
|
591
|
+
let counter = 0
|
|
593
592
|
Math.random = () => {
|
|
594
|
-
counter = (counter * 1103515245 + 12345) & 0x7fffffff
|
|
595
|
-
return (counter % 1000000) / 1000000
|
|
596
|
-
}
|
|
593
|
+
counter = (counter * 1103515245 + 12345) & 0x7fffffff
|
|
594
|
+
return (counter % 1000000) / 1000000
|
|
595
|
+
}
|
|
597
596
|
const PatchedDate = function (this: unknown, ...args: unknown[]) {
|
|
598
|
-
if (!new.target) return new RealDate(deterministicTime).toString()
|
|
599
|
-
if (args.length === 0) return new RealDate(deterministicTime)
|
|
600
|
-
return Reflect.construct(RealDate, args) as Date
|
|
601
|
-
} as unknown as DateConstructor
|
|
602
|
-
Object.setPrototypeOf(PatchedDate, RealDate)
|
|
603
|
-
Object.defineProperty(PatchedDate, 'prototype', { value: RealDate.prototype })
|
|
604
|
-
PatchedDate.now = () => deterministicTime
|
|
597
|
+
if (!new.target) return new RealDate(deterministicTime).toString()
|
|
598
|
+
if (args.length === 0) return new RealDate(deterministicTime)
|
|
599
|
+
return Reflect.construct(RealDate, args) as Date
|
|
600
|
+
} as unknown as DateConstructor
|
|
601
|
+
Object.setPrototypeOf(PatchedDate, RealDate)
|
|
602
|
+
Object.defineProperty(PatchedDate, 'prototype', { value: RealDate.prototype })
|
|
603
|
+
PatchedDate.now = () => deterministicTime
|
|
605
604
|
// eslint-disable-next-line no-global-assign
|
|
606
|
-
Date = PatchedDate
|
|
605
|
+
Date = PatchedDate
|
|
607
606
|
try {
|
|
608
|
-
return await fn()
|
|
607
|
+
return await fn()
|
|
609
608
|
} finally {
|
|
610
|
-
Math.random = realRandom
|
|
609
|
+
Math.random = realRandom
|
|
611
610
|
// eslint-disable-next-line no-global-assign
|
|
612
|
-
Date = RealDate
|
|
611
|
+
Date = RealDate
|
|
613
612
|
}
|
|
614
613
|
}
|
|
615
614
|
|
|
@@ -636,8 +635,8 @@ export async function runWithPrerenderDeterminism<T>(fn: () => Promise<T>): Prom
|
|
|
636
635
|
* since `await` on a native promise bypasses a monkey-patched `then`.
|
|
637
636
|
*/
|
|
638
637
|
export function markRuntimeApiOnAwait<T>(promise: Promise<T>): Promise<T> {
|
|
639
|
-
const scope = prerenderStorage.getStore()
|
|
640
|
-
if (scope?.runtimePrefetch !== true) return promise
|
|
638
|
+
const scope = prerenderStorage.getStore()
|
|
639
|
+
if (scope?.runtimePrefetch !== true) return promise
|
|
641
640
|
return new Proxy(promise, {
|
|
642
641
|
get(target, property) {
|
|
643
642
|
if (property === 'then') {
|
|
@@ -645,129 +644,129 @@ export function markRuntimeApiOnAwait<T>(promise: Promise<T>): Promise<T> {
|
|
|
645
644
|
// A fulfillment handler means the value is being consumed (an await or
|
|
646
645
|
// a value-taking `.then`) — the point Next considers the runtime API
|
|
647
646
|
// resolved into the render.
|
|
648
|
-
if (typeof args[0] === 'function') scope.awaitedRuntimeApi = true
|
|
649
|
-
return target.then(...args)
|
|
650
|
-
}
|
|
647
|
+
if (typeof args[0] === 'function') scope.awaitedRuntimeApi = true
|
|
648
|
+
return target.then(...args)
|
|
649
|
+
}
|
|
651
650
|
}
|
|
652
|
-
return Reflect.get(target, property, target) as unknown
|
|
651
|
+
return Reflect.get(target, property, target) as unknown
|
|
653
652
|
},
|
|
654
|
-
})
|
|
653
|
+
})
|
|
655
654
|
}
|
|
656
655
|
|
|
657
656
|
/** Throw the boundary-aborting postpone when sync IO happens post-runtime-API. */
|
|
658
657
|
function abortOnSynchronousPlatformIOAccess(): void {
|
|
659
|
-
const scope = prerenderStorage.getStore()
|
|
660
|
-
if (scope?.runtimePrefetch !== true || scope.awaitedRuntimeApi !== true) return
|
|
658
|
+
const scope = prerenderStorage.getStore()
|
|
659
|
+
if (scope?.runtimePrefetch !== true || scope.awaitedRuntimeApi !== true) return
|
|
661
660
|
// Sync IO inside a `use cache` body is legal — see insideUseCacheScope above.
|
|
662
|
-
if (insideUseCacheScope()) return
|
|
663
|
-
throw new PostponeError('sync IO')
|
|
661
|
+
if (insideUseCacheScope()) return
|
|
662
|
+
throw new PostponeError('sync IO')
|
|
664
663
|
}
|
|
665
664
|
|
|
666
665
|
/** Install `value` as an own property of `owner`, returning a restore thunk. */
|
|
667
666
|
function patchMethod(owner: object, key: string, value: unknown): () => void {
|
|
668
|
-
const hadOwn = Object.prototype.hasOwnProperty.call(owner, key)
|
|
669
|
-
const descriptor = Object.getOwnPropertyDescriptor(owner, key)
|
|
667
|
+
const hadOwn = Object.prototype.hasOwnProperty.call(owner, key)
|
|
668
|
+
const descriptor = Object.getOwnPropertyDescriptor(owner, key)
|
|
670
669
|
try {
|
|
671
670
|
Object.defineProperty(owner, key, {
|
|
672
671
|
value,
|
|
673
672
|
configurable: true,
|
|
674
673
|
writable: true,
|
|
675
674
|
enumerable: descriptor?.enumerable ?? false,
|
|
676
|
-
})
|
|
675
|
+
})
|
|
677
676
|
} catch {
|
|
678
|
-
return () => undefined
|
|
677
|
+
return () => undefined
|
|
679
678
|
}
|
|
680
679
|
return () => {
|
|
681
680
|
try {
|
|
682
|
-
if (hadOwn && descriptor) Object.defineProperty(owner, key, descriptor)
|
|
683
|
-
else delete (owner as Record<string, unknown>)[key]
|
|
681
|
+
if (hadOwn && descriptor) Object.defineProperty(owner, key, descriptor)
|
|
682
|
+
else delete (owner as Record<string, unknown>)[key]
|
|
684
683
|
} catch {
|
|
685
684
|
/* nothing sensible to do if the global refuses to be restored */
|
|
686
685
|
}
|
|
687
|
-
}
|
|
686
|
+
}
|
|
688
687
|
}
|
|
689
688
|
|
|
690
689
|
// Two runtime prefetches can be in flight at once, so installation is
|
|
691
690
|
// refcounted: the shims go in on 0→1 and come out on 1→0. Anchored on
|
|
692
691
|
// globalThis for the usual dual-module-copy reason.
|
|
693
|
-
const SYNC_IO_SHIMS = Symbol.for('pnext.runtimePrefetchSyncIoShims')
|
|
692
|
+
const SYNC_IO_SHIMS = Symbol.for('pnext.runtimePrefetchSyncIoShims')
|
|
694
693
|
interface SyncIoShimState {
|
|
695
|
-
depth: number
|
|
696
|
-
restore: (() => void)[]
|
|
694
|
+
depth: number
|
|
695
|
+
restore: (() => void)[]
|
|
697
696
|
}
|
|
698
697
|
function syncIoShimState(): SyncIoShimState {
|
|
699
|
-
const root = globalThis as Record<PropertyKey, unknown
|
|
700
|
-
return (root[SYNC_IO_SHIMS] ??= { depth: 0, restore: [] }) as SyncIoShimState
|
|
698
|
+
const root = globalThis as Record<PropertyKey, unknown>
|
|
699
|
+
return (root[SYNC_IO_SHIMS] ??= { depth: 0, restore: [] }) as SyncIoShimState
|
|
701
700
|
}
|
|
702
701
|
|
|
703
702
|
function installSyncIoShims(): void {
|
|
704
|
-
const state = syncIoShimState()
|
|
705
|
-
if (++state.depth > 1) return
|
|
706
|
-
const root = globalThis as Record<PropertyKey, unknown
|
|
707
|
-
const RealDate = Date
|
|
708
|
-
const realRandom = Math.random
|
|
703
|
+
const state = syncIoShimState()
|
|
704
|
+
if (++state.depth > 1) return
|
|
705
|
+
const root = globalThis as Record<PropertyKey, unknown>
|
|
706
|
+
const RealDate = Date
|
|
707
|
+
const realRandom = Math.random
|
|
709
708
|
// realNow() must keep reporting the true wall clock while Date.now is shimmed
|
|
710
709
|
// — cache bookkeeping (storedAt/expiry) reads it during the render.
|
|
711
|
-
const previousRealNow = root[REAL_NOW]
|
|
712
|
-
root[REAL_NOW] = RealDate.now.bind(RealDate)
|
|
710
|
+
const previousRealNow = root[REAL_NOW]
|
|
711
|
+
root[REAL_NOW] = RealDate.now.bind(RealDate)
|
|
713
712
|
const PatchedDate = function (this: unknown, ...args: unknown[]) {
|
|
714
713
|
if (!new.target) {
|
|
715
|
-
abortOnSynchronousPlatformIOAccess()
|
|
716
|
-
return new RealDate().toString()
|
|
714
|
+
abortOnSynchronousPlatformIOAccess()
|
|
715
|
+
return new RealDate().toString()
|
|
717
716
|
}
|
|
718
717
|
if (args.length === 0) {
|
|
719
|
-
abortOnSynchronousPlatformIOAccess()
|
|
720
|
-
return new RealDate()
|
|
718
|
+
abortOnSynchronousPlatformIOAccess()
|
|
719
|
+
return new RealDate()
|
|
721
720
|
}
|
|
722
|
-
return Reflect.construct(RealDate, args) as Date
|
|
723
|
-
} as unknown as DateConstructor
|
|
724
|
-
Object.setPrototypeOf(PatchedDate, RealDate)
|
|
725
|
-
Object.defineProperty(PatchedDate, 'prototype', { value: RealDate.prototype })
|
|
721
|
+
return Reflect.construct(RealDate, args) as Date
|
|
722
|
+
} as unknown as DateConstructor
|
|
723
|
+
Object.setPrototypeOf(PatchedDate, RealDate)
|
|
724
|
+
Object.defineProperty(PatchedDate, 'prototype', { value: RealDate.prototype })
|
|
726
725
|
PatchedDate.now = () => {
|
|
727
|
-
abortOnSynchronousPlatformIOAccess()
|
|
728
|
-
return RealDate.now()
|
|
729
|
-
}
|
|
726
|
+
abortOnSynchronousPlatformIOAccess()
|
|
727
|
+
return RealDate.now()
|
|
728
|
+
}
|
|
730
729
|
// eslint-disable-next-line no-global-assign
|
|
731
|
-
Date = PatchedDate
|
|
730
|
+
Date = PatchedDate
|
|
732
731
|
Math.random = () => {
|
|
733
|
-
abortOnSynchronousPlatformIOAccess()
|
|
734
|
-
return realRandom()
|
|
735
|
-
}
|
|
732
|
+
abortOnSynchronousPlatformIOAccess()
|
|
733
|
+
return realRandom()
|
|
734
|
+
}
|
|
736
735
|
state.restore.push(() => {
|
|
737
736
|
// eslint-disable-next-line no-global-assign
|
|
738
|
-
Date = RealDate
|
|
739
|
-
Math.random = realRandom
|
|
740
|
-
root[REAL_NOW] = previousRealNow
|
|
741
|
-
})
|
|
742
|
-
const perf = globalThis.performance as Performance | undefined
|
|
737
|
+
Date = RealDate
|
|
738
|
+
Math.random = realRandom
|
|
739
|
+
root[REAL_NOW] = previousRealNow
|
|
740
|
+
})
|
|
741
|
+
const perf = globalThis.performance as Performance | undefined
|
|
743
742
|
if (perf) {
|
|
744
|
-
const realPerfNow = perf.now.bind(perf)
|
|
743
|
+
const realPerfNow = perf.now.bind(perf)
|
|
745
744
|
state.restore.push(
|
|
746
745
|
patchMethod(perf, 'now', () => {
|
|
747
|
-
abortOnSynchronousPlatformIOAccess()
|
|
748
|
-
return realPerfNow()
|
|
746
|
+
abortOnSynchronousPlatformIOAccess()
|
|
747
|
+
return realPerfNow()
|
|
749
748
|
}),
|
|
750
|
-
)
|
|
749
|
+
)
|
|
751
750
|
}
|
|
752
|
-
const webCrypto = globalThis.crypto as Crypto | undefined
|
|
751
|
+
const webCrypto = globalThis.crypto as Crypto | undefined
|
|
753
752
|
if (typeof webCrypto?.getRandomValues === 'function') {
|
|
754
|
-
const realGetRandomValues = webCrypto.getRandomValues.bind(webCrypto)
|
|
753
|
+
const realGetRandomValues = webCrypto.getRandomValues.bind(webCrypto)
|
|
755
754
|
state.restore.push(
|
|
756
755
|
patchMethod(webCrypto, 'getRandomValues', (array: ArrayBufferView) => {
|
|
757
|
-
abortOnSynchronousPlatformIOAccess()
|
|
758
|
-
return realGetRandomValues(array as never)
|
|
756
|
+
abortOnSynchronousPlatformIOAccess()
|
|
757
|
+
return realGetRandomValues(array as never)
|
|
759
758
|
}),
|
|
760
|
-
)
|
|
759
|
+
)
|
|
761
760
|
}
|
|
762
761
|
}
|
|
763
762
|
|
|
764
763
|
function restoreSyncIoShims(): void {
|
|
765
|
-
const state = syncIoShimState()
|
|
766
|
-
if (--state.depth > 0) return
|
|
767
|
-
state.depth = 0
|
|
768
|
-
const restore = state.restore
|
|
769
|
-
state.restore = []
|
|
770
|
-
for (const undo of restore) undo()
|
|
764
|
+
const state = syncIoShimState()
|
|
765
|
+
if (--state.depth > 0) return
|
|
766
|
+
state.depth = 0
|
|
767
|
+
const restore = state.restore
|
|
768
|
+
state.restore = []
|
|
769
|
+
for (const undo of restore) undo()
|
|
771
770
|
}
|
|
772
771
|
|
|
773
772
|
/**
|
|
@@ -776,10 +775,10 @@ function restoreSyncIoShims(): void {
|
|
|
776
775
|
* postpones its nearest <Suspense> boundary instead of returning a value.
|
|
777
776
|
*/
|
|
778
777
|
export async function runWithRuntimePrefetchSyncIoAbort<T>(fn: () => Promise<T>): Promise<T> {
|
|
779
|
-
installSyncIoShims()
|
|
778
|
+
installSyncIoShims()
|
|
780
779
|
try {
|
|
781
|
-
return await fn()
|
|
780
|
+
return await fn()
|
|
782
781
|
} finally {
|
|
783
|
-
restoreSyncIoShims()
|
|
782
|
+
restoreSyncIoShims()
|
|
784
783
|
}
|
|
785
784
|
}
|