@withl5e/l5e 0.3.1 → 0.3.3-alpha.0
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/entry-server.js +118 -116
- package/dist/entry-server.js.map +1 -1
- package/dist/{generateMetadata-Cn2uJjg_.js → generateMetadata-Cn8BIxq6.js} +4 -4
- package/dist/{generateMetadata-Cn2uJjg_.js.map → generateMetadata-Cn8BIxq6.js.map} +1 -1
- package/dist/index.js +40 -37
- package/dist/island/runtime.js +40 -23
- package/dist/island/runtime.js.map +1 -1
- package/dist/island.js +34 -28
- package/dist/island.js.map +1 -1
- package/dist/{jsx-runtime-Bokflh8Q.js → jsx-runtime-DqAp8xlt.js} +86 -60
- package/dist/jsx-runtime-DqAp8xlt.js.map +1 -0
- package/dist/jsx-runtime.js +20 -17
- package/dist/{render-DTXfJu0d.js → render-CRag-5V7.js} +2 -2
- package/dist/{render-DTXfJu0d.js.map → render-CRag-5V7.js.map} +1 -1
- package/dist/seo.js +3 -3
- package/dist/server.js +246 -241
- package/dist/server.js.map +1 -1
- package/dist/vite-plugin.js +17 -15
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +1 -1
- package/src/core/entry-server.ts +24 -2
- package/src/core/jsx-runtime.ts +68 -6
- package/src/core/server.ts +43 -4
- package/src/core/vite-plugin.ts +24 -2
- package/src/island/ClientIsland.ts +24 -1
- package/src/island/runtime.ts +27 -1
- package/dist/jsx-runtime-Bokflh8Q.js.map +0 -1
package/dist/entry-server.js
CHANGED
|
@@ -1,157 +1,159 @@
|
|
|
1
|
-
import { r as
|
|
2
|
-
import { M as
|
|
3
|
-
import { N as
|
|
4
|
-
import {
|
|
5
|
-
import { viewLoaders as
|
|
6
|
-
import
|
|
7
|
-
import { globalLoader as
|
|
8
|
-
import { loadMiddleware as
|
|
9
|
-
import { islandModules as
|
|
10
|
-
async function
|
|
11
|
-
const
|
|
12
|
-
if (
|
|
13
|
-
let
|
|
1
|
+
import { r as u, s as U } from "./render-CRag-5V7.js";
|
|
2
|
+
import { M as Y } from "./generateMetadata-Cn8BIxq6.js";
|
|
3
|
+
import { N as K, I as T, R as Q, H as W, S as k } from "./exceptions-CHPz01DJ.js";
|
|
4
|
+
import { v as X, w as j, b as N, q as y, r as D, n as f, j as Z, a as B, H as q, d as A, e as L, h as ee, i as te, g as ae, f as F, k as se } from "./jsx-runtime-DqAp8xlt.js";
|
|
5
|
+
import { viewLoaders as I, viewComponents as v } from "virtual:l5e-views";
|
|
6
|
+
import oe from "virtual:l5e-route";
|
|
7
|
+
import { globalLoader as O } from "virtual:l5e-global-loader";
|
|
8
|
+
import { loadMiddleware as Se } from "virtual:l5e-middleware";
|
|
9
|
+
import { islandModules as ne } from "virtual:l5e-islands";
|
|
10
|
+
async function re(s) {
|
|
11
|
+
const o = se();
|
|
12
|
+
if (o.length === 0) return s;
|
|
13
|
+
let c, d;
|
|
14
14
|
try {
|
|
15
|
-
[{ renderToString:
|
|
15
|
+
[{ renderToString: c }, { createElement: d }] = await Promise.all([
|
|
16
16
|
import("react-dom/server"),
|
|
17
17
|
import("react")
|
|
18
18
|
]);
|
|
19
|
-
} catch (
|
|
20
|
-
console.error("[l5e-island] SSR requires react-dom/server + react:",
|
|
21
|
-
for (const
|
|
22
|
-
|
|
23
|
-
return
|
|
19
|
+
} catch (t) {
|
|
20
|
+
console.error("[l5e-island] SSR requires react-dom/server + react:", t);
|
|
21
|
+
for (const a of o)
|
|
22
|
+
s = s.replace(`<!--${a.token}-->`, "").replace(` data-island-ssr="${a.token}"`, "");
|
|
23
|
+
return s;
|
|
24
24
|
}
|
|
25
|
-
for (const
|
|
25
|
+
for (const t of o)
|
|
26
26
|
try {
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
29
|
-
throw new Error(`island module not found in glob: /${
|
|
30
|
-
const
|
|
27
|
+
const a = ne["/" + t.src];
|
|
28
|
+
if (!a)
|
|
29
|
+
throw new Error(`island module not found in glob: /${t.src}`);
|
|
30
|
+
const n = await a(), i = n[t.name] ?? n.default;
|
|
31
31
|
if (!i)
|
|
32
|
-
throw new Error(`no export "${
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
} catch (
|
|
36
|
-
console.error(`[l5e-island] Failed to SSR island "${
|
|
32
|
+
throw new Error(`no export "${t.name}" or default in /${t.src}`);
|
|
33
|
+
const p = c(d(i, t.props));
|
|
34
|
+
s = s.replace(`<!--${t.token}-->`, () => p).replace(`data-island-ssr="${t.token}"`, 'data-island-ssr="1"');
|
|
35
|
+
} catch (a) {
|
|
36
|
+
console.error(`[l5e-island] Failed to SSR island "${t.name}":`, a), s = s.replace(`<!--${t.token}-->`, "").replace(` data-island-ssr="${t.token}"`, "");
|
|
37
37
|
}
|
|
38
|
-
return
|
|
38
|
+
return s;
|
|
39
39
|
}
|
|
40
|
-
async function
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
const
|
|
46
|
-
statusCode:
|
|
47
|
-
message:
|
|
48
|
-
data:
|
|
49
|
-
},
|
|
40
|
+
async function V(s, o) {
|
|
41
|
+
const c = "_error", d = `/src/views/${c}/index.tsx`;
|
|
42
|
+
j(c);
|
|
43
|
+
const t = v[d] ? await v[d]() : null;
|
|
44
|
+
if (t?.default) {
|
|
45
|
+
const a = {
|
|
46
|
+
statusCode: s.statusCode,
|
|
47
|
+
message: s.message,
|
|
48
|
+
data: s.data
|
|
49
|
+
}, n = t.default, i = u(f(n, a)), p = A(), r = L(), h = F(), E = h.length > 0 ? h.map((l) => u(l)).join(`
|
|
50
50
|
`) : void 0;
|
|
51
51
|
return {
|
|
52
52
|
html: i,
|
|
53
|
-
scripts:
|
|
54
|
-
styles:
|
|
53
|
+
scripts: p.map((l) => l.path),
|
|
54
|
+
styles: r.map((l) => l.path),
|
|
55
55
|
head: E,
|
|
56
|
-
lang:
|
|
57
|
-
statusCode:
|
|
56
|
+
lang: o,
|
|
57
|
+
statusCode: s.statusCode
|
|
58
58
|
};
|
|
59
59
|
} else {
|
|
60
|
-
const
|
|
60
|
+
const a = f("div", {}, `${s.statusCode} - ${s.message}`);
|
|
61
61
|
return {
|
|
62
|
-
html:
|
|
63
|
-
statusCode:
|
|
62
|
+
html: u(a),
|
|
63
|
+
statusCode: s.statusCode
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
async function
|
|
68
|
-
|
|
67
|
+
async function fe(s, o = {}, c = {}) {
|
|
68
|
+
const d = c.externalizeIslandProps ?? !0;
|
|
69
|
+
return X(async () => {
|
|
69
70
|
try {
|
|
70
|
-
const t = await
|
|
71
|
+
const t = await oe(o);
|
|
71
72
|
if (!t)
|
|
72
|
-
throw new
|
|
73
|
-
path:
|
|
74
|
-
pathname:
|
|
75
|
-
url:
|
|
73
|
+
throw new K("Page not found", {
|
|
74
|
+
path: o.path,
|
|
75
|
+
pathname: o.pathname,
|
|
76
|
+
url: o.url?.href
|
|
76
77
|
});
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
if (
|
|
83
|
-
console.info(`Global loader ignored for view: ${
|
|
78
|
+
const a = typeof t == "string" ? t : t.view;
|
|
79
|
+
o.params = typeof t == "string" ? {} : t.params ?? {}, j(a);
|
|
80
|
+
let n = {}, i;
|
|
81
|
+
const p = "/src/global-loader.ts", r = O[p] ? await O[p]() : null;
|
|
82
|
+
if (r?.loader)
|
|
83
|
+
if (r.shouldIgnore?.(a) || !1)
|
|
84
|
+
console.info(`Global loader ignored for view: ${a}`);
|
|
84
85
|
else {
|
|
85
|
-
const
|
|
86
|
-
|
|
86
|
+
const g = await r.loader(o);
|
|
87
|
+
n = g.props || {}, i = g.lang, g.cacheTags && N(g.cacheTags);
|
|
87
88
|
}
|
|
88
|
-
let
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
const e = await
|
|
89
|
+
let h = {}, E, l, C, $ = !1;
|
|
90
|
+
const M = `/src/views/${a}/loader.ts`, m = I[M] ? await I[M]() : null;
|
|
91
|
+
if (m?.loader) {
|
|
92
|
+
const e = await m.loader(o);
|
|
92
93
|
if (e.rawResponse)
|
|
93
94
|
return {
|
|
94
95
|
rawResponse: e.rawResponse,
|
|
95
96
|
statusCode: e.rawResponse.statusCode || 200
|
|
96
97
|
};
|
|
97
|
-
|
|
98
|
+
h = e.props || {}, E = e.maxAge, l = e.sMaxAge, C = e.swr, $ = e.rawHtml || !1, e.cacheTags && N(e.cacheTags), e.lang && (i = e.lang);
|
|
98
99
|
} else
|
|
99
|
-
console.info(`No loader for view: ${
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
const e =
|
|
103
|
-
e &&
|
|
100
|
+
console.info(`No loader for view: ${a}`);
|
|
101
|
+
const w = { ...n, ...h };
|
|
102
|
+
if (r?.generateMetadata) {
|
|
103
|
+
const e = r.generateMetadata(o, w);
|
|
104
|
+
e && y(e);
|
|
104
105
|
}
|
|
105
|
-
if (
|
|
106
|
-
const e =
|
|
107
|
-
e &&
|
|
106
|
+
if (m?.generateMetadata) {
|
|
107
|
+
const e = m.generateMetadata(o, w);
|
|
108
|
+
e && y(e);
|
|
108
109
|
}
|
|
109
|
-
if (
|
|
110
|
-
const e =
|
|
111
|
-
e &&
|
|
110
|
+
if (r?.generateSchema) {
|
|
111
|
+
const e = r.generateSchema(o, w);
|
|
112
|
+
e && D(e);
|
|
112
113
|
}
|
|
113
|
-
if (
|
|
114
|
-
const e =
|
|
115
|
-
e &&
|
|
114
|
+
if (m?.generateSchema) {
|
|
115
|
+
const e = m.generateSchema(o, w);
|
|
116
|
+
e && D(e);
|
|
116
117
|
}
|
|
117
|
-
const S = `/src/views/${
|
|
118
|
-
if (
|
|
119
|
-
throw console.error(`View component not found: ${
|
|
120
|
-
viewName:
|
|
118
|
+
const S = `/src/views/${a}/index.tsx`, P = (v[S] ? await v[S]() : null)?.default;
|
|
119
|
+
if (!P)
|
|
120
|
+
throw console.error(`View component not found: ${a}`), process.env.NODE_ENV !== "production" ? new T(`View component not found: "${a}"`, {
|
|
121
|
+
viewName: a,
|
|
121
122
|
expectedPath: S,
|
|
122
|
-
availableViews: Object.keys(
|
|
123
|
+
availableViews: Object.keys(v),
|
|
123
124
|
hint: `Make sure the view component exists at ${S} and exports a default component`,
|
|
124
125
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
125
|
-
}) : new
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
priority:
|
|
130
|
-
children:
|
|
126
|
+
}) : new T("Internal Server Error");
|
|
127
|
+
u(f(Y, {})), Z().forEach((e) => {
|
|
128
|
+
const g = U(e, { isJSON: !0 });
|
|
129
|
+
B({
|
|
130
|
+
priority: q.SEO,
|
|
131
|
+
children: f("script", {
|
|
131
132
|
type: "application/ld+json",
|
|
132
|
-
setHtml:
|
|
133
|
+
setHtml: g
|
|
133
134
|
})
|
|
134
135
|
});
|
|
135
136
|
});
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
const
|
|
137
|
+
let x = u(f(P, w));
|
|
138
|
+
x = await re(x);
|
|
139
|
+
const J = A(), _ = L(), R = ee(), b = te(), z = ae(), H = F(), G = H.length > 0 ? H.map((e) => u(e)).join(`
|
|
139
140
|
`) : void 0;
|
|
140
141
|
return {
|
|
141
|
-
html:
|
|
142
|
-
scripts:
|
|
143
|
-
styles:
|
|
144
|
-
islands:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
142
|
+
html: x,
|
|
143
|
+
scripts: J.map((e) => e.path),
|
|
144
|
+
styles: _.map((e) => e.path),
|
|
145
|
+
islands: R.length > 0 ? R : void 0,
|
|
146
|
+
islandData: b.length > 0 ? b : void 0,
|
|
147
|
+
head: G,
|
|
148
|
+
lang: i,
|
|
149
|
+
maxAge: E,
|
|
150
|
+
sMaxAge: l,
|
|
151
|
+
swr: C,
|
|
152
|
+
cacheTags: z,
|
|
153
|
+
rawHtml: $
|
|
152
154
|
};
|
|
153
155
|
} catch (t) {
|
|
154
|
-
if (t instanceof
|
|
156
|
+
if (t instanceof Q)
|
|
155
157
|
return {
|
|
156
158
|
html: "",
|
|
157
159
|
redirect: {
|
|
@@ -159,20 +161,20 @@ async function ge(o, s = {}) {
|
|
|
159
161
|
statusCode: t.statusCode
|
|
160
162
|
}
|
|
161
163
|
};
|
|
162
|
-
if (t instanceof
|
|
163
|
-
return await
|
|
164
|
+
if (t instanceof W)
|
|
165
|
+
return await V(t);
|
|
164
166
|
console.error("Failed to render:", t);
|
|
165
|
-
const
|
|
167
|
+
const n = process.env.NODE_ENV === "production" ? new k("Internal Server Error") : new k(t.message || "Internal Server Error", {
|
|
166
168
|
originalError: t.name,
|
|
167
169
|
stack: t.stack,
|
|
168
170
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
169
171
|
});
|
|
170
|
-
return await
|
|
172
|
+
return await V(n);
|
|
171
173
|
}
|
|
172
|
-
},
|
|
174
|
+
}, o, void 0, { externalizeIslandProps: d });
|
|
173
175
|
}
|
|
174
176
|
export {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
Se as loadMiddleware,
|
|
178
|
+
fe as render
|
|
177
179
|
};
|
|
178
180
|
//# sourceMappingURL=entry-server.js.map
|
package/dist/entry-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-server.js","sources":["../src/core/entry-server.ts"],"sourcesContent":["/// <reference path=\"./jsx-types.d.ts\" />\nimport serialize from 'serialize-javascript';\nimport { MetadataRenderer } from '../seo/generateMetadata';\nimport type { Metadata } from '../seo/types';\nimport {\n HttpException,\n InternalServerErrorException,\n NotFoundException,\n RedirectException,\n ServiceUnavailableException,\n} from './exceptions';\nimport { HEAD_PRIORITY } from './head-priority';\nimport {\n addCacheTag,\n getCacheTags,\n getClientJsEntries,\n getCssEntries,\n getHeadContent,\n getIslandEntries,\n getSchemas,\n getSsrIslands,\n jsxFactory as h,\n Head,\n pushMetadata,\n pushSchema,\n runInRenderContext,\n setViewName,\n} from './jsx-runtime';\nimport { renderJsxToHtmlString } from './render';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { viewComponents, viewLoaders } from 'virtual:l5e-views';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport routeHandler from 'virtual:l5e-route';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { globalLoader } from 'virtual:l5e-global-loader';\n// @ts-ignore - Virtual modules provided by Vite plugin\nexport { loadMiddleware } from 'virtual:l5e-middleware';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { islandModules } from 'virtual:l5e-islands';\n\n/**\n * Fill `ssr` island placeholders with server-rendered HTML.\n *\n * During the synchronous render pass, each `<ClientIsland ssr>` emits a unique\n * token (as `<!--token-->` body + `data-island-ssr=\"token\"`). Here — after the\n * pass — we can `await import()` the actual React component and renderToString it,\n * then string-replace the token. Only islands present on this page are imported.\n *\n * On failure we strip both the token and the `data-island-ssr` attribute so the\n * client cleanly falls back to a client-only mount (no hydration mismatch).\n */\nasync function fillSsrIslands(htmlBody: string): Promise<string> {\n const pending = getSsrIslands();\n if (pending.length === 0) return htmlBody;\n\n let renderToString: (el: any) => string;\n let createElement: (type: any, props: any) => any;\n try {\n [{ renderToString }, { createElement }] = await Promise.all([\n import('react-dom/server'),\n import('react'),\n ]);\n } catch (err) {\n console.error('[l5e-island] SSR requires react-dom/server + react:', err);\n // Strip every pending token/attr → client-only fallback for all.\n for (const island of pending) {\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, '')\n .replace(` data-island-ssr=\"${island.token}\"`, '');\n }\n return htmlBody;\n }\n\n for (const island of pending) {\n try {\n const loader = islandModules['/' + island.src];\n if (!loader) {\n throw new Error(`island module not found in glob: /${island.src}`);\n }\n const mod: any = await loader();\n const Component = mod[island.name] ?? mod.default;\n if (!Component) {\n throw new Error(`no export \"${island.name}\" or default in /${island.src}`);\n }\n const out = renderToString(createElement(Component, island.props));\n // Replacer fn (not a string) so `$`-sequences in `out` (e.g. \"$&\", \"$$\")\n // aren't interpreted as special replacement patterns.\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, () => out)\n .replace(`data-island-ssr=\"${island.token}\"`, 'data-island-ssr=\"1\"');\n } catch (err) {\n console.error(`[l5e-island] Failed to SSR island \"${island.name}\":`, err);\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, '')\n .replace(` data-island-ssr=\"${island.token}\"`, '');\n }\n }\n\n return htmlBody;\n}\n\nexport interface RawResponse {\n body: string | Buffer;\n contentType: string;\n statusCode?: number;\n headers?: Record<string, string>;\n}\n\nexport interface RenderResult {\n html?: string;\n scripts?: string[];\n styles?: string[];\n islands?: Array<{ key: string; src: string; name: string }>;\n head?: string;\n lang?: string;\n statusCode?: number;\n maxAge?: number;\n sMaxAge?: number;\n swr?: number;\n cacheTags?: string[];\n redirect?: { url: string; statusCode: number };\n rawResponse?: RawResponse;\n rawHtml?: boolean;\n}\n\nexport interface RequestInfo {\n url?: URL;\n path?: string;\n pathname?: string;\n method?: string;\n headers?: Record<string, any>;\n cookies?: Record<string, string>;\n query?: Record<string, any>;\n ip?: string;\n locals?: Record<string, unknown>;\n params?: Record<string, any>;\n}\n\nexport type RouteResult =\n | string\n | null\n | { view: string; params?: Record<string, any> };\n\n// SchemaMarkup type - có thể là single schema hoặc array of schemas\n// Sử dụng any để tương thích với schema-dts types từ frontend\nexport type SchemaMarkup = any | Array<any>;\n\nexport interface LoaderResult {\n props?: Record<string, any>;\n lang?: string;\n maxAge?: number;\n sMaxAge?: number;\n swr?: number;\n cacheTags?: string[] | Record<string, boolean>;\n rawResponse?: RawResponse;\n rawHtml?: boolean;\n}\n\nexport type LoaderFunction = (requestInfo: RequestInfo) => Promise<LoaderResult>;\n\nexport type GenerateMetadataFunction = (requestInfo: RequestInfo, props: any) => Metadata | null;\n\nexport type GenerateSchemaFunction = (requestInfo: RequestInfo, props: any) => SchemaMarkup | null;\n\nexport interface GlobalLoaderModule {\n loader: LoaderFunction;\n generateMetadata?: GenerateMetadataFunction;\n generateSchema?: GenerateSchemaFunction;\n shouldIgnore?: (viewName: string) => boolean;\n}\n\n/**\n * Helper function to render error view\n */\nasync function renderErrorView(err: HttpException, lang?: string): Promise<RenderResult> {\n const errorViewName = `_error`;\n const errorComponentPath = `/src/views/${errorViewName}/index.tsx`;\n\n // Set error view name in context\n setViewName(errorViewName);\n\n // Try to load error view\n const errorComponentModule = viewComponents[errorComponentPath]\n ? await viewComponents[errorComponentPath]()\n : null;\n\n if (errorComponentModule?.default) {\n // Render error view with exception data\n const errorProps = {\n statusCode: err.statusCode,\n message: err.message,\n data: err.data,\n };\n\n const Component = errorComponentModule.default;\n const htmlBody = renderJsxToHtmlString(h(Component, errorProps));\n const clientEntries = getClientJsEntries();\n const cssEntries = getCssEntries();\n const headContent = getHeadContent();\n\n const headHtml =\n headContent.length > 0\n ? headContent.map((content) => renderJsxToHtmlString(content)).join('\\n ')\n : undefined;\n\n return {\n html: htmlBody,\n scripts: clientEntries.map((entry) => entry.path),\n styles: cssEntries.map((entry) => entry.path),\n head: headHtml,\n lang,\n statusCode: err.statusCode,\n };\n } else {\n // No error view found, render default error message\n const html = h('div', {}, `${err.statusCode} - ${err.message}`);\n return {\n html: renderJsxToHtmlString(html),\n statusCode: err.statusCode,\n };\n }\n}\n\nexport async function render(url: string, requestInfo: RequestInfo = {}): Promise<RenderResult> {\n return runInRenderContext(async () => {\n try {\n // Step 1: Call route handler to get view name\n const rawRouteResult: RouteResult = await routeHandler(requestInfo);\n\n if (!rawRouteResult) {\n // Throw NotFoundException to render error_404 view\n throw new NotFoundException('Page not found', {\n path: requestInfo.path,\n pathname: requestInfo.pathname,\n url: requestInfo.url?.href,\n });\n }\n\n const viewName =\n typeof rawRouteResult === 'string' ? rawRouteResult : rawRouteResult.view;\n requestInfo.params =\n typeof rawRouteResult === 'string' ? {} : (rawRouteResult.params ?? {});\n\n // Set view name in render context\n setViewName(viewName);\n\n // Step 2: Load global loader (optional)\n let globalProps: Record<string, any> = {};\n let lang: string | undefined;\n\n // Try to load global loader\n const globalLoaderPathTs = '/src/global-loader.ts';\n\n const globalLoaderModule: GlobalLoaderModule | null = globalLoader[globalLoaderPathTs]\n ? await globalLoader[globalLoaderPathTs]()\n : null;\n\n // Run global loader if exists and not ignored\n if (globalLoaderModule?.loader) {\n const shouldIgnore = globalLoaderModule.shouldIgnore?.(viewName) || false;\n\n if (!shouldIgnore) {\n const globalLoaderResult = await globalLoaderModule.loader(requestInfo);\n\n globalProps = globalLoaderResult.props || {};\n lang = globalLoaderResult.lang; // Extract lang from global loader\n\n if (globalLoaderResult.cacheTags) {\n addCacheTag(globalLoaderResult.cacheTags);\n }\n\n // generateMetadata và generateSchema sẽ được gọi sau khi có props\n } else {\n console.info(`Global loader ignored for view: ${viewName}`);\n }\n }\n\n // Step 3: Dynamic import view loader (optional)\n let viewProps: Record<string, any> = {};\n let maxAge: number | undefined;\n let sMaxAge: number | undefined;\n let swr: number | undefined;\n let rawHtml: boolean = false;\n const loaderPathTs = `/src/views/${viewName}/loader.ts`;\n\n // Try TypeScript loader formats only\n const loaderModule = viewLoaders[loaderPathTs] ? await viewLoaders[loaderPathTs]() : null;\n\n if (loaderModule?.loader) {\n const loaderResult = await loaderModule.loader(requestInfo);\n\n // Check if loader returns raw response\n if (loaderResult.rawResponse) {\n return {\n rawResponse: loaderResult.rawResponse,\n statusCode: loaderResult.rawResponse.statusCode || 200,\n };\n }\n\n viewProps = loaderResult.props || {};\n maxAge = loaderResult.maxAge;\n sMaxAge = loaderResult.sMaxAge;\n swr = loaderResult.swr;\n rawHtml = loaderResult.rawHtml || false;\n\n if (loaderResult.cacheTags) {\n addCacheTag(loaderResult.cacheTags);\n }\n\n // View loader lang overrides global loader lang\n if (loaderResult.lang) {\n lang = loaderResult.lang;\n }\n } else {\n console.info(`No loader for view: ${viewName}`);\n }\n\n // Merge props: global props first, then view props (view can override)\n const props = { ...globalProps, ...viewProps };\n\n // Step 3.5: Generate metadata và schema từ generateMetadata và generateSchema functions\n // Global generateMetadata (parent metadata)\n if (globalLoaderModule?.generateMetadata) {\n const globalMetadata = globalLoaderModule.generateMetadata(requestInfo, props);\n if (globalMetadata) {\n pushMetadata(globalMetadata);\n }\n }\n\n // View generateMetadata (child metadata, sẽ merge với parent)\n if (loaderModule?.generateMetadata) {\n const viewMetadata = loaderModule.generateMetadata(requestInfo, props);\n if (viewMetadata) {\n pushMetadata(viewMetadata);\n }\n }\n\n // Global generateSchema (base schemas)\n if (globalLoaderModule?.generateSchema) {\n const globalSchema = globalLoaderModule.generateSchema(requestInfo, props);\n if (globalSchema) {\n pushSchema(globalSchema);\n }\n }\n\n // View generateSchema (view-specific schemas)\n if (loaderModule?.generateSchema) {\n const viewSchema = loaderModule.generateSchema(requestInfo, props);\n if (viewSchema) {\n pushSchema(viewSchema);\n }\n }\n\n // Step 4: Dynamic import component (required)\n const componentPathTsx = `/src/views/${viewName}/index.tsx`;\n\n const componentModule = viewComponents[componentPathTsx]\n ? await viewComponents[componentPathTsx]()\n : null;\n\n const Component = componentModule?.default;\n\n if (!Component) {\n console.error(`View component not found: ${viewName}`);\n\n // Check if in development or production mode\n const isDevelopment = process.env.NODE_ENV !== 'production';\n\n if (isDevelopment) {\n // Development: provide detailed error information\n throw new InternalServerErrorException(`View component not found: \"${viewName}\"`, {\n viewName,\n expectedPath: componentPathTsx,\n availableViews: Object.keys(viewComponents),\n hint: `Make sure the view component exists at ${componentPathTsx} and exports a default component`,\n timestamp: new Date().toISOString(),\n });\n } else {\n // Production: simple error message\n throw new InternalServerErrorException('Internal Server Error');\n }\n }\n\n // Auto-render MetadataRenderer trước khi render component\n // MetadataRenderer sẽ push metadata vào headRegistry thông qua Head component\n renderJsxToHtmlString(h(MetadataRenderer, {}));\n\n // Auto-render schemas vào headRegistry\n const schemas = getSchemas();\n schemas.forEach((schema) => {\n // serialize-javascript escapes HTML-sensitive chars (<, >, &, U+2028/2029)\n // so schema values cannot break out of the <script> block (XSS).\n const schemaJson = serialize(schema, { isJSON: true });\n // Push schema vào headRegistry thông qua Head component\n // Head component chỉ push vào registry, không cần renderJsxToHtmlString\n Head({\n priority: HEAD_PRIORITY.SEO,\n children: h('script', {\n type: 'application/ld+json',\n setHtml: schemaJson,\n }),\n });\n });\n\n // Render component (có thể có Head components khác)\n let htmlBody = renderJsxToHtmlString(h(Component, props));\n // Fill any opt-in `ssr` island placeholders with server-rendered React HTML.\n htmlBody = await fillSsrIslands(htmlBody);\n const clientEntries = getClientJsEntries();\n const cssEntries = getCssEntries();\n const islandEntries = getIslandEntries();\n const cacheTags = getCacheTags();\n const headContent = getHeadContent();\n\n // Render head content to HTML string\n const headHtml =\n headContent.length > 0\n ? headContent.map((content) => renderJsxToHtmlString(content)).join('\\n ')\n : undefined;\n\n return {\n html: htmlBody,\n scripts: clientEntries.map((entry) => entry.path),\n styles: cssEntries.map((entry) => entry.path),\n islands: islandEntries.length > 0 ? islandEntries : undefined,\n head: headHtml,\n lang,\n maxAge,\n sMaxAge,\n swr,\n cacheTags,\n rawHtml,\n };\n } catch (err: any) {\n // Handle RedirectException\n if (err instanceof RedirectException) {\n return {\n html: '',\n redirect: {\n url: err.url,\n statusCode: err.statusCode,\n },\n };\n }\n\n // Handle HttpException\n if (err instanceof HttpException) {\n return await renderErrorView(err);\n }\n\n // For other (unexpected) errors, convert to ServiceUnavailableException.\n // Intentional HttpExceptions above keep their developer-authored message;\n // but an unexpected error's raw message/stack must not leak to the client\n // in production (it can carry internals, secrets, etc.). Dev keeps detail.\n console.error(`Failed to render:`, err);\n const isProduction = process.env.NODE_ENV === 'production';\n const serviceError = isProduction\n ? new ServiceUnavailableException('Internal Server Error')\n : new ServiceUnavailableException(err.message || 'Internal Server Error', {\n originalError: err.name,\n stack: err.stack,\n timestamp: new Date().toISOString(),\n });\n return await renderErrorView(serviceError);\n }\n }, requestInfo);\n}\n"],"names":["fillSsrIslands","htmlBody","pending","getSsrIslands","renderToString","createElement","err","island","loader","islandModules","mod","Component","out","renderErrorView","lang","errorViewName","errorComponentPath","setViewName","errorComponentModule","viewComponents","errorProps","renderJsxToHtmlString","h","clientEntries","getClientJsEntries","cssEntries","getCssEntries","headContent","getHeadContent","headHtml","content","entry","html","render","url","requestInfo","runInRenderContext","rawRouteResult","routeHandler","NotFoundException","viewName","globalProps","globalLoaderPathTs","globalLoaderModule","globalLoader","globalLoaderResult","addCacheTag","viewProps","maxAge","sMaxAge","swr","rawHtml","loaderPathTs","loaderModule","viewLoaders","loaderResult","props","globalMetadata","pushMetadata","viewMetadata","globalSchema","pushSchema","viewSchema","componentPathTsx","InternalServerErrorException","MetadataRenderer","getSchemas","schema","schemaJson","serialize","Head","HEAD_PRIORITY","islandEntries","getIslandEntries","cacheTags","getCacheTags","RedirectException","HttpException","serviceError","ServiceUnavailableException"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entry-server.js","sources":["../src/core/entry-server.ts"],"sourcesContent":["/// <reference path=\"./jsx-types.d.ts\" />\nimport serialize from 'serialize-javascript';\nimport { MetadataRenderer } from '../seo/generateMetadata';\nimport type { Metadata } from '../seo/types';\nimport {\n HttpException,\n InternalServerErrorException,\n NotFoundException,\n RedirectException,\n ServiceUnavailableException,\n} from './exceptions';\nimport { HEAD_PRIORITY } from './head-priority';\nimport {\n addCacheTag,\n getCacheTags,\n getClientJsEntries,\n getCssEntries,\n getHeadContent,\n getIslandEntries,\n getIslandProps,\n getSchemas,\n getSsrIslands,\n jsxFactory as h,\n Head,\n pushMetadata,\n pushSchema,\n runInRenderContext,\n setViewName,\n} from './jsx-runtime';\nimport { renderJsxToHtmlString } from './render';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { viewComponents, viewLoaders } from 'virtual:l5e-views';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport routeHandler from 'virtual:l5e-route';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { globalLoader } from 'virtual:l5e-global-loader';\n// @ts-ignore - Virtual modules provided by Vite plugin\nexport { loadMiddleware } from 'virtual:l5e-middleware';\n// @ts-ignore - Virtual modules provided by Vite plugin\nimport { islandModules } from 'virtual:l5e-islands';\n\n/**\n * Fill `ssr` island placeholders with server-rendered HTML.\n *\n * During the synchronous render pass, each `<ClientIsland ssr>` emits a unique\n * token (as `<!--token-->` body + `data-island-ssr=\"token\"`). Here — after the\n * pass — we can `await import()` the actual React component and renderToString it,\n * then string-replace the token. Only islands present on this page are imported.\n *\n * On failure we strip both the token and the `data-island-ssr` attribute so the\n * client cleanly falls back to a client-only mount (no hydration mismatch).\n */\nasync function fillSsrIslands(htmlBody: string): Promise<string> {\n const pending = getSsrIslands();\n if (pending.length === 0) return htmlBody;\n\n let renderToString: (el: any) => string;\n let createElement: (type: any, props: any) => any;\n try {\n [{ renderToString }, { createElement }] = await Promise.all([\n import('react-dom/server'),\n import('react'),\n ]);\n } catch (err) {\n console.error('[l5e-island] SSR requires react-dom/server + react:', err);\n // Strip every pending token/attr → client-only fallback for all.\n for (const island of pending) {\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, '')\n .replace(` data-island-ssr=\"${island.token}\"`, '');\n }\n return htmlBody;\n }\n\n for (const island of pending) {\n try {\n const loader = islandModules['/' + island.src];\n if (!loader) {\n throw new Error(`island module not found in glob: /${island.src}`);\n }\n const mod: any = await loader();\n const Component = mod[island.name] ?? mod.default;\n if (!Component) {\n throw new Error(`no export \"${island.name}\" or default in /${island.src}`);\n }\n const out = renderToString(createElement(Component, island.props));\n // Replacer fn (not a string) so `$`-sequences in `out` (e.g. \"$&\", \"$$\")\n // aren't interpreted as special replacement patterns.\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, () => out)\n .replace(`data-island-ssr=\"${island.token}\"`, 'data-island-ssr=\"1\"');\n } catch (err) {\n console.error(`[l5e-island] Failed to SSR island \"${island.name}\":`, err);\n htmlBody = htmlBody\n .replace(`<!--${island.token}-->`, '')\n .replace(` data-island-ssr=\"${island.token}\"`, '');\n }\n }\n\n return htmlBody;\n}\n\nexport interface RawResponse {\n body: string | Buffer;\n contentType: string;\n statusCode?: number;\n headers?: Record<string, string>;\n}\n\nexport interface RenderResult {\n html?: string;\n scripts?: string[];\n styles?: string[];\n islands?: Array<{ key: string; src: string; name: string }>;\n /**\n * Externalized island props (index === element's `data-island-idx`). Present\n * only in externalized mode; createPageResponse serializes it into the\n * `<script id=\"_l5e_data_\">` at the end of the document.\n */\n islandData?: unknown[];\n head?: string;\n lang?: string;\n statusCode?: number;\n maxAge?: number;\n sMaxAge?: number;\n swr?: number;\n cacheTags?: string[];\n redirect?: { url: string; statusCode: number };\n rawResponse?: RawResponse;\n rawHtml?: boolean;\n}\n\nexport interface RequestInfo {\n url?: URL;\n path?: string;\n pathname?: string;\n method?: string;\n headers?: Record<string, any>;\n cookies?: Record<string, string>;\n query?: Record<string, any>;\n ip?: string;\n locals?: Record<string, unknown>;\n params?: Record<string, any>;\n}\n\nexport type RouteResult =\n | string\n | null\n | { view: string; params?: Record<string, any> };\n\n// SchemaMarkup type - có thể là single schema hoặc array of schemas\n// Sử dụng any để tương thích với schema-dts types từ frontend\nexport type SchemaMarkup = any | Array<any>;\n\nexport interface LoaderResult {\n props?: Record<string, any>;\n lang?: string;\n maxAge?: number;\n sMaxAge?: number;\n swr?: number;\n cacheTags?: string[] | Record<string, boolean>;\n rawResponse?: RawResponse;\n rawHtml?: boolean;\n}\n\nexport type LoaderFunction = (requestInfo: RequestInfo) => Promise<LoaderResult>;\n\nexport type GenerateMetadataFunction = (requestInfo: RequestInfo, props: any) => Metadata | null;\n\nexport type GenerateSchemaFunction = (requestInfo: RequestInfo, props: any) => SchemaMarkup | null;\n\nexport interface GlobalLoaderModule {\n loader: LoaderFunction;\n generateMetadata?: GenerateMetadataFunction;\n generateSchema?: GenerateSchemaFunction;\n shouldIgnore?: (viewName: string) => boolean;\n}\n\n/**\n * Helper function to render error view\n */\nasync function renderErrorView(err: HttpException, lang?: string): Promise<RenderResult> {\n const errorViewName = `_error`;\n const errorComponentPath = `/src/views/${errorViewName}/index.tsx`;\n\n // Set error view name in context\n setViewName(errorViewName);\n\n // Try to load error view\n const errorComponentModule = viewComponents[errorComponentPath]\n ? await viewComponents[errorComponentPath]()\n : null;\n\n if (errorComponentModule?.default) {\n // Render error view with exception data\n const errorProps = {\n statusCode: err.statusCode,\n message: err.message,\n data: err.data,\n };\n\n const Component = errorComponentModule.default;\n const htmlBody = renderJsxToHtmlString(h(Component, errorProps));\n const clientEntries = getClientJsEntries();\n const cssEntries = getCssEntries();\n const headContent = getHeadContent();\n\n const headHtml =\n headContent.length > 0\n ? headContent.map((content) => renderJsxToHtmlString(content)).join('\\n ')\n : undefined;\n\n return {\n html: htmlBody,\n scripts: clientEntries.map((entry) => entry.path),\n styles: cssEntries.map((entry) => entry.path),\n head: headHtml,\n lang,\n statusCode: err.statusCode,\n };\n } else {\n // No error view found, render default error message\n const html = h('div', {}, `${err.statusCode} - ${err.message}`);\n return {\n html: renderJsxToHtmlString(html),\n statusCode: err.statusCode,\n };\n }\n}\n\nexport interface RenderOptions {\n /**\n * Externalize island props into the trailing `_l5e_data_` script instead of\n * inlining `data-island-props` on each element. Default true.\n */\n externalizeIslandProps?: boolean;\n}\n\nexport async function render(\n url: string,\n requestInfo: RequestInfo = {},\n options: RenderOptions = {},\n): Promise<RenderResult> {\n const externalizeIslandProps = options.externalizeIslandProps ?? true;\n return runInRenderContext(async () => {\n try {\n // Step 1: Call route handler to get view name\n const rawRouteResult: RouteResult = await routeHandler(requestInfo);\n\n if (!rawRouteResult) {\n // Throw NotFoundException to render error_404 view\n throw new NotFoundException('Page not found', {\n path: requestInfo.path,\n pathname: requestInfo.pathname,\n url: requestInfo.url?.href,\n });\n }\n\n const viewName =\n typeof rawRouteResult === 'string' ? rawRouteResult : rawRouteResult.view;\n requestInfo.params =\n typeof rawRouteResult === 'string' ? {} : (rawRouteResult.params ?? {});\n\n // Set view name in render context\n setViewName(viewName);\n\n // Step 2: Load global loader (optional)\n let globalProps: Record<string, any> = {};\n let lang: string | undefined;\n\n // Try to load global loader\n const globalLoaderPathTs = '/src/global-loader.ts';\n\n const globalLoaderModule: GlobalLoaderModule | null = globalLoader[globalLoaderPathTs]\n ? await globalLoader[globalLoaderPathTs]()\n : null;\n\n // Run global loader if exists and not ignored\n if (globalLoaderModule?.loader) {\n const shouldIgnore = globalLoaderModule.shouldIgnore?.(viewName) || false;\n\n if (!shouldIgnore) {\n const globalLoaderResult = await globalLoaderModule.loader(requestInfo);\n\n globalProps = globalLoaderResult.props || {};\n lang = globalLoaderResult.lang; // Extract lang from global loader\n\n if (globalLoaderResult.cacheTags) {\n addCacheTag(globalLoaderResult.cacheTags);\n }\n\n // generateMetadata và generateSchema sẽ được gọi sau khi có props\n } else {\n console.info(`Global loader ignored for view: ${viewName}`);\n }\n }\n\n // Step 3: Dynamic import view loader (optional)\n let viewProps: Record<string, any> = {};\n let maxAge: number | undefined;\n let sMaxAge: number | undefined;\n let swr: number | undefined;\n let rawHtml: boolean = false;\n const loaderPathTs = `/src/views/${viewName}/loader.ts`;\n\n // Try TypeScript loader formats only\n const loaderModule = viewLoaders[loaderPathTs] ? await viewLoaders[loaderPathTs]() : null;\n\n if (loaderModule?.loader) {\n const loaderResult = await loaderModule.loader(requestInfo);\n\n // Check if loader returns raw response\n if (loaderResult.rawResponse) {\n return {\n rawResponse: loaderResult.rawResponse,\n statusCode: loaderResult.rawResponse.statusCode || 200,\n };\n }\n\n viewProps = loaderResult.props || {};\n maxAge = loaderResult.maxAge;\n sMaxAge = loaderResult.sMaxAge;\n swr = loaderResult.swr;\n rawHtml = loaderResult.rawHtml || false;\n\n if (loaderResult.cacheTags) {\n addCacheTag(loaderResult.cacheTags);\n }\n\n // View loader lang overrides global loader lang\n if (loaderResult.lang) {\n lang = loaderResult.lang;\n }\n } else {\n console.info(`No loader for view: ${viewName}`);\n }\n\n // Merge props: global props first, then view props (view can override)\n const props = { ...globalProps, ...viewProps };\n\n // Step 3.5: Generate metadata và schema từ generateMetadata và generateSchema functions\n // Global generateMetadata (parent metadata)\n if (globalLoaderModule?.generateMetadata) {\n const globalMetadata = globalLoaderModule.generateMetadata(requestInfo, props);\n if (globalMetadata) {\n pushMetadata(globalMetadata);\n }\n }\n\n // View generateMetadata (child metadata, sẽ merge với parent)\n if (loaderModule?.generateMetadata) {\n const viewMetadata = loaderModule.generateMetadata(requestInfo, props);\n if (viewMetadata) {\n pushMetadata(viewMetadata);\n }\n }\n\n // Global generateSchema (base schemas)\n if (globalLoaderModule?.generateSchema) {\n const globalSchema = globalLoaderModule.generateSchema(requestInfo, props);\n if (globalSchema) {\n pushSchema(globalSchema);\n }\n }\n\n // View generateSchema (view-specific schemas)\n if (loaderModule?.generateSchema) {\n const viewSchema = loaderModule.generateSchema(requestInfo, props);\n if (viewSchema) {\n pushSchema(viewSchema);\n }\n }\n\n // Step 4: Dynamic import component (required)\n const componentPathTsx = `/src/views/${viewName}/index.tsx`;\n\n const componentModule = viewComponents[componentPathTsx]\n ? await viewComponents[componentPathTsx]()\n : null;\n\n const Component = componentModule?.default;\n\n if (!Component) {\n console.error(`View component not found: ${viewName}`);\n\n // Check if in development or production mode\n const isDevelopment = process.env.NODE_ENV !== 'production';\n\n if (isDevelopment) {\n // Development: provide detailed error information\n throw new InternalServerErrorException(`View component not found: \"${viewName}\"`, {\n viewName,\n expectedPath: componentPathTsx,\n availableViews: Object.keys(viewComponents),\n hint: `Make sure the view component exists at ${componentPathTsx} and exports a default component`,\n timestamp: new Date().toISOString(),\n });\n } else {\n // Production: simple error message\n throw new InternalServerErrorException('Internal Server Error');\n }\n }\n\n // Auto-render MetadataRenderer trước khi render component\n // MetadataRenderer sẽ push metadata vào headRegistry thông qua Head component\n renderJsxToHtmlString(h(MetadataRenderer, {}));\n\n // Auto-render schemas vào headRegistry\n const schemas = getSchemas();\n schemas.forEach((schema) => {\n // serialize-javascript escapes HTML-sensitive chars (<, >, &, U+2028/2029)\n // so schema values cannot break out of the <script> block (XSS).\n const schemaJson = serialize(schema, { isJSON: true });\n // Push schema vào headRegistry thông qua Head component\n // Head component chỉ push vào registry, không cần renderJsxToHtmlString\n Head({\n priority: HEAD_PRIORITY.SEO,\n children: h('script', {\n type: 'application/ld+json',\n setHtml: schemaJson,\n }),\n });\n });\n\n // Render component (có thể có Head components khác)\n let htmlBody = renderJsxToHtmlString(h(Component, props));\n // Fill any opt-in `ssr` island placeholders with server-rendered React HTML.\n htmlBody = await fillSsrIslands(htmlBody);\n const clientEntries = getClientJsEntries();\n const cssEntries = getCssEntries();\n const islandEntries = getIslandEntries();\n const islandData = getIslandProps();\n const cacheTags = getCacheTags();\n const headContent = getHeadContent();\n\n // Render head content to HTML string\n const headHtml =\n headContent.length > 0\n ? headContent.map((content) => renderJsxToHtmlString(content)).join('\\n ')\n : undefined;\n\n return {\n html: htmlBody,\n scripts: clientEntries.map((entry) => entry.path),\n styles: cssEntries.map((entry) => entry.path),\n islands: islandEntries.length > 0 ? islandEntries : undefined,\n islandData: islandData.length > 0 ? islandData : undefined,\n head: headHtml,\n lang,\n maxAge,\n sMaxAge,\n swr,\n cacheTags,\n rawHtml,\n };\n } catch (err: any) {\n // Handle RedirectException\n if (err instanceof RedirectException) {\n return {\n html: '',\n redirect: {\n url: err.url,\n statusCode: err.statusCode,\n },\n };\n }\n\n // Handle HttpException\n if (err instanceof HttpException) {\n return await renderErrorView(err);\n }\n\n // For other (unexpected) errors, convert to ServiceUnavailableException.\n // Intentional HttpExceptions above keep their developer-authored message;\n // but an unexpected error's raw message/stack must not leak to the client\n // in production (it can carry internals, secrets, etc.). Dev keeps detail.\n console.error(`Failed to render:`, err);\n const isProduction = process.env.NODE_ENV === 'production';\n const serviceError = isProduction\n ? new ServiceUnavailableException('Internal Server Error')\n : new ServiceUnavailableException(err.message || 'Internal Server Error', {\n originalError: err.name,\n stack: err.stack,\n timestamp: new Date().toISOString(),\n });\n return await renderErrorView(serviceError);\n }\n }, requestInfo, undefined, { externalizeIslandProps });\n}\n"],"names":["fillSsrIslands","htmlBody","pending","getSsrIslands","renderToString","createElement","err","island","loader","islandModules","mod","Component","out","renderErrorView","lang","errorViewName","errorComponentPath","setViewName","errorComponentModule","viewComponents","errorProps","renderJsxToHtmlString","h","clientEntries","getClientJsEntries","cssEntries","getCssEntries","headContent","getHeadContent","headHtml","content","entry","html","render","url","requestInfo","options","externalizeIslandProps","runInRenderContext","rawRouteResult","routeHandler","NotFoundException","viewName","globalProps","globalLoaderPathTs","globalLoaderModule","globalLoader","globalLoaderResult","addCacheTag","viewProps","maxAge","sMaxAge","swr","rawHtml","loaderPathTs","loaderModule","viewLoaders","loaderResult","props","globalMetadata","pushMetadata","viewMetadata","globalSchema","pushSchema","viewSchema","componentPathTsx","InternalServerErrorException","MetadataRenderer","getSchemas","schema","schemaJson","serialize","Head","HEAD_PRIORITY","islandEntries","getIslandEntries","islandData","getIslandProps","cacheTags","getCacheTags","RedirectException","HttpException","serviceError","ServiceUnavailableException"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxFactory as t, Fragment as T } from "@withl5e/l5e/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
function
|
|
2
|
+
import { z as j, u as M, o as C, a as s, H as l, F as o } from "./jsx-runtime-DqAp8xlt.js";
|
|
3
|
+
function R({ metadata: h }) {
|
|
4
4
|
const { request: w } = j(), u = M(), e = h ? C(u, h) : u;
|
|
5
5
|
if (!e) return null;
|
|
6
6
|
const g = () => e.title ? typeof e.title == "string" ? e.title : e.title.default : null, G = () => {
|
|
@@ -139,6 +139,6 @@ function q({ metadata: h }) {
|
|
|
139
139
|
)))));
|
|
140
140
|
}
|
|
141
141
|
export {
|
|
142
|
-
|
|
142
|
+
R as M
|
|
143
143
|
};
|
|
144
|
-
//# sourceMappingURL=generateMetadata-
|
|
144
|
+
//# sourceMappingURL=generateMetadata-Cn8BIxq6.js.map
|