@torpor/build 1.4.5 → 1.5.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/README.md +3 -2
- package/dist/{Site-CQ29Opvm.d.mts → Site-Blz32JRD.d.mts} +4 -3
- package/dist/{Site-CQ29Opvm.d.mts.map → Site-Blz32JRD.d.mts.map} +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/clientEntry.mjs +4 -4
- package/dist/clientEntry.mjs.map +1 -1
- package/dist/dataRequest-JosDB_ig.mjs +50 -0
- package/dist/dataRequest-JosDB_ig.mjs.map +1 -0
- package/dist/dev.mjs +1 -1
- package/dist/devPlugin-V689J6l6.mjs +144 -0
- package/dist/devPlugin-V689J6l6.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/load-LWQoFWh-.mjs +349 -0
- package/dist/load-LWQoFWh-.mjs.map +1 -0
- package/dist/nav.mjs +1 -1
- package/dist/nodeDev.d.mts +16 -0
- package/dist/nodeDev.d.mts.map +1 -0
- package/dist/nodeDev.mjs +2 -0
- package/dist/openapi.d.mts +1 -1
- package/dist/{response-CuNPcxsY.mjs → response-sth6FQsj.mjs} +33 -3
- package/dist/response-sth6FQsj.mjs.map +1 -0
- package/dist/response.mjs +2 -2
- package/dist/run.d.mts +1 -1
- package/dist/run.mjs +1 -1
- package/dist/{runOpenApi-CbbrPi4E.mjs → runOpenApi-tnflDjZV.mjs} +10 -143
- package/dist/runOpenApi-tnflDjZV.mjs.map +1 -0
- package/dist/serverEntry-fj0XfTs4.d.mts.map +1 -1
- package/dist/{serverEntry-D3uwudkX.mjs → serverEntry-o6kk_-Wo.mjs} +2 -2
- package/dist/{serverEntry-D3uwudkX.mjs.map → serverEntry-o6kk_-Wo.mjs.map} +1 -1
- package/dist/serverEntry.mjs +1 -1
- package/dist/{serverHandlers-C8qzOSX-.mjs → serverHandlers-F1gJ1lrj.mjs} +194 -30
- package/dist/serverHandlers-F1gJ1lrj.mjs.map +1 -0
- package/dist/test.d.mts +1 -1
- package/dist/test.mjs +1 -1
- package/dist/{unprocessable-D6RcYLh6.mjs → unprocessable-CoMN2zFa.mjs} +2 -32
- package/dist/unprocessable-CoMN2zFa.mjs.map +1 -0
- package/package.json +8 -3
- package/dist/load-Uyj9I60p.mjs +0 -246
- package/dist/load-Uyj9I60p.mjs.map +0 -1
- package/dist/response-CuNPcxsY.mjs.map +0 -1
- package/dist/runOpenApi-CbbrPi4E.mjs.map +0 -1
- package/dist/serverHandlers-C8qzOSX-.mjs.map +0 -1
- package/dist/unprocessable-D6RcYLh6.mjs.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { a as rewriteBaseInHtml, n as getBasePath, o as setBasePath, s as stripBaseFromUrl } from "./basePath-DQnbHc7o.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { n as DATA_REUSE_HEADER, r as findErrorRoute } from "./dataRequest-JosDB_ig.mjs";
|
|
3
|
+
import { n as ok, r as notFound, t as unprocessable } from "./unprocessable-CoMN2zFa.mjs";
|
|
3
4
|
import { n as ValidationError, t as validate } from "./validate-Ok4krlkX.mjs";
|
|
4
5
|
import { $watch } from "@torpor/view/ssr";
|
|
5
6
|
//#region src/form/formDataToRecord.ts
|
|
@@ -168,11 +169,48 @@ function mergeHead(template, head) {
|
|
|
168
169
|
*/
|
|
169
170
|
function createServerLoad(router, basePath = "", middleware = []) {
|
|
170
171
|
setBasePath(basePath);
|
|
172
|
+
/**
|
|
173
|
+
* Finalizes the response of a load or action. Successful responses and
|
|
174
|
+
* redirects pass through; an error response gets the site's error page
|
|
175
|
+
* rendered at the requested url, with the error's status code -- the
|
|
176
|
+
* address bar keeps the url the user asked for, so a transient failure
|
|
177
|
+
* (a random db hiccup, say) can be refreshed, and a typo in the path can
|
|
178
|
+
* be seen and fixed.
|
|
179
|
+
*/
|
|
180
|
+
async function handleResponse(ev, url, template, response, fromForm = false) {
|
|
181
|
+
if (response.status >= 200 && response.status <= 399) return response;
|
|
182
|
+
if (fromForm && response.status >= 400 && response.status <= 499) return response;
|
|
183
|
+
let message = await response.text();
|
|
184
|
+
if (response.headers.get("Content-Type")?.includes("application/json")) try {
|
|
185
|
+
message = JSON.parse(message).message ?? message;
|
|
186
|
+
} catch {}
|
|
187
|
+
return await renderErrorPage(ev, url, template, router, response.status, message) ?? response;
|
|
188
|
+
}
|
|
171
189
|
const handle = async (ev, template) => {
|
|
172
190
|
const url = stripBaseFromUrl(ev.url, basePath);
|
|
173
|
-
if (!url)
|
|
191
|
+
if (!url) {
|
|
192
|
+
$page.url = ev.url;
|
|
193
|
+
return await renderErrorPage(ev, ev.url, template, router, 404, "Not found") ?? notFound();
|
|
194
|
+
}
|
|
174
195
|
const path = url.pathname;
|
|
175
196
|
const query = url.searchParams;
|
|
197
|
+
if (ev.request.method === "GET" && ev.request.headers.has("X-Torpor-Data") && path.endsWith("/~server")) {
|
|
198
|
+
const pagePath = path.slice(0, -8) || "/";
|
|
199
|
+
const pageUrl = new URL(pagePath + url.search, url);
|
|
200
|
+
const pageRoute = router.match(pagePath, query);
|
|
201
|
+
if (pageRoute) {
|
|
202
|
+
$page.url = pageUrl;
|
|
203
|
+
return await loadPageData(ev, pageUrl, pageRoute.handler, pageRoute.params ?? {}, reusedLayoutPaths(ev));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
$page.url = url;
|
|
207
|
+
if (path.endsWith("/_error")) {
|
|
208
|
+
$page.status = parseInt(query.get("status") ?? "404");
|
|
209
|
+
$page.error = { message: query.get("message") ?? "" };
|
|
210
|
+
} else {
|
|
211
|
+
$page.status = 200;
|
|
212
|
+
$page.error = { message: "" };
|
|
213
|
+
}
|
|
176
214
|
let route = router.match(path, query);
|
|
177
215
|
if (!route) {
|
|
178
216
|
if (ev.request.method === "POST" && !path.endsWith("/~server")) {
|
|
@@ -180,17 +218,12 @@ function createServerLoad(router, basePath = "", middleware = []) {
|
|
|
180
218
|
route = router.match(serverPath, query);
|
|
181
219
|
}
|
|
182
220
|
}
|
|
183
|
-
if (!route) return handleResponse(notFound());
|
|
221
|
+
if (!route) return handleResponse(ev, url, template, notFound());
|
|
184
222
|
const handler = route.handler;
|
|
185
223
|
const params = route.params || {};
|
|
186
224
|
const routeMiddleware = [];
|
|
187
225
|
const endPointModule = handler.serverEndPoint ? (await handler.serverEndPoint())?.default : handler.type === 1 || handler.type === 3 ? (await resolveModule(handler))?.default : void 0;
|
|
188
226
|
if (Array.isArray(endPointModule?.middleware)) routeMiddleware.push(...endPointModule.middleware);
|
|
189
|
-
$page.url = url;
|
|
190
|
-
if (path.endsWith("/_error")) {
|
|
191
|
-
$page.status = parseInt(query.get("status") ?? "404");
|
|
192
|
-
$page.error = { message: query.get("message") ?? "" };
|
|
193
|
-
} else $page.status = 200;
|
|
194
227
|
let enteredRoute = 0;
|
|
195
228
|
let routeResponse = void 0;
|
|
196
229
|
try {
|
|
@@ -202,21 +235,21 @@ function createServerLoad(router, basePath = "", middleware = []) {
|
|
|
202
235
|
switch (handler.type) {
|
|
203
236
|
case 0:
|
|
204
237
|
case 4:
|
|
205
|
-
if (ev.request.method === "GET") return handleResponse(await loadView(ev, url, handler, params, template));
|
|
206
|
-
else if (ev.request.method === "POST") return handleResponse(await runAction(ev, url, handler, handler.serverEndPoint && (await handler.serverEndPoint()).default, params, query, template), true);
|
|
238
|
+
if (ev.request.method === "GET") return handleResponse(ev, url, template, await loadView(ev, url, handler, params, template));
|
|
239
|
+
else if (ev.request.method === "POST") return handleResponse(ev, url, template, await runAction(ev, url, handler, handler.serverEndPoint && (await handler.serverEndPoint()).default, params, query, template), true);
|
|
207
240
|
break;
|
|
208
241
|
case 1:
|
|
209
242
|
case 5:
|
|
210
243
|
if (ev.request.method === "GET") return await loadData(ev, url, handler, "load", params);
|
|
211
244
|
else if (ev.request.method === "POST") {
|
|
212
245
|
const serverEndPoint = (await resolveModule(handler)).default;
|
|
213
|
-
return handleResponse(await runAction(ev, url, handler, serverEndPoint, params, query, template), true);
|
|
246
|
+
return handleResponse(ev, url, template, await runAction(ev, url, handler, serverEndPoint, params, query, template), true);
|
|
214
247
|
}
|
|
215
248
|
break;
|
|
216
249
|
case 3: return await loadData(ev, url, handler, ev.request.method.toLowerCase().replace("delete", "del"), params);
|
|
217
250
|
case 6:
|
|
218
251
|
case 7: break;
|
|
219
|
-
case 8: return await loadView(ev, url, handler, params, template);
|
|
252
|
+
case 8: return await loadView(ev, url, handler, params, template, $page.status);
|
|
220
253
|
}
|
|
221
254
|
} finally {
|
|
222
255
|
while (enteredRoute > 0) {
|
|
@@ -238,6 +271,14 @@ function createServerLoad(router, basePath = "", middleware = []) {
|
|
|
238
271
|
return await handle(ev, template);
|
|
239
272
|
} catch (error) {
|
|
240
273
|
ev.error = error;
|
|
274
|
+
try {
|
|
275
|
+
const url = stripBaseFromUrl(ev.url, basePath) ?? ev.url;
|
|
276
|
+
if (router.match(url.pathname, url.searchParams)?.handler.type !== 3) {
|
|
277
|
+
$page.url = url;
|
|
278
|
+
const response = await renderErrorPage(ev, url, template, router, 500, error instanceof Error ? error.message : String(error));
|
|
279
|
+
if (response) return response;
|
|
280
|
+
}
|
|
281
|
+
} catch {}
|
|
241
282
|
throw error;
|
|
242
283
|
} finally {
|
|
243
284
|
while (entered > 0) {
|
|
@@ -258,20 +299,31 @@ async function loadServerHooks(handler) {
|
|
|
258
299
|
if (!handler.serverHooks) return [];
|
|
259
300
|
return handler.resolvedHooks ??= Promise.all(handler.serverHooks.map(async (load) => (await load()).default));
|
|
260
301
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
302
|
+
/**
|
|
303
|
+
* Renders the site's nearest error page for a url, with the given status
|
|
304
|
+
* code and message, at the url itself. Returns undefined when the site has
|
|
305
|
+
* no matching error route, or when rendering the error page failed -- the
|
|
306
|
+
* caller passes the original response or error through instead.
|
|
307
|
+
*
|
|
308
|
+
* The error page runs through the normal view pipeline, so it is rendered
|
|
309
|
+
* inside the layouts of its route (e.g. the root `/_error` gets the root
|
|
310
|
+
* `_layout`).
|
|
311
|
+
*/
|
|
312
|
+
async function renderErrorPage(ev, url, template, router, status, message) {
|
|
313
|
+
const errorPath = findErrorRoute(router, url.pathname);
|
|
314
|
+
if (!errorPath) return;
|
|
315
|
+
const errorRoute = router.match(errorPath, new URLSearchParams());
|
|
316
|
+
if (!errorRoute) return;
|
|
317
|
+
$page.status = status;
|
|
318
|
+
$page.error = { message };
|
|
319
|
+
try {
|
|
320
|
+
const response = await loadView(ev, url, errorRoute.handler, {}, template, status);
|
|
321
|
+
if (response.headers.get("Content-Type")?.includes("text/html")) return response;
|
|
322
|
+
return;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.log(error);
|
|
325
|
+
return;
|
|
273
326
|
}
|
|
274
|
-
return seeOther(`/_error?${params.toString()}`);
|
|
275
327
|
}
|
|
276
328
|
async function loadData(ev, url, handler, functionName, params) {
|
|
277
329
|
const serverEndPoint = (handler.resolvedModule ?? await resolveModule(handler))?.default;
|
|
@@ -309,7 +361,92 @@ async function loadData(ev, url, handler, functionName, params) {
|
|
|
309
361
|
throw error;
|
|
310
362
|
}
|
|
311
363
|
}
|
|
312
|
-
|
|
364
|
+
/**
|
|
365
|
+
* Handles a client data request (see `DATA_REQUEST_HEADER`). Runs the folder
|
|
366
|
+
* hooks once against the page url, then loads the server data for each layout
|
|
367
|
+
* (root to leaf) and the page, returning `{ loads: [...] }` -- one entry per
|
|
368
|
+
* layout plus the page, in the same order as `handler.layouts`. The client
|
|
369
|
+
* runs its own load functions and merges the server entries in.
|
|
370
|
+
*
|
|
371
|
+
* A load that redirects or fails short-circuits the whole request, so the
|
|
372
|
+
* client can fall back to a full page load (redirect) or render the error
|
|
373
|
+
* page (failure), exactly as it would with a single page load.
|
|
374
|
+
*/
|
|
375
|
+
async function loadPageData(ev, pageUrl, handler, params, reusedLayouts) {
|
|
376
|
+
const serverEndPoint = handler.serverEndPoint && (await handler.serverEndPoint())?.default;
|
|
377
|
+
let query;
|
|
378
|
+
if (serverEndPoint) {
|
|
379
|
+
try {
|
|
380
|
+
params = await validateEndpointParams(serverEndPoint, params);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
if (error instanceof ValidationError) return notFound();
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
const loadSchema = endpointSchema(serverEndPoint, "load");
|
|
386
|
+
if (loadSchema) try {
|
|
387
|
+
query = await validate(loadSchema, searchParamsToRecord(pageUrl.searchParams));
|
|
388
|
+
} catch (error) {
|
|
389
|
+
const response = validationErrorResponse(error);
|
|
390
|
+
if (response) return response;
|
|
391
|
+
throw error;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const serverParams = buildServerParams(ev, pageUrl, params, query ? { query } : {});
|
|
395
|
+
const serverHooks = await loadServerHooks(handler);
|
|
396
|
+
const routeMiddleware = Array.isArray(serverEndPoint?.middleware) ? serverEndPoint.middleware : [];
|
|
397
|
+
const loads = [];
|
|
398
|
+
let enteredMiddleware = 0;
|
|
399
|
+
let entered = 0;
|
|
400
|
+
let enterResponse = void 0;
|
|
401
|
+
try {
|
|
402
|
+
for (; enteredMiddleware < routeMiddleware.length && !enterResponse; enteredMiddleware++) {
|
|
403
|
+
const middlewareResult = await routeMiddleware[enteredMiddleware].enter?.(ev);
|
|
404
|
+
if (middlewareResult) enterResponse = middlewareResult;
|
|
405
|
+
}
|
|
406
|
+
for (; entered < serverHooks.length && !enterResponse; entered++) {
|
|
407
|
+
const hookResult = await serverHooks[entered].enter?.(serverParams);
|
|
408
|
+
if (hookResult) enterResponse = hookResult;
|
|
409
|
+
}
|
|
410
|
+
if (enterResponse) return enterResponse;
|
|
411
|
+
for (const layout of handler.layouts ?? []) {
|
|
412
|
+
if (reusedLayouts.has(layout.path)) {
|
|
413
|
+
loads.push(null);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
const result = await loadRouteServerData(layout.serverEndPoint && (await layout.serverEndPoint())?.default, serverParams);
|
|
417
|
+
if (result instanceof Response) return result;
|
|
418
|
+
loads.push(result);
|
|
419
|
+
}
|
|
420
|
+
const pageResult = await loadRouteServerData(serverEndPoint, serverParams);
|
|
421
|
+
if (pageResult instanceof Response) return pageResult;
|
|
422
|
+
loads.push(pageResult);
|
|
423
|
+
return new Response(JSON.stringify({ loads }), { headers: { "Content-Type": "application/json" } });
|
|
424
|
+
} finally {
|
|
425
|
+
while (entered > 0) {
|
|
426
|
+
entered--;
|
|
427
|
+
await serverHooks[entered].exit?.(serverParams);
|
|
428
|
+
}
|
|
429
|
+
while (enteredMiddleware > 0) {
|
|
430
|
+
enteredMiddleware--;
|
|
431
|
+
await routeMiddleware[enteredMiddleware].exit?.(ev);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Runs a single route's server load (if any) as part of a data request.
|
|
437
|
+
* Returns the loaded data, `null` when the route has no load, or the raw
|
|
438
|
+
* Response when the load redirected or failed.
|
|
439
|
+
*/
|
|
440
|
+
async function loadRouteServerData(serverEndPoint, serverParams) {
|
|
441
|
+
if (!serverEndPoint?.load) return null;
|
|
442
|
+
const response = await serverEndPoint.load(serverParams);
|
|
443
|
+
if (!response || response.ok) {
|
|
444
|
+
if (response?.headers.get("Content-Type")?.includes("application/json")) return await response.json();
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
return response;
|
|
448
|
+
}
|
|
449
|
+
async function loadView(ev, url, handler, params, template, status, form, fromForm, appData) {
|
|
313
450
|
const clientEndPoint = (await resolveModule(handler)).default;
|
|
314
451
|
if (!clientEndPoint?.component) return notFound();
|
|
315
452
|
$page.flash = ev.flash.get();
|
|
@@ -418,7 +555,7 @@ async function loadView(ev, url, handler, params, template, formStatus, form, fr
|
|
|
418
555
|
if (missingLayout !== void 0) warnMissingSlotContent(missingLayout);
|
|
419
556
|
}
|
|
420
557
|
return new Response(html, {
|
|
421
|
-
status:
|
|
558
|
+
status: status ?? 200,
|
|
422
559
|
headers: { "Content-Type": "text/html" }
|
|
423
560
|
});
|
|
424
561
|
} finally {
|
|
@@ -518,15 +655,42 @@ function buildClientParams(url, params, data) {
|
|
|
518
655
|
data
|
|
519
656
|
};
|
|
520
657
|
}
|
|
658
|
+
/**
|
|
659
|
+
* The layout paths a data request asked to reuse, from the `X-Torpor-Reuse`
|
|
660
|
+
* header (a JSON array). A malformed header is ignored rather than failing the
|
|
661
|
+
* request -- the client just gets the layouts loaded again.
|
|
662
|
+
*/
|
|
663
|
+
function reusedLayoutPaths(ev) {
|
|
664
|
+
const header = ev.request.headers.get(DATA_REUSE_HEADER);
|
|
665
|
+
if (!header) return /* @__PURE__ */ new Set();
|
|
666
|
+
try {
|
|
667
|
+
const paths = JSON.parse(header);
|
|
668
|
+
if (Array.isArray(paths)) return new Set(paths.filter((p) => typeof p === "string"));
|
|
669
|
+
} catch {}
|
|
670
|
+
return /* @__PURE__ */ new Set();
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* The url user code (hooks, loads, actions, `@head`) should see. Client-side
|
|
674
|
+
* data fetches append `/~server` to the page url, but that suffix is an
|
|
675
|
+
* internal detail: without stripping it, `event.url.pathname` would differ
|
|
676
|
+
* between the server-rendered page and its `~server` request, so a hook
|
|
677
|
+
* guarding on the path (e.g. `path !== "/setup"`) would misfire.
|
|
678
|
+
*/
|
|
679
|
+
function requestUrl(url) {
|
|
680
|
+
if (!url.pathname.endsWith("/~server")) return url;
|
|
681
|
+
const path = url.pathname.slice(0, -8) || "/";
|
|
682
|
+
return new URL(path + url.search, url);
|
|
683
|
+
}
|
|
521
684
|
function buildServerParams(ev, url, params, values = {}, appData = {}) {
|
|
685
|
+
const logicalUrl = requestUrl(url);
|
|
522
686
|
return {
|
|
523
|
-
url,
|
|
687
|
+
url: logicalUrl,
|
|
524
688
|
params,
|
|
525
689
|
appData,
|
|
526
690
|
request: ev.request,
|
|
527
691
|
json: () => values.json !== void 0 ? Promise.resolve(values.json) : ev.json(),
|
|
528
692
|
form: () => values.form !== void 0 ? Promise.resolve(values.form) : formDataToRecord(ev.request),
|
|
529
|
-
query: () => values.query !== void 0 ? Promise.resolve(values.query) : Promise.resolve(searchParamsToRecord(
|
|
693
|
+
query: () => values.query !== void 0 ? Promise.resolve(values.query) : Promise.resolve(searchParamsToRecord(logicalUrl.searchParams)),
|
|
530
694
|
cookies: ev.cookies,
|
|
531
695
|
headers: ev.headers,
|
|
532
696
|
session: ev.session,
|
|
@@ -549,4 +713,4 @@ function escapeHtml(value) {
|
|
|
549
713
|
//#endregion
|
|
550
714
|
export { createServerLoad as t };
|
|
551
715
|
|
|
552
|
-
//# sourceMappingURL=serverHandlers-
|
|
716
|
+
//# sourceMappingURL=serverHandlers-F1gJ1lrj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverHandlers-F1gJ1lrj.mjs","names":[],"sources":["../src/form/formDataToRecord.ts","../src/state/$serverPage.ts","../src/utils/searchParamsToRecord.ts","../src/validation/endpoint.ts","../src/site/layoutSlots.ts","../src/site/mergeHead.ts","../src/site/serverHandlers.ts"],"sourcesContent":["import type { FormDataRecord } from \"../types/ServerLoadEvent\";\n\n/**\n * Converts the submitted fields of a form request into a plain record: one\n * value per field, or an array when a field was submitted with multiple\n * values (e.g. a multi select). File inputs pass through as `File` values;\n * coercing them is left to the schema or the action.\n *\n * @param request The request (or FormData directly)\n * @returns The field values\n */\nexport default async function formDataToRecord(\n\trequest: Request | FormData,\n): Promise<FormDataRecord> {\n\tconst formData = request instanceof FormData ? request : await request.formData();\n\tconst result: FormDataRecord = {};\n\tfor (const key of formData.keys()) {\n\t\tif (key in result) continue;\n\t\tconst values = formData.getAll(key);\n\t\tresult[key] = values.length > 1 ? values : values[0];\n\t}\n\treturn result;\n}\n","import { $watch } from \"@torpor/view/ssr\";\nimport type PageState from \"../types/PageState\";\n\nconst PAGE_SYMBOL: unique symbol = Symbol.for(\"torp.Page\");\n\n// The server request path has no reactive subscribers, so the state is\n// stored plainly ($watch from `@torpor/view/ssr` is a no-op that returns\n// the object itself) instead of through a reactive proxy. Shares the same\n// `globalThis` slot as the client `$page`, so both variants always see the\n// same state object whichever loads first.\nconst $page: PageState =\n\t// @ts-ignore\n\t(globalThis[PAGE_SYMBOL] ??= $watch({\n\t\tstatus: 404,\n\t\turl: new URL(\"http://localhost\"),\n\t\tform: undefined,\n\t\tflash: undefined,\n\t\terror: {\n\t\t\tmessage: \"\",\n\t\t},\n\t}));\n\nexport default $page;\n","import type { QueryRecord } from \"../types/ServerLoadEvent\";\n\n/**\n * Converts a URL's query string into a plain record: one string per param,\n * or an array when a param was repeated.\n *\n * @param searchParams The URL's search params\n * @returns The param values\n */\nexport default function searchParamsToRecord(searchParams: URLSearchParams): QueryRecord {\n\tconst result: QueryRecord = {};\n\tfor (const key of searchParams.keys()) {\n\t\tif (key in result) continue;\n\t\tconst values = searchParams.getAll(key);\n\t\tresult[key] = values.length > 1 ? values : values[0];\n\t}\n\treturn result;\n}\n","import type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport type ServerEndPoint from \"../types/ServerEndPoint\";\nimport type { StandardSchemaV1 } from \"../types/StandardSchema\";\nimport type ServerEvent from \"../server/ServerEvent\";\nimport searchParamsToRecord from \"../utils/searchParamsToRecord\";\nimport unprocessable from \"../response/unprocessable\";\nimport ValidationError from \"./ValidationError\";\nimport validate from \"./validate\";\n\n/**\n * Loose views of an endpoint's schema map, keyed by handler/action name (plus\n * the reserved `params` key). The type-level constraint differs per endpoint\n * type, but the runtime treats them the same.\n */\ntype Schemas = Record<string, StandardSchemaV1 | undefined>;\n\ntype EndPoint = ServerEndPoint | PageServerEndPoint;\n\n/**\n * Gets the standard schema declared for a handler or action, if any. The\n * schemas map is keyed by name; the runtime treats it as a loose record.\n */\nexport function endpointSchema(endPoint: EndPoint, name: string): StandardSchemaV1 | undefined {\n\treturn (endPoint.schema as Schemas | undefined)?.[name];\n}\n\n/**\n * Validates the route params against the endpoint's `params` schema, if it\n * declares one, returning the coerced params. Throws a ValidationError when\n * they don't match, which callers turn into a 404 (params come from the URL,\n * so a failed validation means the resource doesn't exist).\n *\n * @param endPoint The endpoint declaring the (optional) `params` schema\n * @param params The route params from the matched route\n * @returns The validated params\n */\nexport async function validateEndpointParams(\n\tendPoint: EndPoint,\n\tparams: Record<string, any>,\n): Promise<Record<string, any>> {\n\tconst schema = endpointSchema(endPoint, \"params\");\n\treturn schema ? ((await validate(schema, params)) as Record<string, any>) : params;\n}\n\n/**\n * Validates a handler's input against its schema: get/head handlers and load\n * functions validate the URL's query string, other handlers validate the JSON\n * request body. Returns the validated values (an empty object when no schema\n * is declared), which callers pass through to the handler's event.\n *\n * @param schema The handler's (optional) schema\n * @param functionName The handler name (`get`, `post`, `load`, etc)\n * @param url The request URL, for the query string\n * @param ev The server event, for the request body\n * @returns The validated values\n */\nexport async function validateHandlerInput(\n\tschema: StandardSchemaV1 | undefined,\n\tfunctionName: string,\n\turl: URL,\n\tev: ServerEvent,\n): Promise<{ json?: unknown; form?: unknown; query?: unknown }> {\n\tif (!schema) return {};\n\tif (functionName === \"get\" || functionName === \"head\" || functionName === \"load\") {\n\t\treturn { query: await validate(schema, searchParamsToRecord(url.searchParams)) };\n\t}\n\treturn { json: await validate(schema, await ev.json()) };\n}\n\n/**\n * Turns a ValidationError thrown during endpoint validation into a 422\n * response with the schema's issues. Returns undefined for any other error,\n * which callers should rethrow.\n *\n * @param error The error thrown by a handler or validation\n * @returns A 422 response, or undefined when the error isn't a validation failure\n */\nexport function validationErrorResponse(error: unknown): Response | undefined {\n\tif (error instanceof ValidationError) {\n\t\treturn unprocessable({ message: error.message, issues: error.issues });\n\t}\n\treturn undefined;\n}\n","/**\n * Layouts are composed by the layout engine passing each layout (and finally\n * the page) as the default slot of its parent — so every `_layout` component\n * must render `<slot />`, or pass the default slot down to a child component\n * it renders. A layout that doesn't drops its entire content: the server\n * renders the layout's own markup with an empty content area (no error), and\n * the first client-side navigation that reuses the layout crashes on a null\n * slot region.\n *\n * The static `checkLayoutSlots` check catches this at build/dev time; these\n * helpers report it at request time for the cases static analysis can't see\n * (e.g. a `<slot />` rendered conditionally inside `@if`). They are\n * server-side only — nothing here is imported into the client bundle.\n */\n\n/**\n * Returns the path of the outermost layout that never rendered its\n * `<slot />`, or undefined when every level rendered.\n *\n * Slot level j (1-based) is the slot render that layout j - 1 receives: the\n * root layout (layouts[0]) renders level 1, layout i renders level i + 1,\n * and level layouts.length renders the page. A broken level makes every\n * deeper level unreachable, so the first level that never ran identifies\n * the offending layout.\n */\nexport function findMissingSlotLayout(\n\tlayouts: readonly { path: string }[],\n\tinvokedLevels: ReadonlySet<number>,\n): string | undefined {\n\tfor (let level = 1; level <= layouts.length; level++) {\n\t\tif (!invokedLevels.has(level)) {\n\t\t\treturn layouts[level - 1].path;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nconst warnedLayouts = new Set<string>();\n\n/**\n * Reports a layout that dropped its slot content. The condition is a genuine\n * rendering bug (the page content is missing from the output), so it is not\n * dev-gated — but it warns only once per layout path to avoid per-request\n * noise.\n */ export function warnMissingSlotContent(layoutPath: string): void {\n\tif (warnedLayouts.has(layoutPath)) return;\n\twarnedLayouts.add(layoutPath);\n\tconsole.warn(\n\t\t`[torpor] The layout at \"${layoutPath}\" never rendered <slot />, so the page content ` +\n\t\t\t`was not included in the render. Every _layout component must render <slot /> (or ` +\n\t\t\t`pass the default slot down to a child component it renders).`,\n\t);\n}\n","const TITLE_REGEX = /<title(?:\\s[^>]*)?>[\\s\\S]*?<\\/title>/g;\nconst FIRST_TITLE_REGEX = /<title(?:\\s[^>]*)?>[\\s\\S]*?<\\/title>/;\n\n/**\n * Merges the head string rendered by a page (and its layouts) into the site\n * template. The first <title> in the head string -- the page's, since pages\n * render before the layouts around them -- wins, overriding both any later\n * component title (e.g. from a child component) and a static <title> in the\n * template itself. All other head content (styles, meta elements, etc) is\n * appended where %COMPONENT_HEAD% sits in the template, before </head>.\n */\nexport default function mergeHead(template: string, head: string): string {\n\tconst titles = head.match(TITLE_REGEX);\n\tlet html = template;\n\tlet headHtml = head;\n\tif (titles?.length) {\n\t\theadHtml = head.replace(TITLE_REGEX, \"\");\n\t\thtml = html.replace(FIRST_TITLE_REGEX, \"\");\n\t\theadHtml = titles[0] + headHtml;\n\t}\n\treturn html.replace(\"%COMPONENT_HEAD%\", headHtml);\n}\n","import { type ServerComponent, type ServerSlotRender } from \"@torpor/view/ssr\";\nimport { DATA_REUSE_HEADER, DATA_REQUEST_HEADER } from \"../dataRequest.ts\";\nimport formDataToRecord from \"../form/formDataToRecord.ts\";\nimport notFound from \"../response/notFound.ts\";\nimport ok from \"../response/ok.ts\";\nimport ServerEvent from \"../server/ServerEvent.ts\";\nimport type MiddlewareFunction from \"../server/types/MiddlewareFunction\";\nimport $page from \"../state/$serverPage.ts\";\nimport type PageEndPoint from \"../types/PageEndPoint.ts\";\nimport type { HeadElement } from \"../types/PageEndPoint.ts\";\nimport type PageLoadEvent from \"../types/PageLoadEvent.ts\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint.ts\";\nimport type RouteHandler from \"../types/RouteHandler.ts\";\nimport type ServerRequest from \"../types/ServerRequest.ts\";\nimport {\n\tERROR_ROUTE,\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport type ServerEndPoint from \"../types/ServerEndPoint.ts\";\nimport type ServerHook from \"../types/ServerHook.ts\";\nimport type ServerLoadEvent from \"../types/ServerLoadEvent.ts\";\nimport searchParamsToRecord from \"../utils/searchParamsToRecord.ts\";\nimport validate from \"../validation/validate.ts\";\nimport ValidationError from \"../validation/ValidationError.ts\";\nimport {\n\tendpointSchema,\n\tvalidateEndpointParams,\n\tvalidationErrorResponse,\n} from \"../validation/endpoint.ts\";\nimport { findMissingSlotLayout, warnMissingSlotContent } from \"./layoutSlots.ts\";\nimport { getBasePath, rewriteBaseInHtml, setBasePath, stripBaseFromUrl } from \"./basePath.ts\";\nimport findErrorRoute from \"./findErrorRoute.ts\";\nimport mergeHead from \"./mergeHead.ts\";\nimport type Router from \"./Router.ts\";\n\n/**\n * The site's request handler, as created by `createServerLoad`.\n */\nexport type ServerLoad = (ev: ServerEvent, template?: string) => Promise<Response>;\n\n/**\n * Creates the site's request handler for the given router. This is kept\n * separate from serverEntry, which imports the virtual\n * `@torpor/build/manifest` module (it only exists when a site runs or\n * builds), so that tests can exercise the handlers with their own routes.\n *\n * @param router The router, built from the site's routes\n * @param basePath The site's base path, stripped from incoming URLs before\n * routing (see basePath.ts)\n * @param middleware Global middleware (from `site.middleware`), run for\n * every request before routing -- including requests that won't match a\n * route\n * @returns The request handler, which takes the site template\n */\nexport function createServerLoad(\n\trouter: Router,\n\tbasePath = \"\",\n\tmiddleware: MiddlewareFunction[] = [],\n): ServerLoad {\n\t// The base path is shared through module state, so that everything that\n\t// generates URLs (HTML attributes, redirect locations) sees the same\n\t// value the router strips\n\tsetBasePath(basePath);\n\n\t/**\n\t * Finalizes the response of a load or action. Successful responses and\n\t * redirects pass through; an error response gets the site's error page\n\t * rendered at the requested url, with the error's status code -- the\n\t * address bar keeps the url the user asked for, so a transient failure\n\t * (a random db hiccup, say) can be refreshed, and a typo in the path can\n\t * be seen and fixed.\n\t */\n\tasync function handleResponse(\n\t\tev: ServerEvent,\n\t\turl: URL,\n\t\ttemplate: string | undefined,\n\t\tresponse: Response,\n\t\tfromForm = false,\n\t): Promise<Response> {\n\t\t// Success codes and redirect codes are acceptable\n\t\tif (response.status >= 200 && response.status <= 399) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// 4xx error codes are acceptable from form actions\n\t\tif (fromForm && response.status >= 400 && response.status <= 499) {\n\t\t\treturn response;\n\t\t}\n\n\t\tlet message = await response.text();\n\t\tif (response.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\ttry {\n\t\t\t\tconst data = JSON.parse(message);\n\t\t\t\tmessage = data.message ?? message;\n\t\t\t} catch {\n\t\t\t\t// Not actually json, so show the raw body\n\t\t\t}\n\t\t}\n\t\tconst rendered = await renderErrorPage(ev, url, template, router, response.status, message);\n\t\t// No error page (or rendering it failed), so the response is passed\n\t\t// through as-is\n\t\treturn rendered ?? response;\n\t}\n\n\tconst handle = async (ev: ServerEvent, template?: string): Promise<Response> => {\n\t\t// The base is stripped before routing, so that everything below (route\n\t\t// matching, params, user code reading `event.url`) is base-free.\n\t\t// Requests that don't carry the base aren't ours\n\t\tconst url = stripBaseFromUrl(ev.url, basePath);\n\t\tif (!url) {\n\t\t\t// Like any other error, the error page is rendered at the\n\t\t\t// requested url rather than redirecting into the site\n\t\t\t$page.url = ev.url;\n\t\t\tconst response = await renderErrorPage(ev, ev.url, template, router, 404, \"Not found\");\n\t\t\treturn response ?? notFound();\n\t\t}\n\t\tconst path = url.pathname;\n\t\tconst query = url.searchParams;\n\n\t\t// A client data request: one GET to `<page url>/~server` returns the\n\t\t// server data for the page and all of its layouts, with hooks running\n\t\t// once against the page url. It doesn't need a registered `~server`\n\t\t// route (a page may have no `+page.server.ts` but still have layouts\n\t\t// with server loads)\n\t\tif (\n\t\t\tev.request.method === \"GET\" &&\n\t\t\tev.request.headers.has(DATA_REQUEST_HEADER) &&\n\t\t\tpath.endsWith(\"/~server\")\n\t\t) {\n\t\t\tconst pagePath = path.slice(0, -\"/~server\".length) || \"/\";\n\t\t\tconst pageUrl = new URL(pagePath + url.search, url);\n\t\t\tconst pageRoute = router.match(pagePath, query);\n\t\t\tif (pageRoute) {\n\t\t\t\t$page.url = pageUrl;\n\t\t\t\treturn await loadPageData(\n\t\t\t\t\tev,\n\t\t\t\t\tpageUrl,\n\t\t\t\t\tpageRoute.handler,\n\t\t\t\t\tpageRoute.params ?? {},\n\t\t\t\t\treusedLayoutPaths(ev),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\t\t// Update $page before routing, so that a request that doesn't match\n\t\t// any route (and gets the error page) still sees this url\n\t\t$page.url = url;\n\t\tif (path.endsWith(\"/_error\")) {\n\t\t\t$page.status = parseInt(query.get(\"status\") ?? \"404\");\n\t\t\t$page.error = { message: query.get(\"message\") ?? \"\" };\n\t\t} else {\n\t\t\t$page.status = 200;\n\t\t\t$page.error = { message: \"\" };\n\t\t}\n\n\t\tlet route = router.match(path, query);\n\t\tif (!route) {\n\t\t\t// If the route wasn't found, the user may be posting a form to a\n\t\t\t// +page.server.ts route that doesn't have a corresponding +page.ts\n\t\t\t// route, which is allowed, so check for that as well\n\t\t\tif (ev.request.method === \"POST\" && !path.endsWith(\"/~server\")) {\n\t\t\t\tconst serverPath =\n\t\t\t\t\t(path.endsWith(\"/\") ? path.substring(0, path.length - 1) : path) + \"/~server\";\n\t\t\t\troute = router.match(serverPath, query);\n\t\t\t}\n\t\t}\n\t\tif (!route) {\n\t\t\treturn handleResponse(ev, url, template, notFound());\n\t\t}\n\t\tconst handler = route.handler;\n\t\tconst params = route.params || {};\n\t\t// Route middleware, declared on the route's server endpoint\n\t\t// (+page.server.ts / +server.ts). Runs after the global middleware and\n\t\t// before folder hooks, so a guard can skip data loading entirely\n\t\tconst routeMiddleware: MiddlewareFunction[] = [];\n\t\tconst endPointModule = handler.serverEndPoint\n\t\t\t? (await handler.serverEndPoint())?.default\n\t\t\t: handler.type === PAGE_SERVER_ROUTE || handler.type === SERVER_ROUTE\n\t\t\t\t? (await resolveModule(handler))?.default\n\t\t\t\t: undefined;\n\t\tif (Array.isArray(endPointModule?.middleware)) {\n\t\t\trouteMiddleware.push(...endPointModule.middleware);\n\t\t}\n\n\t\t// TODO: Hit the server hook out here\n\t\t// We could maybe set up data loading as middleware on a route??????\n\n\t\t// Run the route's middleware around the handler: enter hooks in order\n\t\t// (a Response short-circuits the request), exit hooks in reverse\n\t\tlet enteredRoute = 0;\n\t\tlet routeResponse: Response | undefined = undefined;\n\t\ttry {\n\t\t\tfor (; enteredRoute < routeMiddleware.length && !routeResponse; enteredRoute++) {\n\t\t\t\tconst result = await routeMiddleware[enteredRoute].enter?.(ev);\n\t\t\t\tif (result) {\n\t\t\t\t\trouteResponse = result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (routeResponse) {\n\t\t\t\treturn routeResponse;\n\t\t\t}\n\n\t\t\tswitch (handler.type) {\n\t\t\t\tcase PAGE_ROUTE:\n\t\t\t\tcase LAYOUT_ROUTE: {\n\t\t\t\t\t// It's a /+page.ts or /_layout.ts endpoint\n\t\t\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\t\t\treturn handleResponse(\n\t\t\t\t\t\t\tev,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttemplate,\n\t\t\t\t\t\t\tawait loadView(ev, url, handler, params, template),\n\t\t\t\t\t\t);\n\t\t\t\t\t} else if (ev.request.method === \"POST\") {\n\t\t\t\t\t\t// The server end point comes from the sibling /+page.server.ts, if applicable\n\t\t\t\t\t\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\t\t\t\t\t\thandler.serverEndPoint && (await handler.serverEndPoint()).default;\n\t\t\t\t\t\treturn handleResponse(\n\t\t\t\t\t\t\tev,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttemplate,\n\t\t\t\t\t\t\tawait runAction(ev, url, handler, serverEndPoint, params, query, template),\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase PAGE_SERVER_ROUTE:\n\t\t\t\tcase LAYOUT_SERVER_ROUTE: {\n\t\t\t\t\t// It's a /+page.server.ts or /_layout.server.ts endpoint\n\t\t\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\t\t\treturn await loadData(ev, url, handler, \"load\", params);\n\t\t\t\t\t} else if (ev.request.method === \"POST\") {\n\t\t\t\t\t\tconst serverEndPoint: PageServerEndPoint | undefined = (await resolveModule(handler))\n\t\t\t\t\t\t\t.default;\n\t\t\t\t\t\treturn handleResponse(\n\t\t\t\t\t\t\tev,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttemplate,\n\t\t\t\t\t\t\tawait runAction(ev, url, handler, serverEndPoint, params, query, template),\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase SERVER_ROUTE: {\n\t\t\t\t\t// It's a /+server.ts endpoint\n\t\t\t\t\tconst functionName = ev.request.method.toLowerCase().replace(\"delete\", \"del\");\n\t\t\t\t\treturn await loadData(ev, url, handler, functionName, params);\n\t\t\t\t}\n\t\t\t\tcase HOOK_ROUTE:\n\t\t\t\tcase HOOK_SERVER_ROUTE: {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ERROR_ROUTE: {\n\t\t\t\t\t// A direct request for the error page (e.g. a bookmark of\n\t\t\t\t\t// the url it used to be redirected to, or the prerender\n\t\t\t\t\t// writing 404.html). It responds with the requested status\n\t\t\t\t\t// rather than 200\n\t\t\t\t\treturn await loadView(ev, url, handler, params, template, $page.status);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\twhile (enteredRoute > 0) {\n\t\t\t\tenteredRoute--;\n\t\t\t\tawait routeMiddleware[enteredRoute].exit?.(ev);\n\t\t\t}\n\t\t}\n\n\t\treturn notFound();\n\t};\n\n\treturn async function load(ev: ServerEvent, template?: string): Promise<Response> {\n\t\t// Global middleware, from `site.middleware`: runs for every request\n\t\t// before routing, including ones that won't match a route\n\t\t// (maintenance mode, legacy url redirects, etc)\n\t\tlet entered = 0;\n\t\ttry {\n\t\t\tlet response: Response | undefined = undefined;\n\t\t\tfor (; entered < middleware.length && !response; entered++) {\n\t\t\t\tconst result = await middleware[entered].enter?.(ev);\n\t\t\t\tif (result) {\n\t\t\t\t\tresponse = result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (response) {\n\t\t\t\treturn response;\n\t\t\t}\n\t\t\treturn await handle(ev, template);\n\t\t} catch (error) {\n\t\t\t// Middleware exits can inspect (and replace, in Server.fetch) the\n\t\t\t// error via `ev.error`\n\t\t\tev.error = error;\n\t\t\t// A thrown exception (a load or component crashing, say) gets the\n\t\t\t// error page rendered at the requested url, like an error response\n\t\t\t// would -- unless the request was for an api endpoint (json in,\n\t\t\t// json out), or there is no error page, or rendering it failed, in\n\t\t\t// which case the error is rethrown for the server adapters\n\t\t\ttry {\n\t\t\t\tconst url = stripBaseFromUrl(ev.url, basePath) ?? ev.url;\n\t\t\t\tconst match = router.match(url.pathname, url.searchParams);\n\t\t\t\tif (match?.handler.type !== SERVER_ROUTE) {\n\t\t\t\t\t$page.url = url;\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tconst response = await renderErrorPage(ev, url, template, router, 500, message);\n\t\t\t\t\tif (response) {\n\t\t\t\t\t\treturn response;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall through to the rethrow\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\twhile (entered > 0) {\n\t\t\t\tentered--;\n\t\t\t\tawait middleware[entered].exit?.(ev);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Resolves the route's endpoint module, caching it on the handler so warm\n * requests don't pay for the loader promise.\n */\nasync function resolveModule(handler: RouteHandler): Promise<any> {\n\treturn (handler.resolvedModule ??= await (handler.modulePromise ??= handler.endPoint()));\n}\n\nasync function loadServerHooks(handler: RouteHandler): Promise<ServerHook[]> {\n\tif (!handler.serverHooks) return [];\n\t// Resolve each hook module once and cache the result on the handler\n\treturn (handler.resolvedHooks ??= Promise.all(\n\t\thandler.serverHooks.map(async (load) => (await load()).default),\n\t));\n}\n\n/**\n * Renders the site's nearest error page for a url, with the given status\n * code and message, at the url itself. Returns undefined when the site has\n * no matching error route, or when rendering the error page failed -- the\n * caller passes the original response or error through instead.\n *\n * The error page runs through the normal view pipeline, so it is rendered\n * inside the layouts of its route (e.g. the root `/_error` gets the root\n * `_layout`).\n */\nasync function renderErrorPage(\n\tev: ServerEvent,\n\turl: URL,\n\ttemplate: string | undefined,\n\trouter: Router,\n\tstatus: number,\n\tmessage: string,\n): Promise<Response | undefined> {\n\tconst errorPath = findErrorRoute(router, url.pathname);\n\tif (!errorPath) {\n\t\treturn undefined;\n\t}\n\t// Matched (rather than picked off `router.routes`) so that the error\n\t// route's layouts, server endpoint and hooks get loaded\n\tconst errorRoute = router.match(errorPath, new URLSearchParams());\n\tif (!errorRoute) {\n\t\treturn undefined;\n\t}\n\n\t$page.status = status;\n\t$page.error = { message };\n\n\ttry {\n\t\tconst response = await loadView(ev, url, errorRoute.handler, {}, template, status);\n\t\t// A load or layout of the error page can itself fail -- loadView\n\t\t// returns its response, which (unlike a rendered error page) won't\n\t\t// be html. The caller passes the original response through instead\n\t\tif (response.headers.get(\"Content-Type\")?.includes(\"text/html\")) {\n\t\t\treturn response;\n\t\t}\n\t\treturn undefined;\n\t} catch (error) {\n\t\t// The error page itself blew up; the caller's original response or\n\t\t// error is the better fallback\n\t\tconsole.log(error);\n\t\treturn undefined;\n\t}\n}\n\nasync function loadData(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tfunctionName: string,\n\tparams: Record<string, any>,\n) {\n\t// The endpoint module is cached on the handler, so once warm this is a\n\t// plain property read\n\tconst mod = handler.resolvedModule ?? (await resolveModule(handler));\n\tconst serverEndPoint: ServerEndPoint | undefined = mod?.default;\n\t// `functionName` is computed from the request method, so the handlers are\n\t// accessed through a loose record\n\tconst handlerFn = (\n\t\tserverEndPoint as unknown as Record<string, ServerRequest | undefined> | undefined\n\t)?.[functionName];\n\tif (!serverEndPoint || !handlerFn) {\n\t\treturn notFound();\n\t}\n\n\t// Route params come from the URL, so a failed validation means the\n\t// resource doesn't exist. Only endpoints declaring a params schema pay\n\t// for validation\n\tconst paramsSchema = endpointSchema(serverEndPoint, \"params\");\n\tif (paramsSchema) {\n\t\ttry {\n\t\t\tparams = (await validate(paramsSchema, params)) as Record<string, any>;\n\t\t} catch (error) {\n\t\t\tif (error instanceof ValidationError) return notFound();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\ttry {\n\t\t// If the endpoint declares a schema for this handler, validate its\n\t\t// input up front and reject with 422 if it fails. get/head/load\n\t\t// schemas validate the query string; other schemas validate the json\n\t\t// body. Endpoints without a schema skip straight to the handler\n\t\tconst schema = endpointSchema(serverEndPoint, functionName);\n\t\tconst values = schema\n\t\t\t? functionName === \"get\" || functionName === \"head\" || functionName === \"load\"\n\t\t\t\t? { query: await validate(schema, searchParamsToRecord(url.searchParams)) }\n\t\t\t\t: { json: await validate(schema, await ev.json()) }\n\t\t\t: {};\n\n\t\tconst serverParams = buildServerParams(ev, url, params, values);\n\n\t\t// Hooks are resolved once per handler; routes without hooks don't\n\t\t// await anything here\n\t\tconst hooks = handler.serverHooks ? await loadServerHooks(handler) : [];\n\n\t\tlet entered = 0;\n\t\tlet enterResponse: Response | undefined = undefined;\n\t\ttry {\n\t\t\t// Hooks run from the root down; a hook's enter can return a\n\t\t\t// Response to short-circuit the request\n\t\t\tfor (; entered < hooks.length && !enterResponse; entered++) {\n\t\t\t\tconst hookResult = await hooks[entered].enter?.(serverParams);\n\t\t\t\tif (hookResult) {\n\t\t\t\t\tenterResponse = hookResult;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A hook's enter response short-circuits the request; otherwise, if\n\t\t\t// there was no response returned from load (such as errors or a\n\t\t\t// redirect), send an ok response\n\t\t\treturn enterResponse || (await handlerFn(serverParams)) || ok();\n\t\t} finally {\n\t\t\t// Run exit hooks in reverse order for hooks that were entered\n\t\t\twhile (entered > 0) {\n\t\t\t\tentered--;\n\t\t\t\tawait hooks[entered].exit?.(serverParams);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst response = validationErrorResponse(error);\n\t\tif (response) return response;\n\t\tthrow error;\n\t}\n}\n\n/**\n * Handles a client data request (see `DATA_REQUEST_HEADER`). Runs the folder\n * hooks once against the page url, then loads the server data for each layout\n * (root to leaf) and the page, returning `{ loads: [...] }` -- one entry per\n * layout plus the page, in the same order as `handler.layouts`. The client\n * runs its own load functions and merges the server entries in.\n *\n * A load that redirects or fails short-circuits the whole request, so the\n * client can fall back to a full page load (redirect) or render the error\n * page (failure), exactly as it would with a single page load.\n */\nasync function loadPageData(\n\tev: ServerEvent,\n\tpageUrl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, any>,\n\treusedLayouts: Set<string>,\n): Promise<Response> {\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t// Validate params and the load query against the page's server endpoint\n\t// schemas, mirroring a normal page render. Params come from the url, so a\n\t// failed params validation means the resource doesn't exist\n\tlet query: unknown;\n\tif (serverEndPoint) {\n\t\ttry {\n\t\t\tparams = await validateEndpointParams(serverEndPoint, params);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ValidationError) return notFound();\n\t\t\tthrow error;\n\t\t}\n\t\tconst loadSchema = endpointSchema(serverEndPoint, \"load\");\n\t\tif (loadSchema) {\n\t\t\ttry {\n\t\t\t\tquery = await validate(loadSchema, searchParamsToRecord(pageUrl.searchParams));\n\t\t\t} catch (error) {\n\t\t\t\tconst response = validationErrorResponse(error);\n\t\t\t\tif (response) return response;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst serverParams = buildServerParams(ev, pageUrl, params, query ? { query } : {});\n\tconst serverHooks = await loadServerHooks(handler);\n\t// Route middleware, declared on the page's server endpoint. Runs before\n\t// the folder hooks, like it does for a normal request\n\tconst routeMiddleware = Array.isArray(serverEndPoint?.middleware)\n\t\t? serverEndPoint.middleware\n\t\t: [];\n\n\t// One entry per layout (root to leaf) followed by the page itself\n\tconst loads: (Record<string, any> | null)[] = [];\n\n\tlet enteredMiddleware = 0;\n\tlet entered = 0;\n\tlet enterResponse: Response | undefined = undefined;\n\ttry {\n\t\tfor (; enteredMiddleware < routeMiddleware.length && !enterResponse; enteredMiddleware++) {\n\t\t\tconst middlewareResult = await routeMiddleware[enteredMiddleware].enter?.(ev);\n\t\t\tif (middlewareResult) {\n\t\t\t\tenterResponse = middlewareResult;\n\t\t\t}\n\t\t}\n\n\t\t// Hooks run from the root down; a hook's enter can return a Response\n\t\t// to short-circuit the request (e.g. an auth redirect)\n\t\tfor (; entered < serverHooks.length && !enterResponse; entered++) {\n\t\t\tconst hookResult = await serverHooks[entered].enter?.(serverParams);\n\t\t\tif (hookResult) {\n\t\t\t\tenterResponse = hookResult;\n\t\t\t}\n\t\t}\n\t\tif (enterResponse) {\n\t\t\treturn enterResponse;\n\t\t}\n\n\t\tfor (const layout of handler.layouts ?? []) {\n\t\t\t// A reused layout keeps its cached data on the client, so skip its\n\t\t\t// load (and any side effects) but keep the slot aligned\n\t\t\tif (reusedLayouts.has(layout.path)) {\n\t\t\t\tloads.push(null);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\tconst result = await loadRouteServerData(layoutServerEndPoint, serverParams);\n\t\t\tif (result instanceof Response) return result;\n\t\t\tloads.push(result);\n\t\t}\n\n\t\tconst pageResult = await loadRouteServerData(serverEndPoint, serverParams);\n\t\tif (pageResult instanceof Response) return pageResult;\n\t\tloads.push(pageResult);\n\n\t\treturn new Response(JSON.stringify({ loads }), {\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t});\n\t} finally {\n\t\t// Run exit hooks in reverse order for hooks that were entered\n\t\twhile (entered > 0) {\n\t\t\tentered--;\n\t\t\tawait serverHooks[entered].exit?.(serverParams);\n\t\t}\n\t\twhile (enteredMiddleware > 0) {\n\t\t\tenteredMiddleware--;\n\t\t\tawait routeMiddleware[enteredMiddleware].exit?.(ev);\n\t\t}\n\t}\n}\n\n/**\n * Runs a single route's server load (if any) as part of a data request.\n * Returns the loaded data, `null` when the route has no load, or the raw\n * Response when the load redirected or failed.\n */\nasync function loadRouteServerData(\n\tserverEndPoint: PageServerEndPoint | undefined,\n\tserverParams: ServerLoadEvent,\n): Promise<Record<string, any> | null | Response> {\n\tif (!serverEndPoint?.load) return null;\n\tconst response = await serverEndPoint.load(serverParams);\n\tif (!response || response.ok) {\n\t\tif (response?.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\treturn await response.json();\n\t\t}\n\t\treturn null;\n\t}\n\treturn response;\n}\n\nasync function loadView(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, any>,\n\ttemplate: string | undefined,\n\t// The status to respond with: a form action's result status, or an\n\t// error page's status (404, 500, ...). Defaults to 200\n\tstatus?: number,\n\tform?: Record<string, string | number>,\n\tfromForm?: boolean,\n\t// The appData that the server hooks populated around the form action,\n\t// passed through so the re-render's loads see the same data\n\tappData?: Record<string, any>,\n) {\n\t// There must be a client endpoint with a component\n\tconst clientEndPoint: PageEndPoint | undefined = (await resolveModule(handler)).default;\n\tif (!clientEndPoint?.component) {\n\t\treturn notFound();\n\t}\n\n\t// Consume the flash message when a page is rendered (but not for API\n\t// requests), so that the following page -- and only that page -- can show\n\t// it. For a form action that re-renders instead of redirecting, the\n\t// message is set and read within this request\n\t$page.flash = ev.flash.get();\n\n\t// The template comes from site.html, which endpoints-only sites don't have\n\tif (!template) {\n\t\tthrow new Error(\n\t\t\t\"Page routes require a src/site.html file, which was not found; add it, or remove page/layout routes to serve endpoints only\",\n\t\t);\n\t}\n\n\t// There may be a server endpoint\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t// Validate the route params and the load query against the server\n\t// endpoint's schemas, if it declares any. Params come from the URL, so a\n\t// failed validation means the resource doesn't exist; a failed query goes\n\t// to the error page like any other load failure\n\tlet query: unknown;\n\tif (serverEndPoint) {\n\t\ttry {\n\t\t\tparams = await validateEndpointParams(serverEndPoint, params);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ValidationError) return notFound();\n\t\t\tthrow error;\n\t\t}\n\t\tconst loadSchema = endpointSchema(serverEndPoint, \"load\");\n\t\tif (loadSchema) {\n\t\t\tconst queryRecord = searchParamsToRecord(url.searchParams);\n\t\t\ttry {\n\t\t\t\tquery = await validate(loadSchema, queryRecord);\n\t\t\t} catch (error) {\n\t\t\t\t// A form re-render's url is the POST's, and a form action can\n\t\t\t\t// drop query params that the load schema requires, so failing\n\t\t\t\t// validation here would lose the form errors. Fall back to the\n\t\t\t\t// raw query values instead and let the load make of them what\n\t\t\t\t// it can\n\t\t\t\tif (fromForm) {\n\t\t\t\t\tquery = queryRecord;\n\t\t\t\t} else {\n\t\t\t\t\tconst response = validationErrorResponse(error);\n\t\t\t\t\tif (response) return response;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Maybe hit the server hooks -- unless they already ran for this request,\n\t// which is the case when the view is re-rendered after a form action. In\n\t// that case the hooks' appData is passed through, so that the loads below\n\t// see the same data (e.g. the user set by an auth hook) as the action did\n\tconst serverParams = buildServerParams(ev, url, params, query ? { query } : {}, appData);\n\tconst serverHooks = fromForm ? [] : await loadServerHooks(handler);\n\tlet entered = 0;\n\tlet enterResponse: Response | undefined = undefined;\n\ttry {\n\t\t// Hooks run from the root down; a hook's enter can return a Response\n\t\t// to short-circuit the request\n\t\tfor (; entered < serverHooks.length && !enterResponse; entered++) {\n\t\t\tconst hookResult = await serverHooks[entered].enter?.(serverParams);\n\t\t\tif (hookResult) {\n\t\t\t\tenterResponse = hookResult;\n\t\t\t}\n\t\t}\n\t\tif (enterResponse) {\n\t\t\treturn enterResponse;\n\t\t}\n\n\t\t// Pass the data into $props\n\t\t// TODO: Promise.all\n\t\t// NOTE: We're loading data from top to bottom, overriding as we go, and I'm\n\t\t// not sure if this is the best way to go\n\t\tlet data = {};\n\t\tif (handler.layouts) {\n\t\t\tfor (let layout of handler.layouts) {\n\t\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;\n\t\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\t\tconst layoutResponse = await loadClientAndServerData(\n\t\t\t\t\turl,\n\t\t\t\t\tparams,\n\t\t\t\t\tserverParams,\n\t\t\t\t\tdata,\n\t\t\t\t\tlayoutEndPoint,\n\t\t\t\t\tlayoutServerEndPoint,\n\t\t\t\t);\n\t\t\t\tif (layoutResponse?.ok === false) {\n\t\t\t\t\treturn layoutResponse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlet endPointResponse = await loadClientAndServerData(\n\t\t\turl,\n\t\t\tparams,\n\t\t\tserverParams,\n\t\t\tdata,\n\t\t\tclientEndPoint,\n\t\t\tserverEndPoint,\n\t\t);\n\t\tif (endPointResponse?.ok === false) {\n\t\t\treturn endPointResponse;\n\t\t}\n\t\tlet $props: Record<string, any> = { data, form };\n\n\t\tlet styles = \"\";\n\n\t\t// If there are layouts, work our way upwards, pushing each component into\n\t\t// the default slot of its parent\n\t\t// TODO: Also handle layout server data\n\t\t// TODO: There's probably a nicer way to do this with reducers or something\n\t\tlet component = clientEndPoint.component as ServerComponent;\n\t\tlet slots: Record<string, ServerSlotRender> | undefined = undefined;\n\t\t// Which slot levels actually ran during the render below, so a layout\n\t\t// that never rendered its <slot /> (silently dropping the page\n\t\t// content) can be reported (see findMissingSlotLayout)\n\t\tconst invokedLevels = new Set<number>();\n\t\tconst trackSlot = (level: number, slot: ServerSlotRender): ServerSlotRender => {\n\t\t\treturn ($slot, $context) => {\n\t\t\t\tinvokedLevels.add(level);\n\t\t\t\treturn slot($slot, $context);\n\t\t\t};\n\t\t};\n\t\tif (handler.layouts) {\n\t\t\tlet slotFunctions: ServerSlotRender[] = [];\n\t\t\t// The last slot function will render the client component\n\t\t\tslotFunctions[handler.layouts.length] = trackSlot(\n\t\t\t\thandler.layouts.length,\n\t\t\t\tasync (_, $context) => {\n\t\t\t\t\tlet { body, head } = await (clientEndPoint.component as ServerComponent)(\n\t\t\t\t\t\t$props,\n\t\t\t\t\t\t$context,\n\t\t\t\t\t);\n\t\t\t\t\tstyles += head;\n\t\t\t\t\treturn body;\n\t\t\t\t},\n\t\t\t);\n\t\t\tfor (let i = handler.layouts.length - 1; i >= 0; i--) {\n\t\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())\n\t\t\t\t\t?.default;\n\t\t\t\tif (layoutEndPoint?.component) {\n\t\t\t\t\tif (i === 0) {\n\t\t\t\t\t\tcomponent = layoutEndPoint.component as ServerComponent;\n\t\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tslotFunctions[i] = trackSlot(i, async (_, $context) => {\n\t\t\t\t\t\t\tlet { body, head } = await (layoutEndPoint.component as ServerComponent)(\n\t\t\t\t\t\t\t\t$props,\n\t\t\t\t\t\t\t\t$context,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t_: slotFunctions[i + 1],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tstyles += head;\n\t\t\t\t\t\t\treturn body;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet html;\n\t\ttry {\n\t\t\tlet { body, head } = await component($props, undefined, slots);\n\n\t\t\t// Render the page's (and its layouts') head element data, if the\n\t\t\t// endpoint declared any. Layouts lose to the page (the nearest\n\t\t\t// endpoint wins, as with @head content), and everything loses to\n\t\t\t// the first title in the compiled head -- which mergeHead keeps\n\t\t\tlet headData = \"\";\n\t\t\tconst event = { url, params, data } as PageLoadEvent;\n\t\t\tconst layoutEndPoints = await Promise.all(\n\t\t\t\t(handler.layouts ?? []).map(async (layout) => await layout.endPoint()),\n\t\t\t);\n\t\t\tconst headPoints = [clientEndPoint, ...layoutEndPoints].reverse();\n\t\t\tfor (const endPoint of headPoints) {\n\t\t\t\tconst headElements =\n\t\t\t\t\ttypeof endPoint.head === \"function\" ? await endPoint.head(event) : endPoint.head;\n\t\t\t\tif (headElements) {\n\t\t\t\t\theadData += headElements.map((element: HeadElement) => markupOf(element)).join(\"\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Put the form info in a hidden input so that it can be accessed on the client\n\t\t\tif (form) {\n\t\t\t\tbody += `\\n<input type=\"hidden\" id=\"t-form-data\" value='${JSON.stringify(form).replaceAll(\"'\", \"\\\\'\")}' />`;\n\t\t\t}\n\n\t\t\tstyles += head;\n\t\t\thtml = rewriteBaseInHtml(\n\t\t\t\tmergeHead(template, styles + headData).replace(\"%COMPONENT_BODY%\", body),\n\t\t\t\tgetBasePath(),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// TODO: Show a proper Error component\n\t\t\thtml = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\t\tconsole.log(error);\n\t\t}\n\n\t\t// A layout that never rendered <slot /> silently drops the whole page\n\t\t// content from the output; find and report the outermost one\n\t\tif (handler.layouts) {\n\t\t\tconst missingLayout = findMissingSlotLayout(handler.layouts, invokedLevels);\n\t\t\tif (missingLayout !== undefined) {\n\t\t\t\twarnMissingSlotContent(missingLayout);\n\t\t\t}\n\t\t}\n\n\t\treturn new Response(html, {\n\t\t\tstatus: status ?? 200,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/html\",\n\t\t\t},\n\t\t});\n\t} finally {\n\t\t// Run exit hooks in reverse order for hooks that were entered\n\t\twhile (entered > 0) {\n\t\t\tentered--;\n\t\t\tawait serverHooks[entered].exit?.(serverParams);\n\t\t}\n\t}\n}\n\nasync function runAction(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tserverEndPoint: PageServerEndPoint | undefined,\n\tparams: Record<string, any>,\n\tquery: URLSearchParams,\n\ttemplate: string | undefined,\n) {\n\t// The action name rides in the query, so look for a `?/name` key rather\n\t// than taking the first key -- the url may carry ordinary load query\n\t// params as well (e.g. `?page=3&/like`, or a default action posted to a\n\t// url that already has a query). A key that names a declared action also\n\t// matches (e.g. `?set`), and a form without an action attribute calls the\n\t// `default` action\n\tconst queryKeys = Array.from(query.keys());\n\tconst actionKey =\n\t\tqueryKeys.find((key) => key.startsWith(\"/\")) ??\n\t\tqueryKeys.find((key) => !!serverEndPoint?.actions?.[key.replace(/^\\//, \"\")]);\n\tconst actionName = (actionKey ?? \"default\").replace(/^\\//, \"\");\n\tif (serverEndPoint?.actions) {\n\t\tconst action = serverEndPoint.actions[actionName];\n\t\tif (action) {\n\t\t\tif (actionName === \"load\" || actionName === \"params\") {\n\t\t\t\t// These names are reserved in the endpoint's schema map: `load`\n\t\t\t\t// validates the query string and `params` the route params, so\n\t\t\t\t// an action with one of these names would get the wrong schema\n\t\t\t\t// applied to its form data\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The action name \"${actionName}\" is reserved. ` +\n\t\t\t\t\t\t`Rename the action (and its schema key, if any), e.g. to \"save\".`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Route params come from the URL, so a failed validation means the\n\t\t\t// resource doesn't exist\n\t\t\ttry {\n\t\t\t\tparams = await validateEndpointParams(serverEndPoint, params);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ValidationError) return notFound();\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tlet result: Response | undefined | void;\n\t\t\t// The event that the hooks and action run with. It's kept around so\n\t\t\t// that the view re-render below can pass its appData (populated by\n\t\t\t// the hooks' enter functions) through to the loads\n\t\t\tlet serverParams: ServerLoadEvent | undefined = undefined;\n\t\t\ttry {\n\t\t\t\t// If the endpoint declares a schema for this action, validate the\n\t\t\t\t// submitted form data up front and reject with 422 if it fails\n\t\t\t\tconst schema = endpointSchema(serverEndPoint, actionName);\n\t\t\t\tconst form = schema\n\t\t\t\t\t? await validate(schema, await formDataToRecord(ev.request))\n\t\t\t\t\t: undefined;\n\n\t\t\t\tserverParams = buildServerParams(ev, url, params, form ? { form } : {});\n\n\t\t\t\tconst serverHooks = await loadServerHooks(handler);\n\t\t\t\tlet entered = 0;\n\t\t\t\tlet enterResponse: Response | undefined = undefined;\n\t\t\t\ttry {\n\t\t\t\t\t// Hooks run from the root down; a hook's enter can return a\n\t\t\t\t\t// Response to short-circuit the action\n\t\t\t\t\tfor (; entered < serverHooks.length && !enterResponse; entered++) {\n\t\t\t\t\t\tconst hookResult = await serverHooks[entered].enter?.(serverParams);\n\t\t\t\t\t\tif (hookResult) {\n\t\t\t\t\t\t\tenterResponse = hookResult;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tresult = enterResponse || (await action(serverParams));\n\t\t\t\t} finally {\n\t\t\t\t\t// Run exit hooks in reverse order for hooks that were entered\n\t\t\t\t\twhile (entered > 0) {\n\t\t\t\t\t\tentered--;\n\t\t\t\t\t\tawait serverHooks[entered].exit?.(serverParams);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst response = validationErrorResponse(error);\n\t\t\t\tif (response) return response;\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (ev.request.headers.has(\"X-Torpor-Form-Submit\")) {\n\t\t\t\t// If the form was submitted from javascript, just return the\n\t\t\t\t// response and it will be handled on the client\n\t\t\t\t// TODO: Should we make the user return a response??\n\t\t\t\tresult ??= ok();\n\n\t\t\t\t// If it's a redirect, we need to stop the browser handling it\n\t\t\t\tif (result.status >= 300 && result.status <= 399) {\n\t\t\t\t\tconst location = result.headers.get(\"Location\") ?? \"\";\n\t\t\t\t\tresult = ok();\n\t\t\t\t\tresult.headers.set(\"X-Torpor-Form-Redirect\", \"\");\n\t\t\t\t\tresult.headers.set(\"Location\", location);\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t} else if (\n\t\t\t\t!result ||\n\t\t\t\t(result.status >= 200 && result.status <= 299) ||\n\t\t\t\t(result.status >= 400 && result.status <= 499)\n\t\t\t) {\n\t\t\t\t// If the form was submitted without javascript, and there was\n\t\t\t\t// no result, an ok result, or a 4xx error, re-render the view\n\t\t\t\t// with the form result. The server hooks already ran around the\n\t\t\t\t// action, so they are not run again here -- but their appData\n\t\t\t\t// is passed through, so that loads guarding on it (e.g. an\n\t\t\t\t// auth hook's user) re-render the page instead of erroring\n\t\t\t\t// Keep the query string, so that loads validating the query see\n\t\t\t\t// the same values as the original GET. If the form action\n\t\t\t\t// dropped params that the load schema requires, loadView falls\n\t\t\t\t// back to the raw query instead of failing validation\n\t\t\t\tconst newUrl = new URL(url.pathname + url.search, url);\n\t\t\t\tconst formStatus = result?.status;\n\t\t\t\tlet formMessage = await result?.text();\n\t\t\t\tif (formMessage && result?.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\t$page.form = JSON.parse(formMessage);\n\t\t\t\t\tformMessage = undefined;\n\t\t\t\t} else {\n\t\t\t\t\t$page.form = {};\n\t\t\t\t}\n\t\t\t\t// Set status and message if they haven't already been set,\n\t\t\t\t// which means that you can just return e.g. forbidden() or\n\t\t\t\t// forbidden(\"no!\") and there will be something you can work\n\t\t\t\t// with in your component, or you can set a completely custom\n\t\t\t\t// object with whatever info you need\n\t\t\t\t$page.form!.status ??= formStatus ?? 0;\n\t\t\t\t$page.form!.message ??= formMessage ?? \"\";\n\t\t\t\treturn await loadView(\n\t\t\t\t\tev,\n\t\t\t\t\tnewUrl,\n\t\t\t\t\thandler,\n\t\t\t\t\tparams,\n\t\t\t\t\ttemplate,\n\t\t\t\t\tformStatus,\n\t\t\t\t\t$page.form,\n\t\t\t\t\ttrue,\n\t\t\t\t\tserverParams?.appData,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// If the form was submitted without javascript and there was a\n\t\t\t\t// redirect or server error, just return the result to handle it\n\t\t\t\t// as normal\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadClientAndServerData(\n\turl: URL,\n\tparams: Record<string, any>,\n\tserverParams: ServerLoadEvent,\n\tdata: Record<string, any>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n) {\n\tif (clientEndPoint?.load) {\n\t\tconst clientParams = buildClientParams(url, params, data);\n\t\tconst clientResponse = await clientEndPoint.load(clientParams);\n\t\tif (clientResponse) {\n\t\t\tif (clientResponse.ok) {\n\t\t\t\tif (clientResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await clientResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn clientResponse;\n\t\t\t}\n\t\t}\n\t}\n\tif (serverEndPoint?.load) {\n\t\tconst serverResponse = await serverEndPoint.load(serverParams);\n\t\tif (serverResponse) {\n\t\t\tif (serverResponse.ok) {\n\t\t\t\tif (serverResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await serverResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn serverResponse;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction buildClientParams(url: URL, params: Record<string, any>, data: Record<string, any>) {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tdata,\n\t};\n}\n\n/**\n * The layout paths a data request asked to reuse, from the `X-Torpor-Reuse`\n * header (a JSON array). A malformed header is ignored rather than failing the\n * request -- the client just gets the layouts loaded again.\n */\nfunction reusedLayoutPaths(ev: ServerEvent): Set<string> {\n\tconst header = ev.request.headers.get(DATA_REUSE_HEADER);\n\tif (!header) return new Set();\n\ttry {\n\t\tconst paths = JSON.parse(header) as unknown;\n\t\tif (Array.isArray(paths)) {\n\t\t\treturn new Set(paths.filter((p): p is string => typeof p === \"string\"));\n\t\t}\n\t} catch {\n\t\t// Not valid json\n\t}\n\treturn new Set();\n}\n\n/**\n * The url user code (hooks, loads, actions, `@head`) should see. Client-side\n * data fetches append `/~server` to the page url, but that suffix is an\n * internal detail: without stripping it, `event.url.pathname` would differ\n * between the server-rendered page and its `~server` request, so a hook\n * guarding on the path (e.g. `path !== \"/setup\"`) would misfire.\n */\nfunction requestUrl(url: URL): URL {\n\tif (!url.pathname.endsWith(\"/~server\")) return url;\n\tconst path = url.pathname.slice(0, -\"/~server\".length) || \"/\";\n\treturn new URL(path + url.search, url);\n}\n\nfunction buildServerParams(\n\tev: ServerEvent,\n\turl: URL,\n\tparams: Record<string, any>,\n\tvalues: { json?: unknown; form?: unknown; query?: unknown } = {},\n\tappData: Record<string, any> = {},\n): ServerLoadEvent {\n\tconst logicalUrl = requestUrl(url);\n\treturn {\n\t\turl: logicalUrl,\n\t\tparams,\n\t\tappData,\n\t\trequest: ev.request,\n\t\t// The inputs may have been validated already, in which case the request\n\t\t// body has been consumed and the parsed values are returned instead.\n\t\t// Their types come from the endpoint's schemas, so they are loosely\n\t\t// typed here\n\t\tjson: (): Promise<any> =>\n\t\t\tvalues.json !== undefined ? Promise.resolve(values.json) : ev.json(),\n\t\tform: (): Promise<any> =>\n\t\t\tvalues.form !== undefined ? Promise.resolve(values.form) : formDataToRecord(ev.request),\n\t\tquery: (): Promise<any> =>\n\t\t\tvalues.query !== undefined\n\t\t\t\t? Promise.resolve(values.query)\n\t\t\t\t: Promise.resolve(searchParamsToRecord(logicalUrl.searchParams)),\n\t\tcookies: ev.cookies,\n\t\theaders: ev.headers,\n\t\tsession: ev.session,\n\t\tflash: ev.flash,\n\t\tadapter: ev.adapter,\n\t};\n}\n\n/**\n * Renders a head element as markup. Attribute values are escaped, since\n * they can come from user data (e.g. a post title passed to `seo()`).\n */\nfunction markupOf(element: HeadElement): string {\n\tif (\"title\" in element) {\n\t\treturn `<title>${escapeHtml(element.title)}</title>`;\n\t}\n\tif (\"name\" in element) {\n\t\treturn `<meta name=\"${escapeHtml(element.name)}\" content=\"${escapeHtml(element.content)}\" />`;\n\t}\n\treturn `<meta property=\"${escapeHtml(element.property)}\" content=\"${escapeHtml(element.content)}\" />`;\n}\n\nfunction escapeHtml(value: string): string {\n\treturn value\n\t\t.replaceAll(\"&\", \"&\")\n\t\t.replaceAll(\"<\", \"<\")\n\t\t.replaceAll(\">\", \">\")\n\t\t.replaceAll('\"', \""\");\n}\n"],"mappings":"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"}
|
package/dist/test.d.mts
CHANGED
package/dist/test.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as Router } from "./Router-C4ADUfhv.mjs";
|
|
2
2
|
import { t as ServerEvent } from "./ServerEvent-BY4f3RVF.mjs";
|
|
3
|
-
import { t as createServerLoad } from "./serverHandlers-
|
|
3
|
+
import { t as createServerLoad } from "./serverHandlers-F1gJ1lrj.mjs";
|
|
4
4
|
import fpath from "node:path";
|
|
5
5
|
//#region src/test/runTest.ts
|
|
6
6
|
/**
|
|
@@ -20,17 +20,6 @@ function response(status, body) {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
|
-
//#region src/response/transfer.ts
|
|
24
|
-
/**
|
|
25
|
-
* Creates a redirect response with the supplied status code.
|
|
26
|
-
*/
|
|
27
|
-
function transfer(status, location) {
|
|
28
|
-
return new Response(null, {
|
|
29
|
-
status,
|
|
30
|
-
headers: { location }
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
//#endregion
|
|
34
23
|
//#region src/response/notFound.ts
|
|
35
24
|
/**
|
|
36
25
|
* 404 Not Found
|
|
@@ -87,25 +76,6 @@ function ok(body) {
|
|
|
87
76
|
return response(200, body);
|
|
88
77
|
}
|
|
89
78
|
//#endregion
|
|
90
|
-
//#region src/response/seeOther.ts
|
|
91
|
-
/**
|
|
92
|
-
* 303 See Other
|
|
93
|
-
*
|
|
94
|
-
* The HTTP 303 See Other redirection response status code indicates that the
|
|
95
|
-
* browser should redirect to the URL in the Location header instead of
|
|
96
|
-
* rendering the requested resource.
|
|
97
|
-
*
|
|
98
|
-
* This response code is often sent back as a result of PUT or POST methods so
|
|
99
|
-
* the client may retrieve a confirmation, or view a representation of a
|
|
100
|
-
* real-world object (see HTTP range-14). The method to retrieve the redirected
|
|
101
|
-
* resource is always GET.
|
|
102
|
-
*
|
|
103
|
-
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/303
|
|
104
|
-
*/
|
|
105
|
-
function seeOther(location) {
|
|
106
|
-
return transfer(303, location);
|
|
107
|
-
}
|
|
108
|
-
//#endregion
|
|
109
79
|
//#region src/response/unprocessable.ts
|
|
110
80
|
/**
|
|
111
81
|
* 422 Unprocessable Content
|
|
@@ -128,6 +98,6 @@ function unprocessable(body) {
|
|
|
128
98
|
return response(422, body ?? "Unprocessable");
|
|
129
99
|
}
|
|
130
100
|
//#endregion
|
|
131
|
-
export {
|
|
101
|
+
export { response as i, ok as n, notFound as r, unprocessable as t };
|
|
132
102
|
|
|
133
|
-
//# sourceMappingURL=unprocessable-
|
|
103
|
+
//# sourceMappingURL=unprocessable-CoMN2zFa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unprocessable-CoMN2zFa.mjs","names":[],"sources":["../src/response/response.ts","../src/response/notFound.ts","../src/response/ok.ts","../src/response/unprocessable.ts"],"sourcesContent":["/**\n * Creates a response with the supplied status code and optional body.\n *\n * If the body is an object, it will be converted to JSON and the Content-Type\n * header set to \"application/json\". Otherwise, if the body is a string, the\n * Content-Type header will be set to \"text/plain\".\n */\nexport default function response(status: number, body?: object | string): Response {\n\tlet headers: Record<string, string> | undefined = undefined;\n\tif (body) {\n\t\tif (typeof body === \"object\") {\n\t\t\theaders = { \"Content-Type\": \"application/json\" };\n\t\t\tbody = JSON.stringify(body);\n\t\t} else {\n\t\t\theaders = { \"Content-Type\": \"text/plain\" };\n\t\t}\n\t}\n\treturn new Response(body, {\n\t\tstatus,\n\t\theaders,\n\t});\n}\n","import response from \"./response\";\n\n/**\n * 404 Not Found\n *\n * The HTTP 404 Not Found client error response status code indicates that the\n * server cannot find the requested resource. Links that lead to a 404 page are\n * often called broken or dead links and can be subject to link rot.\n *\n * A 404 status code only indicates that the resource is missing without\n * indicating if this is temporary or permanent. If a resource is permanently\n * removed, servers should send the 410 Gone status instead.\n *\n * 404 errors on a website can lead to a poor user experience for your visitors,\n * so the number of broken links (internal and external) should be minimized to\n * prevent frustration for readers. Common causes of 404 responses are mistyped\n * URLs or pages that are moved or deleted without redirection. For more\n * information, see the Redirections in HTTP guide.\n *\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/404\n */\nexport default function notFound(body?: object | string): Response {\n\treturn response(404, body ?? \"Not found\");\n}\n","import type { Jsonify } from \"../types/Jsonify\";\nimport type TypedResponse from \"./TypedResponse\";\nimport response from \"./response\";\n\ntype OkResponse<T extends object | string | undefined> = T extends object\n\t? TypedResponse<Jsonify<T>>\n\t: Response;\n\n/**\n * 200 OK\n *\n * The HTTP 200 OK successful response status code indicates that a request has\n * succeeded. A 200 OK response is cacheable by default.\n *\n * A 200 OK response has a different meaning and format depending on the HTTP\n * request method. Here's how they vary for different methods:\n *\n * - GET: A resource was retrieved by the server and included in the response\n * body.\n * - POST: An action succeeded; the response has a message body describing the\n * result.\n * - HEAD: Identical to GET, except there is no message body.\n * - TRACE: The response has a message body containing the request as received\n * by the server.\n *\n * Although possible, successful PUT or DELETE requests often do not result in\n * a 200 OK response. It is more common to see 201 Created if the resource is\n * uploaded or created for the first time, or 204 No Content upon successful\n * deletion of a resource.\n *\n * An object body is typed: the client sees its JSON form through\n * `makeApi`-created callers.\n *\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200\n */\nexport default function ok<T extends object | string | undefined>(body?: T): OkResponse<T> {\n\treturn response(200, body) as OkResponse<T>;\n}\n","import response from \"./response\";\nimport type { Jsonify } from \"../types/Jsonify\";\nimport type TypedResponse from \"./TypedResponse\";\n\ntype UnprocessableResponse<T extends object | string | undefined> = T extends object\n\t? TypedResponse<Jsonify<T>>\n\t: Response;\n\n/**\n * 422 Unprocessable Content\n *\n * The HTTP 422 Unprocessable Content client error response status code\n * indicates that the server understood the content type of the request content,\n * and the syntax of the request content was correct, but it was unable to\n * process the contained instructions.\n *\n * Clients that receive a 422 response should expect that repeating the request\n * without modification will fail with the same error.\n *\n * An object body is typed: it becomes the page's `$props.form` (with its JSON\n * form) after a form submit, so validation errors can be surfaced with their\n * field types via `PageForm`.\n *\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/422\n */\nexport default function unprocessable<T extends object | string | undefined>(\n\tbody?: T,\n): UnprocessableResponse<T> {\n\treturn response(422, body ?? \"Unprocessable\") as UnprocessableResponse<T>;\n}\n"],"mappings":";;;;;;;;AAOA,SAAwB,SAAS,QAAgB,MAAkC;CAClF,IAAI,UAA8C,KAAA;CAClD,IAAI,MAAM;EACT,IAAI,OAAO,SAAS,UAAU;GAC7B,UAAU,EAAE,gBAAgB,mBAAmB;GAC/C,OAAO,KAAK,UAAU,IAAI;EAC3B,OACC,UAAU,EAAE,gBAAgB,aAAa;CAE3C;CACA,OAAO,IAAI,SAAS,MAAM;EACzB;EACA;CACD,CAAC;AACF;;;;;;;;;;;;;;;;;;;;;;ACAA,SAAwB,SAAS,MAAkC;CAClE,OAAO,SAAS,KAAK,QAAQ,WAAW;AACzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACYA,SAAwB,GAA0C,MAAyB;CAC1F,OAAO,SAAS,KAAK,IAAI;AAC1B;;;;;;;;;;;;;;;;;;;;ACZA,SAAwB,cACvB,MAC2B;CAC3B,OAAO,SAAS,KAAK,QAAQ,eAAe;AAC7C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@torpor/build",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A framework for building sites and apps with Torpor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"torpor:source": "./src/dev.ts",
|
|
14
14
|
"import": "./dist/dev.mjs"
|
|
15
15
|
},
|
|
16
|
+
"./node-dev": {
|
|
17
|
+
"types": "./dist/nodeDev.d.mts",
|
|
18
|
+
"torpor:source": "./src/nodeDev.ts",
|
|
19
|
+
"import": "./dist/nodeDev.mjs"
|
|
20
|
+
},
|
|
16
21
|
"./env": {
|
|
17
22
|
"types": "./dist/env.d.mts",
|
|
18
23
|
"import": "./dist/env.mjs"
|
|
@@ -79,8 +84,8 @@
|
|
|
79
84
|
"dotenv": "^17.4.2",
|
|
80
85
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
|
|
81
86
|
"vite-plus": "0.3.0",
|
|
82
|
-
"@torpor/unplugin": "^1.1
|
|
83
|
-
"@torpor/view": "^1.1.
|
|
87
|
+
"@torpor/unplugin": "^1.2.1",
|
|
88
|
+
"@torpor/view": "^1.1.3"
|
|
84
89
|
},
|
|
85
90
|
"devDependencies": {
|
|
86
91
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|