@wular/pnext 0.0.3 → 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 -1961
- 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 -1887
- 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} +152 -143
- package/src/resolve/engine.ts +90 -77
- package/src/resolve/imports.ts +475 -463
- package/src/resolve/scan-facts.ts +442 -186
- 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 +833 -848
- 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
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { isNotFoundError, isRedirectError, type PNextRedirectError } from '../../api/navigation'
|
|
2
|
-
import { runWithRequest, setPhase } from '../../request/context'
|
|
3
|
-
import { toNextRequest } from '../../api/server'
|
|
4
|
-
import { revalidationEventCount } from '../cache/revalidate'
|
|
5
|
-
import { serializeBoundaryError } from '../lifecycle/error-serialize'
|
|
6
|
-
import { lookupAction } from './registry'
|
|
7
|
-
import { instanceActionRouteId, isInstanceActionId, lookupActionInstance } from './instances'
|
|
8
|
-
import { inlineActionModuleKey, isInlineActionId } from './rewrite'
|
|
1
|
+
import { isNotFoundError, isRedirectError, type PNextRedirectError } from '../../api/navigation'
|
|
2
|
+
import { runWithRequest, setPhase } from '../../request/context'
|
|
3
|
+
import { toNextRequest } from '../../api/server'
|
|
4
|
+
import { revalidationEventCount } from '../cache/revalidate'
|
|
5
|
+
import { serializeBoundaryError } from '../lifecycle/error-serialize'
|
|
6
|
+
import { lookupAction } from './registry'
|
|
7
|
+
import { instanceActionRouteId, isInstanceActionId, lookupActionInstance } from './instances'
|
|
8
|
+
import { inlineActionModuleKey, isInlineActionId } from './rewrite'
|
|
9
9
|
import {
|
|
10
10
|
ACTION_STREAM_CONTENT_TYPE,
|
|
11
11
|
createTempRefScope,
|
|
12
12
|
extractTempRefs,
|
|
13
13
|
isReadableStreamReturn,
|
|
14
14
|
serializeReturnWithTempRefs,
|
|
15
|
-
} from '
|
|
15
|
+
} from './return'
|
|
16
16
|
import {
|
|
17
17
|
ACTION_ARGS_FIELD,
|
|
18
18
|
ACTION_ID_FIELD,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
MAX_ACTION_ARGS,
|
|
35
35
|
tooManyArgsMessage,
|
|
36
36
|
type ActionSuccessBody,
|
|
37
|
-
} from './protocol'
|
|
37
|
+
} from './protocol'
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Framework-agnostic runtime handler for a server-action RPC. It reads the action id header, decodes
|
|
@@ -49,38 +49,38 @@ import {
|
|
|
49
49
|
*/
|
|
50
50
|
export interface RunActionOptions {
|
|
51
51
|
/** Load an action module by its registered modulePath. Injected by the caller. */
|
|
52
|
-
importModule: (modulePath: string) => Promise<Record<string, unknown
|
|
52
|
+
importModule: (modulePath: string) => Promise<Record<string, unknown>>
|
|
53
53
|
/**
|
|
54
54
|
* Re-render a route server-side to re-register live inline-action instances
|
|
55
55
|
* (see instances.ts) after a process restart. Optional; without it a cold
|
|
56
56
|
* instance id fails with unknown-action.
|
|
57
57
|
*/
|
|
58
|
-
rerenderRoute?: (routeId: string, request: Request) => Promise<void
|
|
58
|
+
rerenderRoute?: (routeId: string, request: Request) => Promise<void>
|
|
59
59
|
/**
|
|
60
60
|
* Import an app module by its workspace-relative source key so its
|
|
61
61
|
* compile-injected inline-action registrations run (cold 'if:' id lookups).
|
|
62
62
|
*/
|
|
63
|
-
importSourceModule?: (moduleKey: string) => Promise<void
|
|
63
|
+
importSourceModule?: (moduleKey: string) => Promise<void>
|
|
64
64
|
/** Dev mode: error bodies carry real messages instead of the masked text. */
|
|
65
|
-
dev?: boolean
|
|
65
|
+
dev?: boolean
|
|
66
66
|
/** Body size limit in bytes (Next default 1mb). */
|
|
67
|
-
maxBodyBytes?: number
|
|
67
|
+
maxBodyBytes?: number
|
|
68
68
|
/**
|
|
69
69
|
* Report a thrown action error to the app's onRequestError instrumentation.
|
|
70
70
|
* Injected by the caller (compat glue) so this module stays portable; called
|
|
71
71
|
* once for a real (non control-flow) throw before the masked 500 is returned.
|
|
72
72
|
*/
|
|
73
|
-
onError?: (error: unknown, request: Request) => void | Promise<void
|
|
73
|
+
onError?: (error: unknown, request: Request) => void | Promise<void>
|
|
74
74
|
/**
|
|
75
75
|
* Server-render a React element tree an action RETURNED to island wire HTML
|
|
76
76
|
* (the JSON return serializer cannot carry vnode Symbols). Injected by the
|
|
77
77
|
* caller (register-actions) so this module never imports the renderer; when
|
|
78
78
|
* absent, element returns fall through the JSON serializer unchanged.
|
|
79
79
|
*/
|
|
80
|
-
renderActionElement?: (element: unknown) => Promise<string
|
|
80
|
+
renderActionElement?: (element: unknown) => Promise<string>
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
export const DEFAULT_BODY_LIMIT_BYTES = 1024 * 1024
|
|
83
|
+
export const DEFAULT_BODY_LIMIT_BYTES = 1024 * 1024
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* Server-side fallback for client-action stubs. A `'use server'` function imported into a client
|
|
@@ -93,48 +93,48 @@ export const DEFAULT_BODY_LIMIT_BYTES = 1024 * 1024;
|
|
|
93
93
|
function installServerActionDispatch(
|
|
94
94
|
importModule: (modulePath: string) => Promise<Record<string, unknown>>,
|
|
95
95
|
): void {
|
|
96
|
-
(
|
|
96
|
+
;(
|
|
97
97
|
globalThis as {
|
|
98
|
-
__PNEXT_SERVER_ACTIONS__?: { call(id: string, args: unknown[]): Promise<unknown> }
|
|
98
|
+
__PNEXT_SERVER_ACTIONS__?: { call(id: string, args: unknown[]): Promise<unknown> }
|
|
99
99
|
}
|
|
100
100
|
).__PNEXT_SERVER_ACTIONS__ = {
|
|
101
101
|
async call(dispatchId: string, dispatchArgs: unknown[]): Promise<unknown> {
|
|
102
|
-
const target = lookupAction(dispatchId)
|
|
102
|
+
const target = lookupAction(dispatchId)
|
|
103
103
|
if (!target) {
|
|
104
104
|
throw new Error(
|
|
105
105
|
`Failed to find Server Action "${dispatchId}". This request might be from an older or newer deployment.`,
|
|
106
|
-
)
|
|
106
|
+
)
|
|
107
107
|
}
|
|
108
|
-
const module = await importModule(target.modulePath)
|
|
109
|
-
const fn = module[target.exportName]
|
|
108
|
+
const module = await importModule(target.modulePath)
|
|
109
|
+
const fn = module[target.exportName]
|
|
110
110
|
if (typeof fn !== 'function') {
|
|
111
|
-
throw new Error(`Failed to find Server Action "${dispatchId}".`)
|
|
111
|
+
throw new Error(`Failed to find Server Action "${dispatchId}".`)
|
|
112
112
|
}
|
|
113
|
-
return (fn as (...a: unknown[]) => unknown)(...dispatchArgs)
|
|
113
|
+
return (fn as (...a: unknown[]) => unknown)(...dispatchArgs)
|
|
114
114
|
},
|
|
115
|
-
}
|
|
115
|
+
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
export async function runAction(request: Request, options: RunActionOptions): Promise<Response> {
|
|
119
|
-
const id = request.headers.get(ACTION_ID_HEADER)
|
|
119
|
+
const id = request.headers.get(ACTION_ID_HEADER)
|
|
120
120
|
if (!id) {
|
|
121
|
-
return errorResponse(`Missing ${ACTION_ID_HEADER} header`, 400)
|
|
121
|
+
return errorResponse(`Missing ${ACTION_ID_HEADER} header`, 400)
|
|
122
122
|
}
|
|
123
123
|
// Arm the server-side stub dispatcher for this request's module loader before
|
|
124
124
|
// resolving/running the action (a client-imported action may re-render the
|
|
125
125
|
// route, whose SSR captures client stubs that dispatch back through here).
|
|
126
|
-
installServerActionDispatch(options.importModule)
|
|
126
|
+
installServerActionDispatch(options.importModule)
|
|
127
127
|
|
|
128
128
|
// A resolution failure (a compiled action module that fails to import, a route re-render that
|
|
129
129
|
// throws) must surface as the recognizable 404 not-found wire - never an unhandled 500 the client
|
|
130
130
|
// reads as "unexpected response". A forwarded action dispatched from another page hits the same
|
|
131
131
|
// global resolution and needs the same graceful degradation.
|
|
132
|
-
let action: ((...args: unknown[]) => unknown) | undefined
|
|
132
|
+
let action: ((...args: unknown[]) => unknown) | undefined
|
|
133
133
|
try {
|
|
134
|
-
action = await resolveAction(id, request, options)
|
|
134
|
+
action = await resolveAction(id, request, options)
|
|
135
135
|
} catch (error) {
|
|
136
|
-
console.error(error)
|
|
137
|
-
action = undefined
|
|
136
|
+
console.error(error)
|
|
137
|
+
action = undefined
|
|
138
138
|
}
|
|
139
139
|
if (!action) {
|
|
140
140
|
// Wire + log shape asserted by the actions-unrecognized suite: the log is
|
|
@@ -144,94 +144,94 @@ export async function runAction(request: Request, options: RunActionOptions): Pr
|
|
|
144
144
|
console.error(
|
|
145
145
|
`Failed to find Server Action "${id}". This request might be from an older or newer deployment.\n` +
|
|
146
146
|
'Read more: https://nextjs.org/docs/messages/failed-to-find-server-action',
|
|
147
|
-
)
|
|
147
|
+
)
|
|
148
148
|
return new Response(`Server Action "${id}" was not found on the server.`, {
|
|
149
149
|
status: 404,
|
|
150
150
|
headers: {
|
|
151
151
|
'content-type': 'text/plain; charset=utf-8',
|
|
152
152
|
[NEXT_ACTION_NOT_FOUND_HEADER]: '1',
|
|
153
153
|
},
|
|
154
|
-
})
|
|
154
|
+
})
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
const limit = options.maxBodyBytes ?? DEFAULT_BODY_LIMIT_BYTES
|
|
158
|
-
let args: unknown[]
|
|
157
|
+
const limit = options.maxBodyBytes ?? DEFAULT_BODY_LIMIT_BYTES
|
|
158
|
+
let args: unknown[]
|
|
159
159
|
try {
|
|
160
|
-
args = await decodeArgs(request, limit)
|
|
160
|
+
args = await decodeArgs(request, limit)
|
|
161
161
|
} catch (error) {
|
|
162
162
|
if (error instanceof BodyLimitError) {
|
|
163
|
-
console.error(`Error: ${error.message}`)
|
|
163
|
+
console.error(`Error: ${error.message}`)
|
|
164
164
|
console.error(
|
|
165
165
|
'To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit',
|
|
166
|
-
)
|
|
167
|
-
return errorResponse(options.dev ? error.message : MASKED_ACTION_ERROR, 500)
|
|
166
|
+
)
|
|
167
|
+
return errorResponse(options.dev ? error.message : MASKED_ACTION_ERROR, 500)
|
|
168
168
|
}
|
|
169
|
-
return errorResponse(`Invalid action payload: ${messageOf(error)}`, 400)
|
|
169
|
+
return errorResponse(`Invalid action payload: ${messageOf(error)}`, 400)
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
try {
|
|
173
|
-
args = await reviveActionRefs(args, id => resolveAction(id, request, options))
|
|
173
|
+
args = await reviveActionRefs(args, id => resolveAction(id, request, options))
|
|
174
174
|
} catch (error) {
|
|
175
175
|
if (error instanceof UnknownActionReferenceError) {
|
|
176
|
-
return errorResponse(error.message, 404)
|
|
176
|
+
return errorResponse(error.message, 404)
|
|
177
177
|
}
|
|
178
|
-
return errorResponse(`Invalid action payload: ${messageOf(error)}`, 400)
|
|
178
|
+
return errorResponse(`Invalid action payload: ${messageOf(error)}`, 400)
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
if (args.length > MAX_ACTION_ARGS) {
|
|
182
|
-
const message = tooManyArgsMessage(args.length)
|
|
183
|
-
console.error(`Error: ${message}`)
|
|
184
|
-
return errorResponse(options.dev ? message : MASKED_ACTION_ERROR, 500)
|
|
182
|
+
const message = tooManyArgsMessage(args.length)
|
|
183
|
+
console.error(`Error: ${message}`)
|
|
184
|
+
return errorResponse(options.dev ? message : MASKED_ACTION_ERROR, 500)
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
// Temporary-reference scope: strip the client's temp-ref tags off the decoded
|
|
188
188
|
// args (so the action sees clean objects) and remember object -> id, so a
|
|
189
189
|
// returned arg object serializes back to the identical client reference.
|
|
190
|
-
const tempRefs = createTempRefScope()
|
|
191
|
-
args = args.map(arg => extractTempRefs(arg, tempRefs))
|
|
190
|
+
const tempRefs = createTempRefScope()
|
|
191
|
+
args = args.map(arg => extractTempRefs(arg, tempRefs))
|
|
192
192
|
|
|
193
193
|
// Run inside a request scope with a response-headers channel: headers() and
|
|
194
194
|
// cookies() read the RPC request (which carries the browser's live cookies),
|
|
195
195
|
// and cookies().set()/delete() append set-cookie onto the channel.
|
|
196
|
-
const responseHeaders = new Headers()
|
|
197
|
-
const revalidationsBefore = revalidationEventCount()
|
|
198
|
-
const nextRequest = toNextRequest(request)
|
|
196
|
+
const responseHeaders = new Headers()
|
|
197
|
+
const revalidationsBefore = revalidationEventCount()
|
|
198
|
+
const nextRequest = toNextRequest(request)
|
|
199
199
|
try {
|
|
200
200
|
// The action body runs under the 'action' phase so cookies().set() is legal
|
|
201
201
|
// here (and illegal once the phase flips to 'render'/'after' — phase-changes
|
|
202
202
|
// suite). Restored to 'render' once the action settles so a follow-up
|
|
203
203
|
// redirect-target render is treated as a render.
|
|
204
|
-
setPhase('action')
|
|
204
|
+
setPhase('action')
|
|
205
205
|
const data = await runWithRequest(
|
|
206
206
|
nextRequest,
|
|
207
207
|
() => Promise.resolve(action(...args)),
|
|
208
208
|
{},
|
|
209
209
|
{ responseHeaders },
|
|
210
|
-
).finally(() => setPhase('render'))
|
|
210
|
+
).finally(() => setPhase('render'))
|
|
211
211
|
const refresh =
|
|
212
|
-
revalidationEventCount() !== revalidationsBefore || hasSetCookie(responseHeaders)
|
|
212
|
+
revalidationEventCount() !== revalidationsBefore || hasSetCookie(responseHeaders)
|
|
213
213
|
// A ReadableStream return streams the raw bytes to the client unbuffered
|
|
214
214
|
// (actions-streaming): JSON can't carry a stream, so the body IS the stream
|
|
215
215
|
// under a marker content-type the client detects.
|
|
216
216
|
if (isReadableStreamReturn(data)) {
|
|
217
|
-
const headers = new Headers({ 'content-type': ACTION_STREAM_CONTENT_TYPE })
|
|
218
|
-
setRefreshHeaders(headers, refresh)
|
|
219
|
-
return withResponseHeaders(new Response(data, { status: 200, headers }), responseHeaders)
|
|
217
|
+
const headers = new Headers({ 'content-type': ACTION_STREAM_CONTENT_TYPE })
|
|
218
|
+
setRefreshHeaders(headers, refresh)
|
|
219
|
+
return withResponseHeaders(new Response(data, { status: 200, headers }), responseHeaders)
|
|
220
220
|
}
|
|
221
221
|
const serialized = await serializeReturnWithTempRefs(
|
|
222
222
|
data,
|
|
223
223
|
tempRefs,
|
|
224
224
|
options.renderActionElement,
|
|
225
|
-
)
|
|
225
|
+
)
|
|
226
226
|
const body: ActionSuccessBody = {
|
|
227
227
|
data: encodeBinaryReturn(serialized),
|
|
228
|
-
}
|
|
229
|
-
const headers = new Headers({ 'content-type': 'application/json; charset=utf-8' })
|
|
230
|
-
setRefreshHeaders(headers, refresh)
|
|
228
|
+
}
|
|
229
|
+
const headers = new Headers({ 'content-type': 'application/json; charset=utf-8' })
|
|
230
|
+
setRefreshHeaders(headers, refresh)
|
|
231
231
|
return withResponseHeaders(
|
|
232
232
|
new Response(JSON.stringify(body), { status: 200, headers }),
|
|
233
233
|
responseHeaders,
|
|
234
|
-
)
|
|
234
|
+
)
|
|
235
235
|
} catch (error) {
|
|
236
236
|
if (isRedirectError(error)) {
|
|
237
237
|
return withResponseHeaders(
|
|
@@ -240,7 +240,7 @@ export async function runAction(request: Request, options: RunActionOptions): Pr
|
|
|
240
240
|
revalidationEventCount() !== revalidationsBefore || hasSetCookie(responseHeaders),
|
|
241
241
|
),
|
|
242
242
|
responseHeaders,
|
|
243
|
-
)
|
|
243
|
+
)
|
|
244
244
|
}
|
|
245
245
|
if (isNotFoundError(error)) {
|
|
246
246
|
return withResponseHeaders(
|
|
@@ -252,26 +252,26 @@ export async function runAction(request: Request, options: RunActionOptions): Pr
|
|
|
252
252
|
},
|
|
253
253
|
}),
|
|
254
254
|
responseHeaders,
|
|
255
|
-
)
|
|
255
|
+
)
|
|
256
256
|
}
|
|
257
|
-
const message = messageOf(error)
|
|
257
|
+
const message = messageOf(error)
|
|
258
258
|
// Compute the boundary digest with the same deterministic scheme the render
|
|
259
259
|
// path uses (error-serialize.ts) so the client-visible digest and the server
|
|
260
260
|
// log agree. Next's prod server log prints the ORIGINAL error trace followed
|
|
261
261
|
// by `digest: '<digest>'` so operators can correlate the redacted client
|
|
262
262
|
// digest with the full server-side stack.
|
|
263
|
-
let digest: string | undefined
|
|
263
|
+
let digest: string | undefined
|
|
264
264
|
if (error instanceof Error) {
|
|
265
|
-
digest = serializeBoundaryError({ error, dev: Boolean(options.dev) }).digest
|
|
266
|
-
const trace = error.stack ?? error.message
|
|
267
|
-
console.error(typeof digest === 'string' ? `${trace}\n digest: '${digest}'` : trace)
|
|
265
|
+
digest = serializeBoundaryError({ error, dev: Boolean(options.dev) }).digest
|
|
266
|
+
const trace = error.stack ?? error.message
|
|
267
|
+
console.error(typeof digest === 'string' ? `${trace}\n digest: '${digest}'` : trace)
|
|
268
268
|
} else {
|
|
269
|
-
console.error(error)
|
|
269
|
+
console.error(error)
|
|
270
270
|
}
|
|
271
|
-
await options.onError?.(error, request)
|
|
272
|
-
const masked = errorResponse(options.dev ? message : MASKED_ACTION_ERROR, 500)
|
|
273
|
-
if (typeof digest === 'string') masked.headers.set(ACTION_ERROR_DIGEST_HEADER, digest)
|
|
274
|
-
return withResponseHeaders(masked, responseHeaders)
|
|
271
|
+
await options.onError?.(error, request)
|
|
272
|
+
const masked = errorResponse(options.dev ? message : MASKED_ACTION_ERROR, 500)
|
|
273
|
+
if (typeof digest === 'string') masked.headers.set(ACTION_ERROR_DIGEST_HEADER, digest)
|
|
274
|
+
return withResponseHeaders(masked, responseHeaders)
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
@@ -281,41 +281,41 @@ async function resolveAction(
|
|
|
281
281
|
options: RunActionOptions,
|
|
282
282
|
): Promise<((...args: unknown[]) => unknown) | undefined> {
|
|
283
283
|
if (isInlineActionId(id)) {
|
|
284
|
-
let instance = lookupActionInstance(id)
|
|
284
|
+
let instance = lookupActionInstance(id)
|
|
285
285
|
if (!instance && options.importSourceModule) {
|
|
286
|
-
const moduleKey = inlineActionModuleKey(id)
|
|
286
|
+
const moduleKey = inlineActionModuleKey(id)
|
|
287
287
|
if (moduleKey) {
|
|
288
288
|
try {
|
|
289
|
-
await options.importSourceModule(moduleKey)
|
|
289
|
+
await options.importSourceModule(moduleKey)
|
|
290
290
|
} catch {
|
|
291
291
|
// fall through to the unknown-action error
|
|
292
292
|
}
|
|
293
|
-
instance = lookupActionInstance(id)
|
|
293
|
+
instance = lookupActionInstance(id)
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
|
-
return instance
|
|
296
|
+
return instance
|
|
297
297
|
}
|
|
298
298
|
if (isInstanceActionId(id)) {
|
|
299
|
-
let instance = lookupActionInstance(id)
|
|
299
|
+
let instance = lookupActionInstance(id)
|
|
300
300
|
if (!instance && options.rerenderRoute) {
|
|
301
|
-
const routeId = instanceActionRouteId(id)
|
|
301
|
+
const routeId = instanceActionRouteId(id)
|
|
302
302
|
if (routeId) {
|
|
303
303
|
try {
|
|
304
|
-
await options.rerenderRoute(routeId, request)
|
|
304
|
+
await options.rerenderRoute(routeId, request)
|
|
305
305
|
} catch {
|
|
306
306
|
// fall through to the unknown-action error below
|
|
307
307
|
}
|
|
308
|
-
instance = lookupActionInstance(id)
|
|
308
|
+
instance = lookupActionInstance(id)
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
return instance
|
|
311
|
+
return instance
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
const target = lookupAction(id)
|
|
315
|
-
if (!target) return undefined
|
|
316
|
-
const module = await options.importModule(target.modulePath)
|
|
317
|
-
const action = module[target.exportName]
|
|
318
|
-
return typeof action === 'function' ? (action as (...args: unknown[]) => unknown) : undefined
|
|
314
|
+
const target = lookupAction(id)
|
|
315
|
+
if (!target) return undefined
|
|
316
|
+
const module = await options.importModule(target.modulePath)
|
|
317
|
+
const action = module[target.exportName]
|
|
318
|
+
return typeof action === 'function' ? (action as (...args: unknown[]) => unknown) : undefined
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
class BodyLimitError extends Error {}
|
|
@@ -329,27 +329,27 @@ class BodyLimitError extends Error {}
|
|
|
329
329
|
* the buffered body.
|
|
330
330
|
*/
|
|
331
331
|
async function readBodyBytesWithLimit(request: Request, limit: number): Promise<ArrayBuffer> {
|
|
332
|
-
const bytes = await request.arrayBuffer()
|
|
332
|
+
const bytes = await request.arrayBuffer()
|
|
333
333
|
if (bytes.byteLength > limit) {
|
|
334
|
-
throw new BodyLimitError(`Body exceeded ${formatLimit(limit)} limit`)
|
|
334
|
+
throw new BodyLimitError(`Body exceeded ${formatLimit(limit)} limit`)
|
|
335
335
|
}
|
|
336
|
-
return bytes
|
|
336
|
+
return bytes
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
function bufferedFormRequest(request: Request, bytes: ArrayBuffer): Request {
|
|
340
|
-
const headers = new Headers(request.headers)
|
|
341
|
-
headers.delete('content-length')
|
|
340
|
+
const headers = new Headers(request.headers)
|
|
341
|
+
headers.delete('content-length')
|
|
342
342
|
return new Request(request.url, {
|
|
343
343
|
method: request.method,
|
|
344
344
|
headers,
|
|
345
345
|
body: bytes.byteLength === 0 ? undefined : bytes,
|
|
346
|
-
})
|
|
346
|
+
})
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
function formatLimit(limit: number) {
|
|
350
|
-
if (limit % (1024 * 1024) === 0) return `${limit / (1024 * 1024)}mb
|
|
351
|
-
if (limit % 1024 === 0) return `${limit / 1024}kb
|
|
352
|
-
return `${limit} bytes
|
|
350
|
+
if (limit % (1024 * 1024) === 0) return `${limit / (1024 * 1024)}mb`
|
|
351
|
+
if (limit % 1024 === 0) return `${limit / 1024}kb`
|
|
352
|
+
return `${limit} bytes`
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
/**
|
|
@@ -362,41 +362,41 @@ function formatLimit(limit: number) {
|
|
|
362
362
|
* - empty body -> no args.
|
|
363
363
|
*/
|
|
364
364
|
async function decodeArgs(request: Request, limit: number): Promise<unknown[]> {
|
|
365
|
-
const bytes = await readBodyBytesWithLimit(request, limit)
|
|
366
|
-
const contentType = request.headers.get('content-type') ?? ''
|
|
365
|
+
const bytes = await readBodyBytesWithLimit(request, limit)
|
|
366
|
+
const contentType = request.headers.get('content-type') ?? ''
|
|
367
367
|
|
|
368
368
|
if (contentType.includes('multipart/form-data') || contentType.includes('form-urlencoded')) {
|
|
369
|
-
const form = await bufferedFormRequest(request, bytes).formData()
|
|
370
|
-
const argsField = form.get(ACTION_ARGS_FIELD)
|
|
371
|
-
form.delete(ACTION_ID_FIELD)
|
|
369
|
+
const form = await bufferedFormRequest(request, bytes).formData()
|
|
370
|
+
const argsField = form.get(ACTION_ARGS_FIELD)
|
|
371
|
+
form.delete(ACTION_ID_FIELD)
|
|
372
372
|
if (typeof argsField === 'string') {
|
|
373
|
-
form.delete(ACTION_ARGS_FIELD)
|
|
374
|
-
return decodeStructuredArgs(argsField, form)
|
|
373
|
+
form.delete(ACTION_ARGS_FIELD)
|
|
374
|
+
return decodeStructuredArgs(argsField, form)
|
|
375
375
|
}
|
|
376
376
|
// Progressive useActionState submission: the form carries its current
|
|
377
377
|
// state; the action signature is (state, formData).
|
|
378
|
-
const stateField = form.get(FORM_STATE_FIELD)
|
|
378
|
+
const stateField = form.get(FORM_STATE_FIELD)
|
|
379
379
|
if (typeof stateField === 'string') {
|
|
380
|
-
form.delete(FORM_STATE_FIELD)
|
|
381
|
-
let state: unknown = null
|
|
380
|
+
form.delete(FORM_STATE_FIELD)
|
|
381
|
+
let state: unknown = null
|
|
382
382
|
try {
|
|
383
|
-
state = JSON.parse(stateField)
|
|
383
|
+
state = JSON.parse(stateField)
|
|
384
384
|
} catch {
|
|
385
|
-
state = stateField
|
|
385
|
+
state = stateField
|
|
386
386
|
}
|
|
387
|
-
return [state, form]
|
|
387
|
+
return [state, form]
|
|
388
388
|
}
|
|
389
|
-
return [form]
|
|
389
|
+
return [form]
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
// Decode the buffered bytes in one shot (never per-chunk): a streaming or
|
|
393
393
|
// rewrapped body can otherwise split a multi-byte UTF-8 character across
|
|
394
394
|
// chunk boundaries (decode-req-body suite, 100k あ ≈ 300KB).
|
|
395
|
-
const text = new TextDecoder('utf-8').decode(bytes)
|
|
396
|
-
if (text.trim() === '') return []
|
|
395
|
+
const text = new TextDecoder('utf-8').decode(bytes)
|
|
396
|
+
if (text.trim() === '') return []
|
|
397
397
|
|
|
398
|
-
const parsed = JSON.parse(text) as unknown
|
|
399
|
-
return Array.isArray(parsed) ? (parsed as unknown[]) : [parsed]
|
|
398
|
+
const parsed = JSON.parse(text) as unknown
|
|
399
|
+
return Array.isArray(parsed) ? (parsed as unknown[]) : [parsed]
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
/**
|
|
@@ -410,52 +410,52 @@ async function reviveActionRefs(
|
|
|
410
410
|
resolve: (id: string) => Promise<((...a: unknown[]) => unknown) | undefined>,
|
|
411
411
|
): Promise<unknown[]> {
|
|
412
412
|
const reviveValue = async (value: unknown): Promise<unknown> => {
|
|
413
|
-
if (value === null || typeof value !== 'object') return value
|
|
414
|
-
if (Array.isArray(value)) return Promise.all(value.map(reviveValue))
|
|
415
|
-
const record = value as Record<string, unknown
|
|
413
|
+
if (value === null || typeof value !== 'object') return value
|
|
414
|
+
if (Array.isArray(value)) return Promise.all(value.map(reviveValue))
|
|
415
|
+
const record = value as Record<string, unknown>
|
|
416
416
|
if (typeof record[ARG_ACTION_MARKER] === 'string') {
|
|
417
|
-
const fn = await resolve(record[ARG_ACTION_MARKER])
|
|
417
|
+
const fn = await resolve(record[ARG_ACTION_MARKER])
|
|
418
418
|
if (!fn) {
|
|
419
|
-
const id = String(record[ARG_ACTION_MARKER])
|
|
419
|
+
const id = String(record[ARG_ACTION_MARKER])
|
|
420
420
|
console.error(
|
|
421
421
|
`Failed to find Server Action "${id}". This request might be from an older or newer deployment.\n` +
|
|
422
422
|
'Read more: https://nextjs.org/docs/messages/failed-to-find-server-action',
|
|
423
|
-
)
|
|
424
|
-
throw new UnknownActionReferenceError(id)
|
|
423
|
+
)
|
|
424
|
+
throw new UnknownActionReferenceError(id)
|
|
425
425
|
}
|
|
426
|
-
return fn
|
|
426
|
+
return fn
|
|
427
427
|
}
|
|
428
|
-
if (record.$$pnext_undefined === true) return undefined
|
|
429
|
-
const binary = reviveBinaryMarker(record)
|
|
430
|
-
if (binary !== undefined) return binary
|
|
431
|
-
if (typeof record.$$pnext_date === 'string') return new Date(record.$$pnext_date)
|
|
428
|
+
if (record.$$pnext_undefined === true) return undefined
|
|
429
|
+
const binary = reviveBinaryMarker(record)
|
|
430
|
+
if (binary !== undefined) return binary
|
|
431
|
+
if (typeof record.$$pnext_date === 'string') return new Date(record.$$pnext_date)
|
|
432
432
|
if (Array.isArray(record.$$pnext_map)) {
|
|
433
433
|
const entries = await Promise.all(
|
|
434
434
|
(record.$$pnext_map as [unknown, unknown][]).map(
|
|
435
435
|
async ([k, v]) => [await reviveValue(k), await reviveValue(v)] as [unknown, unknown],
|
|
436
436
|
),
|
|
437
|
-
)
|
|
438
|
-
return new Map(entries)
|
|
437
|
+
)
|
|
438
|
+
return new Map(entries)
|
|
439
439
|
}
|
|
440
440
|
if (Array.isArray(record.$$pnext_set)) {
|
|
441
|
-
return new Set(await Promise.all((record.$$pnext_set as unknown[]).map(reviveValue)))
|
|
441
|
+
return new Set(await Promise.all((record.$$pnext_set as unknown[]).map(reviveValue)))
|
|
442
442
|
}
|
|
443
|
-
if (value instanceof FormData || value instanceof Blob) return value
|
|
443
|
+
if (value instanceof FormData || value instanceof Blob) return value
|
|
444
444
|
if (
|
|
445
445
|
Object.getPrototypeOf(value) !== Object.prototype &&
|
|
446
446
|
Object.getPrototypeOf(value) !== null
|
|
447
447
|
) {
|
|
448
|
-
return value
|
|
448
|
+
return value
|
|
449
449
|
}
|
|
450
|
-
const out: Record<string, unknown> = {}
|
|
451
|
-
for (const [key, item] of Object.entries(record)) out[key] = await reviveValue(item)
|
|
452
|
-
return out
|
|
453
|
-
}
|
|
454
|
-
return Promise.all(args.map(reviveValue))
|
|
450
|
+
const out: Record<string, unknown> = {}
|
|
451
|
+
for (const [key, item] of Object.entries(record)) out[key] = await reviveValue(item)
|
|
452
|
+
return out
|
|
453
|
+
}
|
|
454
|
+
return Promise.all(args.map(reviveValue))
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
const TYPED_ARRAY_MARKER = '$$pnext_typed_array'
|
|
458
|
-
const ARRAY_BUFFER_MARKER = '$$pnext_array_buffer'
|
|
457
|
+
const TYPED_ARRAY_MARKER = '$$pnext_typed_array'
|
|
458
|
+
const ARRAY_BUFFER_MARKER = '$$pnext_array_buffer'
|
|
459
459
|
|
|
460
460
|
const TYPED_ARRAY_CTORS: Record<string, new (buffer: ArrayBuffer) => ArrayBufferView> = {
|
|
461
461
|
Int8Array,
|
|
@@ -469,96 +469,96 @@ const TYPED_ARRAY_CTORS: Record<string, new (buffer: ArrayBuffer) => ArrayBuffer
|
|
|
469
469
|
Float64Array,
|
|
470
470
|
BigInt64Array,
|
|
471
471
|
BigUint64Array,
|
|
472
|
-
}
|
|
472
|
+
}
|
|
473
473
|
|
|
474
474
|
function isTypedArrayView(value: unknown): value is ArrayBufferView {
|
|
475
|
-
return ArrayBuffer.isView(value) && !(value instanceof DataView)
|
|
475
|
+
return ArrayBuffer.isView(value) && !(value instanceof DataView)
|
|
476
476
|
}
|
|
477
477
|
|
|
478
478
|
/** Deep-copy a return value, marker-encoding typed arrays / ArrayBuffers. */
|
|
479
479
|
function encodeBinaryReturn(value: unknown, seen = new Set<unknown>()): unknown {
|
|
480
|
-
if (value === null || typeof value !== 'object') return value
|
|
480
|
+
if (value === null || typeof value !== 'object') return value
|
|
481
481
|
if (value instanceof ArrayBuffer) {
|
|
482
|
-
return { [ARRAY_BUFFER_MARKER]: Buffer.from(new Uint8Array(value)).toString('base64') }
|
|
482
|
+
return { [ARRAY_BUFFER_MARKER]: Buffer.from(new Uint8Array(value)).toString('base64') }
|
|
483
483
|
}
|
|
484
484
|
if (isTypedArrayView(value)) {
|
|
485
|
-
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength)
|
|
485
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength)
|
|
486
486
|
return {
|
|
487
487
|
[TYPED_ARRAY_MARKER]: {
|
|
488
488
|
type: value.constructor.name,
|
|
489
489
|
data: Buffer.from(bytes).toString('base64'),
|
|
490
490
|
},
|
|
491
|
-
}
|
|
491
|
+
}
|
|
492
492
|
}
|
|
493
|
-
if (seen.has(value)) return value
|
|
494
|
-
seen.add(value)
|
|
495
|
-
if (Array.isArray(value)) return value.map(item => encodeBinaryReturn(item, seen))
|
|
496
|
-
const proto = Object.getPrototypeOf(value) as object | null
|
|
497
|
-
if (proto !== Object.prototype && proto !== null) return value
|
|
498
|
-
const out: Record<string, unknown> = {}
|
|
493
|
+
if (seen.has(value)) return value
|
|
494
|
+
seen.add(value)
|
|
495
|
+
if (Array.isArray(value)) return value.map(item => encodeBinaryReturn(item, seen))
|
|
496
|
+
const proto = Object.getPrototypeOf(value) as object | null
|
|
497
|
+
if (proto !== Object.prototype && proto !== null) return value
|
|
498
|
+
const out: Record<string, unknown> = {}
|
|
499
499
|
for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
|
|
500
|
-
out[key] = encodeBinaryReturn(item, seen)
|
|
500
|
+
out[key] = encodeBinaryReturn(item, seen)
|
|
501
501
|
}
|
|
502
|
-
return out
|
|
502
|
+
return out
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
/** Revive a typed-array / ArrayBuffer wire marker back into a live view, else undefined. */
|
|
506
506
|
function reviveBinaryMarker(record: Record<string, unknown>): unknown {
|
|
507
|
-
const typed = record[TYPED_ARRAY_MARKER]
|
|
507
|
+
const typed = record[TYPED_ARRAY_MARKER]
|
|
508
508
|
if (typed && typeof typed === 'object') {
|
|
509
|
-
const { type, data } = typed as { type?: string; data?: string }
|
|
510
|
-
const Ctor = type ? TYPED_ARRAY_CTORS[type] : undefined
|
|
509
|
+
const { type, data } = typed as { type?: string; data?: string }
|
|
510
|
+
const Ctor = type ? TYPED_ARRAY_CTORS[type] : undefined
|
|
511
511
|
if (Ctor && typeof data === 'string') {
|
|
512
|
-
const bytes = Buffer.from(data, 'base64')
|
|
513
|
-
return new Ctor(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength))
|
|
512
|
+
const bytes = Buffer.from(data, 'base64')
|
|
513
|
+
return new Ctor(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength))
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
-
const buffer = record[ARRAY_BUFFER_MARKER]
|
|
516
|
+
const buffer = record[ARRAY_BUFFER_MARKER]
|
|
517
517
|
if (typeof buffer === 'string') {
|
|
518
|
-
const bytes = Buffer.from(buffer, 'base64')
|
|
519
|
-
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
518
|
+
const bytes = Buffer.from(buffer, 'base64')
|
|
519
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
520
520
|
}
|
|
521
|
-
return undefined
|
|
521
|
+
return undefined
|
|
522
522
|
}
|
|
523
523
|
|
|
524
524
|
class UnknownActionReferenceError extends Error {
|
|
525
525
|
constructor(public actionId: string) {
|
|
526
|
-
super(`Server Action "${actionId}" was not found on the server.`)
|
|
526
|
+
super(`Server Action "${actionId}" was not found on the server.`)
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
|
|
530
530
|
function decodeStructuredArgs(argsJson: string, form: FormData): unknown[] {
|
|
531
|
-
const parsed = JSON.parse(argsJson) as unknown
|
|
532
|
-
const list = Array.isArray(parsed) ? (parsed as unknown[]) : [parsed]
|
|
533
|
-
return list.map(item => reviveArg(item, form))
|
|
531
|
+
const parsed = JSON.parse(argsJson) as unknown
|
|
532
|
+
const list = Array.isArray(parsed) ? (parsed as unknown[]) : [parsed]
|
|
533
|
+
return list.map(item => reviveArg(item, form))
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
function reviveArg(value: unknown, form: FormData): unknown {
|
|
537
|
-
if (value === null || typeof value !== 'object') return value
|
|
538
|
-
if (Array.isArray(value)) return value.map(item => reviveArg(item, form))
|
|
537
|
+
if (value === null || typeof value !== 'object') return value
|
|
538
|
+
if (Array.isArray(value)) return value.map(item => reviveArg(item, form))
|
|
539
539
|
|
|
540
|
-
const record = value as Record<string, unknown
|
|
540
|
+
const record = value as Record<string, unknown>
|
|
541
541
|
if (typeof record[ARG_FORMDATA_MARKER] === 'number') {
|
|
542
|
-
const slot = record[ARG_FORMDATA_MARKER]
|
|
543
|
-
const prefix = `${ARG_FORMDATA_PREFIX}${slot}
|
|
544
|
-
const data = new FormData()
|
|
542
|
+
const slot = record[ARG_FORMDATA_MARKER]
|
|
543
|
+
const prefix = `${ARG_FORMDATA_PREFIX}${slot}:`
|
|
544
|
+
const data = new FormData()
|
|
545
545
|
for (const [key, item] of form.entries()) {
|
|
546
|
-
if (key.startsWith(prefix)) data.append(key.slice(prefix.length), item as string | Blob)
|
|
546
|
+
if (key.startsWith(prefix)) data.append(key.slice(prefix.length), item as string | Blob)
|
|
547
547
|
}
|
|
548
|
-
return data
|
|
548
|
+
return data
|
|
549
549
|
}
|
|
550
550
|
if (typeof record[ARG_FILE_MARKER] === 'number') {
|
|
551
|
-
const slot = record[ARG_FILE_MARKER]
|
|
552
|
-
return form.get(`${ARG_FILE_PREFIX}${slot}`)
|
|
551
|
+
const slot = record[ARG_FILE_MARKER]
|
|
552
|
+
return form.get(`${ARG_FILE_PREFIX}${slot}`)
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
const revived: Record<string, unknown> = {}
|
|
556
|
-
for (const [key, item] of Object.entries(record)) revived[key] = reviveArg(item, form)
|
|
557
|
-
return revived
|
|
555
|
+
const revived: Record<string, unknown> = {}
|
|
556
|
+
for (const [key, item] of Object.entries(record)) revived[key] = reviveArg(item, form)
|
|
557
|
+
return revived
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
function redirectResponse(error: PNextRedirectError, refresh: boolean): Response {
|
|
561
|
-
const redirectType = (error as PNextRedirectError & { redirectType?: string }).redirectType
|
|
561
|
+
const redirectType = (error as PNextRedirectError & { redirectType?: string }).redirectType
|
|
562
562
|
// 303: fetch() does not follow 307/308 the way a browser follows a nav, and
|
|
563
563
|
// a no-JS form submit needs the browser to follow with a GET. The redirect
|
|
564
564
|
// marker header lets the client runtime treat this as a framework redirect
|
|
@@ -566,37 +566,37 @@ function redirectResponse(error: PNextRedirectError, refresh: boolean): Response
|
|
|
566
566
|
const headers = new Headers({
|
|
567
567
|
location: error.location,
|
|
568
568
|
[ACTION_REDIRECT_HEADER]: error.location,
|
|
569
|
-
})
|
|
570
|
-
if (redirectType === 'replace') headers.set(REDIRECT_TYPE_HEADER, 'replace')
|
|
571
|
-
setRefreshHeaders(headers, refresh)
|
|
572
|
-
return new Response(null, { status: 303, headers })
|
|
569
|
+
})
|
|
570
|
+
if (redirectType === 'replace') headers.set(REDIRECT_TYPE_HEADER, 'replace')
|
|
571
|
+
setRefreshHeaders(headers, refresh)
|
|
572
|
+
return new Response(null, { status: 303, headers })
|
|
573
573
|
}
|
|
574
574
|
|
|
575
575
|
function setRefreshHeaders(headers: Headers, refresh: boolean): void {
|
|
576
|
-
if (!refresh) return
|
|
577
|
-
headers.set(ACTION_REFRESH_HEADER, '1')
|
|
578
|
-
headers.set(NEXT_ACTION_REVALIDATED_HEADER, '1')
|
|
576
|
+
if (!refresh) return
|
|
577
|
+
headers.set(ACTION_REFRESH_HEADER, '1')
|
|
578
|
+
headers.set(NEXT_ACTION_REVALIDATED_HEADER, '1')
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
function errorResponse(message: string, status: number): Response {
|
|
582
582
|
return new Response(message, {
|
|
583
583
|
status,
|
|
584
584
|
headers: { 'content-type': 'text/plain; charset=utf-8' },
|
|
585
|
-
})
|
|
585
|
+
})
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
/** Merge scope-collected headers (set-cookie appends) onto the response. */
|
|
589
589
|
function withResponseHeaders(response: Response, extra: Headers): Response {
|
|
590
|
-
const setCookies = (extra as Headers & { getSetCookie?: () => string[] }).getSetCookie?.() ?? []
|
|
591
|
-
if (setCookies.length === 0) return response
|
|
592
|
-
for (const cookie of setCookies) response.headers.append('set-cookie', cookie)
|
|
593
|
-
return response
|
|
590
|
+
const setCookies = (extra as Headers & { getSetCookie?: () => string[] }).getSetCookie?.() ?? []
|
|
591
|
+
if (setCookies.length === 0) return response
|
|
592
|
+
for (const cookie of setCookies) response.headers.append('set-cookie', cookie)
|
|
593
|
+
return response
|
|
594
594
|
}
|
|
595
595
|
|
|
596
596
|
function hasSetCookie(headers: Headers): boolean {
|
|
597
|
-
return headers.has('set-cookie')
|
|
597
|
+
return headers.has('set-cookie')
|
|
598
598
|
}
|
|
599
599
|
|
|
600
600
|
function messageOf(error: unknown): string {
|
|
601
|
-
return error instanceof Error ? error.message : String(error)
|
|
601
|
+
return error instanceof Error ? error.message : String(error)
|
|
602
602
|
}
|