vinext 0.0.45 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/prerender.js +10 -3
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/standalone.js +4 -3
- package/dist/build/standalone.js.map +1 -1
- package/dist/check.js +30 -18
- package/dist/check.js.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/config/config-matchers.js +1 -0
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +38 -2
- package/dist/config/next-config.js +24 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +18 -23
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +331 -1732
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +24 -0
- package/dist/entries/app-rsc-manifest.js +153 -0
- package/dist/entries/app-rsc-manifest.js.map +1 -0
- package/dist/entries/pages-server-entry.js +13 -103
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.js +54 -34
- package/dist/index.js.map +1 -1
- package/dist/plugins/rsc-client-shim-excludes.d.ts +6 -0
- package/dist/plugins/rsc-client-shim-excludes.js +27 -0
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -0
- package/dist/routing/app-router.d.ts +14 -5
- package/dist/routing/app-router.js +75 -1
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/route-pattern.d.ts +9 -0
- package/dist/routing/route-pattern.js +90 -0
- package/dist/routing/route-pattern.js.map +1 -0
- package/dist/routing/route-trie.js +10 -11
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/server/app-browser-entry.js +30 -2
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-middleware.d.ts +32 -0
- package/dist/server/app-middleware.js +147 -0
- package/dist/server/app-middleware.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +2 -0
- package/dist/server/app-page-boundary-render.js +50 -30
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +12 -1
- package/dist/server/app-page-boundary.js +27 -12
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +4 -1
- package/dist/server/app-page-cache.js +38 -2
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +120 -0
- package/dist/server/app-page-dispatch.js +332 -0
- package/dist/server/app-page-dispatch.js.map +1 -0
- package/dist/server/app-page-execution.d.ts +4 -3
- package/dist/server/app-page-execution.js +5 -8
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +55 -0
- package/dist/server/app-page-head.js +196 -0
- package/dist/server/app-page-head.js.map +1 -0
- package/dist/server/app-page-method.d.ts +16 -0
- package/dist/server/app-page-method.js +30 -0
- package/dist/server/app-page-method.js.map +1 -0
- package/dist/server/app-page-params.d.ts +7 -0
- package/dist/server/app-page-params.js +28 -0
- package/dist/server/app-page-params.js.map +1 -0
- package/dist/server/app-page-render.d.ts +2 -1
- package/dist/server/app-page-render.js +54 -8
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +4 -4
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +14 -3
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +10 -0
- package/dist/server/app-page-stream.js +5 -1
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-endpoints.d.ts +19 -0
- package/dist/server/app-prerender-endpoints.js +96 -0
- package/dist/server/app-prerender-endpoints.js.map +1 -0
- package/dist/server/app-prerender-static-params.d.ts +16 -0
- package/dist/server/app-prerender-static-params.js +14 -0
- package/dist/server/app-prerender-static-params.js.map +1 -0
- package/dist/server/app-route-handler-cache.d.ts +3 -0
- package/dist/server/app-route-handler-cache.js +6 -2
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +42 -0
- package/dist/server/app-route-handler-dispatch.js +147 -0
- package/dist/server/app-route-handler-dispatch.js.map +1 -0
- package/dist/server/app-route-handler-execution.d.ts +6 -2
- package/dist/server/app-route-handler-execution.js +23 -2
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.d.ts +2 -1
- package/dist/server/app-route-handler-response.js +44 -4
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +107 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-errors.d.ts +27 -0
- package/dist/server/app-rsc-errors.js +42 -0
- package/dist/server/app-rsc-errors.js.map +1 -0
- package/dist/server/app-rsc-route-matching.d.ts +40 -0
- package/dist/server/app-rsc-route-matching.js +66 -0
- package/dist/server/app-rsc-route-matching.js.map +1 -0
- package/dist/server/app-server-action-execution.d.ts +86 -1
- package/dist/server/app-server-action-execution.js +255 -5
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +7 -0
- package/dist/server/app-ssr-entry.js +30 -9
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +4 -2
- package/dist/server/app-ssr-stream.js +29 -2
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +15 -0
- package/dist/server/app-static-generation.js +20 -0
- package/dist/server/app-static-generation.js.map +1 -0
- package/dist/server/dev-route-files.d.ts +7 -0
- package/dist/server/dev-route-files.js +73 -0
- package/dist/server/dev-route-files.js.map +1 -0
- package/dist/server/dev-server.js +4 -0
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/file-based-metadata.d.ts +17 -0
- package/dist/server/file-based-metadata.js +356 -0
- package/dist/server/file-based-metadata.js.map +1 -0
- package/dist/server/implicit-tags.d.ts +6 -0
- package/dist/server/implicit-tags.js +42 -0
- package/dist/server/implicit-tags.js.map +1 -0
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +20 -2
- package/dist/server/isr-cache.js +58 -7
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-route-build-data.d.ts +25 -0
- package/dist/server/metadata-route-build-data.js +150 -0
- package/dist/server/metadata-route-build-data.js.map +1 -0
- package/dist/server/metadata-route-response.d.ts +17 -0
- package/dist/server/metadata-route-response.js +187 -0
- package/dist/server/metadata-route-response.js.map +1 -0
- package/dist/server/metadata-routes.d.ts +42 -4
- package/dist/server/metadata-routes.js +127 -11
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.d.ts +15 -0
- package/dist/server/middleware-matcher.js +102 -0
- package/dist/server/middleware-matcher.js.map +1 -0
- package/dist/server/middleware-request-headers.js +2 -1
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +39 -0
- package/dist/server/middleware-runtime.js +159 -0
- package/dist/server/middleware-runtime.js.map +1 -0
- package/dist/server/middleware.d.ts +4 -36
- package/dist/server/middleware.js +18 -228
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +5 -1
- package/dist/server/pages-page-data.js +4 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.js +2 -1
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prerender-work-unit-setup.d.ts +7 -0
- package/dist/server/prerender-work-unit-setup.js +30 -0
- package/dist/server/prerender-work-unit-setup.js.map +1 -0
- package/dist/server/prod-server.js +10 -14
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +46 -5
- package/dist/server/request-pipeline.js +84 -5
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/rsc-stream-hints.d.ts +5 -0
- package/dist/server/rsc-stream-hints.js +35 -0
- package/dist/server/rsc-stream-hints.js.map +1 -0
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.d.ts +9 -0
- package/dist/server/server-action-not-found.js +40 -0
- package/dist/server/server-action-not-found.js.map +1 -0
- package/dist/shims/cache.d.ts +25 -2
- package/dist/shims/cache.js +52 -2
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +50 -5
- package/dist/shims/error-boundary.js +76 -4
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +5 -4
- package/dist/shims/font-google-base.js +61 -13
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/headers.d.ts +14 -2
- package/dist/shims/headers.js +127 -17
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.js +26 -8
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/make-hanging-promise.d.ts +16 -0
- package/dist/shims/internal/make-hanging-promise.js +46 -0
- package/dist/shims/internal/make-hanging-promise.js.map +1 -0
- package/dist/shims/internal/work-unit-async-storage.d.ts +26 -3
- package/dist/shims/internal/work-unit-async-storage.js +6 -3
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/metadata.d.ts +38 -26
- package/dist/shims/metadata.js +75 -45
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +10 -1
- package/dist/shims/navigation.js +18 -1
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +2 -2
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/navigation.react-server.js.map +1 -1
- package/dist/shims/offline.d.ts +5 -0
- package/dist/shims/offline.js +17 -0
- package/dist/shims/offline.js.map +1 -0
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/root-params.d.ts +11 -0
- package/dist/shims/root-params.js +24 -0
- package/dist/shims/root-params.js.map +1 -0
- package/dist/shims/router.js +1 -1
- package/dist/shims/server.d.ts +3 -1
- package/dist/shims/server.js +83 -5
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -0
- package/dist/shims/thenable-params.js +37 -0
- package/dist/shims/thenable-params.js.map +1 -0
- package/dist/shims/unified-request-context.d.ts +2 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/package.json +6 -1
- package/dist/server/middleware-codegen.d.ts +0 -54
- package/dist/server/middleware-codegen.js +0 -414
- package/dist/server/middleware-codegen.js.map +0 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextI18nConfig } from "../config/next-config.js";
|
|
2
|
+
import { MiddlewareModule } from "./middleware-runtime.js";
|
|
3
|
+
|
|
4
|
+
//#region src/server/app-middleware.d.ts
|
|
5
|
+
type AppMiddlewareContext = {
|
|
6
|
+
headers: Headers | null;
|
|
7
|
+
requestHeaders: Headers | null;
|
|
8
|
+
status: number | null;
|
|
9
|
+
};
|
|
10
|
+
type ApplyAppMiddlewareOptions = {
|
|
11
|
+
basePath?: string;
|
|
12
|
+
cleanPathname: string;
|
|
13
|
+
context: AppMiddlewareContext;
|
|
14
|
+
i18nConfig?: NextI18nConfig | null;
|
|
15
|
+
isProxy: boolean;
|
|
16
|
+
module: MiddlewareModule;
|
|
17
|
+
request: Request;
|
|
18
|
+
};
|
|
19
|
+
type ApplyAppMiddlewareResult = {
|
|
20
|
+
kind: "continue";
|
|
21
|
+
cleanPathname: string;
|
|
22
|
+
search: string | null;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "response";
|
|
25
|
+
response: Response;
|
|
26
|
+
};
|
|
27
|
+
declare function isExternalMiddlewareRewrite(rewriteUrl: string, request: Request): boolean;
|
|
28
|
+
declare function proxyExternalMiddlewareRewrite(request: Request, rewriteUrl: string, context: AppMiddlewareContext): Promise<Response>;
|
|
29
|
+
declare function applyAppMiddleware(options: ApplyAppMiddlewareOptions): Promise<ApplyAppMiddlewareResult>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { AppMiddlewareContext, ApplyAppMiddlewareOptions, ApplyAppMiddlewareResult, applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
|
|
32
|
+
//# sourceMappingURL=app-middleware.d.ts.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { buildRequestHeadersFromMiddlewareResponse } from "./middleware-request-headers.js";
|
|
2
|
+
import { isExternalUrl, proxyExternalRequest } from "../config/config-matchers.js";
|
|
3
|
+
import { processMiddlewareHeaders } from "./request-pipeline.js";
|
|
4
|
+
import { executeMiddleware } from "./middleware-runtime.js";
|
|
5
|
+
import { applyMiddlewareRequestHeaders, setHeadersContext } from "../shims/headers.js";
|
|
6
|
+
import { setNavigationContext } from "../shims/navigation.js";
|
|
7
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
8
|
+
//#region src/server/app-middleware.ts
|
|
9
|
+
function isForwardedMiddlewareContext(value) {
|
|
10
|
+
return !!value && typeof value === "object";
|
|
11
|
+
}
|
|
12
|
+
function appendForwardedHeader(headers, value) {
|
|
13
|
+
if (!Array.isArray(value) || value.length < 2) return;
|
|
14
|
+
const key = value[0];
|
|
15
|
+
const headerValue = value[1];
|
|
16
|
+
if (typeof key === "string" && typeof headerValue === "string") headers.append(key, headerValue);
|
|
17
|
+
}
|
|
18
|
+
function responseFromMiddlewareRedirect(result) {
|
|
19
|
+
if (result.response) return result.response;
|
|
20
|
+
const headers = new Headers(result.responseHeaders);
|
|
21
|
+
if (result.redirectUrl) headers.set("Location", result.redirectUrl);
|
|
22
|
+
return new Response(null, {
|
|
23
|
+
status: result.redirectStatus ?? 307,
|
|
24
|
+
headers
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function isExternalMiddlewareRewrite(rewriteUrl, request) {
|
|
28
|
+
return new URL(rewriteUrl, request.url).origin !== new URL(request.url).origin;
|
|
29
|
+
}
|
|
30
|
+
function requestWithMiddlewareRequestHeaders(request, middlewareHeaders) {
|
|
31
|
+
const nextHeaders = middlewareHeaders ? buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders) : null;
|
|
32
|
+
if (!nextHeaders) return request;
|
|
33
|
+
const init = {
|
|
34
|
+
method: request.method,
|
|
35
|
+
headers: nextHeaders,
|
|
36
|
+
body: request.body
|
|
37
|
+
};
|
|
38
|
+
if (request.body) Object.defineProperty(init, "duplex", {
|
|
39
|
+
value: "half",
|
|
40
|
+
enumerable: true
|
|
41
|
+
});
|
|
42
|
+
return new Request(request.url, init);
|
|
43
|
+
}
|
|
44
|
+
async function proxyExternalMiddlewareRewrite(request, rewriteUrl, context) {
|
|
45
|
+
const proxyRequest = requestWithMiddlewareRequestHeaders(request, context.requestHeaders ?? context.headers);
|
|
46
|
+
setHeadersContext(null);
|
|
47
|
+
setNavigationContext(null);
|
|
48
|
+
const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);
|
|
49
|
+
if (!context.headers) return proxyResponse;
|
|
50
|
+
const middlewareHeaders = new Headers(context.headers);
|
|
51
|
+
processMiddlewareHeaders(middlewareHeaders);
|
|
52
|
+
const headers = new Headers(proxyResponse.headers);
|
|
53
|
+
mergeMiddlewareResponseHeaders(headers, middlewareHeaders);
|
|
54
|
+
return new Response(proxyResponse.body, {
|
|
55
|
+
status: proxyResponse.status,
|
|
56
|
+
statusText: proxyResponse.statusText,
|
|
57
|
+
headers
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function applyForwardedMiddlewareContext(request, context) {
|
|
61
|
+
if (process.env.NODE_ENV === "production") return { applied: false };
|
|
62
|
+
const header = request.headers.get("x-vinext-mw-ctx");
|
|
63
|
+
if (!header) return { applied: false };
|
|
64
|
+
try {
|
|
65
|
+
const data = JSON.parse(header);
|
|
66
|
+
if (!isForwardedMiddlewareContext(data)) return { applied: false };
|
|
67
|
+
if (Array.isArray(data.h) && data.h.length > 0) {
|
|
68
|
+
context.headers = new Headers();
|
|
69
|
+
for (const entry of data.h) appendForwardedHeader(context.headers, entry);
|
|
70
|
+
}
|
|
71
|
+
if (typeof data.s === "number") context.status = data.s;
|
|
72
|
+
if (typeof data.r === "string" && data.r.length > 0) return {
|
|
73
|
+
applied: true,
|
|
74
|
+
rewriteUrl: data.r
|
|
75
|
+
};
|
|
76
|
+
return { applied: true };
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error("[vinext] Failed to parse forwarded middleware context:", e);
|
|
79
|
+
return { applied: false };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function applyAppMiddleware(options) {
|
|
83
|
+
const forwarded = applyForwardedMiddlewareContext(options.request, options.context);
|
|
84
|
+
let cleanPathname = options.cleanPathname;
|
|
85
|
+
let search = null;
|
|
86
|
+
if (forwarded.rewriteUrl) try {
|
|
87
|
+
if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, options.request)) return {
|
|
88
|
+
kind: "response",
|
|
89
|
+
response: await proxyExternalMiddlewareRewrite(options.request, forwarded.rewriteUrl, options.context)
|
|
90
|
+
};
|
|
91
|
+
const rewriteParsed = new URL(forwarded.rewriteUrl, options.request.url);
|
|
92
|
+
cleanPathname = rewriteParsed.pathname;
|
|
93
|
+
search = rewriteParsed.search;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
console.error("[vinext] Failed to apply forwarded middleware rewrite:", e);
|
|
96
|
+
forwarded.applied = false;
|
|
97
|
+
}
|
|
98
|
+
if (!forwarded.applied) {
|
|
99
|
+
const result = await executeMiddleware({
|
|
100
|
+
basePath: options.basePath,
|
|
101
|
+
i18nConfig: options.i18nConfig,
|
|
102
|
+
isProxy: options.isProxy,
|
|
103
|
+
module: options.module,
|
|
104
|
+
normalizedPathname: cleanPathname,
|
|
105
|
+
request: options.request
|
|
106
|
+
});
|
|
107
|
+
if (!result.continue) {
|
|
108
|
+
if (result.redirectUrl) return {
|
|
109
|
+
kind: "response",
|
|
110
|
+
response: responseFromMiddlewareRedirect(result)
|
|
111
|
+
};
|
|
112
|
+
if (result.response) return {
|
|
113
|
+
kind: "response",
|
|
114
|
+
response: result.response
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
kind: "response",
|
|
118
|
+
response: new Response("Internal Server Error", { status: 500 })
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (result.responseHeaders) options.context.headers = new Headers(result.responseHeaders);
|
|
122
|
+
if (result.rewriteUrl) {
|
|
123
|
+
if (result.rewriteStatus !== void 0) options.context.status = result.rewriteStatus;
|
|
124
|
+
if (isExternalUrl(result.rewriteUrl)) return {
|
|
125
|
+
kind: "response",
|
|
126
|
+
response: await proxyExternalMiddlewareRewrite(options.request, result.rewriteUrl, options.context)
|
|
127
|
+
};
|
|
128
|
+
const rewriteParsed = new URL(result.rewriteUrl, options.request.url);
|
|
129
|
+
cleanPathname = rewriteParsed.pathname;
|
|
130
|
+
search = rewriteParsed.search;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (options.context.headers) {
|
|
134
|
+
options.context.requestHeaders = new Headers(options.context.headers);
|
|
135
|
+
applyMiddlewareRequestHeaders(options.context.headers);
|
|
136
|
+
processMiddlewareHeaders(options.context.headers);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
kind: "continue",
|
|
140
|
+
cleanPathname,
|
|
141
|
+
search
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { applyAppMiddleware, isExternalMiddlewareRewrite, proxyExternalMiddlewareRewrite };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=app-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-middleware.js","names":[],"sources":["../../src/server/app-middleware.ts"],"sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\nimport { isExternalUrl, proxyExternalRequest } from \"../config/config-matchers.js\";\nimport { applyMiddlewareRequestHeaders, setHeadersContext } from \"vinext/shims/headers\";\nimport { setNavigationContext } from \"vinext/shims/navigation\";\nimport { buildRequestHeadersFromMiddlewareResponse } from \"./middleware-request-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { executeMiddleware, type MiddlewareModule } from \"./middleware-runtime.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type AppMiddlewareContext = {\n headers: Headers | null;\n requestHeaders: Headers | null;\n status: number | null;\n};\n\nexport type ApplyAppMiddlewareOptions = {\n basePath?: string;\n cleanPathname: string;\n context: AppMiddlewareContext;\n i18nConfig?: NextI18nConfig | null;\n isProxy: boolean;\n module: MiddlewareModule;\n request: Request;\n};\n\nexport type ApplyAppMiddlewareResult =\n | {\n kind: \"continue\";\n cleanPathname: string;\n search: string | null;\n }\n | {\n kind: \"response\";\n response: Response;\n };\n\ntype ForwardedMiddlewareContext = {\n h?: unknown;\n r?: unknown;\n s?: unknown;\n};\n\nfunction isForwardedMiddlewareContext(value: unknown): value is ForwardedMiddlewareContext {\n return !!value && typeof value === \"object\";\n}\n\nfunction appendForwardedHeader(headers: Headers, value: unknown): void {\n if (!Array.isArray(value) || value.length < 2) return;\n const key = value[0];\n const headerValue = value[1];\n if (typeof key === \"string\" && typeof headerValue === \"string\") {\n headers.append(key, headerValue);\n }\n}\n\nfunction responseFromMiddlewareRedirect(result: {\n redirectStatus?: number;\n redirectUrl?: string;\n response?: Response;\n responseHeaders?: Headers;\n}): Response {\n if (result.response) return result.response;\n\n const headers = new Headers(result.responseHeaders);\n if (result.redirectUrl) {\n headers.set(\"Location\", result.redirectUrl);\n }\n return new Response(null, {\n status: result.redirectStatus ?? 307,\n headers,\n });\n}\n\nexport function isExternalMiddlewareRewrite(rewriteUrl: string, request: Request): boolean {\n const rewriteParsed = new URL(rewriteUrl, request.url);\n return rewriteParsed.origin !== new URL(request.url).origin;\n}\n\nfunction requestWithMiddlewareRequestHeaders(\n request: Request,\n middlewareHeaders: Headers | null,\n): Request {\n const nextHeaders = middlewareHeaders\n ? buildRequestHeadersFromMiddlewareResponse(request.headers, middlewareHeaders)\n : null;\n if (!nextHeaders) return request;\n\n const init: RequestInit = {\n method: request.method,\n headers: nextHeaders,\n body: request.body,\n };\n if (request.body) {\n Object.defineProperty(init, \"duplex\", { value: \"half\", enumerable: true });\n }\n\n return new Request(request.url, init);\n}\n\nexport async function proxyExternalMiddlewareRewrite(\n request: Request,\n rewriteUrl: string,\n context: AppMiddlewareContext,\n): Promise<Response> {\n const proxyRequest = requestWithMiddlewareRequestHeaders(\n request,\n context.requestHeaders ?? context.headers,\n );\n setHeadersContext(null);\n setNavigationContext(null);\n\n const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);\n if (!context.headers) return proxyResponse;\n\n const middlewareHeaders = new Headers(context.headers);\n processMiddlewareHeaders(middlewareHeaders);\n const headers = new Headers(proxyResponse.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareHeaders);\n return new Response(proxyResponse.body, {\n status: proxyResponse.status,\n statusText: proxyResponse.statusText,\n headers,\n });\n}\n\nfunction applyForwardedMiddlewareContext(\n request: Request,\n context: AppMiddlewareContext,\n): { applied: boolean; rewriteUrl?: string } {\n if (process.env.NODE_ENV === \"production\") {\n return { applied: false };\n }\n\n const header = request.headers.get(\"x-vinext-mw-ctx\");\n if (!header) return { applied: false };\n\n try {\n const data = JSON.parse(header);\n if (!isForwardedMiddlewareContext(data)) return { applied: false };\n\n if (Array.isArray(data.h) && data.h.length > 0) {\n context.headers = new Headers();\n for (const entry of data.h) {\n appendForwardedHeader(context.headers, entry);\n }\n }\n if (typeof data.s === \"number\") {\n context.status = data.s;\n }\n if (typeof data.r === \"string\" && data.r.length > 0) {\n return { applied: true, rewriteUrl: data.r };\n }\n return { applied: true };\n } catch (e) {\n console.error(\"[vinext] Failed to parse forwarded middleware context:\", e);\n return { applied: false };\n }\n}\n\nexport async function applyAppMiddleware(\n options: ApplyAppMiddlewareOptions,\n): Promise<ApplyAppMiddlewareResult> {\n const forwarded = applyForwardedMiddlewareContext(options.request, options.context);\n let cleanPathname = options.cleanPathname;\n let search: string | null = null;\n\n if (forwarded.rewriteUrl) {\n try {\n if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, options.request)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n options.request,\n forwarded.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(forwarded.rewriteUrl, options.request.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n } catch (e) {\n console.error(\"[vinext] Failed to apply forwarded middleware rewrite:\", e);\n forwarded.applied = false;\n }\n }\n\n if (!forwarded.applied) {\n const result = await executeMiddleware({\n basePath: options.basePath,\n i18nConfig: options.i18nConfig,\n isProxy: options.isProxy,\n module: options.module,\n normalizedPathname: cleanPathname,\n request: options.request,\n });\n\n if (!result.continue) {\n if (result.redirectUrl) {\n return { kind: \"response\", response: responseFromMiddlewareRedirect(result) };\n }\n if (result.response) {\n return { kind: \"response\", response: result.response };\n }\n return { kind: \"response\", response: new Response(\"Internal Server Error\", { status: 500 }) };\n }\n\n if (result.responseHeaders) {\n options.context.headers = new Headers(result.responseHeaders);\n }\n\n if (result.rewriteUrl) {\n if (result.rewriteStatus !== undefined) {\n options.context.status = result.rewriteStatus;\n }\n if (isExternalUrl(result.rewriteUrl)) {\n return {\n kind: \"response\",\n response: await proxyExternalMiddlewareRewrite(\n options.request,\n result.rewriteUrl,\n options.context,\n ),\n };\n }\n const rewriteParsed = new URL(result.rewriteUrl, options.request.url);\n cleanPathname = rewriteParsed.pathname;\n search = rewriteParsed.search;\n }\n }\n\n if (options.context.headers) {\n options.context.requestHeaders = new Headers(options.context.headers);\n applyMiddlewareRequestHeaders(options.context.headers);\n processMiddlewareHeaders(options.context.headers);\n }\n\n return { kind: \"continue\", cleanPathname, search };\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
1
2
|
import { AppElements } from "./app-elements.js";
|
|
2
3
|
import { AppPageFontPreload } from "./app-page-execution.js";
|
|
3
4
|
import { AppPageMiddlewareContext } from "./app-page-response.js";
|
|
@@ -36,6 +37,7 @@ type AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageM
|
|
|
36
37
|
loadSsrHandler: () => Promise<AppPageSsrHandler>;
|
|
37
38
|
makeThenableParams: (params: AppPageParams) => unknown;
|
|
38
39
|
middlewareContext: AppPageMiddlewareContext;
|
|
40
|
+
metadataRoutes: MetadataFileRoute[];
|
|
39
41
|
renderToReadableStream: (element: ReactNode | AppElements, options: {
|
|
40
42
|
onError: AppPageBoundaryOnError;
|
|
41
43
|
}) => ReadableStream<Uint8Array>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { APP_INTERCEPTION_CONTEXT_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, createAppPayloadRouteId } from "./app-elements.js";
|
|
2
2
|
import { ErrorBoundary } from "../shims/error-boundary.js";
|
|
3
3
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
4
|
-
import { MetadataHead, ViewportHead
|
|
4
|
+
import { MetadataHead, ViewportHead } from "../shims/metadata.js";
|
|
5
5
|
import { createAppPageLayoutEntries } from "./app-page-route-wiring.js";
|
|
6
6
|
import { buildClientHookErrorMessage } from "../shims/client-hook-error.js";
|
|
7
|
+
import { resolveAppPageHead } from "./app-page-head.js";
|
|
7
8
|
import { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryComponent, wrapAppPageBoundaryElement } from "./app-page-boundary.js";
|
|
8
9
|
import { createAppPageFontData, renderAppPageHtmlResponse } from "./app-page-stream.js";
|
|
9
10
|
import { Fragment, createElement } from "react";
|
|
@@ -11,33 +12,6 @@ import { Fragment, createElement } from "react";
|
|
|
11
12
|
function getDefaultExport(module) {
|
|
12
13
|
return module?.default ?? null;
|
|
13
14
|
}
|
|
14
|
-
async function resolveAppPageLayoutHead(layoutModules, params) {
|
|
15
|
-
const filteredLayouts = layoutModules.filter(Boolean);
|
|
16
|
-
const layoutMetadataPromises = [];
|
|
17
|
-
let accumulatedMetadata = Promise.resolve({});
|
|
18
|
-
for (let index = 0; index < filteredLayouts.length; index++) {
|
|
19
|
-
const parentForLayout = accumulatedMetadata;
|
|
20
|
-
const metadataPromise = resolveModuleMetadata(filteredLayouts[index], params, void 0, parentForLayout).catch((error) => {
|
|
21
|
-
console.error("[vinext] Layout generateMetadata() failed:", error);
|
|
22
|
-
return null;
|
|
23
|
-
});
|
|
24
|
-
layoutMetadataPromises.push(metadataPromise);
|
|
25
|
-
accumulatedMetadata = metadataPromise.then(async (metadataResult) => {
|
|
26
|
-
if (metadataResult) return mergeMetadata([await parentForLayout, metadataResult]);
|
|
27
|
-
return parentForLayout;
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
const [metadataResults, viewportResults] = await Promise.all([Promise.all(layoutMetadataPromises), Promise.all(filteredLayouts.map((layoutModule) => resolveModuleViewport(layoutModule, params).catch((error) => {
|
|
31
|
-
console.error("[vinext] Layout generateViewport() failed:", error);
|
|
32
|
-
return null;
|
|
33
|
-
})))]);
|
|
34
|
-
const metadataList = metadataResults.filter(Boolean);
|
|
35
|
-
const viewportList = viewportResults.filter(Boolean);
|
|
36
|
-
return {
|
|
37
|
-
metadata: metadataList.length > 0 ? mergeMetadata(metadataList) : null,
|
|
38
|
-
viewport: mergeViewport(viewportList)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
15
|
function wrapRenderedBoundaryElement(options) {
|
|
42
16
|
return wrapAppPageBoundaryElement({
|
|
43
17
|
element: options.element,
|
|
@@ -82,6 +56,18 @@ function resolveAppPageBoundaryRootLayoutTreePath(route) {
|
|
|
82
56
|
}
|
|
83
57
|
return null;
|
|
84
58
|
}
|
|
59
|
+
function resolveHttpAccessFallbackHeadRouteSegments(route, layoutModules) {
|
|
60
|
+
if (!route?.routeSegments) return;
|
|
61
|
+
if (!route.layouts || layoutModules.length >= route.layouts.length) return route.routeSegments;
|
|
62
|
+
const lastIncludedLayoutIndex = layoutModules.length - 1;
|
|
63
|
+
if (lastIncludedLayoutIndex < 0) return [];
|
|
64
|
+
const segmentCount = route.layoutTreePositions?.[lastIncludedLayoutIndex] ?? 0;
|
|
65
|
+
return route.routeSegments.slice(0, segmentCount);
|
|
66
|
+
}
|
|
67
|
+
function resolveHttpAccessFallbackHeadLayoutTreePositions(route, layoutModules) {
|
|
68
|
+
if (!route?.layouts || layoutModules.length >= route.layouts.length) return route?.layoutTreePositions;
|
|
69
|
+
return route.layoutTreePositions?.slice(0, layoutModules.length);
|
|
70
|
+
}
|
|
85
71
|
function createAppPageBoundaryRscPayload(options) {
|
|
86
72
|
const routeId = createAppPayloadRouteId(options.pathname, null);
|
|
87
73
|
return {
|
|
@@ -140,7 +126,15 @@ async function renderAppPageHttpAccessFallback(options) {
|
|
|
140
126
|
});
|
|
141
127
|
if (!boundaryComponent) return null;
|
|
142
128
|
const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;
|
|
143
|
-
const
|
|
129
|
+
const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, layoutModules);
|
|
130
|
+
const { metadata, viewport } = await resolveAppPageHead({
|
|
131
|
+
layoutModules,
|
|
132
|
+
layoutTreePositions: resolveHttpAccessFallbackHeadLayoutTreePositions(options.route, layoutModules),
|
|
133
|
+
metadataRoutes: options.metadataRoutes,
|
|
134
|
+
params: options.matchedParams,
|
|
135
|
+
routePath: options.route?.pattern ?? new URL(options.requestUrl).pathname,
|
|
136
|
+
routeSegments
|
|
137
|
+
});
|
|
144
138
|
const headElements = [createElement("meta", {
|
|
145
139
|
charSet: "utf-8",
|
|
146
140
|
key: "charset"
|
|
@@ -191,8 +185,34 @@ async function renderAppPageErrorBoundary(options) {
|
|
|
191
185
|
const errorObject = options.sanitizeErrorForClient(rawError);
|
|
192
186
|
const matchedParams = options.matchedParams ?? options.route?.params ?? {};
|
|
193
187
|
const layoutModules = options.route?.layouts ?? options.rootLayouts;
|
|
188
|
+
const pathname = new URL(options.requestUrl).pathname;
|
|
189
|
+
const headElements = [createElement("meta", {
|
|
190
|
+
charSet: "utf-8",
|
|
191
|
+
key: "charset"
|
|
192
|
+
})];
|
|
193
|
+
if (!errorBoundary.isGlobalError) try {
|
|
194
|
+
const { metadata, viewport } = await resolveAppPageHead({
|
|
195
|
+
fallbackOnFileMetadataError: true,
|
|
196
|
+
layoutModules,
|
|
197
|
+
layoutTreePositions: options.route?.layoutTreePositions,
|
|
198
|
+
metadataRoutes: options.metadataRoutes,
|
|
199
|
+
params: matchedParams,
|
|
200
|
+
routePath: options.route?.pattern ?? pathname,
|
|
201
|
+
routeSegments: options.route?.routeSegments
|
|
202
|
+
});
|
|
203
|
+
if (metadata) headElements.push(createElement(MetadataHead, {
|
|
204
|
+
key: "metadata",
|
|
205
|
+
metadata
|
|
206
|
+
}));
|
|
207
|
+
headElements.push(createElement(ViewportHead, {
|
|
208
|
+
key: "viewport",
|
|
209
|
+
viewport
|
|
210
|
+
}));
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error(`[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`, error);
|
|
213
|
+
}
|
|
194
214
|
const element = wrapRenderedBoundaryElement({
|
|
195
|
-
element: createElement(errorBoundary.component, { error: errorObject }),
|
|
215
|
+
element: createElement(Fragment, null, ...headElements, createElement(errorBoundary.component, { error: errorObject })),
|
|
196
216
|
globalErrorModule: options.globalErrorModule,
|
|
197
217
|
includeGlobalErrorBoundary: !errorBoundary.isGlobalError,
|
|
198
218
|
isRscRequest: options.isRscRequest,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-boundary-render.js","names":[],"sources":["../../src/server/app-page-boundary-render.ts"],"sourcesContent":["import { Fragment, createElement, type ComponentType, type ReactNode } from \"react\";\nimport { buildClientHookErrorMessage } from \"../shims/client-hook-error.js\";\nimport { ErrorBoundary } from \"../shims/error-boundary.js\";\nimport { LayoutSegmentProvider } from \"../shims/layout-segment-context.js\";\nimport {\n MetadataHead,\n ViewportHead,\n mergeMetadata,\n mergeViewport,\n resolveModuleMetadata,\n resolveModuleViewport,\n type Metadata,\n type Viewport,\n} from \"../shims/metadata.js\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport {\n renderAppPageBoundaryResponse,\n resolveAppPageErrorBoundary,\n resolveAppPageHttpAccessBoundaryComponent,\n wrapAppPageBoundaryElement,\n type AppPageParams,\n} from \"./app-page-boundary.js\";\nimport {\n createAppPageFontData,\n renderAppPageHtmlResponse,\n type AppPageSsrHandler,\n} from \"./app-page-stream.js\";\nimport {\n APP_INTERCEPTION_CONTEXT_KEY,\n APP_ROOT_LAYOUT_KEY,\n APP_ROUTE_KEY,\n createAppPayloadRouteId,\n type AppElements,\n} from \"./app-elements.js\";\nimport { createAppPageLayoutEntries } from \"./app-page-route-wiring.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppPageBoundaryRscPayloadOptions<TModule extends AppPageModule = AppPageModule> = {\n element: ReactNode;\n pathname: string;\n route?: AppPageBoundaryRoute<TModule> | null;\n};\n\ntype AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {\n error?: TModule | null;\n errors?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n layoutTreePositions?: readonly number[] | null;\n layouts?: readonly (TModule | null | undefined)[];\n notFound?: TModule | null;\n params?: AppPageParams;\n pattern?: string;\n routeSegments?: readonly string[];\n unauthorized?: TModule | null;\n};\n\ntype AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageModule> = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n clearRequestContext: () => void;\n createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n isRscRequest: boolean;\n loadSsrHandler: () => Promise<AppPageSsrHandler>;\n makeThenableParams: (params: AppPageParams) => unknown;\n middlewareContext: AppPageMiddlewareContext;\n renderToReadableStream: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n requestUrl: string;\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootLayouts: readonly (TModule | null | undefined)[];\n scriptNonce?: string;\n};\n\ntype RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppPageModule> = {\n boundaryComponent?: AppPageComponent | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n matchedParams: AppPageParams;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n statusCode: number;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\ntype RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {\n error: unknown;\n matchedParams?: AppPageParams | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n sanitizeErrorForClient: (error: Error) => Error;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nasync function resolveAppPageLayoutHead<TModule extends AppPageModule>(\n layoutModules: readonly (TModule | null | undefined)[],\n params: AppPageParams,\n): Promise<{ metadata: Metadata | null; viewport: Viewport }> {\n const filteredLayouts = layoutModules.filter(Boolean) as TModule[];\n const layoutMetadataPromises: Promise<Metadata | null>[] = [];\n let accumulatedMetadata = Promise.resolve<Metadata>({});\n\n for (let index = 0; index < filteredLayouts.length; index++) {\n const parentForLayout = accumulatedMetadata;\n const metadataPromise = resolveModuleMetadata(\n filteredLayouts[index],\n params,\n undefined,\n parentForLayout,\n ).catch((error) => {\n console.error(\"[vinext] Layout generateMetadata() failed:\", error);\n return null;\n });\n layoutMetadataPromises.push(metadataPromise);\n accumulatedMetadata = metadataPromise.then(async (metadataResult) => {\n if (metadataResult) {\n return mergeMetadata([await parentForLayout, metadataResult]);\n }\n return parentForLayout;\n });\n }\n\n const [metadataResults, viewportResults] = await Promise.all([\n Promise.all(layoutMetadataPromises),\n Promise.all(\n filteredLayouts.map((layoutModule) =>\n resolveModuleViewport(layoutModule, params).catch((error) => {\n console.error(\"[vinext] Layout generateViewport() failed:\", error);\n return null;\n }),\n ),\n ),\n ]);\n\n const metadataList = metadataResults.filter(Boolean) as Metadata[];\n const viewportList = viewportResults.filter(Boolean) as Viewport[];\n\n return {\n metadata: metadataList.length > 0 ? mergeMetadata(metadataList) : null,\n viewport: mergeViewport(viewportList),\n };\n}\n\nfunction wrapRenderedBoundaryElement<TModule extends AppPageModule>(\n options: Pick<\n AppPageBoundaryRenderCommonOptions<TModule>,\n \"globalErrorModule\" | \"isRscRequest\" | \"makeThenableParams\" | \"resolveChildSegments\"\n > & {\n element: ReactNode;\n includeGlobalErrorBoundary: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n matchedParams: AppPageParams;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n },\n): ReactNode {\n return wrapAppPageBoundaryElement({\n element: options.element,\n getDefaultExport,\n globalErrorComponent: getDefaultExport(options.globalErrorModule),\n includeGlobalErrorBoundary: options.includeGlobalErrorBoundary,\n isRscRequest: options.isRscRequest,\n layoutModules: options.layoutModules,\n layoutTreePositions: options.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n renderErrorBoundary(GlobalErrorComponent, children) {\n return createElement(ErrorBoundary, {\n fallback: GlobalErrorComponent,\n // oxlint-disable-next-line react/no-children-prop\n children,\n });\n },\n renderLayout(LayoutComponent, children, asyncParams) {\n return createElement(LayoutComponent as AppPageComponent, {\n // oxlint-disable-next-line react/no-children-prop\n children,\n params: asyncParams,\n });\n },\n renderLayoutSegmentProvider(segmentMap, children) {\n return createElement(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n LayoutSegmentProvider as ComponentType<any>,\n { segmentMap },\n children,\n );\n },\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.routeSegments ?? [],\n skipLayoutWrapping: options.skipLayoutWrapping,\n });\n}\n\nfunction resolveAppPageBoundaryRootLayoutTreePath<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n): string | null {\n if (route?.layouts) {\n const rootLayoutEntry = createAppPageLayoutEntries({\n errors: route.errors,\n layoutTreePositions: route.layoutTreePositions,\n layouts: route.layouts,\n notFounds: null,\n routeSegments: route.routeSegments,\n })[0];\n\n if (rootLayoutEntry) {\n return rootLayoutEntry.treePath;\n }\n }\n\n // Without route tree metadata we cannot derive a canonical root layout tree path.\n // Returning null keeps boundary payloads soft-navigation compatible.\n return null;\n}\n\nfunction createAppPageBoundaryRscPayload<TModule extends AppPageModule>(\n options: AppPageBoundaryRscPayloadOptions<TModule>,\n): AppElements {\n const routeId = createAppPayloadRouteId(options.pathname, null);\n\n return {\n [APP_INTERCEPTION_CONTEXT_KEY]: null,\n [APP_ROUTE_KEY]: routeId,\n [APP_ROOT_LAYOUT_KEY]: resolveAppPageBoundaryRootLayoutTreePath(options.route),\n [routeId]: options.element,\n };\n}\n\nasync function renderAppPageBoundaryElementResponse<TModule extends AppPageModule>(\n options: AppPageBoundaryRenderCommonOptions<TModule> & {\n element: ReactNode;\n layoutModules: readonly (TModule | null | undefined)[];\n route?: AppPageBoundaryRoute<TModule> | null;\n routePattern?: string;\n status: number;\n },\n): Promise<Response> {\n const pathname = new URL(options.requestUrl).pathname;\n const payload = createAppPageBoundaryRscPayload({\n element: options.element,\n pathname,\n route: options.route,\n });\n\n return renderAppPageBoundaryResponse({\n async createHtmlResponse(rscStream, responseStatus) {\n const fontData = createAppPageFontData({\n getLinks: options.getFontLinks,\n getPreloads: options.getFontPreloads,\n getStyles: options.getFontStyles,\n });\n const ssrHandler = await options.loadSsrHandler();\n return renderAppPageHtmlResponse({\n clearRequestContext: options.clearRequestContext,\n fontData,\n fontLinkHeader: options.buildFontLinkHeader(fontData.preloads),\n middlewareHeaders: options.middlewareContext.headers,\n navigationContext: options.getNavigationContext(),\n rscStream,\n scriptNonce: options.scriptNonce,\n ssrHandler,\n status: responseStatus,\n });\n },\n createRscOnErrorHandler() {\n return options.createRscOnErrorHandler(pathname, options.routePattern ?? pathname);\n },\n element: payload,\n isRscRequest: options.isRscRequest,\n middlewareHeaders: options.middlewareContext.headers,\n renderToReadableStream: options.renderToReadableStream,\n status: options.status,\n });\n}\n\nexport async function renderAppPageHttpAccessFallback<TModule extends AppPageModule>(\n options: RenderAppPageHttpAccessFallbackOptions<TModule>,\n): Promise<Response | null> {\n const boundaryComponent =\n options.boundaryComponent ??\n resolveAppPageHttpAccessBoundaryComponent({\n getDefaultExport,\n rootForbiddenModule: options.rootForbiddenModule,\n rootNotFoundModule: options.rootNotFoundModule,\n rootUnauthorizedModule: options.rootUnauthorizedModule,\n routeForbiddenModule: options.route?.forbidden,\n routeNotFoundModule: options.route?.notFound,\n routeUnauthorizedModule: options.route?.unauthorized,\n statusCode: options.statusCode,\n });\n if (!boundaryComponent) {\n return null;\n }\n\n const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;\n const { metadata, viewport } = await resolveAppPageLayoutHead(\n layoutModules,\n options.matchedParams,\n );\n\n const headElements: ReactNode[] = [\n createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" }),\n createElement(\"meta\", { content: \"noindex\", key: \"robots\", name: \"robots\" }),\n ];\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(Fragment, null, ...headElements, createElement(boundaryComponent)),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: true,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: options.statusCode,\n });\n}\n\nexport async function renderAppPageErrorBoundary<TModule extends AppPageModule>(\n options: RenderAppPageErrorBoundaryOptions<TModule>,\n): Promise<Response | null> {\n const errorBoundary = resolveAppPageErrorBoundary({\n getDefaultExport,\n globalErrorModule: options.globalErrorModule,\n layoutErrorModules: options.route?.errors,\n pageErrorModule: options.route?.error,\n });\n if (!errorBoundary.component) {\n return null;\n }\n\n const rawError =\n options.error instanceof Error ? options.error : new Error(String(options.error));\n rewriteClientHookError(rawError);\n const errorObject = options.sanitizeErrorForClient(rawError);\n const matchedParams = options.matchedParams ?? options.route?.params ?? {};\n const layoutModules = options.route?.layouts ?? options.rootLayouts;\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(errorBoundary.component, {\n error: errorObject,\n }),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: !errorBoundary.isGlobalError,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n skipLayoutWrapping: errorBoundary.isGlobalError,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: 200,\n });\n}\n\n// React client-only hooks that are absent from the `react-server` export\n// condition. When called in a Server Component they produce a TypeError like\n// \"useState is not a function\". Rewrite into an actionable message matching\n// the format used by the next/navigation shims (see client-hook-error.ts).\nconst _clientHookPattern =\n /\\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\\b.*is not a function/;\n\nfunction rewriteClientHookError(error: Error): void {\n const match = error.message.match(_clientHookPattern);\n if (match) {\n error.message = buildClientHookErrorMessage(`${match[1]}()`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-page-boundary-render.js","names":[],"sources":["../../src/server/app-page-boundary-render.ts"],"sourcesContent":["import { Fragment, createElement, type ComponentType, type ReactNode } from \"react\";\nimport { buildClientHookErrorMessage } from \"vinext/shims/client-hook-error\";\nimport { ErrorBoundary } from \"vinext/shims/error-boundary\";\nimport { LayoutSegmentProvider } from \"vinext/shims/layout-segment-context\";\nimport { MetadataHead, ViewportHead } from \"vinext/shims/metadata\";\nimport type { AppPageFontPreload } from \"./app-page-execution.js\";\nimport type { AppPageMiddlewareContext } from \"./app-page-response.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\nimport { resolveAppPageHead } from \"./app-page-head.js\";\nimport {\n renderAppPageBoundaryResponse,\n resolveAppPageErrorBoundary,\n resolveAppPageHttpAccessBoundaryComponent,\n wrapAppPageBoundaryElement,\n type AppPageParams,\n} from \"./app-page-boundary.js\";\nimport {\n createAppPageFontData,\n renderAppPageHtmlResponse,\n type AppPageSsrHandler,\n} from \"./app-page-stream.js\";\nimport {\n APP_INTERCEPTION_CONTEXT_KEY,\n APP_ROOT_LAYOUT_KEY,\n APP_ROUTE_KEY,\n createAppPayloadRouteId,\n type AppElements,\n} from \"./app-elements.js\";\nimport { createAppPageLayoutEntries } from \"./app-page-route-wiring.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AppPageComponent = ComponentType<any>;\ntype AppPageModule = Record<string, unknown> & {\n default?: AppPageComponent | null | undefined;\n};\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype AppPageBoundaryRscPayloadOptions<TModule extends AppPageModule = AppPageModule> = {\n element: ReactNode;\n pathname: string;\n route?: AppPageBoundaryRoute<TModule> | null;\n};\n\ntype AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {\n error?: TModule | null;\n errors?: readonly (TModule | null | undefined)[] | null;\n forbidden?: TModule | null;\n layoutTreePositions?: readonly number[] | null;\n layouts?: readonly (TModule | null | undefined)[];\n notFound?: TModule | null;\n params?: AppPageParams;\n pattern?: string;\n routeSegments?: readonly string[];\n unauthorized?: TModule | null;\n};\n\ntype AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageModule> = {\n buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;\n clearRequestContext: () => void;\n createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;\n getFontLinks: () => string[];\n getFontPreloads: () => AppPageFontPreload[];\n getFontStyles: () => string[];\n getNavigationContext: () => unknown;\n globalErrorModule?: TModule | null;\n isRscRequest: boolean;\n loadSsrHandler: () => Promise<AppPageSsrHandler>;\n makeThenableParams: (params: AppPageParams) => unknown;\n middlewareContext: AppPageMiddlewareContext;\n metadataRoutes: MetadataFileRoute[];\n renderToReadableStream: (\n element: ReactNode | AppElements,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n requestUrl: string;\n resolveChildSegments: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => string[];\n rootLayouts: readonly (TModule | null | undefined)[];\n scriptNonce?: string;\n};\n\ntype RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppPageModule> = {\n boundaryComponent?: AppPageComponent | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n matchedParams: AppPageParams;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n statusCode: number;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\ntype RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {\n error: unknown;\n matchedParams?: AppPageParams | null;\n route?: AppPageBoundaryRoute<TModule> | null;\n sanitizeErrorForClient: (error: Error) => Error;\n} & AppPageBoundaryRenderCommonOptions<TModule>;\n\nfunction getDefaultExport<TModule extends AppPageModule>(\n module: TModule | null | undefined,\n): AppPageComponent | null {\n return module?.default ?? null;\n}\n\nfunction wrapRenderedBoundaryElement<TModule extends AppPageModule>(\n options: Pick<\n AppPageBoundaryRenderCommonOptions<TModule>,\n \"globalErrorModule\" | \"isRscRequest\" | \"makeThenableParams\" | \"resolveChildSegments\"\n > & {\n element: ReactNode;\n includeGlobalErrorBoundary: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n matchedParams: AppPageParams;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n },\n): ReactNode {\n return wrapAppPageBoundaryElement({\n element: options.element,\n getDefaultExport,\n globalErrorComponent: getDefaultExport(options.globalErrorModule),\n includeGlobalErrorBoundary: options.includeGlobalErrorBoundary,\n isRscRequest: options.isRscRequest,\n layoutModules: options.layoutModules,\n layoutTreePositions: options.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n renderErrorBoundary(GlobalErrorComponent, children) {\n return createElement(ErrorBoundary, {\n fallback: GlobalErrorComponent,\n // oxlint-disable-next-line react/no-children-prop\n children,\n });\n },\n renderLayout(LayoutComponent, children, asyncParams) {\n return createElement(LayoutComponent as AppPageComponent, {\n // oxlint-disable-next-line react/no-children-prop\n children,\n params: asyncParams,\n });\n },\n renderLayoutSegmentProvider(segmentMap, children) {\n return createElement(\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n LayoutSegmentProvider as ComponentType<any>,\n { segmentMap },\n children,\n );\n },\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.routeSegments ?? [],\n skipLayoutWrapping: options.skipLayoutWrapping,\n });\n}\n\nfunction resolveAppPageBoundaryRootLayoutTreePath<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n): string | null {\n if (route?.layouts) {\n const rootLayoutEntry = createAppPageLayoutEntries({\n errors: route.errors,\n layoutTreePositions: route.layoutTreePositions,\n layouts: route.layouts,\n notFounds: null,\n routeSegments: route.routeSegments,\n })[0];\n\n if (rootLayoutEntry) {\n return rootLayoutEntry.treePath;\n }\n }\n\n // Without route tree metadata we cannot derive a canonical root layout tree path.\n // Returning null keeps boundary payloads soft-navigation compatible.\n return null;\n}\n\nfunction resolveHttpAccessFallbackHeadRouteSegments<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly string[] | undefined {\n if (!route?.routeSegments) {\n return undefined;\n }\n\n if (!route.layouts || layoutModules.length >= route.layouts.length) {\n return route.routeSegments;\n }\n\n const lastIncludedLayoutIndex = layoutModules.length - 1;\n if (lastIncludedLayoutIndex < 0) {\n return [];\n }\n\n const segmentCount = route.layoutTreePositions?.[lastIncludedLayoutIndex] ?? 0;\n return route.routeSegments.slice(0, segmentCount);\n}\n\nfunction resolveHttpAccessFallbackHeadLayoutTreePositions<TModule extends AppPageModule>(\n route: AppPageBoundaryRoute<TModule> | null | undefined,\n layoutModules: readonly (TModule | null | undefined)[],\n): readonly number[] | null | undefined {\n if (!route?.layouts || layoutModules.length >= route.layouts.length) {\n return route?.layoutTreePositions;\n }\n\n return route.layoutTreePositions?.slice(0, layoutModules.length);\n}\n\nfunction createAppPageBoundaryRscPayload<TModule extends AppPageModule>(\n options: AppPageBoundaryRscPayloadOptions<TModule>,\n): AppElements {\n const routeId = createAppPayloadRouteId(options.pathname, null);\n\n return {\n [APP_INTERCEPTION_CONTEXT_KEY]: null,\n [APP_ROUTE_KEY]: routeId,\n [APP_ROOT_LAYOUT_KEY]: resolveAppPageBoundaryRootLayoutTreePath(options.route),\n [routeId]: options.element,\n };\n}\n\nasync function renderAppPageBoundaryElementResponse<TModule extends AppPageModule>(\n options: AppPageBoundaryRenderCommonOptions<TModule> & {\n element: ReactNode;\n layoutModules: readonly (TModule | null | undefined)[];\n route?: AppPageBoundaryRoute<TModule> | null;\n routePattern?: string;\n status: number;\n },\n): Promise<Response> {\n const pathname = new URL(options.requestUrl).pathname;\n const payload = createAppPageBoundaryRscPayload({\n element: options.element,\n pathname,\n route: options.route,\n });\n\n return renderAppPageBoundaryResponse({\n async createHtmlResponse(rscStream, responseStatus) {\n const fontData = createAppPageFontData({\n getLinks: options.getFontLinks,\n getPreloads: options.getFontPreloads,\n getStyles: options.getFontStyles,\n });\n const ssrHandler = await options.loadSsrHandler();\n return renderAppPageHtmlResponse({\n clearRequestContext: options.clearRequestContext,\n fontData,\n fontLinkHeader: options.buildFontLinkHeader(fontData.preloads),\n middlewareHeaders: options.middlewareContext.headers,\n navigationContext: options.getNavigationContext(),\n rscStream,\n scriptNonce: options.scriptNonce,\n ssrHandler,\n status: responseStatus,\n });\n },\n createRscOnErrorHandler() {\n return options.createRscOnErrorHandler(pathname, options.routePattern ?? pathname);\n },\n element: payload,\n isRscRequest: options.isRscRequest,\n middlewareHeaders: options.middlewareContext.headers,\n renderToReadableStream: options.renderToReadableStream,\n status: options.status,\n });\n}\n\nexport async function renderAppPageHttpAccessFallback<TModule extends AppPageModule>(\n options: RenderAppPageHttpAccessFallbackOptions<TModule>,\n): Promise<Response | null> {\n const boundaryComponent =\n options.boundaryComponent ??\n resolveAppPageHttpAccessBoundaryComponent({\n getDefaultExport,\n rootForbiddenModule: options.rootForbiddenModule,\n rootNotFoundModule: options.rootNotFoundModule,\n rootUnauthorizedModule: options.rootUnauthorizedModule,\n routeForbiddenModule: options.route?.forbidden,\n routeNotFoundModule: options.route?.notFound,\n routeUnauthorizedModule: options.route?.unauthorized,\n statusCode: options.statusCode,\n });\n if (!boundaryComponent) {\n return null;\n }\n\n const layoutModules = options.layoutModules ?? options.route?.layouts ?? options.rootLayouts;\n const routeSegments = resolveHttpAccessFallbackHeadRouteSegments(options.route, layoutModules);\n const { metadata, viewport } = await resolveAppPageHead({\n layoutModules,\n layoutTreePositions: resolveHttpAccessFallbackHeadLayoutTreePositions(\n options.route,\n layoutModules,\n ),\n metadataRoutes: options.metadataRoutes,\n params: options.matchedParams,\n routePath: options.route?.pattern ?? new URL(options.requestUrl).pathname,\n routeSegments,\n });\n\n const headElements: ReactNode[] = [\n createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" }),\n createElement(\"meta\", { content: \"noindex\", key: \"robots\", name: \"robots\" }),\n ];\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(Fragment, null, ...headElements, createElement(boundaryComponent)),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: true,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams: options.matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: options.statusCode,\n });\n}\n\nexport async function renderAppPageErrorBoundary<TModule extends AppPageModule>(\n options: RenderAppPageErrorBoundaryOptions<TModule>,\n): Promise<Response | null> {\n const errorBoundary = resolveAppPageErrorBoundary({\n getDefaultExport,\n globalErrorModule: options.globalErrorModule,\n layoutErrorModules: options.route?.errors,\n pageErrorModule: options.route?.error,\n });\n if (!errorBoundary.component) {\n return null;\n }\n\n const rawError =\n options.error instanceof Error ? options.error : new Error(String(options.error));\n rewriteClientHookError(rawError);\n const errorObject = options.sanitizeErrorForClient(rawError);\n const matchedParams = options.matchedParams ?? options.route?.params ?? {};\n const layoutModules = options.route?.layouts ?? options.rootLayouts;\n const pathname = new URL(options.requestUrl).pathname;\n\n const headElements: ReactNode[] = [createElement(\"meta\", { charSet: \"utf-8\", key: \"charset\" })];\n if (!errorBoundary.isGlobalError) {\n try {\n const { metadata, viewport } = await resolveAppPageHead({\n fallbackOnFileMetadataError: true,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n metadataRoutes: options.metadataRoutes,\n params: matchedParams,\n routePath: options.route?.pattern ?? pathname,\n routeSegments: options.route?.routeSegments,\n });\n if (metadata) {\n headElements.push(createElement(MetadataHead, { key: \"metadata\", metadata }));\n }\n headElements.push(createElement(ViewportHead, { key: \"viewport\", viewport }));\n } catch (error) {\n console.error(\n `[vinext] App page error boundary head resolution failed for ${options.route?.pattern ?? pathname}:`,\n error,\n );\n }\n }\n\n const element = wrapRenderedBoundaryElement({\n element: createElement(\n Fragment,\n null,\n ...headElements,\n createElement(errorBoundary.component, {\n error: errorObject,\n }),\n ),\n globalErrorModule: options.globalErrorModule,\n includeGlobalErrorBoundary: !errorBoundary.isGlobalError,\n isRscRequest: options.isRscRequest,\n layoutModules,\n layoutTreePositions: options.route?.layoutTreePositions,\n makeThenableParams: options.makeThenableParams,\n matchedParams,\n resolveChildSegments: options.resolveChildSegments,\n routeSegments: options.route?.routeSegments,\n skipLayoutWrapping: errorBoundary.isGlobalError,\n });\n\n return renderAppPageBoundaryElementResponse({\n ...options,\n element,\n layoutModules,\n route: options.route,\n routePattern: options.route?.pattern,\n status: 200,\n });\n}\n\n// React client-only hooks that are absent from the `react-server` export\n// condition. When called in a Server Component they produce a TypeError like\n// \"useState is not a function\". Rewrite into an actionable message matching\n// the format used by the next/navigation shims (see client-hook-error.ts).\nconst _clientHookPattern =\n /\\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\\b.*is not a function/;\n\nfunction rewriteClientHookError(error: Error): void {\n const match = error.message.match(_clientHookPattern);\n if (match) {\n error.message = buildClientHookErrorMessage(`${match[1]}()`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,6 +10,16 @@ type ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent> = {
|
|
|
10
10
|
routeUnauthorizedModule?: TModule | null;
|
|
11
11
|
statusCode: number;
|
|
12
12
|
};
|
|
13
|
+
type ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule> = {
|
|
14
|
+
layoutIndex: number;
|
|
15
|
+
rootForbiddenModule?: TModule | null;
|
|
16
|
+
rootNotFoundModule?: TModule | null;
|
|
17
|
+
rootUnauthorizedModule?: TModule | null;
|
|
18
|
+
routeForbiddenModules?: readonly (TModule | null | undefined)[] | null;
|
|
19
|
+
routeNotFoundModules?: readonly (TModule | null | undefined)[] | null;
|
|
20
|
+
routeUnauthorizedModules?: readonly (TModule | null | undefined)[] | null;
|
|
21
|
+
statusCode: number;
|
|
22
|
+
};
|
|
13
23
|
type ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {
|
|
14
24
|
getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;
|
|
15
25
|
globalErrorModule?: TModule | null;
|
|
@@ -52,9 +62,10 @@ type RenderAppPageBoundaryResponseOptions<TElement> = {
|
|
|
52
62
|
status: number;
|
|
53
63
|
};
|
|
54
64
|
declare function resolveAppPageHttpAccessBoundaryComponent<TModule, TComponent>(options: ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent>): TComponent | null;
|
|
65
|
+
declare function resolveAppPageParentHttpAccessBoundaryModule<TModule>(options: ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule>): TModule | null;
|
|
55
66
|
declare function resolveAppPageErrorBoundary<TModule, TComponent>(options: ResolveAppPageErrorBoundaryOptions<TModule, TComponent>): ResolveAppPageErrorBoundaryResult<TComponent>;
|
|
56
67
|
declare function wrapAppPageBoundaryElement<TElement, TLayoutModule, TLayoutComponent, TChildSegments, TGlobalErrorComponent>(options: WrapAppPageBoundaryElementOptions<TElement, TLayoutModule, TLayoutComponent, TChildSegments, TGlobalErrorComponent>): TElement;
|
|
57
68
|
declare function renderAppPageBoundaryResponse<TElement>(options: RenderAppPageBoundaryResponseOptions<TElement>): Promise<Response>;
|
|
58
69
|
//#endregion
|
|
59
|
-
export { AppPageParams, renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryComponent, wrapAppPageBoundaryElement };
|
|
70
|
+
export { AppPageParams, renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryComponent, resolveAppPageParentHttpAccessBoundaryModule, wrapAppPageBoundaryElement };
|
|
60
71
|
//# sourceMappingURL=app-page-boundary.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
1
2
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
2
3
|
//#region src/server/app-page-boundary.ts
|
|
3
4
|
function resolveAppPageHttpAccessBoundaryComponent(options) {
|
|
@@ -7,6 +8,22 @@ function resolveAppPageHttpAccessBoundaryComponent(options) {
|
|
|
7
8
|
else boundaryModule = options.routeNotFoundModule ?? options.rootNotFoundModule;
|
|
8
9
|
return options.getDefaultExport(boundaryModule) ?? null;
|
|
9
10
|
}
|
|
11
|
+
function resolveAppPageParentHttpAccessBoundaryModule(options) {
|
|
12
|
+
let routeModules = options.routeNotFoundModules;
|
|
13
|
+
let rootModule = options.rootNotFoundModule;
|
|
14
|
+
if (options.statusCode === 403) {
|
|
15
|
+
routeModules = options.routeForbiddenModules;
|
|
16
|
+
rootModule = options.rootForbiddenModule;
|
|
17
|
+
} else if (options.statusCode === 401) {
|
|
18
|
+
routeModules = options.routeUnauthorizedModules;
|
|
19
|
+
rootModule = options.rootUnauthorizedModule;
|
|
20
|
+
}
|
|
21
|
+
if (routeModules) for (let index = options.layoutIndex - 1; index >= 0; index--) {
|
|
22
|
+
const module = routeModules[index];
|
|
23
|
+
if (module) return module;
|
|
24
|
+
}
|
|
25
|
+
return rootModule ?? null;
|
|
26
|
+
}
|
|
10
27
|
function resolveAppPageErrorBoundary(options) {
|
|
11
28
|
const pageErrorComponent = options.getDefaultExport(options.pageErrorModule);
|
|
12
29
|
if (pageErrorComponent) return {
|
|
@@ -28,17 +45,15 @@ function resolveAppPageErrorBoundary(options) {
|
|
|
28
45
|
}
|
|
29
46
|
function wrapAppPageBoundaryElement(options) {
|
|
30
47
|
let element = options.element;
|
|
31
|
-
if (!options.skipLayoutWrapping) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
element = options.renderLayoutSegmentProvider({ children: childSegments }, element);
|
|
41
|
-
}
|
|
48
|
+
if (!options.skipLayoutWrapping) for (let index = options.layoutModules.length - 1; index >= 0; index--) {
|
|
49
|
+
const layoutComponent = options.getDefaultExport(options.layoutModules[index]);
|
|
50
|
+
if (!layoutComponent) continue;
|
|
51
|
+
const treePosition = options.layoutTreePositions ? options.layoutTreePositions[index] : 0;
|
|
52
|
+
const asyncParams = options.makeThenableParams(resolveAppPageSegmentParams(options.routeSegments, treePosition, options.matchedParams));
|
|
53
|
+
element = options.renderLayout(layoutComponent, element, asyncParams);
|
|
54
|
+
if (options.isRscRequest && options.renderLayoutSegmentProvider && options.resolveChildSegments) {
|
|
55
|
+
const childSegments = options.resolveChildSegments(options.routeSegments ?? [], treePosition, options.matchedParams);
|
|
56
|
+
element = options.renderLayoutSegmentProvider({ children: childSegments }, element);
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
59
|
if (options.isRscRequest && options.includeGlobalErrorBoundary && options.globalErrorComponent) element = options.renderErrorBoundary(options.globalErrorComponent, element);
|
|
@@ -60,6 +75,6 @@ async function renderAppPageBoundaryResponse(options) {
|
|
|
60
75
|
return options.createHtmlResponse(rscStream, options.status);
|
|
61
76
|
}
|
|
62
77
|
//#endregion
|
|
63
|
-
export { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryComponent, wrapAppPageBoundaryElement };
|
|
78
|
+
export { renderAppPageBoundaryResponse, resolveAppPageErrorBoundary, resolveAppPageHttpAccessBoundaryComponent, resolveAppPageParentHttpAccessBoundaryModule, wrapAppPageBoundaryElement };
|
|
64
79
|
|
|
65
80
|
//# sourceMappingURL=app-page-boundary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-boundary.js","names":[],"sources":["../../src/server/app-page-boundary.ts"],"sourcesContent":["import { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\nexport type AppPageParams = Record<string, string | string[]>;\n\ntype ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModule?: TModule | null;\n routeNotFoundModule?: TModule | null;\n routeUnauthorizedModule?: TModule | null;\n statusCode: number;\n};\n\ntype ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n globalErrorModule?: TModule | null;\n layoutErrorModules?: readonly (TModule | null | undefined)[] | null;\n pageErrorModule?: TModule | null;\n};\n\ntype ResolveAppPageErrorBoundaryResult<TComponent> = {\n component: TComponent | null;\n isGlobalError: boolean;\n};\n\ntype WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n> = {\n element: TElement;\n getDefaultExport: (\n module: TLayoutModule | null | undefined,\n ) => TLayoutComponent | null | undefined;\n globalErrorComponent?: TGlobalErrorComponent | null;\n includeGlobalErrorBoundary: boolean;\n isRscRequest: boolean;\n layoutModules: readonly (TLayoutModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n renderErrorBoundary: (component: TGlobalErrorComponent, children: TElement) => TElement;\n renderLayout: (component: TLayoutComponent, children: TElement, params: unknown) => TElement;\n renderLayoutSegmentProvider?: (\n segmentMap: { children: TChildSegments },\n children: TElement,\n ) => TElement;\n resolveChildSegments?: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => TChildSegments;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n};\n\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype RenderAppPageBoundaryResponseOptions<TElement> = {\n createHtmlResponse: (rscStream: ReadableStream<Uint8Array>, status: number) => Promise<Response>;\n createRscOnErrorHandler: () => AppPageBoundaryOnError;\n element: TElement;\n isRscRequest: boolean;\n middlewareHeaders?: Headers | null;\n renderToReadableStream: (\n element: TElement,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n status: number;\n};\n\nexport function resolveAppPageHttpAccessBoundaryComponent<TModule, TComponent>(\n options: ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent>,\n): TComponent | null {\n let boundaryModule: TModule | null | undefined;\n\n if (options.statusCode === 403) {\n boundaryModule = options.routeForbiddenModule ?? options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n boundaryModule = options.routeUnauthorizedModule ?? options.rootUnauthorizedModule;\n } else {\n boundaryModule = options.routeNotFoundModule ?? options.rootNotFoundModule;\n }\n\n return options.getDefaultExport(boundaryModule) ?? null;\n}\n\nexport function resolveAppPageErrorBoundary<TModule, TComponent>(\n options: ResolveAppPageErrorBoundaryOptions<TModule, TComponent>,\n): ResolveAppPageErrorBoundaryResult<TComponent> {\n const pageErrorComponent = options.getDefaultExport(options.pageErrorModule);\n if (pageErrorComponent) {\n return {\n component: pageErrorComponent,\n isGlobalError: false,\n };\n }\n\n if (options.layoutErrorModules) {\n for (let index = options.layoutErrorModules.length - 1; index >= 0; index--) {\n const layoutErrorComponent = options.getDefaultExport(options.layoutErrorModules[index]);\n if (layoutErrorComponent) {\n return {\n component: layoutErrorComponent,\n isGlobalError: false,\n };\n }\n }\n }\n\n const globalErrorComponent = options.getDefaultExport(options.globalErrorModule);\n return {\n component: globalErrorComponent ?? null,\n isGlobalError: Boolean(globalErrorComponent),\n };\n}\n\nexport function wrapAppPageBoundaryElement<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n>(\n options: WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent\n >,\n): TElement {\n let element = options.element;\n\n if (!options.skipLayoutWrapping) {\n const asyncParams = options.makeThenableParams(options.matchedParams);\n\n for (let index = options.layoutModules.length - 1; index >= 0; index--) {\n const layoutComponent = options.getDefaultExport(options.layoutModules[index]);\n if (!layoutComponent) {\n continue;\n }\n\n element = options.renderLayout(layoutComponent, element, asyncParams);\n\n if (\n options.isRscRequest &&\n options.renderLayoutSegmentProvider &&\n options.resolveChildSegments\n ) {\n const treePosition = options.layoutTreePositions ? options.layoutTreePositions[index] : 0;\n const childSegments = options.resolveChildSegments(\n options.routeSegments ?? [],\n treePosition,\n options.matchedParams,\n );\n element = options.renderLayoutSegmentProvider({ children: childSegments }, element);\n }\n }\n }\n\n if (options.isRscRequest && options.includeGlobalErrorBoundary && options.globalErrorComponent) {\n element = options.renderErrorBoundary(options.globalErrorComponent, element);\n }\n\n return element;\n}\n\nexport async function renderAppPageBoundaryResponse<TElement>(\n options: RenderAppPageBoundaryResponseOptions<TElement>,\n): Promise<Response> {\n const rscStream = options.renderToReadableStream(options.element, {\n onError: options.createRscOnErrorHandler(),\n });\n\n if (options.isRscRequest) {\n // Do NOT clear request-scoped context here. RSC responses are consumed lazily\n // by the client, so headers()/cookies() and async server components still need\n // their ALS-backed state while the stream is being read.\n const headers = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(rscStream, {\n status: options.status,\n headers,\n });\n }\n\n return options.createHtmlResponse(rscStream, options.status);\n}\n"],"mappings":";;AA+EA,SAAgB,0CACd,SACmB;CACnB,IAAI;AAEJ,KAAI,QAAQ,eAAe,IACzB,kBAAiB,QAAQ,wBAAwB,QAAQ;UAChD,QAAQ,eAAe,IAChC,kBAAiB,QAAQ,2BAA2B,QAAQ;KAE5D,kBAAiB,QAAQ,uBAAuB,QAAQ;AAG1D,QAAO,QAAQ,iBAAiB,eAAe,IAAI;;AAGrD,SAAgB,4BACd,SAC+C;CAC/C,MAAM,qBAAqB,QAAQ,iBAAiB,QAAQ,gBAAgB;AAC5E,KAAI,mBACF,QAAO;EACL,WAAW;EACX,eAAe;EAChB;AAGH,KAAI,QAAQ,mBACV,MAAK,IAAI,QAAQ,QAAQ,mBAAmB,SAAS,GAAG,SAAS,GAAG,SAAS;EAC3E,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,mBAAmB,OAAO;AACxF,MAAI,qBACF,QAAO;GACL,WAAW;GACX,eAAe;GAChB;;CAKP,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,kBAAkB;AAChF,QAAO;EACL,WAAW,wBAAwB;EACnC,eAAe,QAAQ,qBAAqB;EAC7C;;AAGH,SAAgB,2BAOd,SAOU;CACV,IAAI,UAAU,QAAQ;AAEtB,KAAI,CAAC,QAAQ,oBAAoB;EAC/B,MAAM,cAAc,QAAQ,mBAAmB,QAAQ,cAAc;AAErE,OAAK,IAAI,QAAQ,QAAQ,cAAc,SAAS,GAAG,SAAS,GAAG,SAAS;GACtE,MAAM,kBAAkB,QAAQ,iBAAiB,QAAQ,cAAc,OAAO;AAC9E,OAAI,CAAC,gBACH;AAGF,aAAU,QAAQ,aAAa,iBAAiB,SAAS,YAAY;AAErE,OACE,QAAQ,gBACR,QAAQ,+BACR,QAAQ,sBACR;IACA,MAAM,eAAe,QAAQ,sBAAsB,QAAQ,oBAAoB,SAAS;IACxF,MAAM,gBAAgB,QAAQ,qBAC5B,QAAQ,iBAAiB,EAAE,EAC3B,cACA,QAAQ,cACT;AACD,cAAU,QAAQ,4BAA4B,EAAE,UAAU,eAAe,EAAE,QAAQ;;;;AAKzF,KAAI,QAAQ,gBAAgB,QAAQ,8BAA8B,QAAQ,qBACxE,WAAU,QAAQ,oBAAoB,QAAQ,sBAAsB,QAAQ;AAG9E,QAAO;;AAGT,eAAsB,8BACpB,SACmB;CACnB,MAAM,YAAY,QAAQ,uBAAuB,QAAQ,SAAS,EAChE,SAAS,QAAQ,yBAAyB,EAC3C,CAAC;AAEF,KAAI,QAAQ,cAAc;EAIxB,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;GAChB,MAAM;GACP,CAAC;AACF,iCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAE1E,SAAO,IAAI,SAAS,WAAW;GAC7B,QAAQ,QAAQ;GAChB;GACD,CAAC;;AAGJ,QAAO,QAAQ,mBAAmB,WAAW,QAAQ,OAAO"}
|
|
1
|
+
{"version":3,"file":"app-page-boundary.js","names":[],"sources":["../../src/server/app-page-boundary.ts"],"sourcesContent":["import { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\n\nexport type AppPageParams = Record<string, string | string[]>;\n\ntype ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModule?: TModule | null;\n routeNotFoundModule?: TModule | null;\n routeUnauthorizedModule?: TModule | null;\n statusCode: number;\n};\n\ntype ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule> = {\n layoutIndex: number;\n rootForbiddenModule?: TModule | null;\n rootNotFoundModule?: TModule | null;\n rootUnauthorizedModule?: TModule | null;\n routeForbiddenModules?: readonly (TModule | null | undefined)[] | null;\n routeNotFoundModules?: readonly (TModule | null | undefined)[] | null;\n routeUnauthorizedModules?: readonly (TModule | null | undefined)[] | null;\n statusCode: number;\n};\n\ntype ResolveAppPageErrorBoundaryOptions<TModule, TComponent> = {\n getDefaultExport: (module: TModule | null | undefined) => TComponent | null | undefined;\n globalErrorModule?: TModule | null;\n layoutErrorModules?: readonly (TModule | null | undefined)[] | null;\n pageErrorModule?: TModule | null;\n};\n\ntype ResolveAppPageErrorBoundaryResult<TComponent> = {\n component: TComponent | null;\n isGlobalError: boolean;\n};\n\ntype WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n> = {\n element: TElement;\n getDefaultExport: (\n module: TLayoutModule | null | undefined,\n ) => TLayoutComponent | null | undefined;\n globalErrorComponent?: TGlobalErrorComponent | null;\n includeGlobalErrorBoundary: boolean;\n isRscRequest: boolean;\n layoutModules: readonly (TLayoutModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n makeThenableParams: (params: AppPageParams) => unknown;\n matchedParams: AppPageParams;\n renderErrorBoundary: (component: TGlobalErrorComponent, children: TElement) => TElement;\n renderLayout: (component: TLayoutComponent, children: TElement, params: unknown) => TElement;\n renderLayoutSegmentProvider?: (\n segmentMap: { children: TChildSegments },\n children: TElement,\n ) => TElement;\n resolveChildSegments?: (\n routeSegments: readonly string[],\n treePosition: number,\n params: AppPageParams,\n ) => TChildSegments;\n routeSegments?: readonly string[];\n skipLayoutWrapping?: boolean;\n};\n\ntype AppPageBoundaryOnError = (\n error: unknown,\n requestInfo: unknown,\n errorContext: unknown,\n) => unknown;\n\ntype RenderAppPageBoundaryResponseOptions<TElement> = {\n createHtmlResponse: (rscStream: ReadableStream<Uint8Array>, status: number) => Promise<Response>;\n createRscOnErrorHandler: () => AppPageBoundaryOnError;\n element: TElement;\n isRscRequest: boolean;\n middlewareHeaders?: Headers | null;\n renderToReadableStream: (\n element: TElement,\n options: { onError: AppPageBoundaryOnError },\n ) => ReadableStream<Uint8Array>;\n status: number;\n};\n\nexport function resolveAppPageHttpAccessBoundaryComponent<TModule, TComponent>(\n options: ResolveAppPageHttpAccessBoundaryComponentOptions<TModule, TComponent>,\n): TComponent | null {\n let boundaryModule: TModule | null | undefined;\n\n if (options.statusCode === 403) {\n boundaryModule = options.routeForbiddenModule ?? options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n boundaryModule = options.routeUnauthorizedModule ?? options.rootUnauthorizedModule;\n } else {\n boundaryModule = options.routeNotFoundModule ?? options.rootNotFoundModule;\n }\n\n return options.getDefaultExport(boundaryModule) ?? null;\n}\n\nexport function resolveAppPageParentHttpAccessBoundaryModule<TModule>(\n options: ResolveAppPageParentHttpAccessBoundaryModuleOptions<TModule>,\n): TModule | null {\n let routeModules = options.routeNotFoundModules;\n let rootModule = options.rootNotFoundModule;\n\n if (options.statusCode === 403) {\n routeModules = options.routeForbiddenModules;\n rootModule = options.rootForbiddenModule;\n } else if (options.statusCode === 401) {\n routeModules = options.routeUnauthorizedModules;\n rootModule = options.rootUnauthorizedModule;\n }\n\n if (routeModules) {\n for (let index = options.layoutIndex - 1; index >= 0; index--) {\n const module = routeModules[index];\n if (module) {\n return module;\n }\n }\n }\n\n return rootModule ?? null;\n}\n\nexport function resolveAppPageErrorBoundary<TModule, TComponent>(\n options: ResolveAppPageErrorBoundaryOptions<TModule, TComponent>,\n): ResolveAppPageErrorBoundaryResult<TComponent> {\n const pageErrorComponent = options.getDefaultExport(options.pageErrorModule);\n if (pageErrorComponent) {\n return {\n component: pageErrorComponent,\n isGlobalError: false,\n };\n }\n\n if (options.layoutErrorModules) {\n for (let index = options.layoutErrorModules.length - 1; index >= 0; index--) {\n const layoutErrorComponent = options.getDefaultExport(options.layoutErrorModules[index]);\n if (layoutErrorComponent) {\n return {\n component: layoutErrorComponent,\n isGlobalError: false,\n };\n }\n }\n }\n\n const globalErrorComponent = options.getDefaultExport(options.globalErrorModule);\n return {\n component: globalErrorComponent ?? null,\n isGlobalError: Boolean(globalErrorComponent),\n };\n}\n\nexport function wrapAppPageBoundaryElement<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent,\n>(\n options: WrapAppPageBoundaryElementOptions<\n TElement,\n TLayoutModule,\n TLayoutComponent,\n TChildSegments,\n TGlobalErrorComponent\n >,\n): TElement {\n let element = options.element;\n\n if (!options.skipLayoutWrapping) {\n for (let index = options.layoutModules.length - 1; index >= 0; index--) {\n const layoutComponent = options.getDefaultExport(options.layoutModules[index]);\n if (!layoutComponent) {\n continue;\n }\n\n const treePosition = options.layoutTreePositions ? options.layoutTreePositions[index] : 0;\n const asyncParams = options.makeThenableParams(\n resolveAppPageSegmentParams(options.routeSegments, treePosition, options.matchedParams),\n );\n element = options.renderLayout(layoutComponent, element, asyncParams);\n\n if (\n options.isRscRequest &&\n options.renderLayoutSegmentProvider &&\n options.resolveChildSegments\n ) {\n const childSegments = options.resolveChildSegments(\n options.routeSegments ?? [],\n treePosition,\n options.matchedParams,\n );\n element = options.renderLayoutSegmentProvider({ children: childSegments }, element);\n }\n }\n }\n\n if (options.isRscRequest && options.includeGlobalErrorBoundary && options.globalErrorComponent) {\n element = options.renderErrorBoundary(options.globalErrorComponent, element);\n }\n\n return element;\n}\n\nexport async function renderAppPageBoundaryResponse<TElement>(\n options: RenderAppPageBoundaryResponseOptions<TElement>,\n): Promise<Response> {\n const rscStream = options.renderToReadableStream(options.element, {\n onError: options.createRscOnErrorHandler(),\n });\n\n if (options.isRscRequest) {\n // Do NOT clear request-scoped context here. RSC responses are consumed lazily\n // by the client, so headers()/cookies() and async server components still need\n // their ALS-backed state while the stream is being read.\n const headers = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n\n return new Response(rscStream, {\n status: options.status,\n headers,\n });\n }\n\n return options.createHtmlResponse(rscStream, options.status);\n}\n"],"mappings":";;;AA2FA,SAAgB,0CACd,SACmB;CACnB,IAAI;AAEJ,KAAI,QAAQ,eAAe,IACzB,kBAAiB,QAAQ,wBAAwB,QAAQ;UAChD,QAAQ,eAAe,IAChC,kBAAiB,QAAQ,2BAA2B,QAAQ;KAE5D,kBAAiB,QAAQ,uBAAuB,QAAQ;AAG1D,QAAO,QAAQ,iBAAiB,eAAe,IAAI;;AAGrD,SAAgB,6CACd,SACgB;CAChB,IAAI,eAAe,QAAQ;CAC3B,IAAI,aAAa,QAAQ;AAEzB,KAAI,QAAQ,eAAe,KAAK;AAC9B,iBAAe,QAAQ;AACvB,eAAa,QAAQ;YACZ,QAAQ,eAAe,KAAK;AACrC,iBAAe,QAAQ;AACvB,eAAa,QAAQ;;AAGvB,KAAI,aACF,MAAK,IAAI,QAAQ,QAAQ,cAAc,GAAG,SAAS,GAAG,SAAS;EAC7D,MAAM,SAAS,aAAa;AAC5B,MAAI,OACF,QAAO;;AAKb,QAAO,cAAc;;AAGvB,SAAgB,4BACd,SAC+C;CAC/C,MAAM,qBAAqB,QAAQ,iBAAiB,QAAQ,gBAAgB;AAC5E,KAAI,mBACF,QAAO;EACL,WAAW;EACX,eAAe;EAChB;AAGH,KAAI,QAAQ,mBACV,MAAK,IAAI,QAAQ,QAAQ,mBAAmB,SAAS,GAAG,SAAS,GAAG,SAAS;EAC3E,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,mBAAmB,OAAO;AACxF,MAAI,qBACF,QAAO;GACL,WAAW;GACX,eAAe;GAChB;;CAKP,MAAM,uBAAuB,QAAQ,iBAAiB,QAAQ,kBAAkB;AAChF,QAAO;EACL,WAAW,wBAAwB;EACnC,eAAe,QAAQ,qBAAqB;EAC7C;;AAGH,SAAgB,2BAOd,SAOU;CACV,IAAI,UAAU,QAAQ;AAEtB,KAAI,CAAC,QAAQ,mBACX,MAAK,IAAI,QAAQ,QAAQ,cAAc,SAAS,GAAG,SAAS,GAAG,SAAS;EACtE,MAAM,kBAAkB,QAAQ,iBAAiB,QAAQ,cAAc,OAAO;AAC9E,MAAI,CAAC,gBACH;EAGF,MAAM,eAAe,QAAQ,sBAAsB,QAAQ,oBAAoB,SAAS;EACxF,MAAM,cAAc,QAAQ,mBAC1B,4BAA4B,QAAQ,eAAe,cAAc,QAAQ,cAAc,CACxF;AACD,YAAU,QAAQ,aAAa,iBAAiB,SAAS,YAAY;AAErE,MACE,QAAQ,gBACR,QAAQ,+BACR,QAAQ,sBACR;GACA,MAAM,gBAAgB,QAAQ,qBAC5B,QAAQ,iBAAiB,EAAE,EAC3B,cACA,QAAQ,cACT;AACD,aAAU,QAAQ,4BAA4B,EAAE,UAAU,eAAe,EAAE,QAAQ;;;AAKzF,KAAI,QAAQ,gBAAgB,QAAQ,8BAA8B,QAAQ,qBACxE,WAAU,QAAQ,oBAAoB,QAAQ,sBAAsB,QAAQ;AAG9E,QAAO;;AAGT,eAAsB,8BACpB,SACmB;CACnB,MAAM,YAAY,QAAQ,uBAAuB,QAAQ,SAAS,EAChE,SAAS,QAAQ,yBAAyB,EAC3C,CAAC;AAEF,KAAI,QAAQ,cAAc;EAIxB,MAAM,UAAU,IAAI,QAAQ;GAC1B,gBAAgB;GAChB,MAAM;GACP,CAAC;AACF,iCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAE1E,SAAO,IAAI,SAAS,WAAW;GAC7B,QAAQ,QAAQ;GAChB;GACD,CAAC;;AAGJ,QAAO,QAAQ,mBAAmB,WAAW,QAAQ,OAAO"}
|
|
@@ -34,6 +34,7 @@ type ReadAppPageCacheResponseOptions = {
|
|
|
34
34
|
type FinalizeAppPageHtmlCacheResponseOptions = {
|
|
35
35
|
capturedRscDataPromise: Promise<ArrayBuffer> | null;
|
|
36
36
|
cleanPathname: string;
|
|
37
|
+
consumeDynamicUsage: () => boolean;
|
|
37
38
|
getPageTags: () => string[];
|
|
38
39
|
isrDebug?: AppPageDebugLogger;
|
|
39
40
|
isrHtmlKey: (pathname: string) => string;
|
|
@@ -55,10 +56,12 @@ type ScheduleAppPageRscCacheWriteOptions = {
|
|
|
55
56
|
revalidateSeconds: number;
|
|
56
57
|
waitUntil?: (promise: Promise<void>) => void;
|
|
57
58
|
};
|
|
59
|
+
declare function buildAppPageCacheTags(pathname: string, extraTags: readonly string[]): string[];
|
|
58
60
|
declare function buildAppPageCachedResponse(cachedValue: CachedAppPageValue, options: BuildAppPageCachedResponseOptions): Response | null;
|
|
59
61
|
declare function readAppPageCacheResponse(options: ReadAppPageCacheResponseOptions): Promise<Response | null>;
|
|
60
62
|
declare function finalizeAppPageHtmlCacheResponse(response: Response, options: FinalizeAppPageHtmlCacheResponseOptions): Response;
|
|
63
|
+
declare function finalizeAppPageRscCacheResponse(response: Response, options: ScheduleAppPageRscCacheWriteOptions): Response;
|
|
61
64
|
declare function scheduleAppPageRscCacheWrite(options: ScheduleAppPageRscCacheWriteOptions): boolean;
|
|
62
65
|
//#endregion
|
|
63
|
-
export { buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, readAppPageCacheResponse, scheduleAppPageRscCacheWrite };
|
|
66
|
+
export { buildAppPageCacheTags, buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse, readAppPageCacheResponse, scheduleAppPageRscCacheWrite };
|
|
64
67
|
//# sourceMappingURL=app-page-cache.d.ts.map
|