@reckona/mreact-router 0.0.181 → 0.0.182
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/actions.d.ts.map +1 -1
- package/dist/actions.js +20 -8
- package/dist/actions.js.map +1 -1
- package/dist/built-assets.d.ts.map +1 -1
- package/dist/built-assets.js +2 -2
- package/dist/built-assets.js.map +1 -1
- package/dist/cache-config.d.ts +1 -1
- package/dist/cache-config.d.ts.map +1 -1
- package/dist/cache-config.js.map +1 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +18 -1
- package/dist/cache.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +16 -6
- package/dist/client.js.map +1 -1
- package/dist/csrf.js +10 -6
- package/dist/csrf.js.map +1 -1
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +14 -1
- package/dist/navigation.js.map +1 -1
- package/dist/render.d.ts +2 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +81 -38
- package/dist/render.js.map +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +5 -3
- package/dist/vite.js.map +1 -1
- package/package.json +11 -11
- package/src/actions.ts +26 -9
- package/src/built-assets.ts +2 -3
- package/src/cache-config.ts +1 -0
- package/src/cache.ts +20 -1
- package/src/client.ts +16 -6
- package/src/csrf.ts +13 -6
- package/src/navigation.ts +16 -1
- package/src/render.ts +168 -70
- package/src/vite.ts +6 -3
package/dist/csrf.js
CHANGED
|
@@ -6,14 +6,14 @@ const formFieldCsrf = "__mreact_csrf";
|
|
|
6
6
|
*/
|
|
7
7
|
export const formCsrfFieldName = formFieldCsrf;
|
|
8
8
|
export function serverActionCookie(csrfToken) {
|
|
9
|
-
const
|
|
9
|
+
const secure = shouldUseSecureCsrfCookie();
|
|
10
10
|
const parts = [
|
|
11
11
|
`${currentCsrfCookieName()}=${encodeURIComponent(csrfToken)}`,
|
|
12
12
|
"Path=/",
|
|
13
13
|
"SameSite=Lax",
|
|
14
14
|
"HttpOnly",
|
|
15
15
|
];
|
|
16
|
-
if (
|
|
16
|
+
if (secure) {
|
|
17
17
|
parts.push("Secure");
|
|
18
18
|
}
|
|
19
19
|
return parts.join("; ");
|
|
@@ -77,14 +77,18 @@ function randomToken() {
|
|
|
77
77
|
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
|
|
78
78
|
return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
|
|
79
79
|
}
|
|
80
|
-
function
|
|
81
|
-
return typeof process !== "undefined" &&
|
|
80
|
+
function isLocalCsrfEnvironment() {
|
|
81
|
+
return (typeof process !== "undefined" &&
|
|
82
|
+
(process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test"));
|
|
83
|
+
}
|
|
84
|
+
function shouldUseSecureCsrfCookie() {
|
|
85
|
+
return !isLocalCsrfEnvironment();
|
|
82
86
|
}
|
|
83
87
|
function currentCsrfCookieName() {
|
|
84
|
-
return
|
|
88
|
+
return shouldUseSecureCsrfCookie() ? csrfCookieNameProduction : csrfCookieNameDevelopment;
|
|
85
89
|
}
|
|
86
90
|
function csrfCookieNamesRead() {
|
|
87
|
-
return
|
|
91
|
+
return shouldUseSecureCsrfCookie()
|
|
88
92
|
? [csrfCookieNameProduction]
|
|
89
93
|
: [csrfCookieNameProduction, csrfCookieNameDevelopment];
|
|
90
94
|
}
|
package/dist/csrf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"AAAA,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AACtD,MAAM,yBAAyB,GAAG,aAAa,CAAC;AAChD,MAAM,aAAa,GAAG,eAAe,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,MAAM,
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../src/csrf.ts"],"names":[],"mappings":"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","sourcesContent":["const csrfCookieNameProduction = \"__Host-mreact.csrf\";\nconst csrfCookieNameDevelopment = \"mreact.csrf\";\nconst formFieldCsrf = \"__mreact_csrf\";\n\n/**\n * Names the hidden form field used for app-router CSRF validation.\n */\nexport const formCsrfFieldName = formFieldCsrf;\n\nexport function serverActionCookie(csrfToken: string): string {\n const secure = shouldUseSecureCsrfCookie();\n const parts = [\n `${currentCsrfCookieName()}=${encodeURIComponent(csrfToken)}`,\n \"Path=/\",\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n\n if (secure) {\n parts.push(\"Secure\");\n }\n\n return parts.join(\"; \");\n}\n\nexport function serverActionCookieName(): string {\n return currentCsrfCookieName();\n}\n\n/**\n * Creates or reuses the CSRF token embedded into server-rendered forms.\n */\nexport function createFormCsrfToken(request?: Request | undefined): string {\n return readExistingFormCsrfToken(request) ?? randomToken();\n}\n\n/**\n * Serializes the CSRF cookie used to validate app-router form submissions.\n */\nexport function formCsrfCookie(csrfToken: string): string {\n return serverActionCookie(csrfToken);\n}\n\n/**\n * Validates the CSRF cookie and hidden form field for a form submission.\n */\nexport function validateFormCsrf(request: Request, formData: FormData): Response | undefined {\n const formToken = stringFormValue(formData.get(formFieldCsrf));\n const cookieHeader = request.headers.get(\"cookie\");\n const cookieToken = csrfCookieNamesRead()\n .map((name) => readCookie(cookieHeader, name))\n .find((token) => token !== undefined);\n\n if (formToken === undefined || cookieToken === undefined) {\n return jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n }\n\n return timingSafeStringEqual(formToken, cookieToken)\n ? undefined\n : jsonResponse({ ok: false, error: \"Invalid CSRF token.\" }, 403);\n}\n\nexport function readExistingFormCsrfToken(request: Request | undefined): string | undefined {\n const cookieHeader = request?.headers.get(\"cookie\") ?? null;\n\n for (const name of csrfCookieNamesRead()) {\n const token = readCookie(cookieHeader, name);\n\n if (token !== undefined && isCsrfTokenShape(token)) {\n return token;\n }\n }\n\n return undefined;\n}\n\nfunction isCsrfTokenShape(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);\n}\n\nfunction randomToken(): string {\n const cryptoApi = globalThis.crypto;\n\n if (typeof cryptoApi?.randomUUID === \"function\") {\n return cryptoApi.randomUUID();\n }\n\n if (typeof cryptoApi?.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto is required to create a CSRF token.\");\n }\n\n const bytes = new Uint8Array(16);\n cryptoApi.getRandomValues(bytes);\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n return `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10).join(\"\")}`;\n}\n\nfunction isLocalCsrfEnvironment(): boolean {\n return (\n typeof process !== \"undefined\" &&\n (process.env?.NODE_ENV === \"development\" || process.env?.NODE_ENV === \"test\")\n );\n}\n\nfunction shouldUseSecureCsrfCookie(): boolean {\n return !isLocalCsrfEnvironment();\n}\n\nfunction currentCsrfCookieName(): string {\n return shouldUseSecureCsrfCookie() ? csrfCookieNameProduction : csrfCookieNameDevelopment;\n}\n\nfunction csrfCookieNamesRead(): readonly string[] {\n return shouldUseSecureCsrfCookie()\n ? [csrfCookieNameProduction]\n : [csrfCookieNameProduction, csrfCookieNameDevelopment];\n}\n\nfunction timingSafeStringEqual(left: string, right: string): boolean {\n let diff = left.length ^ right.length;\n const length = Math.max(left.length, right.length);\n\n for (let index = 0; index < length; index += 1) {\n diff |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);\n }\n\n return diff === 0;\n}\n\nfunction stringFormValue(value: FormDataEntryValue | null): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readCookie(cookieHeader: string | null, name: string): string | undefined {\n if (cookieHeader === null || cookieHeader.trim() === \"\") {\n return undefined;\n }\n\n for (const part of cookieHeader.split(\";\")) {\n const [rawName, ...rawValue] = part.trim().split(\"=\");\n\n if (rawName !== name) {\n continue;\n }\n\n try {\n return decodeURIComponent(rawValue.join(\"=\"));\n } catch {\n return rawValue.join(\"=\");\n }\n }\n\n return undefined;\n}\n\nfunction jsonResponse(payload: unknown, status: number): Response {\n return Response.json(payload, { status });\n}\n"]}
|
package/dist/navigation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACtC;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACtC;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC;CAC3B;AA+DD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,KAAK,CAS/E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAoB,GAC5B,KAAK,CASP;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAa/E;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAY1F;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AACrE,wBAAsB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAUzF;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAKhC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,KAAK,CAErC;AAED;;GAEG;AACH,wBAAgB,IAAI,IAAI,cAAc,CAErC;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAiB3E;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAElE;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAkBrE;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEjD;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,CAYxD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAOtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAIrG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEvD"}
|
package/dist/navigation.js
CHANGED
|
@@ -13,11 +13,22 @@ function stripLeadingControlOrWhitespace(value) {
|
|
|
13
13
|
}
|
|
14
14
|
return value.slice(start);
|
|
15
15
|
}
|
|
16
|
+
function containsControlCharacter(value) {
|
|
17
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
18
|
+
const code = value.charCodeAt(index);
|
|
19
|
+
if (code <= 0x1f || code === 0x7f) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
16
25
|
// Returns true if `location` is safe to use as a same-origin Location header.
|
|
17
26
|
// Allowed: path-absolute (`/foo`), query-only (`?x=1`), hash-only (`#x`),
|
|
18
27
|
// relative (`foo`). Rejected: protocol-relative (`//evil`), backslash variants
|
|
19
28
|
// (`/\evil`, `\\evil`), and anything with a scheme like `javascript:`.
|
|
20
29
|
function isSafeInternalRedirect(location) {
|
|
30
|
+
if (containsControlCharacter(location))
|
|
31
|
+
return false;
|
|
21
32
|
const trimmed = stripLeadingControlOrWhitespace(location);
|
|
22
33
|
if (trimmed === "")
|
|
23
34
|
return false;
|
|
@@ -33,6 +44,8 @@ function isSafeInternalRedirect(location) {
|
|
|
33
44
|
return true;
|
|
34
45
|
}
|
|
35
46
|
function isSafeExternalRedirect(location) {
|
|
47
|
+
if (containsControlCharacter(location))
|
|
48
|
+
return false;
|
|
36
49
|
const trimmed = stripLeadingControlOrWhitespace(location);
|
|
37
50
|
const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);
|
|
38
51
|
if (match === null || match[1] === undefined)
|
|
@@ -44,7 +57,7 @@ function throwUnsafeRedirect(location) {
|
|
|
44
57
|
throw new TypeError(`unsafe redirect target: ${JSON.stringify(location)} - use redirectExternal() for off-site destinations and ensure the URL is http(s)`);
|
|
45
58
|
}
|
|
46
59
|
function throwUnsafeRewrite(location) {
|
|
47
|
-
throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);
|
|
60
|
+
throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)} - rewrite() only accepts same-origin paths, query strings, or hashes; external, protocol-relative, backslash, and control-character targets are rejected`);
|
|
48
61
|
}
|
|
49
62
|
/**
|
|
50
63
|
* Throws an internal redirect for loaders, middleware, route handlers, or server actions.
|
package/dist/navigation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseCookieHeader } from \"./cookies.js\";\n\nconst redirectErrorName = \"MReactRedirect\";\nconst notFoundErrorName = \"MReactNotFound\";\nconst rewriteHeaderName = \"x-mreact-rewrite\";\nconst rewriteLocationSymbol = Symbol.for(\"mreact.router.rewriteLocation\");\n\nexport interface RedirectOptions {\n status?: 301 | 302 | 303 | 307 | 308;\n}\n\nexport type MiddlewareNext = undefined;\n\n/**\n * Describes a parser used by `parseForm()` to validate submitted form data.\n */\nexport interface ParseSchema<T> {\n parse(value: FormData): T;\n}\n\n// Strip leading C0 controls + ASCII whitespace per WHATWG URL parsing.\n// Browsers ignore these characters when resolving the Location header,\n// so attacker payloads must be rejected after the same normalization.\nfunction stripLeadingControlOrWhitespace(value: string): string {\n let start = 0;\n\n while (start < value.length && value.charCodeAt(start) <= 0x20) {\n start += 1;\n }\n\n return value.slice(start);\n}\n\n// Returns true if `location` is safe to use as a same-origin Location header.\n// Allowed: path-absolute (`/foo`), query-only (`?x=1`), hash-only (`#x`),\n// relative (`foo`). Rejected: protocol-relative (`//evil`), backslash variants\n// (`/\\evil`, `\\\\evil`), and anything with a scheme like `javascript:`.\nfunction isSafeInternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n if (trimmed === \"\") return false;\n if (trimmed.startsWith(\"//\")) return false;\n if (trimmed.startsWith(\"/\\\\\")) return false;\n if (trimmed.startsWith(\"\\\\\")) return false;\n // Reject anything that parses as a URL with a scheme.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;\n return true;\n}\n\nfunction isSafeExternalRedirect(location: string): boolean {\n const trimmed = stripLeadingControlOrWhitespace(location);\n const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);\n if (match === null || match[1] === undefined) return false;\n const scheme = match[1].toLowerCase();\n return scheme === \"http\" || scheme === \"https\";\n}\n\nfunction throwUnsafeRedirect(location: string): never {\n throw new TypeError(\n `unsafe redirect target: ${JSON.stringify(location)} - use redirectExternal() for off-site destinations and ensure the URL is http(s)`,\n );\n}\n\nfunction throwUnsafeRewrite(location: string): never {\n throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);\n}\n\n/**\n * Throws an internal redirect for loaders, middleware, route handlers, or server actions.\n *\n * The target must be same-origin or relative; use `redirectExternal()` for trusted `http` or `https` destinations. The default status is `303`.\n */\nexport function redirect(location: string, options: RedirectOptions = {}): never {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 303,\n });\n}\n\n/**\n * Throws an external redirect for trusted `http` or `https` destinations.\n *\n * This helper is intentionally separate from `redirect()` so off-site navigation is explicit. The default status is `307`.\n */\nexport function redirectExternal(\n location: string,\n options: RedirectOptions = {},\n): never {\n if (!isSafeExternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 307,\n });\n}\n\n/**\n * Creates a same-origin `303 See Other` redirect response.\n *\n * Use this from route handlers when returning a `Response` is more convenient than throwing through the app-router control flow.\n */\nexport function redirect303(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n\n const headers = new Headers(init.headers);\n headers.set(\"location\", location);\n\n return new Response(null, {\n ...init,\n headers,\n status: 303,\n });\n}\n\n/**\n * Creates a plain-text error response with a default `text/plain` content type.\n */\nexport function textError(message: string, status = 400, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/plain; charset=utf-8\");\n }\n\n return new Response(message, {\n ...init,\n headers,\n status,\n });\n}\n\n/**\n * Reads `request.formData()` and optionally validates it with a schema-like parser.\n *\n * Pass a schema object with `parse(FormData)` when a route handler or server action should receive typed form data.\n */\nexport async function parseForm(request: Request): Promise<FormData>;\nexport async function parseForm<T>(request: Request, schema: ParseSchema<T>): Promise<T>;\nexport async function parseForm<T>(\n request: Request,\n schema?: ParseSchema<T>,\n): Promise<FormData | T> {\n const form = await request.formData();\n\n return schema === undefined ? form : schema.parse(form);\n}\n\n/**\n * Throws a route-level 404 control error.\n *\n * Use this from loaders, metadata, middleware, or route handlers when the matched route is valid but the requested resource is absent.\n */\nexport function notFound(): never {\n throw Object.assign(new Error(\"Not Found\"), {\n name: notFoundErrorName,\n status: 404,\n });\n}\n\n/**\n * Alias for `notFound()` for codebases that prefer an explicit throwing helper name.\n */\nexport function throwNotFound(): never {\n return notFound();\n}\n\n/**\n * Continues middleware processing without changing the request.\n */\nexport function next(): MiddlewareNext {\n return undefined;\n}\n\n/**\n * Creates an internal rewrite response consumed by app-router middleware.\n *\n * The target must be a same-origin route path, query, hash, or relative URL; protocol-relative, external, and control-character targets are rejected.\n */\nexport function rewrite(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRewrite(location);\n }\n\n const response = new Response(null, {\n ...init,\n status: init.status ?? 200,\n });\n\n Object.defineProperty(response, rewriteLocationSymbol, {\n configurable: false,\n enumerable: false,\n value: location,\n });\n\n return response;\n}\n\n/**\n * Creates a JSON response using the platform `Response.json()` implementation.\n */\nexport function json(value: unknown, init?: ResponseInit): Response {\n return Response.json(value, init);\n}\n\n/**\n * Creates an HTML response and defaults the content type to `text/html; charset=utf-8`.\n */\nexport function html(value: string, init: ResponseInit = {}): Response {\n if (init.headers === undefined) {\n return new Response(value, {\n ...init,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n }\n\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n return new Response(value, {\n ...init,\n headers,\n });\n}\n\n/**\n * Returns the request headers object for route code that follows app-router helper naming.\n */\nexport function headers(request: Request): Headers {\n return request.headers;\n}\n\nexport interface RequestCookies {\n entries(): IterableIterator<[string, string]>;\n get(name: string): string | undefined;\n has(name: string): boolean;\n}\n\n/**\n * Parses request cookies into a small read-only helper.\n *\n * Values are decoded with `decodeURIComponent`; malformed encoded values are ignored rather than throwing during request handling.\n */\nexport function cookies(request: Request): RequestCookies {\n let values: ReadonlyMap<string, string> | undefined;\n const cookieValues = () => {\n values ??= parseCookieHeader(request.headers.get(\"cookie\"));\n return values;\n };\n\n return {\n entries: () => cookieValues().entries(),\n get: (name) => cookieValues().get(name),\n has: (name) => cookieValues().has(name),\n };\n}\n\nexport function rewriteLocation(response: Response): string | undefined {\n const marked = (response as { [rewriteLocationSymbol]?: unknown })[rewriteLocationSymbol];\n const candidate = typeof marked === \"string\"\n ? marked\n : response.headers.get(rewriteHeaderName) ?? undefined;\n\n return candidate !== undefined && isSafeInternalRedirect(candidate) ? candidate : undefined;\n}\n\n/**\n * Checks whether an unknown error is an app-router redirect signal.\n */\nexport function isRedirectError(error: unknown): error is Error & { location: string; status: number } {\n return error instanceof Error &&\n error.name === redirectErrorName &&\n typeof (error as { location?: unknown }).location === \"string\";\n}\n\n/**\n * Checks whether an unknown error is an app-router not-found signal.\n */\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.name === notFoundErrorName;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseCookieHeader } from \"./cookies.js\";\n\nconst redirectErrorName = \"MReactRedirect\";\nconst notFoundErrorName = \"MReactNotFound\";\nconst rewriteHeaderName = \"x-mreact-rewrite\";\nconst rewriteLocationSymbol = Symbol.for(\"mreact.router.rewriteLocation\");\n\nexport interface RedirectOptions {\n status?: 301 | 302 | 303 | 307 | 308;\n}\n\nexport type MiddlewareNext = undefined;\n\n/**\n * Describes a parser used by `parseForm()` to validate submitted form data.\n */\nexport interface ParseSchema<T> {\n parse(value: FormData): T;\n}\n\n// Strip leading C0 controls + ASCII whitespace per WHATWG URL parsing.\n// Browsers ignore these characters when resolving the Location header,\n// so attacker payloads must be rejected after the same normalization.\nfunction stripLeadingControlOrWhitespace(value: string): string {\n let start = 0;\n\n while (start < value.length && value.charCodeAt(start) <= 0x20) {\n start += 1;\n }\n\n return value.slice(start);\n}\n\nfunction containsControlCharacter(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code <= 0x1f || code === 0x7f) {\n return true;\n }\n }\n\n return false;\n}\n\n// Returns true if `location` is safe to use as a same-origin Location header.\n// Allowed: path-absolute (`/foo`), query-only (`?x=1`), hash-only (`#x`),\n// relative (`foo`). Rejected: protocol-relative (`//evil`), backslash variants\n// (`/\\evil`, `\\\\evil`), and anything with a scheme like `javascript:`.\nfunction isSafeInternalRedirect(location: string): boolean {\n if (containsControlCharacter(location)) return false;\n const trimmed = stripLeadingControlOrWhitespace(location);\n if (trimmed === \"\") return false;\n if (trimmed.startsWith(\"//\")) return false;\n if (trimmed.startsWith(\"/\\\\\")) return false;\n if (trimmed.startsWith(\"\\\\\")) return false;\n // Reject anything that parses as a URL with a scheme.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;\n return true;\n}\n\nfunction isSafeExternalRedirect(location: string): boolean {\n if (containsControlCharacter(location)) return false;\n const trimmed = stripLeadingControlOrWhitespace(location);\n const match = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);\n if (match === null || match[1] === undefined) return false;\n const scheme = match[1].toLowerCase();\n return scheme === \"http\" || scheme === \"https\";\n}\n\nfunction throwUnsafeRedirect(location: string): never {\n throw new TypeError(\n `unsafe redirect target: ${JSON.stringify(location)} - use redirectExternal() for off-site destinations and ensure the URL is http(s)`,\n );\n}\n\nfunction throwUnsafeRewrite(location: string): never {\n throw new TypeError(\n `unsafe rewrite target: ${JSON.stringify(location)} - rewrite() only accepts same-origin paths, query strings, or hashes; external, protocol-relative, backslash, and control-character targets are rejected`,\n );\n}\n\n/**\n * Throws an internal redirect for loaders, middleware, route handlers, or server actions.\n *\n * The target must be same-origin or relative; use `redirectExternal()` for trusted `http` or `https` destinations. The default status is `303`.\n */\nexport function redirect(location: string, options: RedirectOptions = {}): never {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 303,\n });\n}\n\n/**\n * Throws an external redirect for trusted `http` or `https` destinations.\n *\n * This helper is intentionally separate from `redirect()` so off-site navigation is explicit. The default status is `307`.\n */\nexport function redirectExternal(\n location: string,\n options: RedirectOptions = {},\n): never {\n if (!isSafeExternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n throw Object.assign(new Error(`Redirect to ${location}`), {\n location,\n name: redirectErrorName,\n status: options.status ?? 307,\n });\n}\n\n/**\n * Creates a same-origin `303 See Other` redirect response.\n *\n * Use this from route handlers when returning a `Response` is more convenient than throwing through the app-router control flow.\n */\nexport function redirect303(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRedirect(location);\n }\n\n const headers = new Headers(init.headers);\n headers.set(\"location\", location);\n\n return new Response(null, {\n ...init,\n headers,\n status: 303,\n });\n}\n\n/**\n * Creates a plain-text error response with a default `text/plain` content type.\n */\nexport function textError(message: string, status = 400, init: ResponseInit = {}): Response {\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/plain; charset=utf-8\");\n }\n\n return new Response(message, {\n ...init,\n headers,\n status,\n });\n}\n\n/**\n * Reads `request.formData()` and optionally validates it with a schema-like parser.\n *\n * Pass a schema object with `parse(FormData)` when a route handler or server action should receive typed form data.\n */\nexport async function parseForm(request: Request): Promise<FormData>;\nexport async function parseForm<T>(request: Request, schema: ParseSchema<T>): Promise<T>;\nexport async function parseForm<T>(\n request: Request,\n schema?: ParseSchema<T>,\n): Promise<FormData | T> {\n const form = await request.formData();\n\n return schema === undefined ? form : schema.parse(form);\n}\n\n/**\n * Throws a route-level 404 control error.\n *\n * Use this from loaders, metadata, middleware, or route handlers when the matched route is valid but the requested resource is absent.\n */\nexport function notFound(): never {\n throw Object.assign(new Error(\"Not Found\"), {\n name: notFoundErrorName,\n status: 404,\n });\n}\n\n/**\n * Alias for `notFound()` for codebases that prefer an explicit throwing helper name.\n */\nexport function throwNotFound(): never {\n return notFound();\n}\n\n/**\n * Continues middleware processing without changing the request.\n */\nexport function next(): MiddlewareNext {\n return undefined;\n}\n\n/**\n * Creates an internal rewrite response consumed by app-router middleware.\n *\n * The target must be a same-origin route path, query, hash, or relative URL; protocol-relative, external, and control-character targets are rejected.\n */\nexport function rewrite(location: string, init: ResponseInit = {}): Response {\n if (!isSafeInternalRedirect(location)) {\n throwUnsafeRewrite(location);\n }\n\n const response = new Response(null, {\n ...init,\n status: init.status ?? 200,\n });\n\n Object.defineProperty(response, rewriteLocationSymbol, {\n configurable: false,\n enumerable: false,\n value: location,\n });\n\n return response;\n}\n\n/**\n * Creates a JSON response using the platform `Response.json()` implementation.\n */\nexport function json(value: unknown, init?: ResponseInit): Response {\n return Response.json(value, init);\n}\n\n/**\n * Creates an HTML response and defaults the content type to `text/html; charset=utf-8`.\n */\nexport function html(value: string, init: ResponseInit = {}): Response {\n if (init.headers === undefined) {\n return new Response(value, {\n ...init,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n }\n\n const headers = new Headers(init.headers);\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n return new Response(value, {\n ...init,\n headers,\n });\n}\n\n/**\n * Returns the request headers object for route code that follows app-router helper naming.\n */\nexport function headers(request: Request): Headers {\n return request.headers;\n}\n\nexport interface RequestCookies {\n entries(): IterableIterator<[string, string]>;\n get(name: string): string | undefined;\n has(name: string): boolean;\n}\n\n/**\n * Parses request cookies into a small read-only helper.\n *\n * Values are decoded with `decodeURIComponent`; malformed encoded values are ignored rather than throwing during request handling.\n */\nexport function cookies(request: Request): RequestCookies {\n let values: ReadonlyMap<string, string> | undefined;\n const cookieValues = () => {\n values ??= parseCookieHeader(request.headers.get(\"cookie\"));\n return values;\n };\n\n return {\n entries: () => cookieValues().entries(),\n get: (name) => cookieValues().get(name),\n has: (name) => cookieValues().has(name),\n };\n}\n\nexport function rewriteLocation(response: Response): string | undefined {\n const marked = (response as { [rewriteLocationSymbol]?: unknown })[rewriteLocationSymbol];\n const candidate = typeof marked === \"string\"\n ? marked\n : response.headers.get(rewriteHeaderName) ?? undefined;\n\n return candidate !== undefined && isSafeInternalRedirect(candidate) ? candidate : undefined;\n}\n\n/**\n * Checks whether an unknown error is an app-router redirect signal.\n */\nexport function isRedirectError(error: unknown): error is Error & { location: string; status: number } {\n return error instanceof Error &&\n error.name === redirectErrorName &&\n typeof (error as { location?: unknown }).location === \"string\";\n}\n\n/**\n * Checks whether an unknown error is an app-router not-found signal.\n */\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.name === notFoundErrorName;\n}\n"]}
|
package/dist/render.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export interface RenderAppRequestOptions {
|
|
|
46
46
|
routes?: readonly AppRoute[] | undefined;
|
|
47
47
|
serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
|
|
48
48
|
serverModuleCacheVersion?: string | undefined;
|
|
49
|
+
devServerModuleCacheVersion?: string | undefined;
|
|
49
50
|
dev?: boolean | undefined;
|
|
50
51
|
serverSourceFiles?: ReadonlyMap<string, string> | undefined;
|
|
51
52
|
serverActions?: AppRouterServerActionOptions | undefined;
|
|
@@ -145,6 +146,7 @@ declare function composedRouteMetadataCacheKey(options: {
|
|
|
145
146
|
appDir: string;
|
|
146
147
|
code: string;
|
|
147
148
|
define?: UserConfig["define"] | undefined;
|
|
149
|
+
devServerModuleCacheVersion?: string | undefined;
|
|
148
150
|
filename: string;
|
|
149
151
|
importPolicy?: AppRouterImportPolicy | undefined;
|
|
150
152
|
serverModuleCacheVersion?: string | undefined;
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,gBAAgB,EAChB,eAAe,EAChB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAC;AAS/B,OAAO,EAIL,KAAK,yBAAyB,EAE/B,MAAM,6BAA6B,CAAC;AAUrC,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAIjC,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,KAAK,cAAc,EAMpB,MAAM,YAAY,CAAC;AAWpB,OAAO,EAAqC,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEnG,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACrD,OAAO,KAAK,EAAmC,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAY7F,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAKL,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,EAQL,KAAK,sBAAsB,EAC5B,MAAM,iBAAiB,CAAC;AAqDzB,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,mCAAmC;IAClD,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,yBAAyB,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;IAClE,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAC5D,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC5D,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC/C,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;IAC7B,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACxC,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;IACzC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAC3E,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/render.js
CHANGED
|
@@ -212,6 +212,8 @@ const routeOutOfOrderBoundaryAnalysisCache = new Map();
|
|
|
212
212
|
const routeOutOfOrderBoundaryAnalysisCacheCounters = createRouterRuntimeCacheCounters();
|
|
213
213
|
const routeLoaderModuleCache = new Map();
|
|
214
214
|
const routeLoaderModuleCacheCounters = createRouterRuntimeCacheCounters();
|
|
215
|
+
const routeMetadataModuleCache = new Map();
|
|
216
|
+
const routeMetadataModuleCacheCounters = createRouterRuntimeCacheCounters();
|
|
215
217
|
const middlewareModuleCache = new Map();
|
|
216
218
|
const middlewareModuleCacheCounters = createRouterRuntimeCacheCounters();
|
|
217
219
|
const serverRouteModuleCache = new Map();
|
|
@@ -223,6 +225,7 @@ const maxServerSourceFileCacheEntries = resolveRouterCacheLimit("SERVER_SOURCE_F
|
|
|
223
225
|
const maxRouteSourceAnalysisCacheEntries = resolveRouterCacheLimit("ROUTE_SOURCE_ANALYSIS", 512);
|
|
224
226
|
const maxRouteOutOfOrderBoundaryAnalysisCacheEntries = resolveRouterCacheLimit("ROUTE_OUT_OF_ORDER_BOUNDARY_ANALYSIS", 512);
|
|
225
227
|
const maxRouteLoaderModuleCacheEntries = resolveRouterCacheLimit("ROUTE_LOADER_MODULE", 512);
|
|
228
|
+
const maxRouteMetadataModuleCacheEntries = resolveRouterCacheLimit("ROUTE_METADATA_MODULE", 512);
|
|
226
229
|
const maxMiddlewareModuleCacheEntries = resolveRouterCacheLimit("MIDDLEWARE_MODULE", 64);
|
|
227
230
|
const maxServerRouteModuleCacheEntries = resolveRouterCacheLimit("SERVER_ROUTE_MODULE", 512);
|
|
228
231
|
const maxComposedRouteMetadataCacheEntries = resolveRouterCacheLimit("COMPOSED_ROUTE_METADATA", 512);
|
|
@@ -233,6 +236,7 @@ export function routerRenderRuntimeCacheStats() {
|
|
|
233
236
|
routerRuntimeCacheStat("route-source-analysis", routeSourceAnalysisCache, maxRouteSourceAnalysisCacheEntries, routeSourceAnalysisCacheCounters),
|
|
234
237
|
routerRuntimeCacheStat("route-out-of-order-boundary-analysis", routeOutOfOrderBoundaryAnalysisCache, maxRouteOutOfOrderBoundaryAnalysisCacheEntries, routeOutOfOrderBoundaryAnalysisCacheCounters),
|
|
235
238
|
routerRuntimeCacheStat("route-loader-module", routeLoaderModuleCache, maxRouteLoaderModuleCacheEntries, routeLoaderModuleCacheCounters),
|
|
239
|
+
routerRuntimeCacheStat("route-metadata-module", routeMetadataModuleCache, maxRouteMetadataModuleCacheEntries, routeMetadataModuleCacheCounters),
|
|
236
240
|
routerRuntimeCacheStat("middleware-module", middlewareModuleCache, maxMiddlewareModuleCacheEntries, middlewareModuleCacheCounters),
|
|
237
241
|
routerRuntimeCacheStat("server-route-module", serverRouteModuleCache, maxServerRouteModuleCacheEntries, serverRouteModuleCacheCounters),
|
|
238
242
|
routerRuntimeCacheStat("composed-route-metadata", composedRouteMetadataCache, maxComposedRouteMetadataCacheEntries, composedRouteMetadataCacheCounters),
|
|
@@ -304,9 +308,9 @@ function addRenderTimingPhaseDuration(timing, startedAt, phaseName) {
|
|
|
304
308
|
timing.phases[phaseName] = (timing.phases[phaseName] ?? 0) + logDurationMs(startedAt);
|
|
305
309
|
}
|
|
306
310
|
function routeLoaderMayReturnControlResponse(code) {
|
|
307
|
-
return /\b(?:redirect|redirectExternal|rewrite|notFound|throwNotFound)\s*\(/.test(code) ||
|
|
311
|
+
return (/\b(?:redirect|redirectExternal|rewrite|notFound|throwNotFound)\s*\(/.test(code) ||
|
|
308
312
|
/\bnew\s+Response\s*\(/.test(code) ||
|
|
309
|
-
/\bResponse\.(?:redirect|json)\s*\(/.test(code);
|
|
313
|
+
/\bResponse\.(?:redirect|json)\s*\(/.test(code));
|
|
310
314
|
}
|
|
311
315
|
async function waitForRenderPreload(options, timing) {
|
|
312
316
|
if (options.preload?.wait !== "before-render") {
|
|
@@ -368,7 +372,9 @@ async function renderAppRequestInternal(options) {
|
|
|
368
372
|
finishRenderTimingPhase(timing, phaseStartedAt, "routeScanMs");
|
|
369
373
|
const url = options.requestUrl ?? new URL(options.request.url);
|
|
370
374
|
phaseStartedAt = renderTimingPhaseStartedAt(timing);
|
|
371
|
-
const matched = options.matchedRoute ??
|
|
375
|
+
const matched = options.matchedRoute ??
|
|
376
|
+
options.routeMatcher?.match(url.pathname) ??
|
|
377
|
+
matchRoute(routes, url.pathname);
|
|
372
378
|
finishRenderTimingPhase(timing, phaseStartedAt, "routeMatchMs");
|
|
373
379
|
const hasMiddleware = options.skipMiddleware === true
|
|
374
380
|
? false
|
|
@@ -675,7 +681,7 @@ async function renderAppRequestInternal(options) {
|
|
|
675
681
|
params: matched.params,
|
|
676
682
|
queryClient,
|
|
677
683
|
request: options.request,
|
|
678
|
-
}, matched.route.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, undefined, options.importPolicy));
|
|
684
|
+
}, matched.route.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, undefined, options.importPolicy, options.devServerModuleCacheVersion));
|
|
679
685
|
const pageHtml = renderedPage.html;
|
|
680
686
|
const pageHtmlForLayout = clientRoute
|
|
681
687
|
? withHydrationMarkers({
|
|
@@ -728,6 +734,7 @@ async function renderAppRequestInternal(options) {
|
|
|
728
734
|
routes,
|
|
729
735
|
serverModules: options.serverModules,
|
|
730
736
|
serverModuleCacheVersion: options.serverModuleCacheVersion,
|
|
737
|
+
devServerModuleCacheVersion: options.devServerModuleCacheVersion,
|
|
731
738
|
serverSourceFiles: options.serverSourceFiles,
|
|
732
739
|
define: options.define,
|
|
733
740
|
vitePlugins: options.vitePlugins,
|
|
@@ -908,7 +915,7 @@ async function renderAppRequestInternal(options) {
|
|
|
908
915
|
params: matched.params,
|
|
909
916
|
queryClient,
|
|
910
917
|
request: options.request,
|
|
911
|
-
}, matched.route.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, timing, options.importPolicy));
|
|
918
|
+
}, matched.route.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, timing, options.importPolicy, options.devServerModuleCacheVersion));
|
|
912
919
|
finishRenderTimingPhase(timing, phaseStartedAt, "pageRenderMs");
|
|
913
920
|
const pageHtml = renderedPage.html;
|
|
914
921
|
// Wrap the page (not the full document) with the hydration marker so
|
|
@@ -969,6 +976,7 @@ async function renderAppRequestInternal(options) {
|
|
|
969
976
|
routes,
|
|
970
977
|
serverModules: options.serverModules,
|
|
971
978
|
serverModuleCacheVersion: options.serverModuleCacheVersion,
|
|
979
|
+
devServerModuleCacheVersion: options.devServerModuleCacheVersion,
|
|
972
980
|
serverSourceFiles: options.serverSourceFiles,
|
|
973
981
|
define: options.define,
|
|
974
982
|
vitePlugins: options.vitePlugins,
|
|
@@ -1897,9 +1905,9 @@ async function runServerModule(code, props, sourcefile, serverModules, serverMod
|
|
|
1897
1905
|
async function renderServerComponentResult(value) {
|
|
1898
1906
|
return typeof value === "string" ? value : renderReactNodeToString(value);
|
|
1899
1907
|
}
|
|
1900
|
-
async function runServerModuleWithSlots(code, props, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, timing, importPolicy) {
|
|
1908
|
+
async function runServerModuleWithSlots(code, props, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, timing, importPolicy, devServerModuleCacheVersion) {
|
|
1901
1909
|
const moduleLoadStartedAt = renderTimingPhaseStartedAt(timing);
|
|
1902
|
-
const module = await loadServerModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy);
|
|
1910
|
+
const module = await loadServerModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy, devServerModuleCacheVersion);
|
|
1903
1911
|
finishRenderTimingPhase(timing, moduleLoadStartedAt, "pageModuleLoadMs");
|
|
1904
1912
|
const component = selectServerComponent(module);
|
|
1905
1913
|
const componentStartedAt = renderTimingPhaseStartedAt(timing);
|
|
@@ -1913,7 +1921,7 @@ async function runServerModuleWithSlots(code, props, sourcefile, serverModules,
|
|
|
1913
1921
|
slots,
|
|
1914
1922
|
};
|
|
1915
1923
|
}
|
|
1916
|
-
async function loadServerModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy) {
|
|
1924
|
+
async function loadServerModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy, devServerModuleCacheVersion) {
|
|
1917
1925
|
const artifact = serverModules?.get(sourcefile)?.string;
|
|
1918
1926
|
const codeHash = memoizedHashText(code);
|
|
1919
1927
|
const prebuiltCode = prebuiltServerComponentModuleCode(artifact, code, codeHash);
|
|
@@ -1927,10 +1935,13 @@ async function loadServerModule(code, sourcefile, serverModules, serverModuleCac
|
|
|
1927
1935
|
serverModuleCacheVersion,
|
|
1928
1936
|
});
|
|
1929
1937
|
}
|
|
1930
|
-
const moduleCode = prebuiltCode === undefined
|
|
1931
|
-
|
|
1938
|
+
const moduleCode = prebuiltCode === undefined
|
|
1939
|
+
? code
|
|
1940
|
+
: rewriteCompatVendorPlaceholderImportsForRunner(prebuiltCode);
|
|
1941
|
+
const sourceModuleCacheVersion = serverModuleCacheVersion ?? devServerModuleCacheVersion;
|
|
1942
|
+
const cacheKey = sourceModuleCacheVersion === undefined
|
|
1932
1943
|
? undefined
|
|
1933
|
-
: `server-component:${serverModuleCacheVersion}:${sourcefile}:${moduleCode === code ? codeHash : memoizedHashText(moduleCode)}:${importPolicyCacheKey(importPolicy)}:${viteDefineCacheKey(define)}:${vitePluginsCacheKey(vitePlugins)}`;
|
|
1944
|
+
: `server-component:${serverModuleCacheVersion === undefined ? "dev" : "build"}:${sourceModuleCacheVersion}:${sourcefile}:${moduleCode === code ? codeHash : memoizedHashText(moduleCode)}:${importPolicyCacheKey(importPolicy)}:${viteDefineCacheKey(define)}:${vitePluginsCacheKey(vitePlugins)}`;
|
|
1934
1945
|
return await importAppRouterSourceModule({
|
|
1935
1946
|
cacheKey,
|
|
1936
1947
|
code: moduleCode,
|
|
@@ -2258,7 +2269,9 @@ async function loadServerStreamModule(code, sourcefile, serverModules, serverMod
|
|
|
2258
2269
|
serverModuleCacheVersion,
|
|
2259
2270
|
});
|
|
2260
2271
|
}
|
|
2261
|
-
const moduleCode = prebuiltCode === undefined
|
|
2272
|
+
const moduleCode = prebuiltCode === undefined
|
|
2273
|
+
? code
|
|
2274
|
+
: rewriteCompatVendorPlaceholderImportsForRunner(prebuiltCode);
|
|
2262
2275
|
const cacheKey = serverModuleCacheVersion === undefined
|
|
2263
2276
|
? undefined
|
|
2264
2277
|
: `server-stream-component:${serverModuleCacheVersion}:${sourcefile}:${moduleCode === code ? codeHash : memoizedHashText(moduleCode)}:${importPolicyCacheKey(importPolicy)}:${viteDefineCacheKey(define)}:${vitePluginsCacheKey(vitePlugins)}`;
|
|
@@ -2524,8 +2537,7 @@ async function shellFilesForPage(appDir, pageFile, serverModuleCacheVersion) {
|
|
|
2524
2537
|
if (devCacheKey !== undefined) {
|
|
2525
2538
|
const directoryStats = await routeShellDirectoryStats(appDir, pageFile);
|
|
2526
2539
|
const cached = devShellFilesCache.get(devCacheKey);
|
|
2527
|
-
if (cached !== undefined &&
|
|
2528
|
-
sameFileStats(cached.directoryStats, directoryStats)) {
|
|
2540
|
+
if (cached !== undefined && sameFileStats(cached.directoryStats, directoryStats)) {
|
|
2529
2541
|
return cached.files;
|
|
2530
2542
|
}
|
|
2531
2543
|
const files = await shellFilesForPageUncached(appDir, pageFile);
|
|
@@ -2587,8 +2599,7 @@ async function hasAppMiddleware(options) {
|
|
|
2587
2599
|
if (cacheKey === undefined) {
|
|
2588
2600
|
const directoryStat = await fileStat(options.appDir);
|
|
2589
2601
|
const cached = devAppMiddlewareFileCache.get(options.appDir);
|
|
2590
|
-
if (cached !== undefined &&
|
|
2591
|
-
sameFileStat(cached.directoryStat, directoryStat)) {
|
|
2602
|
+
if (cached !== undefined && sameFileStat(cached.directoryStat, directoryStat)) {
|
|
2592
2603
|
return cached.hasMiddleware;
|
|
2593
2604
|
}
|
|
2594
2605
|
const hasMiddleware = await hasAppMiddlewareUncached(middlewareFiles);
|
|
@@ -2855,19 +2866,54 @@ async function loadRouteMetadata(options) {
|
|
|
2855
2866
|
});
|
|
2856
2867
|
return await resolveRouteMetadataModule(module, options.context);
|
|
2857
2868
|
}
|
|
2858
|
-
const
|
|
2859
|
-
const module = await importAppRouterSourceModule({
|
|
2860
|
-
...(options.serverModuleCacheVersion === undefined
|
|
2861
|
-
? {}
|
|
2862
|
-
: {
|
|
2863
|
-
cacheKey: `metadata:${options.filename}:${options.serverModuleCacheVersion}:${memoizedHashText(code)}:${viteDefineCacheKey(options.define)}`,
|
|
2864
|
-
}),
|
|
2865
|
-
code,
|
|
2866
|
-
define: options.define,
|
|
2867
|
-
label: `metadata:${options.filename}`,
|
|
2868
|
-
});
|
|
2869
|
+
const module = await loadRouteMetadataModule(options, prebuiltArtifact);
|
|
2869
2870
|
return await resolveRouteMetadataModule(module, options.context);
|
|
2870
2871
|
}
|
|
2872
|
+
async function loadRouteMetadataModule(options, prebuiltArtifact) {
|
|
2873
|
+
if (prebuiltArtifact?.moduleFile !== undefined) {
|
|
2874
|
+
return await importBuiltServerModuleFile({
|
|
2875
|
+
file: prebuiltArtifact.moduleFile,
|
|
2876
|
+
label: `metadata:${options.filename}`,
|
|
2877
|
+
serverModuleCacheVersion: options.serverModuleCacheVersion,
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2880
|
+
const sourceHash = memoizedHashText(options.code);
|
|
2881
|
+
const moduleCacheVersion = options.serverModuleCacheVersion ?? options.devServerModuleCacheVersion;
|
|
2882
|
+
const moduleCacheKey = moduleCacheVersion === undefined
|
|
2883
|
+
? undefined
|
|
2884
|
+
: `metadata-module:${options.serverModuleCacheVersion === undefined ? "dev" : "build"}:${options.filename}:${moduleCacheVersion}:${sourceHash}:${viteDefineCacheKey(options.define)}:${vitePluginsCacheKey(options.vitePlugins)}`;
|
|
2885
|
+
if (moduleCacheKey !== undefined) {
|
|
2886
|
+
const cached = readRouterRuntimeCacheEntry(routeMetadataModuleCache, moduleCacheKey, routeMetadataModuleCacheCounters);
|
|
2887
|
+
if (cached !== undefined) {
|
|
2888
|
+
return await cached;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
const loaded = (async () => {
|
|
2892
|
+
const code = prebuiltArtifact?.code ?? (await bundleRouteMetadataModuleCode(options));
|
|
2893
|
+
return await importAppRouterSourceModule({
|
|
2894
|
+
...(moduleCacheVersion === undefined
|
|
2895
|
+
? {}
|
|
2896
|
+
: {
|
|
2897
|
+
cacheKey: `metadata:${options.serverModuleCacheVersion === undefined ? "dev" : "build"}:${options.filename}:${moduleCacheVersion}:${memoizedHashText(code)}:${viteDefineCacheKey(options.define)}`,
|
|
2898
|
+
}),
|
|
2899
|
+
code,
|
|
2900
|
+
define: options.define,
|
|
2901
|
+
label: `metadata:${options.filename}`,
|
|
2902
|
+
});
|
|
2903
|
+
})();
|
|
2904
|
+
if (moduleCacheKey !== undefined) {
|
|
2905
|
+
setBoundedCacheEntry(routeMetadataModuleCache, moduleCacheKey, loaded, maxRouteMetadataModuleCacheEntries, routeMetadataModuleCacheCounters);
|
|
2906
|
+
}
|
|
2907
|
+
try {
|
|
2908
|
+
return await loaded;
|
|
2909
|
+
}
|
|
2910
|
+
catch (error) {
|
|
2911
|
+
if (moduleCacheKey !== undefined) {
|
|
2912
|
+
routeMetadataModuleCache.delete(moduleCacheKey);
|
|
2913
|
+
}
|
|
2914
|
+
throw error;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2871
2917
|
async function resolveRouteMetadataModule(module, context) {
|
|
2872
2918
|
const staticMetadata = validateRouteMetadata(module.metadata);
|
|
2873
2919
|
if (module.generateMetadata === undefined) {
|
|
@@ -2937,9 +2983,10 @@ async function loadComposedRouteMetadata(options) {
|
|
|
2937
2983
|
}
|
|
2938
2984
|
}
|
|
2939
2985
|
function composedRouteMetadataCacheKey(options) {
|
|
2940
|
-
|
|
2986
|
+
const moduleCacheVersion = options.serverModuleCacheVersion ?? options.devServerModuleCacheVersion;
|
|
2987
|
+
return moduleCacheVersion === undefined
|
|
2941
2988
|
? undefined
|
|
2942
|
-
: `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion}\0${memoizedHashText(options.code)}\0${importPolicyCacheKey(options.importPolicy)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
|
|
2989
|
+
: `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion === undefined ? "dev" : "build"}\0${moduleCacheVersion}\0${memoizedHashText(options.code)}\0${importPolicyCacheKey(options.importPolicy)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
|
|
2943
2990
|
}
|
|
2944
2991
|
export const __composedRouteMetadataCacheKeyForTesting = composedRouteMetadataCacheKey;
|
|
2945
2992
|
async function loadComposedRouteMetadataUncached(options) {
|
|
@@ -2959,6 +3006,7 @@ async function loadComposedRouteMetadataUncached(options) {
|
|
|
2959
3006
|
importPolicy: options.importPolicy,
|
|
2960
3007
|
serverModules: options.serverModules,
|
|
2961
3008
|
serverModuleCacheVersion: options.serverModuleCacheVersion,
|
|
3009
|
+
devServerModuleCacheVersion: options.devServerModuleCacheVersion,
|
|
2962
3010
|
define: options.define,
|
|
2963
3011
|
vitePlugins: options.vitePlugins,
|
|
2964
3012
|
});
|
|
@@ -2972,6 +3020,7 @@ async function loadComposedRouteMetadataUncached(options) {
|
|
|
2972
3020
|
importPolicy: options.importPolicy,
|
|
2973
3021
|
serverModules: options.serverModules,
|
|
2974
3022
|
serverModuleCacheVersion: options.serverModuleCacheVersion,
|
|
3023
|
+
devServerModuleCacheVersion: options.devServerModuleCacheVersion,
|
|
2975
3024
|
define: options.define,
|
|
2976
3025
|
vitePlugins: options.vitePlugins,
|
|
2977
3026
|
});
|
|
@@ -3134,18 +3183,14 @@ function injectQueryState(html, state) {
|
|
|
3134
3183
|
return html;
|
|
3135
3184
|
}
|
|
3136
3185
|
const script = `<script type="application/json" id="${__MREACT_QUERY_STATE_SCRIPT_ID}">${escapeJsonForHtml(JSON.stringify(state))}</script>`;
|
|
3137
|
-
return /<\/body>/i.test(html)
|
|
3138
|
-
? replaceFinalBodyCloseTag(html, script)
|
|
3139
|
-
: `${html}${script}`;
|
|
3186
|
+
return /<\/body>/i.test(html) ? replaceFinalBodyCloseTag(html, script) : `${html}${script}`;
|
|
3140
3187
|
}
|
|
3141
3188
|
function injectAuthSessionClaims(html, claims) {
|
|
3142
3189
|
if (claims === undefined) {
|
|
3143
3190
|
return html;
|
|
3144
3191
|
}
|
|
3145
3192
|
const script = `<script type="application/json" id="${authSessionScriptId}">${escapeJsonForHtml(JSON.stringify(claims))}</script>`;
|
|
3146
|
-
return /<\/body>/i.test(html)
|
|
3147
|
-
? replaceFinalBodyCloseTag(html, script)
|
|
3148
|
-
: `${html}${script}`;
|
|
3193
|
+
return /<\/body>/i.test(html) ? replaceFinalBodyCloseTag(html, script) : `${html}${script}`;
|
|
3149
3194
|
}
|
|
3150
3195
|
function replaceFinalBodyCloseTag(html, insertion) {
|
|
3151
3196
|
const matches = [...html.matchAll(/<\/body>/gi)];
|
|
@@ -3198,9 +3243,7 @@ function readServerSourceFile(file, serverModuleCacheVersion, serverSourceFiles)
|
|
|
3198
3243
|
async function readDevServerSourceFile(file) {
|
|
3199
3244
|
const stats = await fileStat(file);
|
|
3200
3245
|
const cached = devServerSourceFileCache.get(file);
|
|
3201
|
-
if (cached !== undefined &&
|
|
3202
|
-
cached.mtimeMs === stats.mtimeMs &&
|
|
3203
|
-
cached.size === stats.size) {
|
|
3246
|
+
if (cached !== undefined && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
3204
3247
|
return cached.source;
|
|
3205
3248
|
}
|
|
3206
3249
|
const source = await readFile(file, "utf8");
|