@reckona/mreact-router 0.0.152 → 0.0.154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/actions.d.ts +10 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +6 -0
- package/dist/actions.js.map +1 -1
- package/dist/adapters/aws-lambda.d.ts +18 -0
- package/dist/adapters/aws-lambda.d.ts.map +1 -1
- package/dist/adapters/aws-lambda.js +18 -0
- package/dist/adapters/aws-lambda.js.map +1 -1
- package/dist/adapters/cloudflare.d.ts +33 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +33 -0
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/edge.d.ts +5 -0
- package/dist/adapters/edge.d.ts.map +1 -1
- package/dist/adapters/edge.js +5 -0
- package/dist/adapters/edge.js.map +1 -1
- package/dist/adapters/node.d.ts +5 -0
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +5 -0
- package/dist/adapters/node.js.map +1 -1
- package/dist/adapters/static.d.ts +5 -0
- package/dist/adapters/static.d.ts.map +1 -1
- package/dist/adapters/static.js +5 -0
- package/dist/adapters/static.js.map +1 -1
- package/dist/build.d.ts +15 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +85 -2
- package/dist/build.js.map +1 -1
- package/dist/cache.d.ts +15 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +15 -0
- package/dist/cache.js.map +1 -1
- package/dist/cookies.d.ts +16 -0
- package/dist/cookies.d.ts.map +1 -1
- package/dist/cookies.js +16 -0
- package/dist/cookies.js.map +1 -1
- package/dist/dev-server.d.ts +5 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +5 -0
- package/dist/dev-server.js.map +1 -1
- package/dist/link.d.ts +10 -0
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +5 -0
- package/dist/link.js.map +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +39 -4
- package/dist/middleware.js.map +1 -1
- package/dist/module-runner.d.ts +6 -0
- package/dist/module-runner.d.ts.map +1 -1
- package/dist/module-runner.js +71 -0
- package/dist/module-runner.js.map +1 -1
- package/dist/navigation.d.ts +53 -0
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +48 -0
- package/dist/navigation.js.map +1 -1
- package/dist/render.d.ts +34 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +161 -27
- package/dist/render.js.map +1 -1
- package/dist/route-module-loader.d.ts +6 -1
- package/dist/route-module-loader.d.ts.map +1 -1
- package/dist/route-module-loader.js +8 -1
- package/dist/route-module-loader.js.map +1 -1
- package/dist/serve.d.ts +5 -0
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +5 -0
- package/dist/serve.js.map +1 -1
- package/dist/session.d.ts +19 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +19 -0
- package/dist/session.js.map +1 -1
- package/dist/typed-routes.d.ts +5 -0
- package/dist/typed-routes.d.ts.map +1 -1
- package/dist/typed-routes.js +5 -0
- package/dist/typed-routes.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +1 -0
- package/dist/vite.js.map +1 -1
- package/package.json +11 -11
- package/src/actions.ts +18 -0
- package/src/adapters/aws-lambda.ts +18 -0
- package/src/adapters/cloudflare.ts +33 -0
- package/src/adapters/edge.ts +5 -0
- package/src/adapters/node.ts +5 -0
- package/src/adapters/static.ts +5 -0
- package/src/build.ts +118 -1
- package/src/cache.ts +15 -0
- package/src/cookies.ts +16 -0
- package/src/dev-server.ts +5 -0
- package/src/link.ts +10 -0
- package/src/middleware.ts +54 -4
- package/src/module-runner.ts +91 -0
- package/src/navigation.ts +53 -0
- package/src/render.ts +229 -25
- package/src/route-module-loader.ts +15 -0
- package/src/serve.ts +5 -0
- package/src/session.ts +19 -0
- package/src/typed-routes.ts +5 -0
- package/src/types.ts +15 -0
- package/src/vite.ts +1 -0
package/dist/navigation.js
CHANGED
|
@@ -46,6 +46,11 @@ function throwUnsafeRedirect(location) {
|
|
|
46
46
|
function throwUnsafeRewrite(location) {
|
|
47
47
|
throw new TypeError(`unsafe rewrite target: ${JSON.stringify(location)}`);
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Throws an internal redirect for loaders, middleware, route handlers, or server actions.
|
|
51
|
+
*
|
|
52
|
+
* The target must be same-origin or relative; use `redirectExternal()` for trusted `http` or `https` destinations. The default status is `303`.
|
|
53
|
+
*/
|
|
49
54
|
export function redirect(location, options = {}) {
|
|
50
55
|
if (!isSafeInternalRedirect(location)) {
|
|
51
56
|
throwUnsafeRedirect(location);
|
|
@@ -56,6 +61,11 @@ export function redirect(location, options = {}) {
|
|
|
56
61
|
status: options.status ?? 303,
|
|
57
62
|
});
|
|
58
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Throws an external redirect for trusted `http` or `https` destinations.
|
|
66
|
+
*
|
|
67
|
+
* This helper is intentionally separate from `redirect()` so off-site navigation is explicit. The default status is `307`.
|
|
68
|
+
*/
|
|
59
69
|
export function redirectExternal(location, options = {}) {
|
|
60
70
|
if (!isSafeExternalRedirect(location)) {
|
|
61
71
|
throwUnsafeRedirect(location);
|
|
@@ -66,6 +76,11 @@ export function redirectExternal(location, options = {}) {
|
|
|
66
76
|
status: options.status ?? 307,
|
|
67
77
|
});
|
|
68
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates a same-origin `303 See Other` redirect response.
|
|
81
|
+
*
|
|
82
|
+
* Use this from route handlers when returning a `Response` is more convenient than throwing through the app-router control flow.
|
|
83
|
+
*/
|
|
69
84
|
export function redirect303(location, init = {}) {
|
|
70
85
|
if (!isSafeInternalRedirect(location)) {
|
|
71
86
|
throwUnsafeRedirect(location);
|
|
@@ -78,6 +93,9 @@ export function redirect303(location, init = {}) {
|
|
|
78
93
|
status: 303,
|
|
79
94
|
});
|
|
80
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Creates a plain-text error response with a default `text/plain` content type.
|
|
98
|
+
*/
|
|
81
99
|
export function textError(message, status = 400, init = {}) {
|
|
82
100
|
const headers = new Headers(init.headers);
|
|
83
101
|
if (!headers.has("content-type")) {
|
|
@@ -93,18 +111,34 @@ export async function parseForm(request, schema) {
|
|
|
93
111
|
const form = await request.formData();
|
|
94
112
|
return schema === undefined ? form : schema.parse(form);
|
|
95
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Throws a route-level 404 control error.
|
|
116
|
+
*
|
|
117
|
+
* Use this from loaders, metadata, middleware, or route handlers when the matched route is valid but the requested resource is absent.
|
|
118
|
+
*/
|
|
96
119
|
export function notFound() {
|
|
97
120
|
throw Object.assign(new Error("Not Found"), {
|
|
98
121
|
name: notFoundErrorName,
|
|
99
122
|
status: 404,
|
|
100
123
|
});
|
|
101
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Alias for `notFound()` for codebases that prefer an explicit throwing helper name.
|
|
127
|
+
*/
|
|
102
128
|
export function throwNotFound() {
|
|
103
129
|
return notFound();
|
|
104
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Continues middleware processing without changing the request.
|
|
133
|
+
*/
|
|
105
134
|
export function next() {
|
|
106
135
|
return undefined;
|
|
107
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Creates an internal rewrite response consumed by app-router middleware.
|
|
139
|
+
*
|
|
140
|
+
* The target must be a same-origin route path, query, hash, or relative URL; protocol-relative, external, and control-character targets are rejected.
|
|
141
|
+
*/
|
|
108
142
|
export function rewrite(location, init = {}) {
|
|
109
143
|
if (!isSafeInternalRedirect(location)) {
|
|
110
144
|
throwUnsafeRewrite(location);
|
|
@@ -120,9 +154,15 @@ export function rewrite(location, init = {}) {
|
|
|
120
154
|
});
|
|
121
155
|
return response;
|
|
122
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Creates a JSON response using the platform `Response.json()` implementation.
|
|
159
|
+
*/
|
|
123
160
|
export function json(value, init) {
|
|
124
161
|
return Response.json(value, init);
|
|
125
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Creates an HTML response and defaults the content type to `text/html; charset=utf-8`.
|
|
165
|
+
*/
|
|
126
166
|
export function html(value, init = {}) {
|
|
127
167
|
if (init.headers === undefined) {
|
|
128
168
|
return new Response(value, {
|
|
@@ -139,9 +179,17 @@ export function html(value, init = {}) {
|
|
|
139
179
|
headers,
|
|
140
180
|
});
|
|
141
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns the request headers object for route code that follows app-router helper naming.
|
|
184
|
+
*/
|
|
142
185
|
export function headers(request) {
|
|
143
186
|
return request.headers;
|
|
144
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Parses request cookies into a small read-only helper.
|
|
190
|
+
*
|
|
191
|
+
* Values are decoded with `decodeURIComponent`; malformed encoded values are ignored rather than throwing during request handling.
|
|
192
|
+
*/
|
|
145
193
|
export function cookies(request) {
|
|
146
194
|
let values;
|
|
147
195
|
const cookieValues = () => {
|
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\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\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\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\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\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\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\nexport function notFound(): never {\n throw Object.assign(new Error(\"Not Found\"), {\n name: notFoundErrorName,\n status: 404,\n });\n}\n\nexport function throwNotFound(): never {\n return notFound();\n}\n\nexport function next(): MiddlewareNext {\n return undefined;\n}\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\nexport function json(value: unknown, init?: ResponseInit): Response {\n return Response.json(value, init);\n}\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\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\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\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\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\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\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\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.name === notFoundErrorName;\n}\n"]}
|
package/dist/render.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ServerOutputMode, TransformOutput } from "@reckona/mreact-shared/compiler-contract";
|
|
1
2
|
import { type QueryClient } from "@reckona/mreact-query";
|
|
2
3
|
import { type ClientRouteInferenceCache } from "./client-route-inference.js";
|
|
3
4
|
import type { AppRoute, MatchedRoute, RouteMatcher } from "./routes.js";
|
|
@@ -36,6 +37,7 @@ export interface RenderAppRequestOptions {
|
|
|
36
37
|
routes?: readonly AppRoute[] | undefined;
|
|
37
38
|
serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
|
|
38
39
|
serverModuleCacheVersion?: string | undefined;
|
|
40
|
+
dev?: boolean | undefined;
|
|
39
41
|
serverSourceFiles?: ReadonlyMap<string, string> | undefined;
|
|
40
42
|
serverActions?: AppRouterServerActionOptions | undefined;
|
|
41
43
|
serverActionReferencesByFile?: ReadonlyMap<string, readonly PreparedFormActionReference[]> | undefined;
|
|
@@ -92,6 +94,21 @@ export declare function bundleMiddlewareModuleCode(options: {
|
|
|
92
94
|
importPolicy?: AppRouterImportPolicy | undefined;
|
|
93
95
|
vitePlugins?: readonly PluginOption[] | undefined;
|
|
94
96
|
}): Promise<string>;
|
|
97
|
+
declare function transformServerModule(options: {
|
|
98
|
+
code: string;
|
|
99
|
+
clientBoundaryImports?: readonly string[];
|
|
100
|
+
clientBoundaryFallbackImports?: readonly string[];
|
|
101
|
+
filename: string;
|
|
102
|
+
serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
|
|
103
|
+
serverOutput: ServerOutputMode;
|
|
104
|
+
serverAwaitHydration?: boolean;
|
|
105
|
+
}): TransformOutput;
|
|
106
|
+
export declare const __transformServerModuleForTesting: typeof transformServerModule;
|
|
107
|
+
export declare function __resetProductionRenderWarningsForTesting(): void;
|
|
108
|
+
export declare function __warnProductionRenderWithoutPrebuiltModulesForTesting(options: {
|
|
109
|
+
dev?: boolean | undefined;
|
|
110
|
+
serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
|
|
111
|
+
}): void;
|
|
95
112
|
export declare function bundleRouteLoaderModuleCode(options: {
|
|
96
113
|
appDir: string;
|
|
97
114
|
code: string;
|
|
@@ -101,5 +118,22 @@ export declare function bundleRouteLoaderModuleCode(options: {
|
|
|
101
118
|
importPolicy?: AppRouterImportPolicy | undefined;
|
|
102
119
|
vitePlugins?: readonly PluginOption[] | undefined;
|
|
103
120
|
}): Promise<string>;
|
|
121
|
+
declare function composedRouteMetadataCacheKey(options: {
|
|
122
|
+
appDir: string;
|
|
123
|
+
code: string;
|
|
124
|
+
define?: UserConfig["define"] | undefined;
|
|
125
|
+
filename: string;
|
|
126
|
+
importPolicy?: AppRouterImportPolicy | undefined;
|
|
127
|
+
serverModuleCacheVersion?: string | undefined;
|
|
128
|
+
vitePlugins?: readonly PluginOption[] | undefined;
|
|
129
|
+
}): string | undefined;
|
|
130
|
+
export declare const __composedRouteMetadataCacheKeyForTesting: typeof composedRouteMetadataCacheKey;
|
|
131
|
+
interface InlineCspTag {
|
|
132
|
+
attributes: ReadonlyMap<string, string>;
|
|
133
|
+
content: string;
|
|
134
|
+
name: "script" | "style";
|
|
135
|
+
}
|
|
136
|
+
declare function inlineCspTags(html: string): InlineCspTag[];
|
|
137
|
+
export declare const __inlineCspTagsForTesting: typeof inlineCspTags;
|
|
104
138
|
export {};
|
|
105
139
|
//# sourceMappingURL=render.d.ts.map
|
package/dist/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"
|
|
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,EAGjC,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,KAAK,cAAc,EAMpB,MAAM,YAAY,CAAC;AAUpB,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;AAU7F,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;AA+CzB,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,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;IAG9C,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC5D,aAAa,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACzD,4BAA4B,CAAC,EACzB,WAAW,CAAC,MAAM,EAAE,SAAS,2BAA2B,EAAE,CAAC,GAC3D,SAAS,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAC7C,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,MAAM,qBAAqB,GAAG,CAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,4BAA4B,KAClC,QAAQ,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;AAExE,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAC3E,wBAAwB,EAAE,MAAM,CAAC;IACjC,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EhB;AAsND,wBAAgB,6BAA6B,IAAI,sBAAsB,EAAE,CAyDxE;AAiCD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuB1F;AA4GD,MAAM,MAAM,yBAAyB,GACjC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACtC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAE7C,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,eAAe,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACpD,iBAAiB,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAC3E,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC5D,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAiBrC;AA0tDD,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBlB;AA4CD,iBAAS,qBAAqB,CAAC,OAAO,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,6BAA6B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAC3E,YAAY,EAAE,gBAAgB,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GAAG,eAAe,CAsFlB;AAED,eAAO,MAAM,iCAAiC,8BAAwB,CAAC;AAIvE,wBAAgB,yCAAyC,IAAI,IAAI,CAGhE;AAKD,wBAAgB,sDAAsD,CAAC,OAAO,EAAE;IAC9E,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;CAC5E,GAAG,IAAI,CAEP;AA6uDD,wBAAsB,2BAA2B,CAAC,OAAO,EAAE;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,8BAA8B,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBlB;AA8MD,iBAAS,6BAA6B,CAAC,OAAO,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACjD,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;CACnD,GAAG,MAAM,GAAG,SAAS,CAIrB;AAED,eAAO,MAAM,yCAAyC,sCAAgC,CAAC;AAkMvF,UAAU,YAAY;IACpB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC1B;AAED,iBAAS,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAmDnD;AAED,eAAO,MAAM,yBAAyB,sBAAgB,CAAC"}
|
package/dist/render.js
CHANGED
|
@@ -29,7 +29,7 @@ import { invokeRouterInstrumentation, traceContextFromRequest, } from "./trace.j
|
|
|
29
29
|
import { mergeRouteMiddlewareControls, middlewareMatches, parseRouteMiddlewareControl, parseStaticMiddlewareConfig, shouldSkipMiddleware, validateRouteMiddlewareControl, } from "./middleware.js";
|
|
30
30
|
import { applyFileConventionMetadata, injectHeadMetadata, mergeRouteMetadata, responseHeadersForMetadata, serializeRobots, serializeSitemap, validateRouteMetadata, } from "./metadata.js";
|
|
31
31
|
import { createSlotRenderContext, markShellBoundary, shellBoundaryId, splitLayoutSlot, warnUnconsumedRouteSlots, } from "./layout-composer.js";
|
|
32
|
-
import { importPolicyCacheKey, memoizedHashText, prebuiltRequestModuleArtifact, prebuiltRouteLoaderModuleArtifact, prebuiltServerComponentModuleCode, prebuiltServerModuleOutputMatches, } from "./route-module-loader.js";
|
|
32
|
+
import { importPolicyCacheKey, memoizedHashText, prebuiltRequestModuleArtifact, prebuiltRouteLoaderModuleArtifact, prebuiltServerComponentModuleCode, prebuiltServerModuleOutputMatches, prebuiltServerModuleOutputOptionsMatch, } from "./route-module-loader.js";
|
|
33
33
|
const nativeEscapeTransform = {
|
|
34
34
|
batchImportName: "escapeHtmlBatch",
|
|
35
35
|
batchImportSource: "@reckona/mreact-router/native-escape",
|
|
@@ -134,7 +134,7 @@ async function preloadBuiltPageRouteModules(options) {
|
|
|
134
134
|
serverAwaitHydration: options.analysis.clientInference.client,
|
|
135
135
|
});
|
|
136
136
|
assertNoFatalServerDiagnostics(options.file, streamOutput.diagnostics);
|
|
137
|
-
await loadServerStreamModule(streamOutput.code, options.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins);
|
|
137
|
+
await loadServerStreamModule(streamOutput.code, options.file, options.serverModules, options.serverModuleCacheVersion, options.define, options.vitePlugins, undefined, { serverAwaitHydration: options.analysis.clientInference.client });
|
|
138
138
|
}
|
|
139
139
|
await preloadShellModulesForPage({
|
|
140
140
|
appDir: options.appDir,
|
|
@@ -193,6 +193,7 @@ function assertNoFatalServerDiagnostics(filename, diagnostics) {
|
|
|
193
193
|
}
|
|
194
194
|
const serverTransformCache = new Map();
|
|
195
195
|
const serverTransformCacheCounters = createRouterRuntimeCacheCounters();
|
|
196
|
+
const productionDynamicServerTransformWarned = new Set();
|
|
196
197
|
const serverSourceFileCache = new Map();
|
|
197
198
|
const serverSourceFileCacheCounters = createRouterRuntimeCacheCounters();
|
|
198
199
|
const routeSourceAnalysisCache = new Map();
|
|
@@ -275,12 +276,25 @@ function finishRenderTimingPhase(timing, startedAt, phaseName) {
|
|
|
275
276
|
}
|
|
276
277
|
timing.phases[phaseName] = logDurationMs(startedAt);
|
|
277
278
|
}
|
|
279
|
+
async function readSettledPromiseAtNextTask(promise) {
|
|
280
|
+
return await Promise.race([
|
|
281
|
+
promise.then((value) => ({ settled: true, value })),
|
|
282
|
+
new Promise((resolve) => {
|
|
283
|
+
setTimeout(() => resolve({ settled: false }), 0);
|
|
284
|
+
}),
|
|
285
|
+
]);
|
|
286
|
+
}
|
|
278
287
|
function addRenderTimingPhaseDuration(timing, startedAt, phaseName) {
|
|
279
288
|
if (timing === undefined || startedAt === undefined) {
|
|
280
289
|
return;
|
|
281
290
|
}
|
|
282
291
|
timing.phases[phaseName] = (timing.phases[phaseName] ?? 0) + logDurationMs(startedAt);
|
|
283
292
|
}
|
|
293
|
+
function routeLoaderMayReturnControlResponse(code) {
|
|
294
|
+
return /\b(?:redirect|redirectExternal|rewrite|notFound|throwNotFound)\s*\(/.test(code) ||
|
|
295
|
+
/\bnew\s+Response\s*\(/.test(code) ||
|
|
296
|
+
/\bResponse\.(?:redirect|json)\s*\(/.test(code);
|
|
297
|
+
}
|
|
284
298
|
async function waitForRenderPreload(options, timing) {
|
|
285
299
|
if (options.preload?.wait !== "before-render") {
|
|
286
300
|
return;
|
|
@@ -333,6 +347,7 @@ export async function resolveAppRouterMiddleware(options) {
|
|
|
333
347
|
return { response: middlewareResponse, type: "response" };
|
|
334
348
|
}
|
|
335
349
|
async function renderAppRequestInternal(options) {
|
|
350
|
+
warnProductionRenderWithoutPrebuiltModules(options);
|
|
336
351
|
const timing = createRenderTiming(options.logger);
|
|
337
352
|
const clientRouteInferenceCache = options.clientRouteInferenceCache ?? createClientRouteInferenceCache();
|
|
338
353
|
let phaseStartedAt = renderTimingPhaseStartedAt(timing);
|
|
@@ -413,6 +428,7 @@ async function renderAppRequestInternal(options) {
|
|
|
413
428
|
appDir: options.appDir,
|
|
414
429
|
filename: "not-found.mreact.tsx",
|
|
415
430
|
pathname: url.pathname,
|
|
431
|
+
serverSourceFiles: options.serverSourceFiles,
|
|
416
432
|
});
|
|
417
433
|
const response = await renderSpecialRoute({
|
|
418
434
|
appDir: options.appDir,
|
|
@@ -735,8 +751,9 @@ async function renderAppRequestInternal(options) {
|
|
|
735
751
|
return response;
|
|
736
752
|
}
|
|
737
753
|
let streamData;
|
|
738
|
-
|
|
739
|
-
|
|
754
|
+
let streamDataPromise = dataPromise ?? Promise.resolve(undefined);
|
|
755
|
+
phaseStartedAt = renderTimingPhaseStartedAt(timing);
|
|
756
|
+
if (loadingFile === undefined || routeLoaderMayReturnControlResponse(code)) {
|
|
740
757
|
try {
|
|
741
758
|
streamData = dataPromise === undefined ? undefined : await dataPromise;
|
|
742
759
|
}
|
|
@@ -747,6 +764,22 @@ async function renderAppRequestInternal(options) {
|
|
|
747
764
|
emitRenderTiming(options, timing, streamData.status);
|
|
748
765
|
return streamData;
|
|
749
766
|
}
|
|
767
|
+
streamDataPromise = Promise.resolve(streamData);
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
try {
|
|
771
|
+
const settledData = await readSettledPromiseAtNextTask(streamDataPromise);
|
|
772
|
+
if (settledData.settled) {
|
|
773
|
+
if (settledData.value instanceof Response) {
|
|
774
|
+
emitRenderTiming(options, timing, settledData.value.status);
|
|
775
|
+
return settledData.value;
|
|
776
|
+
}
|
|
777
|
+
streamDataPromise = Promise.resolve(settledData.value);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
finally {
|
|
781
|
+
finishRenderTimingPhase(timing, phaseStartedAt, "loaderWaitMs");
|
|
782
|
+
}
|
|
750
783
|
}
|
|
751
784
|
await waitForRenderPreload(options, timing);
|
|
752
785
|
await loadServerRenderArtifacts(options, matched.route.file, timing);
|
|
@@ -774,7 +807,7 @@ async function renderAppRequestInternal(options) {
|
|
|
774
807
|
appDir: options.appDir,
|
|
775
808
|
assetBaseUrl: options.assetBaseUrl,
|
|
776
809
|
clientRoute,
|
|
777
|
-
data:
|
|
810
|
+
data: streamDataPromise,
|
|
778
811
|
define: options.define,
|
|
779
812
|
loadingFile,
|
|
780
813
|
pageFile: matched.route.file,
|
|
@@ -1149,17 +1182,24 @@ async function nearestBoundaryFileForPath(options) {
|
|
|
1149
1182
|
const parts = options.pathname
|
|
1150
1183
|
.replace(/^\/+|\/+$/g, "")
|
|
1151
1184
|
.split("/")
|
|
1152
|
-
.filter((part) => part.length > 0);
|
|
1153
|
-
return nearestBoundaryFileFromParts({
|
|
1185
|
+
.filter((part) => part.length > 0 && part !== "." && part !== "..");
|
|
1186
|
+
return await nearestBoundaryFileFromParts({
|
|
1154
1187
|
appDir: options.appDir,
|
|
1155
1188
|
filename: options.filename,
|
|
1156
1189
|
parts,
|
|
1190
|
+
serverSourceFiles: options.serverSourceFiles,
|
|
1157
1191
|
});
|
|
1158
1192
|
}
|
|
1159
1193
|
async function nearestBoundaryFileFromParts(options) {
|
|
1160
1194
|
for (let count = options.parts.length; count >= 0; count -= 1) {
|
|
1161
1195
|
for (const filename of boundaryFilenameCandidates(options.filename)) {
|
|
1162
1196
|
const candidate = join(options.appDir, ...options.parts.slice(0, count), filename);
|
|
1197
|
+
if (options.serverSourceFiles !== undefined) {
|
|
1198
|
+
if (options.serverSourceFiles.has(candidate)) {
|
|
1199
|
+
return candidate;
|
|
1200
|
+
}
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1163
1203
|
try {
|
|
1164
1204
|
await access(candidate);
|
|
1165
1205
|
return candidate;
|
|
@@ -1200,11 +1240,18 @@ function boundaryFilenameCandidates(filename) {
|
|
|
1200
1240
|
return [standardFilename, filename];
|
|
1201
1241
|
}
|
|
1202
1242
|
async function renderSpecialRoute(options) {
|
|
1203
|
-
|
|
1204
|
-
|
|
1243
|
+
if (options.serverSourceFiles !== undefined) {
|
|
1244
|
+
if (!options.serverSourceFiles.has(options.routeFile)) {
|
|
1245
|
+
return new Response(options.textFallback, { status: options.status });
|
|
1246
|
+
}
|
|
1205
1247
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1248
|
+
else {
|
|
1249
|
+
try {
|
|
1250
|
+
await access(options.routeFile);
|
|
1251
|
+
}
|
|
1252
|
+
catch {
|
|
1253
|
+
return new Response(options.textFallback, { status: options.status });
|
|
1254
|
+
}
|
|
1208
1255
|
}
|
|
1209
1256
|
const props = {
|
|
1210
1257
|
data: undefined,
|
|
@@ -1286,7 +1333,10 @@ async function dispatchServerRoute(options) {
|
|
|
1286
1333
|
const module = await loadServerRouteModule(options);
|
|
1287
1334
|
const handler = module[options.request.method] ?? module.ALL ?? module.default;
|
|
1288
1335
|
if (typeof handler !== "function") {
|
|
1289
|
-
return new Response("Method Not Allowed", {
|
|
1336
|
+
return new Response("Method Not Allowed", {
|
|
1337
|
+
headers: { allow: allowedServerRouteMethods(module).join(", ") },
|
|
1338
|
+
status: 405,
|
|
1339
|
+
});
|
|
1290
1340
|
}
|
|
1291
1341
|
let response;
|
|
1292
1342
|
try {
|
|
@@ -1307,6 +1357,9 @@ async function dispatchServerRoute(options) {
|
|
|
1307
1357
|
? response
|
|
1308
1358
|
: new Response("Invalid route response", { status: 500 });
|
|
1309
1359
|
}
|
|
1360
|
+
function allowedServerRouteMethods(module) {
|
|
1361
|
+
return ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"].filter((method) => typeof module[method] === "function");
|
|
1362
|
+
}
|
|
1310
1363
|
async function dispatchConventionAssetRoute(options) {
|
|
1311
1364
|
if (options.request.method !== "GET" && options.request.method !== "HEAD") {
|
|
1312
1365
|
return new Response("Method Not Allowed", {
|
|
@@ -1664,7 +1717,7 @@ function transformServerModule(options) {
|
|
|
1664
1717
|
const artifact = options.serverModules?.get(options.filename)?.[options.serverOutput];
|
|
1665
1718
|
if (artifact !== undefined &&
|
|
1666
1719
|
artifact.sourceHash === sourceHash &&
|
|
1667
|
-
options.serverAwaitHydration
|
|
1720
|
+
prebuiltServerModuleOutputOptionsMatch(artifact, options.serverAwaitHydration === true ? { serverAwaitHydration: true } : {})) {
|
|
1668
1721
|
return {
|
|
1669
1722
|
code: artifact.code,
|
|
1670
1723
|
diagnostics: [],
|
|
@@ -1690,6 +1743,15 @@ function transformServerModule(options) {
|
|
|
1690
1743
|
if (cached !== undefined) {
|
|
1691
1744
|
return cached;
|
|
1692
1745
|
}
|
|
1746
|
+
// Only renders that were handed a prebuild map can have a prebuild gap;
|
|
1747
|
+
// dev servers pass no serverModules and transform at request time by design.
|
|
1748
|
+
if (options.serverModules !== undefined) {
|
|
1749
|
+
warnProductionDynamicServerTransform(options.filename, options.serverOutput, artifact === undefined
|
|
1750
|
+
? "no prebuilt server module for this output mode"
|
|
1751
|
+
: !prebuiltServerModuleOutputOptionsMatch(artifact, options.serverAwaitHydration === true ? { serverAwaitHydration: true } : {})
|
|
1752
|
+
? `serverAwaitHydration mismatch (artifact=${artifact.metadata?.serverAwaitHydration === true}, requested=${options.serverAwaitHydration === true})`
|
|
1753
|
+
: "stale prebuilt server module (source hash changed)");
|
|
1754
|
+
}
|
|
1693
1755
|
const output = transform({
|
|
1694
1756
|
code: options.code,
|
|
1695
1757
|
...(options.clientBoundaryImports === undefined
|
|
@@ -1708,6 +1770,39 @@ function transformServerModule(options) {
|
|
|
1708
1770
|
setBoundedCacheEntry(serverTransformCache, key, output, maxServerTransformCacheEntries, serverTransformCacheCounters);
|
|
1709
1771
|
return output;
|
|
1710
1772
|
}
|
|
1773
|
+
export const __transformServerModuleForTesting = transformServerModule;
|
|
1774
|
+
let productionRenderWithoutPrebuiltModulesWarned = false;
|
|
1775
|
+
export function __resetProductionRenderWarningsForTesting() {
|
|
1776
|
+
productionRenderWithoutPrebuiltModulesWarned = false;
|
|
1777
|
+
productionDynamicServerTransformWarned.clear();
|
|
1778
|
+
}
|
|
1779
|
+
// Covers the deployment that forgot prebuilt modules entirely; per-module
|
|
1780
|
+
// gaps inside a provided prebuild map are reported by
|
|
1781
|
+
// warnProductionDynamicServerTransform with the affected file instead.
|
|
1782
|
+
export function __warnProductionRenderWithoutPrebuiltModulesForTesting(options) {
|
|
1783
|
+
warnProductionRenderWithoutPrebuiltModules(options);
|
|
1784
|
+
}
|
|
1785
|
+
function warnProductionRenderWithoutPrebuiltModules(options) {
|
|
1786
|
+
if (process.env.NODE_ENV !== "production" ||
|
|
1787
|
+
options.dev === true ||
|
|
1788
|
+
options.serverModules !== undefined ||
|
|
1789
|
+
productionRenderWithoutPrebuiltModulesWarned) {
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
productionRenderWithoutPrebuiltModulesWarned = true;
|
|
1793
|
+
console.warn("mreact router: production render without prebuilt serverModules. Request-time transforms use development compiler settings; pass the build output's serverModules (or set dev: true for dev servers).");
|
|
1794
|
+
}
|
|
1795
|
+
function warnProductionDynamicServerTransform(filename, serverOutput, reason) {
|
|
1796
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
const warnedKey = `${filename}\0${serverOutput}`;
|
|
1800
|
+
if (productionDynamicServerTransformWarned.has(warnedKey)) {
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
productionDynamicServerTransformWarned.add(warnedKey);
|
|
1804
|
+
console.warn(`mreact router: dynamic server transform path ran in production for ${filename} (serverOutput=${serverOutput}): ${reason}. Production deployments should provide prebuilt serverModules; otherwise request-time transforms use development compiler settings.`);
|
|
1805
|
+
}
|
|
1711
1806
|
async function analyzeRouteSource(options) {
|
|
1712
1807
|
const sourceHash = memoizedHashText(options.code);
|
|
1713
1808
|
if (options.artifact !== undefined &&
|
|
@@ -2123,11 +2218,12 @@ async function renderServerStreamSlots(code, options) {
|
|
|
2123
2218
|
function hasRouteSlotsExport(code) {
|
|
2124
2219
|
return /^\s*export\s+const\s+slots\s*=/m.test(code);
|
|
2125
2220
|
}
|
|
2126
|
-
async function loadServerStreamModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy) {
|
|
2221
|
+
async function loadServerStreamModule(code, sourcefile, serverModules, serverModuleCacheVersion, define, vitePlugins, importPolicy, outputOptions = {}) {
|
|
2127
2222
|
const artifactCode = serverModules?.get(sourcefile)?.stream;
|
|
2128
2223
|
const codeHash = memoizedHashText(code);
|
|
2129
|
-
const prebuiltCode = prebuiltServerComponentModuleCode(artifactCode, code, codeHash);
|
|
2224
|
+
const prebuiltCode = prebuiltServerComponentModuleCode(artifactCode, code, codeHash, outputOptions);
|
|
2130
2225
|
if (artifactCode !== undefined &&
|
|
2226
|
+
prebuiltServerModuleOutputOptionsMatch(artifactCode, outputOptions) &&
|
|
2131
2227
|
prebuiltServerModuleOutputMatches(artifactCode, code, codeHash) &&
|
|
2132
2228
|
artifactCode.moduleFile !== undefined) {
|
|
2133
2229
|
return await importBuiltServerModuleFile({
|
|
@@ -2806,9 +2902,7 @@ async function bundleRouteMetadataModuleCode(options) {
|
|
|
2806
2902
|
return code;
|
|
2807
2903
|
}
|
|
2808
2904
|
async function loadComposedRouteMetadata(options) {
|
|
2809
|
-
const cacheKey = options
|
|
2810
|
-
? undefined
|
|
2811
|
-
: `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion}\0${memoizedHashText(options.code)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
|
|
2905
|
+
const cacheKey = composedRouteMetadataCacheKey(options);
|
|
2812
2906
|
if (cacheKey !== undefined) {
|
|
2813
2907
|
const cached = readRouterRuntimeCacheEntry(composedRouteMetadataCache, cacheKey, composedRouteMetadataCacheCounters);
|
|
2814
2908
|
if (cached !== undefined) {
|
|
@@ -2829,6 +2923,12 @@ async function loadComposedRouteMetadata(options) {
|
|
|
2829
2923
|
throw error;
|
|
2830
2924
|
}
|
|
2831
2925
|
}
|
|
2926
|
+
function composedRouteMetadataCacheKey(options) {
|
|
2927
|
+
return options.serverModuleCacheVersion === undefined
|
|
2928
|
+
? undefined
|
|
2929
|
+
: `${options.appDir}\0${options.filename}\0${options.serverModuleCacheVersion}\0${memoizedHashText(options.code)}\0${importPolicyCacheKey(options.importPolicy)}\0${viteDefineCacheKey(options.define)}\0${vitePluginsCacheKey(options.vitePlugins)}`;
|
|
2930
|
+
}
|
|
2931
|
+
export const __composedRouteMetadataCacheKeyForTesting = composedRouteMetadataCacheKey;
|
|
2832
2932
|
async function loadComposedRouteMetadataUncached(options) {
|
|
2833
2933
|
const layoutFiles = await shellFilesForPage(options.appDir, options.filename, options.serverModuleCacheVersion);
|
|
2834
2934
|
const metadata = [];
|
|
@@ -2951,21 +3051,47 @@ function cspDirectiveNonces(csp, directive) {
|
|
|
2951
3051
|
}
|
|
2952
3052
|
function inlineCspTags(html) {
|
|
2953
3053
|
const tags = [];
|
|
2954
|
-
const
|
|
2955
|
-
let
|
|
2956
|
-
while (
|
|
2957
|
-
const
|
|
2958
|
-
|
|
3054
|
+
const lowerHtml = html.toLowerCase();
|
|
3055
|
+
let position = 0;
|
|
3056
|
+
while (position < html.length) {
|
|
3057
|
+
const scriptIndex = lowerHtml.indexOf("<script", position);
|
|
3058
|
+
const styleIndex = lowerHtml.indexOf("<style", position);
|
|
3059
|
+
const openerIndex = scriptIndex === -1
|
|
3060
|
+
? styleIndex
|
|
3061
|
+
: styleIndex === -1
|
|
3062
|
+
? scriptIndex
|
|
3063
|
+
: Math.min(scriptIndex, styleIndex);
|
|
3064
|
+
if (openerIndex === -1) {
|
|
3065
|
+
break;
|
|
3066
|
+
}
|
|
3067
|
+
const name = lowerHtml.startsWith("<script", openerIndex) ? "script" : "style";
|
|
3068
|
+
const tagEnd = html.indexOf(">", openerIndex + 1);
|
|
3069
|
+
if (tagEnd === -1) {
|
|
3070
|
+
break;
|
|
3071
|
+
}
|
|
3072
|
+
const closeToken = `</${name}>`;
|
|
3073
|
+
const closeIndex = lowerHtml.indexOf(closeToken, tagEnd + 1);
|
|
3074
|
+
const nextScriptIndex = lowerHtml.indexOf("<script", tagEnd + 1);
|
|
3075
|
+
const nextStyleIndex = lowerHtml.indexOf("<style", tagEnd + 1);
|
|
3076
|
+
const nextOpenerIndex = nextScriptIndex === -1
|
|
3077
|
+
? nextStyleIndex
|
|
3078
|
+
: nextStyleIndex === -1
|
|
3079
|
+
? nextScriptIndex
|
|
3080
|
+
: Math.min(nextScriptIndex, nextStyleIndex);
|
|
3081
|
+
if (closeIndex === -1 || (nextOpenerIndex !== -1 && nextOpenerIndex < closeIndex)) {
|
|
3082
|
+
position = tagEnd + 1;
|
|
2959
3083
|
continue;
|
|
2960
3084
|
}
|
|
2961
3085
|
tags.push({
|
|
2962
|
-
attributes: parseTagAttributes(
|
|
2963
|
-
content:
|
|
3086
|
+
attributes: parseTagAttributes(html.slice(openerIndex + name.length + 1, tagEnd)),
|
|
3087
|
+
content: html.slice(tagEnd + 1, closeIndex),
|
|
2964
3088
|
name,
|
|
2965
3089
|
});
|
|
3090
|
+
position = closeIndex + closeToken.length;
|
|
2966
3091
|
}
|
|
2967
3092
|
return tags;
|
|
2968
3093
|
}
|
|
3094
|
+
export const __inlineCspTagsForTesting = inlineCspTags;
|
|
2969
3095
|
function parseTagAttributes(source) {
|
|
2970
3096
|
const attributes = new Map();
|
|
2971
3097
|
const pattern = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
@@ -2996,7 +3122,7 @@ function injectQueryState(html, state) {
|
|
|
2996
3122
|
}
|
|
2997
3123
|
const script = `<script type="application/json" id="${__MREACT_QUERY_STATE_SCRIPT_ID}">${escapeJsonForHtml(JSON.stringify(state))}</script>`;
|
|
2998
3124
|
return /<\/body>/i.test(html)
|
|
2999
|
-
? html
|
|
3125
|
+
? replaceFinalBodyCloseTag(html, script)
|
|
3000
3126
|
: `${html}${script}`;
|
|
3001
3127
|
}
|
|
3002
3128
|
function injectAuthSessionClaims(html, claims) {
|
|
@@ -3005,9 +3131,17 @@ function injectAuthSessionClaims(html, claims) {
|
|
|
3005
3131
|
}
|
|
3006
3132
|
const script = `<script type="application/json" id="${authSessionScriptId}">${escapeJsonForHtml(JSON.stringify(claims))}</script>`;
|
|
3007
3133
|
return /<\/body>/i.test(html)
|
|
3008
|
-
? html
|
|
3134
|
+
? replaceFinalBodyCloseTag(html, script)
|
|
3009
3135
|
: `${html}${script}`;
|
|
3010
3136
|
}
|
|
3137
|
+
function replaceFinalBodyCloseTag(html, insertion) {
|
|
3138
|
+
const matches = [...html.matchAll(/<\/body>/gi)];
|
|
3139
|
+
const last = matches.at(-1);
|
|
3140
|
+
if (last?.index === undefined) {
|
|
3141
|
+
return `${html}${insertion}`;
|
|
3142
|
+
}
|
|
3143
|
+
return `${html.slice(0, last.index)}${insertion}${html.slice(last.index)}`;
|
|
3144
|
+
}
|
|
3011
3145
|
function authIncludesClaims(code) {
|
|
3012
3146
|
return /\bexport\s+const\s+auth\s*=\s*["']include-claims["']\s*;?/.test(code);
|
|
3013
3147
|
}
|