@moonsjs/vite 0.1.17 → 0.1.18
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/{index-v5sbd3az.js → index-1ksjfvnz.js} +18 -18
- package/dist/index-1ksjfvnz.js.map +15 -0
- package/dist/{index-snbxks72.js → index-tbph0859.js} +80 -80
- package/dist/{index-snbxks72.js.map → index-tbph0859.js.map} +4 -4
- package/dist/index.js +33 -33
- package/dist/index.js.map +4 -4
- package/dist/server/index.js +86 -86
- package/dist/server/index.js.map +9 -9
- package/dist/transform.js +1 -1
- package/package.json +1 -1
- package/src/api.ts +14 -14
- package/src/devtools.ts +5 -5
- package/src/manifest.ts +2 -2
- package/src/plugin.ts +21 -21
- package/src/server/dev.ts +1 -1
- package/src/server/handler.ts +39 -39
- package/src/server/isr.ts +5 -5
- package/src/server/node-server.ts +6 -6
- package/src/server/node.ts +2 -2
- package/src/server/plugins.ts +1 -1
- package/src/server/prerender.ts +29 -29
- package/src/server/shell.ts +8 -8
- package/src/server/shutdown.ts +5 -5
- package/src/server/storage.ts +1 -1
- package/src/server-only.ts +7 -7
- package/src/transform.ts +76 -76
- package/dist/index-v5sbd3az.js.map +0 -15
package/dist/server/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
DEFAULT_SECURITY_HEADERS,
|
|
14
14
|
sendNodeResponse2,
|
|
15
15
|
installDevMiddleware2
|
|
16
|
-
} from "../index-
|
|
16
|
+
} from "../index-1ksjfvnz.js";
|
|
17
17
|
|
|
18
18
|
// src/server/handler.ts
|
|
19
19
|
import {
|
|
@@ -93,9 +93,9 @@ function createRequestHandler(options) {
|
|
|
93
93
|
return apiErrorResponse(new MoonsError({
|
|
94
94
|
code: "E_API_HANDLER_INVALID",
|
|
95
95
|
file: route.file,
|
|
96
|
-
message: `
|
|
97
|
-
details: "
|
|
98
|
-
suggestions: ["
|
|
96
|
+
message: `API module \`${route.path}\` could not be loaded`,
|
|
97
|
+
details: "The `loadApi` map does not contain this route (build/dev out of sync).",
|
|
98
|
+
suggestions: ["Rebuild / restart the dev server"]
|
|
99
99
|
}), route);
|
|
100
100
|
}
|
|
101
101
|
let mod;
|
|
@@ -108,9 +108,9 @@ function createRequestHandler(options) {
|
|
|
108
108
|
return apiErrorResponse(new MoonsError({
|
|
109
109
|
code: "E_API_HANDLER_INVALID",
|
|
110
110
|
file: route.file,
|
|
111
|
-
message: "
|
|
112
|
-
details: `
|
|
113
|
-
suggestions: ["Export `GET`/`POST`/…
|
|
111
|
+
message: "API module does not export a handler object",
|
|
112
|
+
details: `Module \`${route.path}\` must export method handlers.`,
|
|
113
|
+
suggestions: ["Export `GET`/`POST`/… as `(args) => Response` functions"]
|
|
114
114
|
}), route);
|
|
115
115
|
}
|
|
116
116
|
const record = mod;
|
|
@@ -137,9 +137,9 @@ function createRequestHandler(options) {
|
|
|
137
137
|
return apiErrorResponse(new MoonsError({
|
|
138
138
|
code: "E_API_HANDLER_INVALID",
|
|
139
139
|
file: route.file,
|
|
140
|
-
message: `handler \`${requestMethod}\`
|
|
141
|
-
details: "
|
|
142
|
-
suggestions: ["
|
|
140
|
+
message: `handler \`${requestMethod}\` did not return a \`Response\``,
|
|
141
|
+
details: "API handlers must return `new Response(...)`.",
|
|
142
|
+
suggestions: ["Return `new Response(body, { status, headers })`"]
|
|
143
143
|
}), route);
|
|
144
144
|
}
|
|
145
145
|
if (stripBody) {
|
|
@@ -159,11 +159,11 @@ function createRequestHandler(options) {
|
|
|
159
159
|
const markup = renderToMarkup({ page: key, layouts: [] }, { page: module, layouts: [] }, {}, {});
|
|
160
160
|
return htmlResponse(await shell(markup, payload, request.url), 404);
|
|
161
161
|
} catch (error) {
|
|
162
|
-
console.error("[moons]
|
|
162
|
+
console.error("[moons] failed to render custom _404:", error);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
const payload = encodeSsrPayload({ key: "", params: {}, data: {} });
|
|
166
|
-
const html = await shell("<h1>404</h1><p>
|
|
166
|
+
const html = await shell("<h1>404</h1><p>Page not found.</p>", payload, request.url);
|
|
167
167
|
return htmlResponse(html, 404);
|
|
168
168
|
}
|
|
169
169
|
async function routeErrorResponse(error, request, resolved) {
|
|
@@ -184,7 +184,7 @@ function createRequestHandler(options) {
|
|
|
184
184
|
const markup = renderToMarkup({ page: key, layouts: [] }, { page: module, layouts: [] }, {}, {}, {}, serialized === undefined ? undefined : reviveError(serialized));
|
|
185
185
|
return htmlResponse(await shell(markup, payload, request.url), 500);
|
|
186
186
|
} catch (renderError) {
|
|
187
|
-
console.error("[moons]
|
|
187
|
+
console.error("[moons] failed to render custom _error:", renderError);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
return internalErrorResponse(error, { log: false });
|
|
@@ -198,9 +198,9 @@ function createRequestHandler(options) {
|
|
|
198
198
|
throw new MoonsError({
|
|
199
199
|
code: "E_MIDDLEWARE_INVALID",
|
|
200
200
|
file: definition.file,
|
|
201
|
-
message: "middleware
|
|
202
|
-
details: "
|
|
203
|
-
suggestions: ["Restart dev server /
|
|
201
|
+
message: "directory middleware could not be loaded",
|
|
202
|
+
details: "The `loadRoute` map does not contain this `_middleware.ts`.",
|
|
203
|
+
suggestions: ["Restart the dev server / rebuild"]
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
const module = await load();
|
|
@@ -209,8 +209,8 @@ function createRequestHandler(options) {
|
|
|
209
209
|
throw new MoonsError({
|
|
210
210
|
code: "E_MIDDLEWARE_INVALID",
|
|
211
211
|
file: definition.file,
|
|
212
|
-
message: "`_middleware.ts`
|
|
213
|
-
details: "
|
|
212
|
+
message: "`_middleware.ts` does not default-export a function",
|
|
213
|
+
details: "Directory middleware follows the `(args) => Promise<Response>` shape.",
|
|
214
214
|
suggestions: ["Export default `async ({ req, ctx, next }) => await next()`"]
|
|
215
215
|
});
|
|
216
216
|
}
|
|
@@ -226,9 +226,9 @@ function createRequestHandler(options) {
|
|
|
226
226
|
throw new MoonsError({
|
|
227
227
|
code: "E_MIDDLEWARE_INVALID",
|
|
228
228
|
file: definition.file,
|
|
229
|
-
message: "middleware
|
|
230
|
-
details: "
|
|
231
|
-
suggestions: ["Restart dev server /
|
|
229
|
+
message: "API middleware could not be loaded",
|
|
230
|
+
details: "The `loadApiMiddleware` map does not contain this `_middleware.ts`.",
|
|
231
|
+
suggestions: ["Restart the dev server / rebuild"]
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
234
|
const module = await load();
|
|
@@ -236,8 +236,8 @@ function createRequestHandler(options) {
|
|
|
236
236
|
throw new MoonsError({
|
|
237
237
|
code: "E_MIDDLEWARE_INVALID",
|
|
238
238
|
file: definition.file,
|
|
239
|
-
message: "`_middleware.ts`
|
|
240
|
-
details: "
|
|
239
|
+
message: "`_middleware.ts` does not default-export a function",
|
|
240
|
+
details: "Directory middleware follows the `(args) => Promise<Response>` shape.",
|
|
241
241
|
suggestions: ["Export default `async ({ req, ctx, next }) => await next()`"]
|
|
242
242
|
});
|
|
243
243
|
}
|
|
@@ -268,7 +268,7 @@ function createRequestHandler(options) {
|
|
|
268
268
|
return await handleApiRequest(apiMatch.route, apiMatch.params, request, ctx);
|
|
269
269
|
}
|
|
270
270
|
const middlewares = await loadApiDirMiddlewares(apiChain);
|
|
271
|
-
return await composeMiddleware(middlewares, ctx, () => handleApiRequest(apiMatch.route, apiMatch.params, request, ctx), { code: "E_MIDDLEWARE_INVALID", label: "middleware
|
|
271
|
+
return await composeMiddleware(middlewares, ctx, () => handleApiRequest(apiMatch.route, apiMatch.params, request, ctx), { code: "E_MIDDLEWARE_INVALID", label: "API middleware" })(request);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
const resolved = resolveRoute(url.pathname, routes);
|
|
@@ -281,7 +281,7 @@ function createRequestHandler(options) {
|
|
|
281
281
|
return await renderRoute(resolved, request, ctx);
|
|
282
282
|
}
|
|
283
283
|
const middlewares = await loadDirMiddlewares(dirChain);
|
|
284
|
-
return await composeMiddleware(middlewares, ctx, () => renderRoute(resolved, request, ctx), { code: "E_MIDDLEWARE_INVALID", label: "middleware
|
|
284
|
+
return await composeMiddleware(middlewares, ctx, () => renderRoute(resolved, request, ctx), { code: "E_MIDDLEWARE_INVALID", label: "directory middleware" })(request);
|
|
285
285
|
} catch (error) {
|
|
286
286
|
if (isRedirectSignal(error)) {
|
|
287
287
|
return new Response(null, {
|
|
@@ -386,9 +386,9 @@ async function loadModules(keys, loadRoute) {
|
|
|
386
386
|
if (load === undefined) {
|
|
387
387
|
throw new MoonsError({
|
|
388
388
|
code: "E_INTERNAL",
|
|
389
|
-
message: `
|
|
390
|
-
details: "
|
|
391
|
-
suggestions: ["
|
|
389
|
+
message: `route module \`${key}\` is not registered`,
|
|
390
|
+
details: "The route registry is out of sync with the scan result.",
|
|
391
|
+
suggestions: ["Run `bun run build` again, or restart the dev server"]
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
394
|
return await load();
|
|
@@ -403,11 +403,11 @@ async function runRouteMeta(pageModule, pageData, file) {
|
|
|
403
403
|
throw new MoonsError({
|
|
404
404
|
code: "E_INTERNAL",
|
|
405
405
|
file,
|
|
406
|
-
message: "export `meta`
|
|
407
|
-
details: "
|
|
406
|
+
message: "export `meta` must be a function `({ data }) => RouteMeta`",
|
|
407
|
+
details: "The `meta` shape follows `RouteMeta`.",
|
|
408
408
|
suggestions: [
|
|
409
|
-
'
|
|
410
|
-
"
|
|
409
|
+
'Change it to `export const meta = ({ data }) => ({ title: "..." })`',
|
|
410
|
+
"Or remove the `meta` export"
|
|
411
411
|
]
|
|
412
412
|
});
|
|
413
413
|
}
|
|
@@ -416,9 +416,9 @@ async function runRouteMeta(pageModule, pageData, file) {
|
|
|
416
416
|
throw new MoonsError({
|
|
417
417
|
code: "E_INTERNAL",
|
|
418
418
|
file,
|
|
419
|
-
message: "`meta()`
|
|
420
|
-
details: "
|
|
421
|
-
suggestions: ['
|
|
419
|
+
message: "`meta()` must return a RouteMeta object",
|
|
420
|
+
details: "The returned value is used for <title>/description/og.",
|
|
421
|
+
suggestions: ['Return an object, e.g. `({ title: "Home" })`']
|
|
422
422
|
});
|
|
423
423
|
}
|
|
424
424
|
return result;
|
|
@@ -427,13 +427,13 @@ function apiErrorResponse(error, route) {
|
|
|
427
427
|
const isProduction = process.env["NODE_ENV"] === "production";
|
|
428
428
|
if (error instanceof MoonsError) {
|
|
429
429
|
console.error(`[moons] API ${route.path}: ${error.format()}`);
|
|
430
|
-
return new Response(isProduction ? "
|
|
430
|
+
return new Response(isProduction ? "Internal server error." : error.format(), {
|
|
431
431
|
status: 500,
|
|
432
432
|
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
433
433
|
});
|
|
434
434
|
}
|
|
435
435
|
console.error(`[moons] API ${route.path}:`, error);
|
|
436
|
-
return new Response(isProduction ? "
|
|
436
|
+
return new Response(isProduction ? "Internal server error." : String(error), {
|
|
437
437
|
status: 500,
|
|
438
438
|
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
439
439
|
});
|
|
@@ -442,8 +442,8 @@ function internalErrorResponse(error, options = {}) {
|
|
|
442
442
|
if (options.log !== false) {
|
|
443
443
|
console.error("[moons] request error:", error);
|
|
444
444
|
}
|
|
445
|
-
const detail = process.env["NODE_ENV"] !== "production" && error instanceof MoonsError ? `<pre>${escapeHtml(error.format())}</pre>` : "<p>
|
|
446
|
-
return htmlResponse(`<!doctype html><html lang="
|
|
445
|
+
const detail = process.env["NODE_ENV"] !== "production" && error instanceof MoonsError ? `<pre>${escapeHtml(error.format())}</pre>` : "<p>Internal server error.</p>";
|
|
446
|
+
return htmlResponse(`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>500</title></head><body><h1>500</h1>${detail}</body></html>`, 500);
|
|
447
447
|
}
|
|
448
448
|
function htmlResponse(html, status) {
|
|
449
449
|
return new Response(html, {
|
|
@@ -477,7 +477,7 @@ function warnPayloadFindings(payload, scan, warned) {
|
|
|
477
477
|
continue;
|
|
478
478
|
}
|
|
479
479
|
warned.add(label);
|
|
480
|
-
console.warn(`[moons]
|
|
480
|
+
console.warn(`[moons] dev warning: SSR payload contains ${label} — do not return secrets from loaders.`);
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
// src/server/node-server.ts
|
|
@@ -517,7 +517,7 @@ async function runRevalidate(options) {
|
|
|
517
517
|
headers: { "x-moons-prerender": "1" }
|
|
518
518
|
}));
|
|
519
519
|
if (response.status !== 200) {
|
|
520
|
-
log(`[moons] isr:
|
|
520
|
+
log(`[moons] isr: skipped ${options.pathname} (status ${response.status})`);
|
|
521
521
|
return;
|
|
522
522
|
}
|
|
523
523
|
const html = await response.text();
|
|
@@ -527,7 +527,7 @@ async function runRevalidate(options) {
|
|
|
527
527
|
});
|
|
528
528
|
if (findings.length > 0) {
|
|
529
529
|
const labels = findings.map((finding) => finding.kind === "canary" ? "canary" : `env(${finding.label})`).join(", ");
|
|
530
|
-
log(`[moons] isr:
|
|
530
|
+
log(`[moons] isr: NOT writing ${options.pathname} — contains ${labels}`);
|
|
531
531
|
return;
|
|
532
532
|
}
|
|
533
533
|
if (options.storage !== undefined) {
|
|
@@ -535,14 +535,14 @@ async function runRevalidate(options) {
|
|
|
535
535
|
return;
|
|
536
536
|
}
|
|
537
537
|
if (options.file === undefined) {
|
|
538
|
-
log(`[moons] isr:
|
|
538
|
+
log(`[moons] isr: skipped ${options.pathname} — no destination file/storage`);
|
|
539
539
|
return;
|
|
540
540
|
}
|
|
541
541
|
const tmp = `${options.file}.tmp-${process.pid}`;
|
|
542
542
|
writeFileSync(tmp, html);
|
|
543
543
|
renameSync(tmp, options.file);
|
|
544
544
|
} catch (error) {
|
|
545
|
-
log(`[moons] isr:
|
|
545
|
+
log(`[moons] isr: failed to regenerate ${options.pathname}: ${String(error)}`);
|
|
546
546
|
}
|
|
547
547
|
}
|
|
548
548
|
|
|
@@ -562,7 +562,7 @@ function createFileStorage(clientDir) {
|
|
|
562
562
|
async write(pathname, body) {
|
|
563
563
|
const target = staticFileTarget(clientDir, pathname);
|
|
564
564
|
if (target === null) {
|
|
565
|
-
throw new Error(`[moons] isr: path
|
|
565
|
+
throw new Error(`[moons] isr: invalid path to write: ${pathname}`);
|
|
566
566
|
}
|
|
567
567
|
mkdirSync(dirname(target), { recursive: true });
|
|
568
568
|
const tmp = `${target}.tmp-${process.pid}`;
|
|
@@ -645,9 +645,9 @@ function installGracefulShutdown(server, options = {}) {
|
|
|
645
645
|
return;
|
|
646
646
|
}
|
|
647
647
|
shuttingDown = true;
|
|
648
|
-
log(`[moons]
|
|
648
|
+
log(`[moons] received ${signal} — no longer accepting connections, draining...`);
|
|
649
649
|
const timer = setTimeout(() => {
|
|
650
|
-
log(`[moons] drain
|
|
650
|
+
log(`[moons] drain exceeded ${timeoutMs}ms — forcing exit`);
|
|
651
651
|
const closeAll = server.closeAllConnections;
|
|
652
652
|
try {
|
|
653
653
|
closeAll?.call(server);
|
|
@@ -661,7 +661,7 @@ function installGracefulShutdown(server, options = {}) {
|
|
|
661
661
|
server.close(async (error) => {
|
|
662
662
|
if (error !== undefined) {
|
|
663
663
|
clearTimeout(timer);
|
|
664
|
-
log(`[moons]
|
|
664
|
+
log(`[moons] server close failed: ${error.message}`);
|
|
665
665
|
exit(1);
|
|
666
666
|
return;
|
|
667
667
|
}
|
|
@@ -670,11 +670,11 @@ function installGracefulShutdown(server, options = {}) {
|
|
|
670
670
|
try {
|
|
671
671
|
await options.onShutdown();
|
|
672
672
|
} catch (hookError) {
|
|
673
|
-
log(`[moons] onShutdown
|
|
673
|
+
log(`[moons] onShutdown failed: ${String(hookError)}`);
|
|
674
674
|
}
|
|
675
675
|
}
|
|
676
676
|
clearTimeout(timer);
|
|
677
|
-
log("[moons] shutdown
|
|
677
|
+
log("[moons] shutdown complete (full drain)");
|
|
678
678
|
exit(0);
|
|
679
679
|
});
|
|
680
680
|
};
|
|
@@ -921,11 +921,11 @@ function rpcBodyTooLargeText(limit, size) {
|
|
|
921
921
|
const megabytes = (bytes) => (bytes / 1e6).toFixed(1);
|
|
922
922
|
return new MoonsError2({
|
|
923
923
|
code: "E_RPC_BODY_TOO_LARGE",
|
|
924
|
-
message: size === null ? `body
|
|
925
|
-
details: "Body
|
|
924
|
+
message: size === null ? `body exceeds the ${megabytes(limit)} MB limit` : `body ${megabytes(size)} MB exceeds the ${megabytes(limit)} MB limit`,
|
|
925
|
+
details: "Body exceeds `security.bodyLimitBytes`; reading stops at the transport before the body is fully buffered.",
|
|
926
926
|
suggestions: [
|
|
927
|
-
"
|
|
928
|
-
"
|
|
927
|
+
"Reduce the payload size, or",
|
|
928
|
+
"Increase security.bodyLimitBytes if you really need to"
|
|
929
929
|
]
|
|
930
930
|
}).format();
|
|
931
931
|
}
|
|
@@ -1030,7 +1030,7 @@ function scheduleRevalidation(input) {
|
|
|
1030
1030
|
if (logger !== null) {
|
|
1031
1031
|
logger({ msg: "isr:revalidate-failed", level: "warn", path: normalized, error: message });
|
|
1032
1032
|
} else {
|
|
1033
|
-
console.error(`[moons] isr
|
|
1033
|
+
console.error(`[moons] isr regeneration failed (${normalized}): ${message}`);
|
|
1034
1034
|
}
|
|
1035
1035
|
});
|
|
1036
1036
|
}
|
|
@@ -1091,7 +1091,7 @@ function createPluginRuntime(options) {
|
|
|
1091
1091
|
try {
|
|
1092
1092
|
await plugin.onShutdown?.(app);
|
|
1093
1093
|
} catch (error) {
|
|
1094
|
-
log(`[moons] plugin \`${plugin.name}\`
|
|
1094
|
+
log(`[moons] plugin \`${plugin.name}\` failed during onShutdown: ${String(error)}`);
|
|
1095
1095
|
}
|
|
1096
1096
|
}
|
|
1097
1097
|
},
|
|
@@ -1133,18 +1133,18 @@ async function runPrerender(options) {
|
|
|
1133
1133
|
throw new MoonsError3({
|
|
1134
1134
|
code: "E_ISR_INVALID",
|
|
1135
1135
|
file: route.file,
|
|
1136
|
-
message: "`revalidate`
|
|
1137
|
-
details: "ISR
|
|
1136
|
+
message: "`revalidate` is invalid or used without `prerender = true`",
|
|
1137
|
+
details: "File-based ISR: `revalidate` (seconds, number >= 0) + `prerender`.",
|
|
1138
1138
|
suggestions: [
|
|
1139
|
-
"
|
|
1140
|
-
"
|
|
1139
|
+
"Use a number of seconds, e.g. `export const revalidate = 60`",
|
|
1140
|
+
"Add `export const prerender = true` to the same page"
|
|
1141
1141
|
]
|
|
1142
1142
|
});
|
|
1143
1143
|
}
|
|
1144
1144
|
}
|
|
1145
1145
|
if (prerender !== true) {
|
|
1146
1146
|
if (prerender !== undefined && prerender !== false) {
|
|
1147
|
-
throw prerenderError(route, "`prerender`
|
|
1147
|
+
throw prerenderError(route, "`prerender` must be a boolean (`true`/`false`)");
|
|
1148
1148
|
}
|
|
1149
1149
|
continue;
|
|
1150
1150
|
}
|
|
@@ -1155,15 +1155,15 @@ async function runPrerender(options) {
|
|
|
1155
1155
|
headers: { "x-moons-prerender": "1" }
|
|
1156
1156
|
}));
|
|
1157
1157
|
if (response.status === 404) {
|
|
1158
|
-
log(`[moons] prerender:
|
|
1158
|
+
log(`[moons] prerender: skipped ${pathname} (notFound)`);
|
|
1159
1159
|
skipped += 1;
|
|
1160
1160
|
continue;
|
|
1161
1161
|
}
|
|
1162
1162
|
if (response.status >= 300 && response.status < 400) {
|
|
1163
|
-
throw prerenderError(route, `\`redirect()\`
|
|
1163
|
+
throw prerenderError(route, `\`redirect()\` is not supported during prerender (${pathname})`);
|
|
1164
1164
|
}
|
|
1165
1165
|
if (response.status !== 200) {
|
|
1166
|
-
throw prerenderError(route, `status ${response.status}
|
|
1166
|
+
throw prerenderError(route, `status ${response.status} while rendering ${pathname}`);
|
|
1167
1167
|
}
|
|
1168
1168
|
const html = await response.text();
|
|
1169
1169
|
assertNoLeak(html, pathname, route.file, options, env);
|
|
@@ -1184,7 +1184,7 @@ async function runPrerender(options) {
|
|
|
1184
1184
|
`);
|
|
1185
1185
|
const emitted = emitStaticFiles(options.clientDir, options.staticConfig, entries);
|
|
1186
1186
|
const extras = [...wrote404 ? [NOT_FOUND_FILE] : [], ...emitted];
|
|
1187
|
-
log(`[moons] prerender
|
|
1187
|
+
log(`[moons] prerender done: ${written} file${extras.length > 0 ? ` + ${extras.join(" + ")}` : ""} (${skipped} skipped)`);
|
|
1188
1188
|
return { written, skipped };
|
|
1189
1189
|
}
|
|
1190
1190
|
function emitStaticFiles(clientDir, staticConfig, entries) {
|
|
@@ -1249,7 +1249,7 @@ async function renderStaticNotFound(options, env, log) {
|
|
|
1249
1249
|
headers: { "x-moons-prerender": "1" }
|
|
1250
1250
|
}));
|
|
1251
1251
|
if (response.status !== 404) {
|
|
1252
|
-
log(`[moons] prerender: ${NOT_FOUND_FILE}
|
|
1252
|
+
log(`[moons] prerender: ${NOT_FOUND_FILE} skipped (sentinel \`${NOT_FOUND_SENTINEL}\` → ${response.status})`);
|
|
1253
1253
|
return null;
|
|
1254
1254
|
}
|
|
1255
1255
|
const html = await response.text();
|
|
@@ -1268,11 +1268,11 @@ function assertNoLeak(html, pathname, file, options, env) {
|
|
|
1268
1268
|
throw new MoonsError3({
|
|
1269
1269
|
code: "E_PRERENDER_LEAK",
|
|
1270
1270
|
file,
|
|
1271
|
-
message: `
|
|
1272
|
-
details: "HTML
|
|
1271
|
+
message: `prerender output \`${pathname}\` contains ${labels}`,
|
|
1272
|
+
details: "Static HTML is permanent — a prerendered secret cannot be retracted.",
|
|
1273
1273
|
suggestions: [
|
|
1274
|
-
"
|
|
1275
|
-
"
|
|
1274
|
+
"Do not return secret env values from a loader that runs at prerender time",
|
|
1275
|
+
"Turn off `prerender` for this route or move the data to a request-time serverFn"
|
|
1276
1276
|
]
|
|
1277
1277
|
});
|
|
1278
1278
|
}
|
|
@@ -1290,35 +1290,35 @@ async function resolvePathnames(route, module) {
|
|
|
1290
1290
|
throw new MoonsError3({
|
|
1291
1291
|
code: "E_PRERENDER_NO_PATHS",
|
|
1292
1292
|
file: route.file,
|
|
1293
|
-
message: "route
|
|
1294
|
-
details: "
|
|
1293
|
+
message: "dynamic route with `prerender = true` without `export const paths`",
|
|
1294
|
+
details: "Prerendering needs a param list to render each path.",
|
|
1295
1295
|
suggestions: [
|
|
1296
|
-
'
|
|
1297
|
-
"
|
|
1296
|
+
'Add `export const paths = () => [{ id: "…" }]`',
|
|
1297
|
+
"Or remove `prerender` so the route renders at request time (SSR)"
|
|
1298
1298
|
]
|
|
1299
1299
|
});
|
|
1300
1300
|
}
|
|
1301
1301
|
const raw = await paths();
|
|
1302
1302
|
if (!Array.isArray(raw)) {
|
|
1303
|
-
throw prerenderError(route, "`paths()`
|
|
1303
|
+
throw prerenderError(route, "`paths()` must return an array");
|
|
1304
1304
|
}
|
|
1305
1305
|
const expected = new Set(route.params);
|
|
1306
1306
|
const result = [];
|
|
1307
1307
|
for (const item of raw) {
|
|
1308
1308
|
if (item === null || typeof item !== "object" || Array.isArray(item)) {
|
|
1309
|
-
throw prerenderError(route, "
|
|
1309
|
+
throw prerenderError(route, "`paths()` items must be objects with string params");
|
|
1310
1310
|
}
|
|
1311
1311
|
const record = item;
|
|
1312
1312
|
const keys = Object.keys(record);
|
|
1313
1313
|
for (const name of expected) {
|
|
1314
1314
|
const value = record[name];
|
|
1315
1315
|
if (typeof value !== "string" || value.length === 0) {
|
|
1316
|
-
throw prerenderError(route, `param \`${name}\`
|
|
1316
|
+
throw prerenderError(route, `param \`${name}\` must be a non-empty string`);
|
|
1317
1317
|
}
|
|
1318
1318
|
}
|
|
1319
1319
|
for (const key of keys) {
|
|
1320
1320
|
if (!expected.has(key)) {
|
|
1321
|
-
throw prerenderError(route, `param \`${key}\`
|
|
1321
|
+
throw prerenderError(route, `param \`${key}\` is not in the route pattern`);
|
|
1322
1322
|
}
|
|
1323
1323
|
}
|
|
1324
1324
|
result.push(buildPathname(route, record));
|
|
@@ -1351,7 +1351,7 @@ function buildPathname(route, params) {
|
|
|
1351
1351
|
}
|
|
1352
1352
|
function encodeSegment(route, value) {
|
|
1353
1353
|
if (value.length === 0 || /^\.+$/.test(value)) {
|
|
1354
|
-
throw prerenderError(route, `
|
|
1354
|
+
throw prerenderError(route, `param value \`${value}\` is not valid for a file path`);
|
|
1355
1355
|
}
|
|
1356
1356
|
return encodeURIComponent(value);
|
|
1357
1357
|
}
|
|
@@ -1362,9 +1362,9 @@ function outputFile(clientDir, pathname) {
|
|
|
1362
1362
|
if (file !== base && !file.startsWith(base + sep2)) {
|
|
1363
1363
|
throw new MoonsError3({
|
|
1364
1364
|
code: "E_PRERENDER_INVALID",
|
|
1365
|
-
message: `
|
|
1366
|
-
details: "
|
|
1367
|
-
suggestions: ["
|
|
1365
|
+
message: `prerender path escapes the client directory (\`${pathname}\`)`,
|
|
1366
|
+
details: "The file name must stay inside `dist/client`.",
|
|
1367
|
+
suggestions: ["Check the `paths` param values — do not use `..`"]
|
|
1368
1368
|
});
|
|
1369
1369
|
}
|
|
1370
1370
|
return file;
|
|
@@ -1374,10 +1374,10 @@ function prerenderError(route, message) {
|
|
|
1374
1374
|
code: "E_PRERENDER_INVALID",
|
|
1375
1375
|
file: route.file,
|
|
1376
1376
|
message,
|
|
1377
|
-
details: "
|
|
1377
|
+
details: "The prerender contract is enforced.",
|
|
1378
1378
|
suggestions: [
|
|
1379
|
-
"
|
|
1380
|
-
"
|
|
1379
|
+
"Fix the `paths`/params shape so it matches the route pattern",
|
|
1380
|
+
"Do not use `redirect()` on a prerendered route"
|
|
1381
1381
|
]
|
|
1382
1382
|
});
|
|
1383
1383
|
}
|
|
@@ -1401,4 +1401,4 @@ export {
|
|
|
1401
1401
|
toWebRequest2 as toWebRequest
|
|
1402
1402
|
};
|
|
1403
1403
|
|
|
1404
|
-
//# debugId=
|
|
1404
|
+
//# debugId=01666BCB63B6268E64756E2164756E21
|