vinext 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/google-fonts/build-url.d.ts +10 -0
- package/dist/build/google-fonts/build-url.js +30 -0
- package/dist/build/google-fonts/build-url.js.map +1 -0
- package/dist/build/google-fonts/font-data.js +24985 -0
- package/dist/build/google-fonts/font-data.js.map +1 -0
- package/dist/build/google-fonts/font-metadata.d.ts +17 -0
- package/dist/build/google-fonts/font-metadata.js +7 -0
- package/dist/build/google-fonts/font-metadata.js.map +1 -0
- package/dist/build/google-fonts/get-axes.d.ts +7 -0
- package/dist/build/google-fonts/get-axes.js +39 -0
- package/dist/build/google-fonts/get-axes.js.map +1 -0
- package/dist/build/google-fonts/sort-variants.d.ts +5 -0
- package/dist/build/google-fonts/sort-variants.js +14 -0
- package/dist/build/google-fonts/sort-variants.js.map +1 -0
- package/dist/build/google-fonts/validate.d.ts +28 -0
- package/dist/build/google-fonts/validate.js +56 -0
- package/dist/build/google-fonts/validate.js.map +1 -0
- package/dist/build/layout-classification.d.ts +1 -1
- package/dist/build/layout-classification.js.map +1 -1
- package/dist/build/nitro-route-rules.d.ts +1 -1
- package/dist/build/nitro-route-rules.js.map +1 -1
- package/dist/build/precompress.d.ts +1 -1
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +1 -7
- package/dist/build/prerender.js +17 -6
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/run-prerender.d.ts +1 -13
- package/dist/build/run-prerender.js +5 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/standalone.d.ts +1 -1
- package/dist/build/standalone.js +4 -3
- package/dist/build/standalone.js.map +1 -1
- package/dist/check.js +30 -18
- package/dist/check.js.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts +5 -0
- package/dist/cloudflare/kv-cache-handler.js +56 -35
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +1 -16
- package/dist/cloudflare/tpr.js +1 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.js +1 -0
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/dotenv.d.ts +1 -1
- package/dist/config/dotenv.js.map +1 -1
- package/dist/config/next-config.d.ts +38 -2
- package/dist/config/next-config.js +24 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.d.ts +1 -1
- package/dist/deploy.js +18 -23
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +387 -1718
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +24 -0
- package/dist/entries/app-rsc-manifest.js +153 -0
- package/dist/entries/app-rsc-manifest.js.map +1 -0
- package/dist/entries/pages-server-entry.js +13 -103
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.js +59 -34
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js.map +1 -1
- package/dist/plugins/async-hooks-stub.d.ts +1 -2
- package/dist/plugins/async-hooks-stub.js +2 -2
- package/dist/plugins/async-hooks-stub.js.map +1 -1
- package/dist/plugins/fonts.d.ts +1 -20
- package/dist/plugins/fonts.js +42 -21
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/rsc-client-shim-excludes.d.ts +6 -0
- package/dist/plugins/rsc-client-shim-excludes.js +27 -0
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -0
- package/dist/plugins/server-externals-manifest.d.ts +1 -11
- package/dist/plugins/server-externals-manifest.js +1 -1
- package/dist/plugins/server-externals-manifest.js.map +1 -1
- package/dist/routing/app-router.d.ts +14 -5
- package/dist/routing/app-router.js +82 -5
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +1 -3
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/route-pattern.d.ts +9 -0
- package/dist/routing/route-pattern.js +90 -0
- package/dist/routing/route-pattern.js.map +1 -0
- package/dist/routing/route-trie.js +10 -11
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/utils.d.ts +1 -29
- package/dist/routing/utils.js +1 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/app-browser-entry.js +63 -5
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +1 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +1 -1
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-elements.d.ts +1 -2
- package/dist/server/app-elements.js +1 -1
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-middleware.d.ts +32 -0
- package/dist/server/app-middleware.js +147 -0
- package/dist/server/app-middleware.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +5 -1
- package/dist/server/app-page-boundary-render.js +52 -30
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +13 -1
- package/dist/server/app-page-boundary.js +37 -17
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +4 -1
- package/dist/server/app-page-cache.js +38 -2
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +120 -0
- package/dist/server/app-page-dispatch.js +332 -0
- package/dist/server/app-page-dispatch.js.map +1 -0
- package/dist/server/app-page-execution.d.ts +6 -3
- package/dist/server/app-page-execution.js +22 -10
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +55 -0
- package/dist/server/app-page-head.js +196 -0
- package/dist/server/app-page-head.js.map +1 -0
- package/dist/server/app-page-method.d.ts +16 -0
- package/dist/server/app-page-method.js +30 -0
- package/dist/server/app-page-method.js.map +1 -0
- package/dist/server/app-page-params.d.ts +7 -0
- package/dist/server/app-page-params.js +28 -0
- package/dist/server/app-page-params.js.map +1 -0
- package/dist/server/app-page-probe.d.ts +1 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +4 -3
- package/dist/server/app-page-render.js +54 -8
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +5 -5
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +1 -1
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +15 -11
- package/dist/server/app-page-route-wiring.js +31 -9
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +12 -1
- package/dist/server/app-page-stream.js +10 -4
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-endpoints.d.ts +19 -0
- package/dist/server/app-prerender-endpoints.js +96 -0
- package/dist/server/app-prerender-endpoints.js.map +1 -0
- package/dist/server/app-prerender-static-params.d.ts +16 -0
- package/dist/server/app-prerender-static-params.js +14 -0
- package/dist/server/app-prerender-static-params.js.map +1 -0
- package/dist/server/app-route-handler-cache.d.ts +4 -1
- package/dist/server/app-route-handler-cache.js +6 -2
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +42 -0
- package/dist/server/app-route-handler-dispatch.js +147 -0
- package/dist/server/app-route-handler-dispatch.js.map +1 -0
- package/dist/server/app-route-handler-execution.d.ts +7 -3
- package/dist/server/app-route-handler-execution.js +32 -6
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-policy.d.ts +6 -2
- package/dist/server/app-route-handler-policy.js +8 -3
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.d.ts +2 -1
- package/dist/server/app-route-handler-response.js +44 -4
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +5 -2
- package/dist/server/app-route-handler-runtime.js +108 -2
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-errors.d.ts +27 -0
- package/dist/server/app-rsc-errors.js +42 -0
- package/dist/server/app-rsc-errors.js.map +1 -0
- package/dist/server/app-rsc-route-matching.d.ts +40 -0
- package/dist/server/app-rsc-route-matching.js +66 -0
- package/dist/server/app-rsc-route-matching.js.map +1 -0
- package/dist/server/app-server-action-execution.d.ts +120 -0
- package/dist/server/app-server-action-execution.js +355 -0
- package/dist/server/app-server-action-execution.js.map +1 -0
- package/dist/server/app-ssr-entry.d.ts +7 -0
- package/dist/server/app-ssr-entry.js +30 -9
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +5 -3
- package/dist/server/app-ssr-stream.js +29 -2
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +15 -0
- package/dist/server/app-static-generation.js +20 -0
- package/dist/server/app-static-generation.js.map +1 -0
- package/dist/server/csp.d.ts +1 -2
- package/dist/server/csp.js +1 -1
- package/dist/server/csp.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts +1 -1
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/dev-route-files.d.ts +7 -0
- package/dist/server/dev-route-files.js +73 -0
- package/dist/server/dev-route-files.js.map +1 -0
- package/dist/server/dev-server.js +4 -0
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/file-based-metadata.d.ts +17 -0
- package/dist/server/file-based-metadata.js +356 -0
- package/dist/server/file-based-metadata.js.map +1 -0
- package/dist/server/implicit-tags.d.ts +6 -0
- package/dist/server/implicit-tags.js +42 -0
- package/dist/server/implicit-tags.js.map +1 -0
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +20 -2
- package/dist/server/isr-cache.js +58 -7
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-route-build-data.d.ts +25 -0
- package/dist/server/metadata-route-build-data.js +150 -0
- package/dist/server/metadata-route-build-data.js.map +1 -0
- package/dist/server/metadata-route-response.d.ts +17 -0
- package/dist/server/metadata-route-response.js +187 -0
- package/dist/server/metadata-route-response.js.map +1 -0
- package/dist/server/metadata-routes.d.ts +42 -4
- package/dist/server/metadata-routes.js +127 -11
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.d.ts +15 -0
- package/dist/server/middleware-matcher.js +102 -0
- package/dist/server/middleware-matcher.js.map +1 -0
- package/dist/server/middleware-request-headers.d.ts +1 -3
- package/dist/server/middleware-request-headers.js +5 -4
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +39 -0
- package/dist/server/middleware-runtime.js +159 -0
- package/dist/server/middleware-runtime.js.map +1 -0
- package/dist/server/middleware.d.ts +5 -37
- package/dist/server/middleware.js +18 -228
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +1 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +2 -3
- package/dist/server/pages-i18n.js +1 -1
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/pages-node-compat.d.ts +1 -2
- package/dist/server/pages-node-compat.js +1 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +6 -2
- package/dist/server/pages-page-data.js +4 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +1 -1
- package/dist/server/pages-page-response.js +2 -1
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prerender-work-unit-setup.d.ts +7 -0
- package/dist/server/prerender-work-unit-setup.js +30 -0
- package/dist/server/prerender-work-unit-setup.js.map +1 -0
- package/dist/server/prod-server.js +12 -14
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +46 -5
- package/dist/server/request-pipeline.js +84 -5
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/rsc-stream-hints.d.ts +5 -0
- package/dist/server/rsc-stream-hints.js +35 -0
- package/dist/server/rsc-stream-hints.js.map +1 -0
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.d.ts +9 -0
- package/dist/server/server-action-not-found.js +40 -0
- package/dist/server/server-action-not-found.js.map +1 -0
- package/dist/server/socket-error-backstop.d.ts +17 -0
- package/dist/server/socket-error-backstop.js +129 -0
- package/dist/server/socket-error-backstop.js.map +1 -0
- package/dist/server/static-file-cache.d.ts +1 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/cache-runtime.js +16 -3
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +27 -2
- package/dist/shims/cache.js +135 -24
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +49 -4
- package/dist/shims/error-boundary.js +76 -4
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +10 -1
- package/dist/shims/fetch-cache.js +24 -4
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +21 -22
- package/dist/shims/font-google-base.js +86 -29
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +14 -2
- package/dist/shims/headers.js +127 -17
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.js +26 -8
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/make-hanging-promise.d.ts +16 -0
- package/dist/shims/internal/make-hanging-promise.js +46 -0
- package/dist/shims/internal/make-hanging-promise.js.map +1 -0
- package/dist/shims/internal/work-unit-async-storage.d.ts +26 -3
- package/dist/shims/internal/work-unit-async-storage.js +6 -3
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/link.js +1 -1
- package/dist/shims/metadata.d.ts +38 -26
- package/dist/shims/metadata.js +75 -45
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +17 -4
- package/dist/shims/navigation.js +29 -6
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +2 -2
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/navigation.react-server.js.map +1 -1
- package/dist/shims/offline.d.ts +5 -0
- package/dist/shims/offline.js +17 -0
- package/dist/shims/offline.js.map +1 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/root-params.d.ts +11 -0
- package/dist/shims/root-params.js +24 -0
- package/dist/shims/root-params.js.map +1 -0
- package/dist/shims/router.js +1 -1
- package/dist/shims/server.d.ts +5 -1
- package/dist/shims/server.js +101 -10
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -0
- package/dist/shims/thenable-params.js +37 -0
- package/dist/shims/thenable-params.js.map +1 -0
- package/dist/shims/unified-request-context.d.ts +2 -1
- package/dist/shims/unified-request-context.js +4 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.d.ts +3 -1
- package/dist/shims/url-safety.js +5 -1
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/utils/error-cause.d.ts +5 -0
- package/dist/utils/error-cause.js +97 -0
- package/dist/utils/error-cause.js.map +1 -0
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/package.json +6 -1
- package/dist/server/middleware-codegen.d.ts +0 -54
- package/dist/server/middleware-codegen.js +0 -414
- package/dist/server/middleware-codegen.js.map +0 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { validateCsrfOrigin, validateServerActionPayload } from "./request-pipeline.js";
|
|
2
|
+
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
|
|
3
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
4
|
+
import { resolveAppPageActionRerenderTarget } from "./app-page-request.js";
|
|
5
|
+
//#region src/server/app-server-action-execution.ts
|
|
6
|
+
function isRequestBodyTooLarge(error) {
|
|
7
|
+
return error instanceof Error && error.message === "Request body too large";
|
|
8
|
+
}
|
|
9
|
+
function isAppServerActionFunction(action) {
|
|
10
|
+
return typeof action === "function";
|
|
11
|
+
}
|
|
12
|
+
function normalizeError(error) {
|
|
13
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
14
|
+
}
|
|
15
|
+
function getServerActionFailureMessage(error) {
|
|
16
|
+
return error instanceof Error && error.message ? error.message : String(error);
|
|
17
|
+
}
|
|
18
|
+
async function readActionBodyWithLimit(request, maxBytes) {
|
|
19
|
+
if (!request.body) return "";
|
|
20
|
+
const reader = request.body.getReader();
|
|
21
|
+
const decoder = new TextDecoder();
|
|
22
|
+
const chunks = [];
|
|
23
|
+
let totalSize = 0;
|
|
24
|
+
for (;;) {
|
|
25
|
+
const result = await reader.read();
|
|
26
|
+
if (result.done) break;
|
|
27
|
+
totalSize += result.value.byteLength;
|
|
28
|
+
if (totalSize > maxBytes) {
|
|
29
|
+
await reader.cancel();
|
|
30
|
+
throw new Error("Request body too large");
|
|
31
|
+
}
|
|
32
|
+
chunks.push(decoder.decode(result.value, { stream: true }));
|
|
33
|
+
}
|
|
34
|
+
chunks.push(decoder.decode());
|
|
35
|
+
return chunks.join("");
|
|
36
|
+
}
|
|
37
|
+
async function readActionFormDataWithLimit(request, maxBytes) {
|
|
38
|
+
if (!request.body) return new FormData();
|
|
39
|
+
const reader = request.body.getReader();
|
|
40
|
+
const chunks = [];
|
|
41
|
+
let totalSize = 0;
|
|
42
|
+
for (;;) {
|
|
43
|
+
const result = await reader.read();
|
|
44
|
+
if (result.done) break;
|
|
45
|
+
totalSize += result.value.byteLength;
|
|
46
|
+
if (totalSize > maxBytes) {
|
|
47
|
+
await reader.cancel();
|
|
48
|
+
throw new Error("Request body too large");
|
|
49
|
+
}
|
|
50
|
+
chunks.push(result.value);
|
|
51
|
+
}
|
|
52
|
+
const combined = new Uint8Array(totalSize);
|
|
53
|
+
let offset = 0;
|
|
54
|
+
for (const chunk of chunks) {
|
|
55
|
+
combined.set(chunk, offset);
|
|
56
|
+
offset += chunk.byteLength;
|
|
57
|
+
}
|
|
58
|
+
return new Response(combined, { headers: { "Content-Type": request.headers.get("content-type") || "" } }).formData();
|
|
59
|
+
}
|
|
60
|
+
function getErrorDigest(error) {
|
|
61
|
+
if (!error || typeof error !== "object" || !("digest" in error)) return null;
|
|
62
|
+
return String(error.digest);
|
|
63
|
+
}
|
|
64
|
+
function getActionControlResponse(error) {
|
|
65
|
+
const digest = getErrorDigest(error);
|
|
66
|
+
if (!digest) return null;
|
|
67
|
+
if (digest.startsWith("NEXT_REDIRECT;")) {
|
|
68
|
+
const encodedUrl = digest.split(";")[2];
|
|
69
|
+
if (!encodedUrl) return null;
|
|
70
|
+
return {
|
|
71
|
+
kind: "redirect",
|
|
72
|
+
url: decodeURIComponent(encodedUrl)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (digest === "NEXT_NOT_FOUND" || digest.startsWith("NEXT_HTTP_ERROR_FALLBACK;")) {
|
|
76
|
+
const statusCode = digest === "NEXT_NOT_FOUND" ? 404 : parseInt(digest.split(";")[1], 10);
|
|
77
|
+
if (!Number.isInteger(statusCode)) return null;
|
|
78
|
+
return {
|
|
79
|
+
kind: "status",
|
|
80
|
+
statusCode
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function getActionRedirect(error) {
|
|
86
|
+
const digest = getErrorDigest(error);
|
|
87
|
+
if (!digest?.startsWith("NEXT_REDIRECT;")) return null;
|
|
88
|
+
const parts = digest.split(";");
|
|
89
|
+
const encodedUrl = parts[2];
|
|
90
|
+
if (!encodedUrl) return null;
|
|
91
|
+
return {
|
|
92
|
+
status: parts[3] ? parseInt(parts[3], 10) : 307,
|
|
93
|
+
type: parts[1] || "push",
|
|
94
|
+
url: decodeURIComponent(encodedUrl)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function isActionHttpFallback(error) {
|
|
98
|
+
const digest = getErrorDigest(error);
|
|
99
|
+
return digest === "NEXT_NOT_FOUND" || digest?.startsWith("NEXT_HTTP_ERROR_FALLBACK;") === true;
|
|
100
|
+
}
|
|
101
|
+
function createServerActionErrorResponse(error, options) {
|
|
102
|
+
options.getAndClearPendingCookies();
|
|
103
|
+
console.error("[vinext] Server action error:", error);
|
|
104
|
+
options.reportRequestError(normalizeError(error), {
|
|
105
|
+
path: options.cleanPathname,
|
|
106
|
+
method: options.request.method,
|
|
107
|
+
headers: Object.fromEntries(options.request.headers.entries())
|
|
108
|
+
}, {
|
|
109
|
+
routerKind: "App Router",
|
|
110
|
+
routePath: options.cleanPathname,
|
|
111
|
+
routeType: "action"
|
|
112
|
+
});
|
|
113
|
+
options.clearRequestContext();
|
|
114
|
+
return new Response(process.env.NODE_ENV === "production" ? "Internal Server Error" : "Server action failed: " + getServerActionFailureMessage(error), { status: 500 });
|
|
115
|
+
}
|
|
116
|
+
function createActionNotFoundResponse(actionId, options) {
|
|
117
|
+
options.getAndClearPendingCookies();
|
|
118
|
+
console.warn(getServerActionNotFoundMessage(actionId));
|
|
119
|
+
options.clearRequestContext();
|
|
120
|
+
return createServerActionNotFoundResponse();
|
|
121
|
+
}
|
|
122
|
+
function isProgressiveServerActionRequest(request, contentType, actionId) {
|
|
123
|
+
return request.method.toUpperCase() === "POST" && contentType.startsWith("multipart/form-data") && !actionId;
|
|
124
|
+
}
|
|
125
|
+
async function handleProgressiveServerActionRequest(options) {
|
|
126
|
+
if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) return null;
|
|
127
|
+
const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
|
|
128
|
+
if (csrfResponse) return csrfResponse;
|
|
129
|
+
if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
|
|
130
|
+
options.clearRequestContext();
|
|
131
|
+
return new Response("Payload Too Large", { status: 413 });
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
let body;
|
|
135
|
+
try {
|
|
136
|
+
body = await options.readFormDataWithLimit(options.request.clone(), options.maxActionBodySize);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (isRequestBodyTooLarge(error)) {
|
|
139
|
+
options.clearRequestContext();
|
|
140
|
+
return new Response("Payload Too Large", { status: 413 });
|
|
141
|
+
}
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
const payloadResponse = await validateServerActionPayload(body);
|
|
145
|
+
if (payloadResponse) {
|
|
146
|
+
options.clearRequestContext();
|
|
147
|
+
return payloadResponse;
|
|
148
|
+
}
|
|
149
|
+
const action = await options.decodeAction(body);
|
|
150
|
+
if (typeof action !== "function") return null;
|
|
151
|
+
let actionControlResponse = null;
|
|
152
|
+
const previousHeadersPhase = options.setHeadersAccessPhase("action");
|
|
153
|
+
try {
|
|
154
|
+
await action();
|
|
155
|
+
} catch (error) {
|
|
156
|
+
actionControlResponse = getActionControlResponse(error);
|
|
157
|
+
if (!actionControlResponse) throw error;
|
|
158
|
+
} finally {
|
|
159
|
+
options.setHeadersAccessPhase(previousHeadersPhase);
|
|
160
|
+
}
|
|
161
|
+
if (!actionControlResponse) return null;
|
|
162
|
+
const actionPendingCookies = options.getAndClearPendingCookies();
|
|
163
|
+
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
164
|
+
options.clearRequestContext();
|
|
165
|
+
const headers = new Headers();
|
|
166
|
+
if (actionControlResponse.kind === "redirect") headers.set("Location", new URL(actionControlResponse.url, options.request.url).toString());
|
|
167
|
+
mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);
|
|
168
|
+
for (const cookie of actionPendingCookies) headers.append("Set-Cookie", cookie);
|
|
169
|
+
if (actionDraftCookie) headers.append("Set-Cookie", actionDraftCookie);
|
|
170
|
+
return new Response(null, {
|
|
171
|
+
status: actionControlResponse.kind === "redirect" ? 303 : actionControlResponse.statusCode,
|
|
172
|
+
headers
|
|
173
|
+
});
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (isServerActionNotFoundError(error, null)) return createActionNotFoundResponse(null, {
|
|
176
|
+
clearRequestContext: options.clearRequestContext,
|
|
177
|
+
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
178
|
+
});
|
|
179
|
+
options.getAndClearPendingCookies();
|
|
180
|
+
console.error("[vinext] Server action error:", error);
|
|
181
|
+
options.reportRequestError(normalizeError(error), {
|
|
182
|
+
path: options.cleanPathname,
|
|
183
|
+
method: options.request.method,
|
|
184
|
+
headers: Object.fromEntries(options.request.headers.entries())
|
|
185
|
+
}, {
|
|
186
|
+
routerKind: "App Router",
|
|
187
|
+
routePath: options.cleanPathname,
|
|
188
|
+
routeType: "action"
|
|
189
|
+
});
|
|
190
|
+
options.clearRequestContext();
|
|
191
|
+
return new Response(process.env.NODE_ENV === "production" ? "Internal Server Error" : "Server action failed: " + getServerActionFailureMessage(error), { status: 500 });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function handleServerActionRscRequest(options) {
|
|
195
|
+
if (options.request.method.toUpperCase() !== "POST" || !options.actionId) return null;
|
|
196
|
+
const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
|
|
197
|
+
if (csrfResponse) return csrfResponse;
|
|
198
|
+
if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
|
|
199
|
+
options.clearRequestContext();
|
|
200
|
+
return new Response("Payload Too Large", { status: 413 });
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
let body;
|
|
204
|
+
try {
|
|
205
|
+
body = options.contentType.startsWith("multipart/form-data") ? await options.readFormDataWithLimit(options.request, options.maxActionBodySize) : await options.readBodyWithLimit(options.request, options.maxActionBodySize);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (isRequestBodyTooLarge(error)) {
|
|
208
|
+
options.clearRequestContext();
|
|
209
|
+
return new Response("Payload Too Large", { status: 413 });
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
const payloadResponse = await validateServerActionPayload(body);
|
|
214
|
+
if (payloadResponse) {
|
|
215
|
+
options.clearRequestContext();
|
|
216
|
+
return payloadResponse;
|
|
217
|
+
}
|
|
218
|
+
let action;
|
|
219
|
+
try {
|
|
220
|
+
action = await options.loadServerAction(options.actionId);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (isServerActionNotFoundError(error, options.actionId)) return createActionNotFoundResponse(options.actionId, {
|
|
223
|
+
clearRequestContext: options.clearRequestContext,
|
|
224
|
+
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
225
|
+
});
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
if (!isAppServerActionFunction(action)) return createActionNotFoundResponse(options.actionId, {
|
|
229
|
+
clearRequestContext: options.clearRequestContext,
|
|
230
|
+
getAndClearPendingCookies: options.getAndClearPendingCookies
|
|
231
|
+
});
|
|
232
|
+
const temporaryReferences = options.createTemporaryReferenceSet();
|
|
233
|
+
const args = await options.decodeReply(body, { temporaryReferences });
|
|
234
|
+
let returnValue;
|
|
235
|
+
let actionRedirect = null;
|
|
236
|
+
const previousHeadersPhase = options.setHeadersAccessPhase("action");
|
|
237
|
+
try {
|
|
238
|
+
try {
|
|
239
|
+
returnValue = {
|
|
240
|
+
ok: true,
|
|
241
|
+
data: await action.apply(null, args)
|
|
242
|
+
};
|
|
243
|
+
} catch (error) {
|
|
244
|
+
actionRedirect = getActionRedirect(error);
|
|
245
|
+
if (actionRedirect) returnValue = {
|
|
246
|
+
ok: true,
|
|
247
|
+
data: void 0
|
|
248
|
+
};
|
|
249
|
+
else if (isActionHttpFallback(error)) returnValue = {
|
|
250
|
+
ok: false,
|
|
251
|
+
data: error
|
|
252
|
+
};
|
|
253
|
+
else {
|
|
254
|
+
console.error("[vinext] Server action error:", error);
|
|
255
|
+
returnValue = {
|
|
256
|
+
ok: false,
|
|
257
|
+
data: options.sanitizeErrorForClient(error)
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} finally {
|
|
262
|
+
options.setHeadersAccessPhase(previousHeadersPhase);
|
|
263
|
+
}
|
|
264
|
+
if (actionRedirect) {
|
|
265
|
+
const actionPendingCookies = options.getAndClearPendingCookies();
|
|
266
|
+
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
267
|
+
options.clearRequestContext();
|
|
268
|
+
const redirectHeaders = new Headers({
|
|
269
|
+
"Content-Type": "text/x-component; charset=utf-8",
|
|
270
|
+
Vary: "RSC, Accept"
|
|
271
|
+
});
|
|
272
|
+
mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);
|
|
273
|
+
redirectHeaders.set("x-action-redirect", actionRedirect.url);
|
|
274
|
+
redirectHeaders.set("x-action-redirect-type", actionRedirect.type);
|
|
275
|
+
redirectHeaders.set("x-action-redirect-status", String(actionRedirect.status));
|
|
276
|
+
for (const cookie of actionPendingCookies) redirectHeaders.append("Set-Cookie", cookie);
|
|
277
|
+
if (actionDraftCookie) redirectHeaders.append("Set-Cookie", actionDraftCookie);
|
|
278
|
+
return new Response("", {
|
|
279
|
+
status: 200,
|
|
280
|
+
headers: redirectHeaders
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
const match = options.matchRoute(options.cleanPathname);
|
|
284
|
+
let element;
|
|
285
|
+
let errorPattern = match ? match.route.pattern : options.cleanPathname;
|
|
286
|
+
if (match) {
|
|
287
|
+
const { route: actionRoute, params: actionParams } = match;
|
|
288
|
+
const actionRerenderTarget = resolveAppPageActionRerenderTarget({
|
|
289
|
+
cleanPathname: options.cleanPathname,
|
|
290
|
+
currentParams: actionParams,
|
|
291
|
+
currentRoute: actionRoute,
|
|
292
|
+
findIntercept: options.findIntercept,
|
|
293
|
+
getRouteParamNames: options.getRouteParamNames,
|
|
294
|
+
getSourceRoute: options.getSourceRoute,
|
|
295
|
+
isRscRequest: options.isRscRequest,
|
|
296
|
+
toInterceptOpts: options.toInterceptOpts
|
|
297
|
+
});
|
|
298
|
+
options.setNavigationContext({
|
|
299
|
+
pathname: options.cleanPathname,
|
|
300
|
+
searchParams: options.searchParams,
|
|
301
|
+
params: actionRerenderTarget.navigationParams
|
|
302
|
+
});
|
|
303
|
+
element = options.buildPageElement({
|
|
304
|
+
cleanPathname: options.cleanPathname,
|
|
305
|
+
interceptOpts: actionRerenderTarget.interceptOpts,
|
|
306
|
+
isRscRequest: options.isRscRequest,
|
|
307
|
+
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
308
|
+
params: actionRerenderTarget.params,
|
|
309
|
+
request: options.request,
|
|
310
|
+
route: actionRerenderTarget.route,
|
|
311
|
+
searchParams: options.searchParams
|
|
312
|
+
});
|
|
313
|
+
errorPattern = actionRerenderTarget.route.pattern;
|
|
314
|
+
} else {
|
|
315
|
+
const actionRouteId = options.createPayloadRouteId(options.cleanPathname, null);
|
|
316
|
+
element = options.createNotFoundElement(actionRouteId);
|
|
317
|
+
}
|
|
318
|
+
const onRenderError = options.createRscOnErrorHandler(options.request, options.cleanPathname, errorPattern);
|
|
319
|
+
const rscStream = await options.renderToReadableStream({
|
|
320
|
+
root: element,
|
|
321
|
+
returnValue
|
|
322
|
+
}, {
|
|
323
|
+
temporaryReferences,
|
|
324
|
+
onError: onRenderError
|
|
325
|
+
});
|
|
326
|
+
const actionPendingCookies = options.getAndClearPendingCookies();
|
|
327
|
+
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
328
|
+
const actionHeaders = new Headers({
|
|
329
|
+
"Content-Type": "text/x-component; charset=utf-8",
|
|
330
|
+
Vary: "RSC, Accept"
|
|
331
|
+
});
|
|
332
|
+
mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);
|
|
333
|
+
const actionResponse = new Response(rscStream, {
|
|
334
|
+
status: options.middlewareStatus ?? 200,
|
|
335
|
+
headers: actionHeaders
|
|
336
|
+
});
|
|
337
|
+
if (actionPendingCookies.length > 0 || actionDraftCookie) {
|
|
338
|
+
for (const cookie of actionPendingCookies) actionResponse.headers.append("Set-Cookie", cookie);
|
|
339
|
+
if (actionDraftCookie) actionResponse.headers.append("Set-Cookie", actionDraftCookie);
|
|
340
|
+
}
|
|
341
|
+
return actionResponse;
|
|
342
|
+
} catch (error) {
|
|
343
|
+
return createServerActionErrorResponse(error, {
|
|
344
|
+
cleanPathname: options.cleanPathname,
|
|
345
|
+
clearRequestContext: options.clearRequestContext,
|
|
346
|
+
getAndClearPendingCookies: options.getAndClearPendingCookies,
|
|
347
|
+
reportRequestError: options.reportRequestError,
|
|
348
|
+
request: options.request
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
export { handleProgressiveServerActionRequest, handleServerActionRscRequest, isProgressiveServerActionRequest, readActionBodyWithLimit, readActionFormDataWithLimit };
|
|
354
|
+
|
|
355
|
+
//# sourceMappingURL=app-server-action-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-server-action-execution.js","names":[],"sources":["../../src/server/app-server-action-execution.ts"],"sourcesContent":["import type { HeadersAccessPhase } from \"vinext/shims/headers\";\nimport { resolveAppPageActionRerenderTarget } from \"./app-page-request.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { validateCsrfOrigin, validateServerActionPayload } from \"./request-pipeline.js\";\nimport {\n createServerActionNotFoundResponse,\n getServerActionNotFoundMessage,\n isServerActionNotFoundError,\n} from \"./server-action-not-found.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\n\ntype AppServerActionErrorReporter = (\n error: Error,\n request: { path: string; method: string; headers: Record<string, string> },\n route: { routerKind: \"App Router\"; routePath: string; routeType: \"action\" },\n) => void;\n\ntype AppServerActionDecoder = (body: FormData) => Promise<unknown>;\n\ntype ReadFormDataWithLimit = (request: Request, maxBytes: number) => Promise<FormData>;\n\ntype ReadBodyWithLimit = (request: Request, maxBytes: number) => Promise<string>;\n\ntype AppServerActionFunction = (...args: unknown[]) => unknown;\n\ntype AppServerActionReturnValue =\n | {\n data: unknown;\n ok: true;\n }\n | {\n data: unknown;\n ok: false;\n };\n\ntype AppServerActionRedirect = {\n status: number;\n type: string;\n url: string;\n};\n\ntype AppServerActionRoute = {\n pattern: string;\n};\n\ntype AppServerActionMatch<TRoute extends AppServerActionRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype AppServerActionIntercept<TPage = unknown> = {\n matchedParams: AppPageParams;\n page: TPage;\n slotKey: string;\n sourceRouteIndex: number;\n};\n\ntype BuildServerActionPageElementOptions<TRoute extends AppServerActionRoute, TInterceptOpts> = {\n cleanPathname: string;\n interceptOpts: TInterceptOpts | undefined;\n isRscRequest: boolean;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype AppServerActionRscModel<TElement> = {\n returnValue: AppServerActionReturnValue;\n root: TElement;\n};\n\ntype RenderServerActionRscStreamOptions<TTemporaryReferences> = {\n onError: (error: unknown) => unknown;\n temporaryReferences: TTemporaryReferences;\n};\n\ntype DecodeServerActionReplyOptions<TTemporaryReferences> = {\n temporaryReferences: TTemporaryReferences;\n};\n\nexport type HandleProgressiveServerActionRequestOptions = {\n actionId: string | null;\n allowedOrigins: string[];\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n decodeAction: AppServerActionDecoder;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n readFormDataWithLimit: ReadFormDataWithLimit;\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n};\n\nexport type HandleServerActionRscRequestOptions<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n> = {\n actionId: string | null;\n allowedOrigins: string[];\n buildPageElement: (\n options: BuildServerActionPageElementOptions<TRoute, TInterceptOpts>,\n ) => TElement;\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n createNotFoundElement: (routeId: string) => TElement;\n createPayloadRouteId: (pathname: string, interceptionContext: string | null) => string;\n createRscOnErrorHandler: (\n request: Request,\n pathname: string,\n pattern: string,\n ) => (error: unknown) => unknown;\n createTemporaryReferenceSet: () => TTemporaryReferences;\n decodeReply: (\n body: string | FormData,\n options: DecodeServerActionReplyOptions<TTemporaryReferences>,\n ) => Promise<unknown[]> | unknown[];\n findIntercept: (pathname: string) => AppServerActionIntercept<TPage> | null;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n getRouteParamNames: (route: TRoute) => readonly string[];\n getSourceRoute: (sourceRouteIndex: number) => TRoute | undefined;\n isRscRequest: boolean;\n loadServerAction: (actionId: string) => Promise<unknown>;\n matchRoute: (pathname: string) => AppServerActionMatch<TRoute> | null;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n middlewareStatus: number | null | undefined;\n mountedSlotsHeader: string | null;\n readBodyWithLimit: ReadBodyWithLimit;\n readFormDataWithLimit: ReadFormDataWithLimit;\n renderToReadableStream: (\n model: AppServerActionRscModel<TElement>,\n options: RenderServerActionRscStreamOptions<TTemporaryReferences>,\n ) => BodyInit | null | Promise<BodyInit | null>;\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n sanitizeErrorForClient: (error: unknown) => unknown;\n searchParams: URLSearchParams;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n setNavigationContext: (context: {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n }) => void;\n toInterceptOpts: (intercept: AppServerActionIntercept<TPage>) => TInterceptOpts;\n};\n\ntype ActionControlResponse =\n | {\n kind: \"redirect\";\n url: string;\n }\n | {\n kind: \"status\";\n statusCode: number;\n };\n\nfunction isRequestBodyTooLarge(error: unknown): boolean {\n return error instanceof Error && error.message === \"Request body too large\";\n}\n\nfunction isAppServerActionFunction(action: unknown): action is AppServerActionFunction {\n return typeof action === \"function\";\n}\n\nfunction normalizeError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction getServerActionFailureMessage(error: unknown): string {\n return error instanceof Error && error.message ? error.message : String(error);\n}\n\nexport async function readActionBodyWithLimit(request: Request, maxBytes: number): Promise<string> {\n if (!request.body) return \"\";\n\n const reader = request.body.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n let totalSize = 0;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n throw new Error(\"Request body too large\");\n }\n chunks.push(decoder.decode(result.value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n}\n\nexport async function readActionFormDataWithLimit(\n request: Request,\n maxBytes: number,\n): Promise<FormData> {\n if (!request.body) return new FormData();\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n throw new Error(\"Request body too large\");\n }\n chunks.push(result.value);\n }\n\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new Response(combined, {\n headers: { \"Content-Type\": request.headers.get(\"content-type\") || \"\" },\n }).formData();\n}\n\nfunction getErrorDigest(error: unknown): string | null {\n if (!error || typeof error !== \"object\" || !(\"digest\" in error)) {\n return null;\n }\n\n return String(error.digest);\n}\n\nfunction getActionControlResponse(error: unknown): ActionControlResponse | null {\n const digest = getErrorDigest(error);\n if (!digest) return null;\n\n if (digest.startsWith(\"NEXT_REDIRECT;\")) {\n const parts = digest.split(\";\");\n const encodedUrl = parts[2];\n if (!encodedUrl) {\n return null;\n }\n\n return {\n kind: \"redirect\",\n url: decodeURIComponent(encodedUrl),\n };\n }\n\n if (digest === \"NEXT_NOT_FOUND\" || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n const statusCode = digest === \"NEXT_NOT_FOUND\" ? 404 : parseInt(digest.split(\";\")[1], 10);\n if (!Number.isInteger(statusCode)) {\n return null;\n }\n\n return {\n kind: \"status\",\n statusCode,\n };\n }\n\n return null;\n}\n\nfunction getActionRedirect(error: unknown): AppServerActionRedirect | null {\n const digest = getErrorDigest(error);\n if (!digest?.startsWith(\"NEXT_REDIRECT;\")) {\n return null;\n }\n\n const parts = digest.split(\";\");\n const encodedUrl = parts[2];\n if (!encodedUrl) {\n return null;\n }\n\n return {\n status: parts[3] ? parseInt(parts[3], 10) : 307,\n type: parts[1] || \"push\",\n url: decodeURIComponent(encodedUrl),\n };\n}\n\nfunction isActionHttpFallback(error: unknown): boolean {\n const digest = getErrorDigest(error);\n return digest === \"NEXT_NOT_FOUND\" || digest?.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\") === true;\n}\n\nfunction createServerActionErrorResponse(\n error: unknown,\n options: {\n cleanPathname: string;\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n },\n): Response {\n options.getAndClearPendingCookies();\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return new Response(\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n { status: 500 },\n );\n}\n\nfunction createActionNotFoundResponse(\n actionId: string | null,\n options: {\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n },\n): Response {\n options.getAndClearPendingCookies();\n console.warn(getServerActionNotFoundMessage(actionId));\n options.clearRequestContext();\n return createServerActionNotFoundResponse();\n}\n\nexport function isProgressiveServerActionRequest(\n request: Pick<Request, \"method\">,\n contentType: string,\n actionId: string | null,\n): boolean {\n return (\n request.method.toUpperCase() === \"POST\" &&\n contentType.startsWith(\"multipart/form-data\") &&\n !actionId\n );\n}\n\nexport async function handleProgressiveServerActionRequest(\n options: HandleProgressiveServerActionRequestOptions,\n): Promise<Response | null> {\n if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) {\n return csrfResponse;\n }\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n\n try {\n let body: FormData;\n try {\n // Progressive submissions can still fall through to a regular page render when\n // the multipart body is not an action payload. Read a clone so that fallback\n // code can still consume the original request body.\n body = await options.readFormDataWithLimit(\n options.request.clone(),\n options.maxActionBodySize,\n );\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n const action = await options.decodeAction(body);\n if (typeof action !== \"function\") {\n return null;\n }\n\n let actionControlResponse: ActionControlResponse | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n await action();\n } catch (error) {\n actionControlResponse = getActionControlResponse(error);\n if (!actionControlResponse) {\n throw error;\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (!actionControlResponse) {\n // Next.js decodes form state and re-renders after a successful MPA action.\n // vinext currently supports the redirect/error status cases; successful\n // non-redirect actions intentionally fall through to the page render.\n return null;\n }\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n\n const headers = new Headers();\n if (actionControlResponse.kind === \"redirect\") {\n headers.set(\"Location\", new URL(actionControlResponse.url, options.request.url).toString());\n }\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);\n for (const cookie of actionPendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) {\n headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n\n return new Response(null, {\n status: actionControlResponse.kind === \"redirect\" ? 303 : actionControlResponse.statusCode,\n headers,\n });\n } catch (error) {\n if (isServerActionNotFoundError(error, null)) {\n return createActionNotFoundResponse(null, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n options.getAndClearPendingCookies();\n // Next.js rethrows generic MPA action errors into its page render path.\n // vinext does not yet implement that form-state render path, so unexpected\n // action failures remain request failures here.\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return new Response(\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n { status: 500 },\n );\n }\n}\n\nexport async function handleServerActionRscRequest<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n>(\n options: HandleServerActionRscRequestOptions<\n TElement,\n TRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage\n >,\n): Promise<Response | null> {\n if (options.request.method.toUpperCase() !== \"POST\" || !options.actionId) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) return csrfResponse;\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n\n try {\n let body: string | FormData;\n try {\n body = options.contentType.startsWith(\"multipart/form-data\")\n ? await options.readFormDataWithLimit(options.request, options.maxActionBodySize)\n : await options.readBodyWithLimit(options.request, options.maxActionBodySize);\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n let action: unknown;\n try {\n action = await options.loadServerAction(options.actionId);\n } catch (error) {\n if (isServerActionNotFoundError(error, options.actionId)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n throw error;\n }\n\n if (!isAppServerActionFunction(action)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n const temporaryReferences = options.createTemporaryReferenceSet();\n const args = await options.decodeReply(body, { temporaryReferences });\n let returnValue: AppServerActionReturnValue;\n let actionRedirect: AppServerActionRedirect | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n try {\n const data = await action.apply(null, args);\n returnValue = { ok: true, data };\n } catch (error) {\n actionRedirect = getActionRedirect(error);\n if (actionRedirect) {\n returnValue = { ok: true, data: undefined };\n } else if (isActionHttpFallback(error)) {\n returnValue = { ok: false, data: error };\n } else {\n console.error(\"[vinext] Server action error:\", error);\n returnValue = { ok: false, data: options.sanitizeErrorForClient(error) };\n }\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (actionRedirect) {\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n const redirectHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);\n redirectHeaders.set(\"x-action-redirect\", actionRedirect.url);\n redirectHeaders.set(\"x-action-redirect-type\", actionRedirect.type);\n redirectHeaders.set(\"x-action-redirect-status\", String(actionRedirect.status));\n for (const cookie of actionPendingCookies) {\n redirectHeaders.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) redirectHeaders.append(\"Set-Cookie\", actionDraftCookie);\n return new Response(\"\", { status: 200, headers: redirectHeaders });\n }\n\n const match = options.matchRoute(options.cleanPathname);\n let element: TElement;\n let errorPattern = match ? match.route.pattern : options.cleanPathname;\n if (match) {\n const { route: actionRoute, params: actionParams } = match;\n const actionRerenderTarget = resolveAppPageActionRerenderTarget({\n cleanPathname: options.cleanPathname,\n currentParams: actionParams,\n currentRoute: actionRoute,\n findIntercept: options.findIntercept,\n getRouteParamNames: options.getRouteParamNames,\n getSourceRoute: options.getSourceRoute,\n isRscRequest: options.isRscRequest,\n toInterceptOpts: options.toInterceptOpts,\n });\n\n options.setNavigationContext({\n pathname: options.cleanPathname,\n searchParams: options.searchParams,\n params: actionRerenderTarget.navigationParams,\n });\n element = options.buildPageElement({\n cleanPathname: options.cleanPathname,\n interceptOpts: actionRerenderTarget.interceptOpts,\n isRscRequest: options.isRscRequest,\n mountedSlotsHeader: options.mountedSlotsHeader,\n params: actionRerenderTarget.params,\n request: options.request,\n route: actionRerenderTarget.route,\n searchParams: options.searchParams,\n });\n errorPattern = actionRerenderTarget.route.pattern;\n } else {\n const actionRouteId = options.createPayloadRouteId(options.cleanPathname, null);\n element = options.createNotFoundElement(actionRouteId);\n }\n\n const onRenderError = options.createRscOnErrorHandler(\n options.request,\n options.cleanPathname,\n errorPattern,\n );\n const rscStream = await options.renderToReadableStream(\n { root: element, returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n\n const actionHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n const actionResponse = new Response(rscStream, {\n status: options.middlewareStatus ?? 200,\n headers: actionHeaders,\n });\n if (actionPendingCookies.length > 0 || actionDraftCookie) {\n for (const cookie of actionPendingCookies) {\n actionResponse.headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) actionResponse.headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n return actionResponse;\n } catch (error) {\n return createServerActionErrorResponse(error, {\n cleanPathname: options.cleanPathname,\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n reportRequestError: options.reportRequestError,\n request: options.request,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -12,6 +12,13 @@ type FontData = {
|
|
|
12
12
|
};
|
|
13
13
|
declare function handleSsr(rscStream: ReadableStream<Uint8Array>, navContext: NavigationContext | null, fontData?: FontData, options?: {
|
|
14
14
|
scriptNonce?: string;
|
|
15
|
+
/** Pre-split side stream for embed+capture fusion. When provided,
|
|
16
|
+
* rscStream is fed directly to createFromReadableStream (no internal tee).
|
|
17
|
+
* The embed transform accumulates raw bytes. */
|
|
18
|
+
sideStream?: ReadableStream<Uint8Array>; /** Out-parameter: filled with accumulated raw RSC bytes when sideStream is consumed. */
|
|
19
|
+
capturedRscDataRef?: {
|
|
20
|
+
value: Promise<ArrayBuffer> | null;
|
|
21
|
+
};
|
|
15
22
|
}): Promise<ReadableStream<Uint8Array>>;
|
|
16
23
|
declare const _default: {
|
|
17
24
|
fetch(request: Request): Promise<Response>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isOpenRedirectShaped } from "./request-pipeline.js";
|
|
1
2
|
import { normalizeAppElements, readAppElementsMetadata } from "./app-elements.js";
|
|
2
|
-
import { ServerInsertedHTMLContext, clearServerInsertedHTML,
|
|
3
|
+
import { ServerInsertedHTMLContext, clearServerInsertedHTML, renderServerInsertedHTML, setNavigationContext, useServerInsertedHTML } from "../shims/navigation.js";
|
|
3
4
|
import { runWithNavigationContext } from "../shims/navigation-state.js";
|
|
4
5
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
5
6
|
import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
|
|
6
7
|
import { ElementsContext, Slot } from "../shims/slot.js";
|
|
7
|
-
import {
|
|
8
|
+
import { deferUntilStreamConsumed } from "./app-page-stream.js";
|
|
8
9
|
import { createRscEmbedTransform, createTickBufferedTransform } from "./app-ssr-stream.js";
|
|
9
10
|
import { Fragment, createElement, use } from "react";
|
|
10
11
|
import { renderToReadableStream, renderToStaticMarkup } from "react-dom/server.edge";
|
|
@@ -68,9 +69,22 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
68
69
|
await preloadClientReferences();
|
|
69
70
|
if (navContext) setNavigationContext(navContext);
|
|
70
71
|
clearServerInsertedHTML();
|
|
72
|
+
const cleanup = () => {
|
|
73
|
+
setNavigationContext(null);
|
|
74
|
+
clearServerInsertedHTML();
|
|
75
|
+
};
|
|
71
76
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
let ssrStream;
|
|
78
|
+
let rscEmbed;
|
|
79
|
+
if (options?.sideStream) {
|
|
80
|
+
ssrStream = rscStream;
|
|
81
|
+
rscEmbed = createRscEmbedTransform(options.sideStream, options?.scriptNonce);
|
|
82
|
+
if (options.capturedRscDataRef) options.capturedRscDataRef.value = rscEmbed.getRawBuffer();
|
|
83
|
+
} else {
|
|
84
|
+
const [s1, s2] = rscStream.tee();
|
|
85
|
+
ssrStream = s1;
|
|
86
|
+
rscEmbed = createRscEmbedTransform(s2, options?.scriptNonce);
|
|
87
|
+
}
|
|
74
88
|
let flightRoot = null;
|
|
75
89
|
function VinextFlightRoot() {
|
|
76
90
|
if (!flightRoot) flightRoot = createFromReadableStream(ssrStream);
|
|
@@ -89,11 +103,18 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
89
103
|
if (process.env.NODE_ENV === "production" && error) return ssrErrorDigest(getErrorMessage(error) + (error instanceof Error ? error.stack ?? "" : ""));
|
|
90
104
|
}
|
|
91
105
|
});
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
106
|
+
const fontHTML = renderFontHtml(fontData, options?.scriptNonce);
|
|
107
|
+
let didInjectHeadHTML = false;
|
|
108
|
+
const getInsertedHTML = () => {
|
|
109
|
+
const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());
|
|
110
|
+
if (didInjectHeadHTML) return insertedHTML;
|
|
111
|
+
didInjectHeadHTML = true;
|
|
112
|
+
return buildHeadInjectionHtml(navContext, bootstrapScriptContent, insertedHTML, fontHTML, options?.scriptNonce);
|
|
113
|
+
};
|
|
114
|
+
return deferUntilStreamConsumed(htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, getInsertedHTML)), cleanup);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
cleanup();
|
|
117
|
+
throw error;
|
|
97
118
|
}
|
|
98
119
|
});
|
|
99
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport type { ReactNode } from \"react\";\nimport { Fragment, createElement as createReactElement, use } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport * as clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"../shims/navigation.js\";\nimport {\n ServerInsertedHTMLContext,\n clearServerInsertedHTML,\n flushServerInsertedHTML,\n setNavigationContext,\n useServerInsertedHTML,\n} from \"../shims/navigation.js\";\nimport { runWithNavigationContext } from \"../shims/navigation-state.js\";\nimport { isOpenRedirectShaped } from \"./request-pipeline.js\";\nimport { withScriptNonce } from \"../shims/script-nonce-context.js\";\nimport {\n createInlineScriptTag,\n createNonceAttribute,\n escapeHtmlAttr,\n safeJsonStringify,\n} from \"./html.js\";\nimport { createRscEmbedTransform, createTickBufferedTransform } from \"./app-ssr-stream.js\";\nimport {\n normalizeAppElements,\n readAppElementsMetadata,\n type AppWireElements,\n} from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"../shims/slot.js\";\n\nexport type FontPreload = {\n href: string;\n type: string;\n};\n\nexport type FontData = {\n links?: string[];\n styles?: string[];\n preloads?: FontPreload[];\n};\n\ntype ClientRequire = (id: string) => Promise<unknown>;\n\nlet clientRefsPreloaded = false;\n\nfunction getClientReferenceRequire(): ClientRequire | undefined {\n return (\n globalThis as typeof globalThis & {\n __vite_rsc_client_require__?: ClientRequire;\n }\n ).__vite_rsc_client_require__;\n}\n\nasync function preloadClientReferences(): Promise<void> {\n if (clientRefsPreloaded) return;\n\n const refs = (clientReferences as { default?: Record<string, unknown> }).default;\n const clientRequire = getClientReferenceRequire();\n if (!refs || !clientRequire) return;\n\n await Promise.all(\n Object.keys(refs).map((id) =>\n clientRequire(id).catch((error) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n }),\n ),\n );\n\n clientRefsPreloaded = true;\n}\n\nfunction ssrErrorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return Object.prototype.toString.call(error);\n}\n\nfunction renderInsertedHtml(insertedElements: readonly unknown[]): string {\n let insertedHTML = \"\";\n\n for (const element of insertedElements) {\n try {\n insertedHTML += renderToStaticMarkup(\n createReactElement(Fragment, null, element as ReactNode),\n );\n } catch {\n // Ignore individual callback failures so the rest of the page can render.\n }\n }\n\n return insertedHTML;\n}\n\nfunction renderFontHtml(fontData?: FontData, nonce?: string): string {\n if (!fontData) return \"\";\n\n let fontHTML = \"\";\n const nonceAttr = createNonceAttribute(nonce);\n\n for (const url of fontData.links ?? []) {\n fontHTML += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(url)}\" />\\n`;\n }\n\n for (const preload of fontData.preloads ?? []) {\n fontHTML += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n`;\n }\n\n if (fontData.styles && fontData.styles.length > 0) {\n fontHTML += `<style data-vinext-fonts${nonceAttr}>${fontData.styles.join(\"\\n\")}</style>\\n`;\n }\n\n return fontHTML;\n}\n\nfunction extractModulePreloadHtml(bootstrapScriptContent?: string, nonce?: string): string {\n if (!bootstrapScriptContent) return \"\";\n\n const match = bootstrapScriptContent.match(/import\\(\"([^\"]+)\"\\)/);\n if (!match?.[1]) return \"\";\n\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(match[1])}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapScriptContent: string | undefined,\n insertedHTML: string,\n fontHTML: string,\n scriptNonce?: string,\n): string {\n const paramsScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_PARAMS__=\" + safeJsonStringify(navContext?.params ?? {}),\n scriptNonce,\n );\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const navScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_NAV__=\" + safeJsonStringify(navPayload),\n scriptNonce,\n );\n\n return (\n paramsScript +\n navScript +\n extractModulePreloadHtml(bootstrapScriptContent, scriptNonce) +\n insertedHTML +\n fontHTML\n );\n}\n\nexport async function handleSsr(\n rscStream: ReadableStream<Uint8Array>,\n navContext: NavigationContext | null,\n fontData?: FontData,\n options?: { scriptNonce?: string },\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await preloadClientReferences();\n\n if (navContext) {\n setNavigationContext(navContext);\n }\n\n clearServerInsertedHTML();\n\n try {\n const [ssrStream, embedStream] = rscStream.tee();\n const rscEmbed = createRscEmbedTransform(embedStream, options?.scriptNonce);\n\n let flightRoot: PromiseLike<AppWireElements> | null = null;\n\n function VinextFlightRoot(): ReactNode {\n if (!flightRoot) {\n flightRoot = createFromReadableStream<AppWireElements>(ssrStream);\n }\n const wireElements = use(flightRoot);\n const elements = normalizeAppElements(wireElements);\n const metadata = readAppElementsMetadata(elements);\n return createReactElement(\n ElementsContext.Provider,\n { value: elements },\n createReactElement(Slot, { id: metadata.routeId }),\n );\n }\n\n const root = createReactElement(VinextFlightRoot);\n const ssrTree = ServerInsertedHTMLContext\n ? createReactElement(\n ServerInsertedHTMLContext.Provider,\n { value: useServerInsertedHTML },\n root,\n )\n : root;\n const ssrRoot = withScriptNonce(ssrTree, options?.scriptNonce);\n\n const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\"index\");\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n bootstrapScriptContent,\n nonce: options?.scriptNonce,\n onError(error) {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n return String(error.digest);\n }\n\n if (process.env.NODE_ENV === \"production\" && error) {\n const message = getErrorMessage(error);\n const stack = error instanceof Error ? (error.stack ?? \"\") : \"\";\n return ssrErrorDigest(message + stack);\n }\n\n return undefined;\n },\n });\n\n const insertedHTML = renderInsertedHtml(flushServerInsertedHTML());\n const fontHTML = renderFontHtml(fontData, options?.scriptNonce);\n const injectHTML = buildHeadInjectionHtml(\n navContext,\n bootstrapScriptContent,\n insertedHTML,\n fontHTML,\n options?.scriptNonce,\n );\n\n return htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, injectHTML));\n } finally {\n setNavigationContext(null);\n clearServerInsertedHTML();\n }\n }) as Promise<ReadableStream<Uint8Array>>;\n}\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n // Block protocol-relative URL open redirects (including percent-encoded\n // variants like /%5Cevil.com/). See request-pipeline.ts for details.\n if (isOpenRedirectShaped(url.pathname)) {\n return new Response(\"404 Not Found\", { status: 404 });\n }\n\n const rscModule = await import.meta.viteRsc.loadModule<{\n default(request: Request): Promise<Response | string | null | undefined>;\n }>(\"rsc\", \"index\");\n const result = await rscModule.default(request);\n\n if (result instanceof Response) {\n return result;\n }\n\n if (result == null) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport type { ReactNode } from \"react\";\nimport { Fragment, createElement as createReactElement, use } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport * as clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"vinext/shims/navigation\";\nimport {\n ServerInsertedHTMLContext,\n clearServerInsertedHTML,\n renderServerInsertedHTML,\n setNavigationContext,\n useServerInsertedHTML,\n} from \"vinext/shims/navigation\";\nimport { runWithNavigationContext } from \"vinext/shims/navigation-state\";\nimport { isOpenRedirectShaped } from \"./request-pipeline.js\";\nimport { withScriptNonce } from \"vinext/shims/script-nonce-context\";\nimport {\n createInlineScriptTag,\n createNonceAttribute,\n escapeHtmlAttr,\n safeJsonStringify,\n} from \"./html.js\";\nimport { createRscEmbedTransform, createTickBufferedTransform } from \"./app-ssr-stream.js\";\nimport { deferUntilStreamConsumed } from \"./app-page-stream.js\";\nimport {\n normalizeAppElements,\n readAppElementsMetadata,\n type AppWireElements,\n} from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"vinext/shims/slot\";\n\nexport type FontPreload = {\n href: string;\n type: string;\n};\n\nexport type FontData = {\n links?: string[];\n styles?: string[];\n preloads?: FontPreload[];\n};\n\ntype ClientRequire = (id: string) => Promise<unknown>;\n\nlet clientRefsPreloaded = false;\n\nfunction getClientReferenceRequire(): ClientRequire | undefined {\n return (\n globalThis as typeof globalThis & {\n __vite_rsc_client_require__?: ClientRequire;\n }\n ).__vite_rsc_client_require__;\n}\n\nasync function preloadClientReferences(): Promise<void> {\n if (clientRefsPreloaded) return;\n\n const refs = (clientReferences as { default?: Record<string, unknown> }).default;\n const clientRequire = getClientReferenceRequire();\n if (!refs || !clientRequire) return;\n\n await Promise.all(\n Object.keys(refs).map((id) =>\n clientRequire(id).catch((error) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n }),\n ),\n );\n\n clientRefsPreloaded = true;\n}\n\nfunction ssrErrorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return Object.prototype.toString.call(error);\n}\n\nfunction renderInsertedHtml(insertedElements: readonly unknown[]): string {\n let insertedHTML = \"\";\n\n for (const element of insertedElements) {\n try {\n insertedHTML += renderToStaticMarkup(\n createReactElement(Fragment, null, element as ReactNode),\n );\n } catch {\n // Ignore individual callback failures so the rest of the page can render.\n }\n }\n\n return insertedHTML;\n}\n\nfunction renderFontHtml(fontData?: FontData, nonce?: string): string {\n if (!fontData) return \"\";\n\n let fontHTML = \"\";\n const nonceAttr = createNonceAttribute(nonce);\n\n for (const url of fontData.links ?? []) {\n fontHTML += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(url)}\" />\\n`;\n }\n\n for (const preload of fontData.preloads ?? []) {\n fontHTML += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n`;\n }\n\n if (fontData.styles && fontData.styles.length > 0) {\n fontHTML += `<style data-vinext-fonts${nonceAttr}>${fontData.styles.join(\"\\n\")}</style>\\n`;\n }\n\n return fontHTML;\n}\n\nfunction extractModulePreloadHtml(bootstrapScriptContent?: string, nonce?: string): string {\n if (!bootstrapScriptContent) return \"\";\n\n const match = bootstrapScriptContent.match(/import\\(\"([^\"]+)\"\\)/);\n if (!match?.[1]) return \"\";\n\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(match[1])}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapScriptContent: string | undefined,\n insertedHTML: string,\n fontHTML: string,\n scriptNonce?: string,\n): string {\n const paramsScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_PARAMS__=\" + safeJsonStringify(navContext?.params ?? {}),\n scriptNonce,\n );\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const navScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_NAV__=\" + safeJsonStringify(navPayload),\n scriptNonce,\n );\n\n return (\n paramsScript +\n navScript +\n extractModulePreloadHtml(bootstrapScriptContent, scriptNonce) +\n insertedHTML +\n fontHTML\n );\n}\n\nexport async function handleSsr(\n rscStream: ReadableStream<Uint8Array>,\n navContext: NavigationContext | null,\n fontData?: FontData,\n options?: {\n scriptNonce?: string;\n /** Pre-split side stream for embed+capture fusion. When provided,\n * rscStream is fed directly to createFromReadableStream (no internal tee).\n * The embed transform accumulates raw bytes. */\n sideStream?: ReadableStream<Uint8Array>;\n /** Out-parameter: filled with accumulated raw RSC bytes when sideStream is consumed. */\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n },\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await preloadClientReferences();\n\n if (navContext) {\n setNavigationContext(navContext);\n }\n\n clearServerInsertedHTML();\n\n const cleanup = (): void => {\n setNavigationContext(null);\n clearServerInsertedHTML();\n };\n\n try {\n // Fused tee path (#981): caller pre-split the stream. No internal tee needed.\n // sideStream carries both the embed transform and raw byte accumulation.\n // rscStream is used directly for createFromReadableStream (SSR).\n let ssrStream: ReadableStream<Uint8Array>;\n let rscEmbed;\n\n if (options?.sideStream) {\n ssrStream = rscStream;\n rscEmbed = createRscEmbedTransform(options.sideStream, options?.scriptNonce);\n if (options.capturedRscDataRef) {\n options.capturedRscDataRef.value = rscEmbed.getRawBuffer();\n }\n } else {\n const [s1, s2] = rscStream.tee();\n ssrStream = s1;\n rscEmbed = createRscEmbedTransform(s2, options?.scriptNonce);\n }\n\n let flightRoot: PromiseLike<AppWireElements> | null = null;\n\n function VinextFlightRoot(): ReactNode {\n if (!flightRoot) {\n flightRoot = createFromReadableStream<AppWireElements>(ssrStream);\n }\n const wireElements = use(flightRoot);\n const elements = normalizeAppElements(wireElements);\n const metadata = readAppElementsMetadata(elements);\n return createReactElement(\n ElementsContext.Provider,\n { value: elements },\n createReactElement(Slot, { id: metadata.routeId }),\n );\n }\n\n const root = createReactElement(VinextFlightRoot);\n const ssrTree = ServerInsertedHTMLContext\n ? createReactElement(\n ServerInsertedHTMLContext.Provider,\n { value: useServerInsertedHTML },\n root,\n )\n : root;\n const ssrRoot = withScriptNonce(ssrTree, options?.scriptNonce);\n\n const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\"index\");\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n bootstrapScriptContent,\n nonce: options?.scriptNonce,\n onError(error) {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n return String(error.digest);\n }\n\n if (process.env.NODE_ENV === \"production\" && error) {\n const message = getErrorMessage(error);\n const stack = error instanceof Error ? (error.stack ?? \"\") : \"\";\n return ssrErrorDigest(message + stack);\n }\n\n return undefined;\n },\n });\n\n const fontHTML = renderFontHtml(fontData, options?.scriptNonce);\n let didInjectHeadHTML = false;\n const getInsertedHTML = (): string => {\n const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());\n if (didInjectHeadHTML) return insertedHTML;\n\n didInjectHeadHTML = true;\n return buildHeadInjectionHtml(\n navContext,\n bootstrapScriptContent,\n insertedHTML,\n fontHTML,\n options?.scriptNonce,\n );\n };\n\n return deferUntilStreamConsumed(\n htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, getInsertedHTML)),\n cleanup,\n );\n } catch (error) {\n cleanup();\n throw error;\n }\n }) as Promise<ReadableStream<Uint8Array>>;\n}\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n // Block protocol-relative URL open redirects (including percent-encoded\n // variants like /%5Cevil.com/). See request-pipeline.ts for details.\n if (isOpenRedirectShaped(url.pathname)) {\n return new Response(\"404 Not Found\", { status: 404 });\n }\n\n const rscModule = await import.meta.viteRsc.loadModule<{\n default(request: Request): Promise<Response | string | null | undefined>;\n }>(\"rsc\", \"index\");\n const result = await rscModule.default(request);\n\n if (result instanceof Response) {\n return result;\n }\n\n if (result == null) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
//#region src/server/app-ssr-stream.d.ts
|
|
2
2
|
type RscEmbedTransform = {
|
|
3
3
|
flush(): string;
|
|
4
|
-
finalize(): Promise<string>;
|
|
4
|
+
finalize(): Promise<string>; /** Resolves when all raw bytes from the embed stream have been read. */
|
|
5
|
+
getRawBuffer(): Promise<ArrayBuffer>;
|
|
5
6
|
};
|
|
7
|
+
type HtmlInsertion = string | (() => string);
|
|
6
8
|
/**
|
|
7
9
|
* Fix invalid preload "as" values in RSC Flight hint lines before they reach
|
|
8
10
|
* the client. React Flight emits HL hints with as="stylesheet" for CSS, but
|
|
@@ -24,7 +26,7 @@ declare function fixPreloadAs(html: string): string;
|
|
|
24
26
|
* Create the tick-buffered HTML transform that injects RSC scripts between
|
|
25
27
|
* React Fizz flush cycles without corrupting split HTML chunks.
|
|
26
28
|
*/
|
|
27
|
-
declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?:
|
|
29
|
+
declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?: HtmlInsertion): TransformStream<Uint8Array, Uint8Array>;
|
|
28
30
|
//#endregion
|
|
29
|
-
export {
|
|
31
|
+
export { createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs };
|
|
30
32
|
//# sourceMappingURL=app-ssr-stream.d.ts.map
|