@torpor/build 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Site-CWyj0R-l.d.mts → Site-CQ29Opvm.d.mts} +8 -1
- package/dist/{Site-CWyj0R-l.d.mts.map → Site-CQ29Opvm.d.mts.map} +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/clientEntry.mjs +2 -1
- package/dist/clientEntry.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -1
- package/dist/{load-CydkUApM.mjs → load-Uyj9I60p.mjs} +4 -3
- package/dist/load-Uyj9I60p.mjs.map +1 -0
- package/dist/nav.mjs +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/run.d.mts +1 -1
- package/dist/run.d.mts.map +1 -1
- package/dist/run.mjs +1 -1
- package/dist/{runOpenApi-6iKszj_5.mjs → runOpenApi-DWfPiAv0.mjs} +10 -7
- package/dist/runOpenApi-DWfPiAv0.mjs.map +1 -0
- package/dist/server.d.mts +16 -1
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +16 -1
- package/dist/server.mjs.map +1 -1
- package/dist/test.d.mts +1 -1
- package/package.json +3 -3
- package/src/types/manifest.d.ts +1 -0
- package/dist/load-CydkUApM.mjs.map +0 -1
- package/dist/runOpenApi-6iKszj_5.mjs.map +0 -1
|
@@ -371,6 +371,13 @@ declare class Site {
|
|
|
371
371
|
* gets it added. Server code and markup stay base-free.
|
|
372
372
|
*/
|
|
373
373
|
basePath: string;
|
|
374
|
+
/**
|
|
375
|
+
* Wraps client-side navigations in the View Transitions API -- where the
|
|
376
|
+
* browser supports it -- so pages cross-fade by default and can be
|
|
377
|
+
* animated with `::view-transition-old/new` CSS. Opt-in: off unless set
|
|
378
|
+
* to `true`. The initial hydration never transitions.
|
|
379
|
+
*/
|
|
380
|
+
viewTransitions?: boolean;
|
|
374
381
|
/**
|
|
375
382
|
* Prerendering, applied to every page route that doesn't have (or
|
|
376
383
|
* inherit) a `prerender` flag of its own. `true` prerenders everything;
|
|
@@ -498,4 +505,4 @@ declare class Site {
|
|
|
498
505
|
}
|
|
499
506
|
//#endregion
|
|
500
507
|
export { ServerEndPoint as a, ActionBody as c, PageServerActionSchemas as d, PageServerEndPoint as f, Adapter as g, SitePlugin as h, SchemaQuery as i, LoadParams as l, PageServerAction as m, ParamsOf as n, ServerEndPointSchemas as o, PageServerLoad as p, SchemaBody as r, ServerRequest as s, Site as t, LoadQuery as u };
|
|
501
|
-
//# sourceMappingURL=Site-
|
|
508
|
+
//# sourceMappingURL=Site-CQ29Opvm.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Site-
|
|
1
|
+
{"version":3,"file":"Site-CQ29Opvm.d.mts","names":[],"sources":["../src/types/Adapter.ts","../src/types/SitePlugin.ts","../src/types/PageServerAction.ts","../src/types/PageServerLoad.ts","../src/types/PageServerEndPoint.ts","../src/types/ServerRequest.ts","../src/types/ServerEndPoint.ts","../src/types/RouteType.ts","../src/types/Route.ts","../src/site/Site.ts"],"mappings":";;;;;;;;;UAIyB;EACxB,YAAY,MAAM,SAAS;EAC3B,aAAa,MAAM,SAAS;;;;;;;EAO5B,OAAO,MAAM,SAAS,SAAS;;;;;EAK/B,QAAQ,QAAQ,QAAQ,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;KCG1C,cAAc,MAAM,gBAAgB;;;KCjBpC,iBACJ,8CACA,WAAW,gBACX,SAAS,cAAc,WAEvB,OAAO,gBAAgB,gBAAgB,UAAU,aAAa,YAC1D,8BAA8B,QAAQ;;;KCLtC,eACJ,8CACA,OAAO,qBACP,YAAY,aACZ,SAAS,cAAc,WAEvB,OAAO,gBAAgB,gBAAgB,gBAAgB,WAAW,YAC9D,eAAe,QAAQ,QAAQ,eAAe;;;;;;;;;;;;;;;;;;;;;KCavC;EACX,SAAS;EACT,OAAO;GACW,iBAAA;;;;;;KAOP,WAAW,gBAAgB,yBAAyB,wBAC/D,qBACgB,oBACd,QAAQ,cAAc,mBACrB,iBAAiB,YAAY,QAAQ,SACrC,iBACD;;;;KAKS,UAAU,gBAAgB,2BAA2B;EAChE,MAAM;IAEJ,iBAAiB,YAAY,mBAC7B;;;;KAKS,WACX,gBAAgB,yBAChB,oCACG;EAAkB,QAAQ;IAC3B,iBAAiB,YAAY,qBAC7B,cAAc;;;;;;;;UASQ,mBACxB,8CACA,OAAO,qBACP,gBAAgB,0BAA0B;;;;;EAM1C,OAAO,eAAe,OAAO,MAAM,UAAU,UAAU,WAAW,SAAS;;;;EAI3E,aACE,iBAAiB,iBACjB,OACA,WAAW,SAAS,OACpB,WAAW,SAAS;;;;;;;;;;;;;;;;;;;;;EAuBtB,SAAS;;;;;;;;;;;EAWT;IAAwB,QAAQ,WAAW,SAAS;;;;;;;;EAOpD,aAAa;;;;KC3HT,cACJ,8CACA,gBACA,WAAW,gBACX,YAAY,aACZ,SAAS,cAAc,WAEvB,OAAO,gBAAgB,OAAO,MAAM,UAAU,WAAW,YACrD,8BAA8B,QAAQ;;;;;;;;;;;;;;;;;;;;KCW/B;EACX,SAAS;EACT,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM;EACN,MAAM;EACN,UAAU;EACV,OAAO;;;;;;KAOI,WAAW,gBAAgB,uBAAuB,0BAC7D,uBACgB,oBACd,QAAQ,gBAAgB,mBACvB,iBAAiB,YAAY,QAAQ;;;;;KAQ7B,YAAY,gBAAgB,uBAAuB,0BAC9D,uBACgB,oBACd,QAAQ,gBAAgB,mBACvB,iBAAiB,YAAY,QAAQ,WACrC,cACD;;;;;KAMS,SACX;EAAkB,SAAS;GAC3B,oCACG;EAAkB,QAAQ;IAC3B,iBAAiB,YAAY,qBAC7B,cAAc;;;;;;;KAQZ,eACJ,8CACA,gBAAgB,wBAAwB;;;;;;;;;;;;;;;;;;EAmBxC,SAAS;;;;EAIT,MAAM,cACL,gBAEA,gBACA,YAAY,iBACZ,SAAS,SAAS;;;;EAKnB,OAAO,cACN,OACA,WAAW,kBACX,gBACA,aACA,SAAS,SAAS;;;;EAKnB,QAAQ,cACP,OACA,WAAW,mBACX,gBACA,aACA,SAAS,SAAS;;;;EAKnB,MAAM,cACL,OACA,WAAW,iBACX,gBACA,aACA,SAAS,SAAS;;;;EAKnB,MAAM,cACL,OACA,WAAW,iBACX,gBACA,aACA,SAAS,SAAS;;;;EAKnB,UAAU,cACT,OACA,WAAW,qBACX,gBACA,aACA,SAAS,SAAS;;;;EAKnB,OAAO,cACN,gBAEA,gBACA,YAAY,kBACZ,SAAS,SAAS;;;;;;;EAQnB,aAAa;;;;cC7KD;cACA;cACA;cACA;cACA;cACA;cACA;cACA;KAED,mBACF,oBACA,2BACA,sBACA,sBACA,6BACA,oBACA,2BACA;;;;;;KCRE,iBAAiB,qBAAqB,iBAAiB,aAAa;;;;UAKvD;EACxB;;;;;EAKA;;;;;;EAMA,WAAW;EACX,MAAM;EACN;;;;;;;;cCOoB;;EACpB;EACA,QAAQ;;;;;;;EAOR,SAAS;;;;EAIT,aAAa;;;;;;;;;EASb,SAAS;;;;;;EAMT;;;;;;;EAOA,aAAa;;;;;EAKb;;;;;;;;;;;;;;;;EAgBA,aAAa,IAAI;;;;;;;EAOjB;;;;;;;EAOA;;;;;;;;;EASA,sBAAsB;;;;;;EAMtB;;;;;;;;;;;;EAYA,YAAY;;;;;;;;;;;EAWZ,UAAU;;;;;;;;;EASV,MAAM,0BAA0B;;;;;EAKhC,iBAAiB,eAAe;EAEhC;;;;;;;;;EAYA,eAAqB,gBAAgB,qBAAqB;;;;;;;;EAiC1D,aACC,cACA,cACA,kHASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+HD,SACC,cACA;IACC;IACA,sBAAsB;IACtB,kBAAkB;IAClB;IACA,wBAAwB;IACxB,sBAAsB;IACtB;KAED"}
|
package/dist/bin/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import { n as loadSite, r as run, t as runOpenApi } from "../runOpenApi-
|
|
2
|
+
import { n as loadSite, r as run, t as runOpenApi } from "../runOpenApi-DWfPiAv0.mjs";
|
|
3
3
|
//#region src/bin/index.ts
|
|
4
4
|
const workingDir = process.cwd();
|
|
5
5
|
if (process.argv.includes("--openapi")) {
|
package/dist/clientEntry.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { t as Router } from "./Router-C4ADUfhv.mjs";
|
|
2
2
|
import { o as setBasePath } from "./basePath-DQnbHc7o.mjs";
|
|
3
3
|
import { t as $page } from "./_page-CW6SLuT4.mjs";
|
|
4
|
-
import { a as client, n as navigate, r as loadData } from "./load-
|
|
4
|
+
import { a as client, n as navigate, r as loadData } from "./load-Uyj9I60p.mjs";
|
|
5
5
|
import manifest from "@torpor/build/manifest";
|
|
6
6
|
//#region src/site/clientEntry.ts
|
|
7
7
|
setBasePath(manifest.base);
|
|
8
8
|
const router = new Router();
|
|
9
9
|
router.addPages(manifest.routes);
|
|
10
10
|
client.router = router;
|
|
11
|
+
client.viewTransitions = manifest.viewTransitions ?? false;
|
|
11
12
|
window.addEventListener("click", async (e) => {
|
|
12
13
|
const link = getLink(e.target);
|
|
13
14
|
if (link) {
|
package/dist/clientEntry.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clientEntry.mjs","names":[],"sources":["../src/site/clientEntry.ts"],"sourcesContent":["import manifest from \"@torpor/build/manifest\";\nimport loadData from \"../nav/loadData.ts\";\nimport navigate from \"../nav/navigate.ts\";\nimport $page from \"../state/$page.ts\";\nimport client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport Router from \"./Router.ts\";\nimport { setBasePath } from \"./basePath.ts\";\n\nsetBasePath(manifest.base);\n\n// Build the router from the Site object created by the user\nconst router = new Router();\nrouter.addPages(manifest.routes);\n\n// Put it in client state so that it can be accessed from navigate. We can't\n// just import it to navigate because that gets built by tsdown, without Vite\n// and the manifest\nclient.router = router;\n\n// Intercept clicks on links\nwindow.addEventListener(\"click\", async (e) => {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tif (await navigate(url)) {\n\t\t\t// Save the scroll position of the outgoing page on the current\n\t\t\t// history entry, so that going (or coming) back can restore it\n\t\t\twindow.history.replaceState({ scroll: window.scrollY }, \"\", document.location.href);\n\t\t\twindow.history.pushState({ scroll: 0 }, \"\", url);\n\t\t} else {\n\t\t\twindow.location.href = href;\n\t\t}\n\t}\n});\n\n// Intercept mouseover/focus/touchstart on links for prefetching\n// TODO: settings e.g. <a href=\"\" data-tb-prefetch=\"eager\"/\"visible\"/\"hover\"/\"touch\">\nwindow.addEventListener(\"mouseover\", maybePrefetch);\nwindow.addEventListener(\"touchstart\", maybePrefetch);\n\nasync function maybePrefetch(e: MouseEvent | TouchEvent) {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tconst path = url.pathname;\n\t\tconst query = url.searchParams;\n\t\tconst route = router.match(path, query);\n\t\tif (route) {\n\t\t\tconst handler = route.handler;\n\t\t\tconst params = route.params || {};\n\n\t\t\t// There should be a client endpoint\n\t\t\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\n\t\t\t// There may be a server endpoint\n\t\t\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\t\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t\t\t// Just dummy this up\n\t\t\tlet newStack: LayoutPath[] = [];\n\n\t\t\tawait loadData(handler, params, path, query, newStack, clientEndPoint, serverEndPoint, true);\n\t\t}\n\t}\n}\n\nfunction getLink(target: EventTarget | null): HTMLAnchorElement | undefined {\n\t// The target may be a child element of the link (e.g. an icon inside it),\n\t// so walk up to the nearest actual link. Fragment-only links (href=\"#...\")\n\t// are left to the browser's native jump-to-anchor behavior\n\tif (!(target instanceof Element)) return;\n\tconst link = target.closest(\"a[href]\");\n\tif (link?.getAttribute(\"href\")?.startsWith(\"#\")) return;\n\treturn (link as HTMLAnchorElement) ?? undefined;\n}\n\nfunction ignoreAnchorMouseEvent(link: HTMLAnchorElement, e: MouseEvent | TouchEvent) {\n\t// Ignore the event if it was already handled (e.g. a user handler calling\n\t// preventDefault), a modifier key is pressed, the target is not \"_self\"\n\t// (e.g. \"_blank\"), rel=\"external\", it's a download link, or it's in a\n\t// contenteditable region\n\treturn (\n\t\te.defaultPrevented ||\n\t\te.altKey ||\n\t\te.ctrlKey ||\n\t\te.metaKey ||\n\t\te.shiftKey ||\n\t\t(link.target && link.target !== \"_self\") ||\n\t\tlink.rel === \"external\" ||\n\t\tlink.hasAttribute(\"download\") ||\n\t\tlink.isContentEditable\n\t);\n}\n\n// Listen for changes to the URL that occur when the user navigates using the\n// back or forward buttons\nwindow.addEventListener(\"popstate\", async () => {\n\tconst navigated = await navigateToLocation(document.location);\n\tif (!navigated) {\n\t\twindow.location.reload();\n\t\treturn;\n\t}\n\t// Restore the scroll position that was saved on the history entry\n\trequestAnimationFrame(() => {\n\t\tconst state = window.history.state as { scroll?: number } | null;\n\t\twindow.scrollTo(0, state?.scroll ?? 0);\n\t});\n});\n\n// Do the initial navigation and hydration\nawait navigateToLocation(document.location, true);\n\nasync function navigateToLocation(location: Location, firstTime = false) {\n\t// Reset $page on submit and link navigation\n\t// TODO: Should we put data in $page.data??\n\t$page.form = undefined;\n\n\treturn await navigate(new URL(location.toString()), firstTime);\n}\n"],"mappings":";;;;;;AAWA,YAAY,SAAS,IAAI;AAGzB,MAAM,SAAS,IAAI,OAAO;AAC1B,OAAO,SAAS,SAAS,MAAM;AAK/B,OAAO,SAAS;
|
|
1
|
+
{"version":3,"file":"clientEntry.mjs","names":[],"sources":["../src/site/clientEntry.ts"],"sourcesContent":["import manifest from \"@torpor/build/manifest\";\nimport loadData from \"../nav/loadData.ts\";\nimport navigate from \"../nav/navigate.ts\";\nimport $page from \"../state/$page.ts\";\nimport client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport Router from \"./Router.ts\";\nimport { setBasePath } from \"./basePath.ts\";\n\nsetBasePath(manifest.base);\n\n// Build the router from the Site object created by the user\nconst router = new Router();\nrouter.addPages(manifest.routes);\n\n// Put it in client state so that it can be accessed from navigate. We can't\n// just import it to navigate because that gets built by tsdown, without Vite\n// and the manifest\nclient.router = router;\nclient.viewTransitions = manifest.viewTransitions ?? false;\n\n// Intercept clicks on links\nwindow.addEventListener(\"click\", async (e) => {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tif (await navigate(url)) {\n\t\t\t// Save the scroll position of the outgoing page on the current\n\t\t\t// history entry, so that going (or coming) back can restore it\n\t\t\twindow.history.replaceState({ scroll: window.scrollY }, \"\", document.location.href);\n\t\t\twindow.history.pushState({ scroll: 0 }, \"\", url);\n\t\t} else {\n\t\t\twindow.location.href = href;\n\t\t}\n\t}\n});\n\n// Intercept mouseover/focus/touchstart on links for prefetching\n// TODO: settings e.g. <a href=\"\" data-tb-prefetch=\"eager\"/\"visible\"/\"hover\"/\"touch\">\nwindow.addEventListener(\"mouseover\", maybePrefetch);\nwindow.addEventListener(\"touchstart\", maybePrefetch);\n\nasync function maybePrefetch(e: MouseEvent | TouchEvent) {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tconst path = url.pathname;\n\t\tconst query = url.searchParams;\n\t\tconst route = router.match(path, query);\n\t\tif (route) {\n\t\t\tconst handler = route.handler;\n\t\t\tconst params = route.params || {};\n\n\t\t\t// There should be a client endpoint\n\t\t\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\n\t\t\t// There may be a server endpoint\n\t\t\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\t\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t\t\t// Just dummy this up\n\t\t\tlet newStack: LayoutPath[] = [];\n\n\t\t\tawait loadData(handler, params, path, query, newStack, clientEndPoint, serverEndPoint, true);\n\t\t}\n\t}\n}\n\nfunction getLink(target: EventTarget | null): HTMLAnchorElement | undefined {\n\t// The target may be a child element of the link (e.g. an icon inside it),\n\t// so walk up to the nearest actual link. Fragment-only links (href=\"#...\")\n\t// are left to the browser's native jump-to-anchor behavior\n\tif (!(target instanceof Element)) return;\n\tconst link = target.closest(\"a[href]\");\n\tif (link?.getAttribute(\"href\")?.startsWith(\"#\")) return;\n\treturn (link as HTMLAnchorElement) ?? undefined;\n}\n\nfunction ignoreAnchorMouseEvent(link: HTMLAnchorElement, e: MouseEvent | TouchEvent) {\n\t// Ignore the event if it was already handled (e.g. a user handler calling\n\t// preventDefault), a modifier key is pressed, the target is not \"_self\"\n\t// (e.g. \"_blank\"), rel=\"external\", it's a download link, or it's in a\n\t// contenteditable region\n\treturn (\n\t\te.defaultPrevented ||\n\t\te.altKey ||\n\t\te.ctrlKey ||\n\t\te.metaKey ||\n\t\te.shiftKey ||\n\t\t(link.target && link.target !== \"_self\") ||\n\t\tlink.rel === \"external\" ||\n\t\tlink.hasAttribute(\"download\") ||\n\t\tlink.isContentEditable\n\t);\n}\n\n// Listen for changes to the URL that occur when the user navigates using the\n// back or forward buttons\nwindow.addEventListener(\"popstate\", async () => {\n\tconst navigated = await navigateToLocation(document.location);\n\tif (!navigated) {\n\t\twindow.location.reload();\n\t\treturn;\n\t}\n\t// Restore the scroll position that was saved on the history entry\n\trequestAnimationFrame(() => {\n\t\tconst state = window.history.state as { scroll?: number } | null;\n\t\twindow.scrollTo(0, state?.scroll ?? 0);\n\t});\n});\n\n// Do the initial navigation and hydration\nawait navigateToLocation(document.location, true);\n\nasync function navigateToLocation(location: Location, firstTime = false) {\n\t// Reset $page on submit and link navigation\n\t// TODO: Should we put data in $page.data??\n\t$page.form = undefined;\n\n\treturn await navigate(new URL(location.toString()), firstTime);\n}\n"],"mappings":";;;;;;AAWA,YAAY,SAAS,IAAI;AAGzB,MAAM,SAAS,IAAI,OAAO;AAC1B,OAAO,SAAS,SAAS,MAAM;AAK/B,OAAO,SAAS;AAChB,OAAO,kBAAkB,SAAS,mBAAmB;AAGrD,OAAO,iBAAiB,SAAS,OAAO,MAAM;CAC7C,MAAM,OAAO,QAAQ,EAAE,MAAM;CAC7B,IAAI,MAAM;EACT,IAAI,uBAAuB,MAAM,CAAC,GACjC;EAGD,EAAE,eAAe;EAEjB,MAAM,OAAO,KAAK;EAClB,MAAM,MAAM,IAAI,IAAI,IAAI;EAExB,IAAI,MAAM,SAAS,GAAG,GAAG;GAGxB,OAAO,QAAQ,aAAa,EAAE,QAAQ,OAAO,QAAQ,GAAG,IAAI,SAAS,SAAS,IAAI;GAClF,OAAO,QAAQ,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG;EAChD,OACC,OAAO,SAAS,OAAO;CAEzB;AACD,CAAC;AAID,OAAO,iBAAiB,aAAa,aAAa;AAClD,OAAO,iBAAiB,cAAc,aAAa;AAEnD,eAAe,cAAc,GAA4B;CACxD,MAAM,OAAO,QAAQ,EAAE,MAAM;CAC7B,IAAI,MAAM;EACT,IAAI,uBAAuB,MAAM,CAAC,GACjC;EAGD,MAAM,OAAO,KAAK;EAClB,MAAM,MAAM,IAAI,IAAI,IAAI;EAExB,MAAM,OAAO,IAAI;EACjB,MAAM,QAAQ,IAAI;EAClB,MAAM,QAAQ,OAAO,MAAM,MAAM,KAAK;EACtC,IAAI,OAAO;GACV,MAAM,UAAU,MAAM;GACtB,MAAM,SAAS,MAAM,UAAU,CAAC;GAGhC,MAAM,kBAA4C,MAAM,QAAQ,SAAS,EAAA,CAAG;GAG5E,MAAM,iBACL,QAAQ,mBAAmB,MAAM,QAAQ,eAAe,EAAA,EAAI;GAK7D,MAAM,SAAS,SAAS,QAAQ,MAAM,OAAO,CAAO,GAAG,gBAAgB,gBAAgB,IAAI;EAC5F;CACD;AACD;AAEA,SAAS,QAAQ,QAA2D;CAI3E,IAAI,EAAE,kBAAkB,UAAU;CAClC,MAAM,OAAO,OAAO,QAAQ,SAAS;CACrC,IAAI,MAAM,aAAa,MAAM,CAAC,EAAE,WAAW,GAAG,GAAG;CACjD,OAAQ,QAA8B,KAAA;AACvC;AAEA,SAAS,uBAAuB,MAAyB,GAA4B;CAKpF,OACC,EAAE,oBACF,EAAE,UACF,EAAE,WACF,EAAE,WACF,EAAE,YACD,KAAK,UAAU,KAAK,WAAW,WAChC,KAAK,QAAQ,cACb,KAAK,aAAa,UAAU,KAC5B,KAAK;AAEP;AAIA,OAAO,iBAAiB,YAAY,YAAY;CAE/C,IAAI,CAAC,MADmB,mBAAmB,SAAS,QAAQ,GAC5C;EACf,OAAO,SAAS,OAAO;EACvB;CACD;CAEA,4BAA4B;EAC3B,MAAM,QAAQ,OAAO,QAAQ;EAC7B,OAAO,SAAS,GAAG,OAAO,UAAU,CAAC;CACtC,CAAC;AACF,CAAC;AAGD,MAAM,mBAAmB,SAAS,UAAU,IAAI;AAEhD,eAAe,mBAAmB,UAAoB,YAAY,OAAO;CAGxE,MAAM,OAAO,KAAA;CAEb,OAAO,MAAM,SAAS,IAAI,IAAI,SAAS,SAAS,CAAC,GAAG,SAAS;AAC9D"}
|
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ import { t as ServerHook } from "./ServerHook-BTSGfLiJ.mjs";
|
|
|
5
5
|
import { a as PageLoadReturn, i as PageEndPoint, o as PageLoadEvent } from "./sitemap-BjqN4d4W.mjs";
|
|
6
6
|
import { n as UntypedResponse, t as TypedResponse } from "./TypedResponse-6lznqN4U.mjs";
|
|
7
7
|
import { t as StandardSchemaV1 } from "./StandardSchema-D28L8_zZ.mjs";
|
|
8
|
-
import { a as ServerEndPoint, c as ActionBody, d as PageServerActionSchemas, f as PageServerEndPoint, g as Adapter, h as SitePlugin, i as SchemaQuery, l as LoadParams, m as PageServerAction, n as ParamsOf, o as ServerEndPointSchemas, p as PageServerLoad, r as SchemaBody, s as ServerRequest, t as Site, u as LoadQuery } from "./Site-
|
|
8
|
+
import { a as ServerEndPoint, c as ActionBody, d as PageServerActionSchemas, f as PageServerEndPoint, g as Adapter, h as SitePlugin, i as SchemaQuery, l as LoadParams, m as PageServerAction, n as ParamsOf, o as ServerEndPointSchemas, p as PageServerLoad, r as SchemaBody, s as ServerRequest, t as Site, u as LoadQuery } from "./Site-CQ29Opvm.mjs";
|
|
9
9
|
import { t as Jsonify } from "./Jsonify-Dg6gChd3.mjs";
|
|
10
10
|
//#region src/types/PageData.d.ts
|
|
11
11
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -218,6 +218,13 @@ var Site = class {
|
|
|
218
218
|
*/
|
|
219
219
|
basePath = "";
|
|
220
220
|
/**
|
|
221
|
+
* Wraps client-side navigations in the View Transitions API -- where the
|
|
222
|
+
* browser supports it -- so pages cross-fade by default and can be
|
|
223
|
+
* animated with `::view-transition-old/new` CSS. Opt-in: off unless set
|
|
224
|
+
* to `true`. The initial hydration never transitions.
|
|
225
|
+
*/
|
|
226
|
+
viewTransitions;
|
|
227
|
+
/**
|
|
221
228
|
* Prerendering, applied to every page route that doesn't have (or
|
|
222
229
|
* inherit) a `prerender` flag of its own. `true` prerenders everything;
|
|
223
230
|
* a `Record<string, boolean>` maps route paths -- exact (`/about`) or
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["fs","#routePath","#routeType","#sortRoutes","#routeTypeFromString","#pushRoute"],"sources":["../src/site/defaultAdapter.ts","../src/site/Site.ts"],"sourcesContent":["import type Server from \"../server/Server\";\nimport type Adapter from \"../types/Adapter\";\n\n/**\n * The known adapter packages, in preference order, with the platform env\n * markers that select them when the site is built in a deployment\n * environment. Only packages that are actually installed (somewhere in the\n * site's node_modules) can be resolved.\n */\nconst ADAPTER_PACKAGES = [\n\t{\n\t\t// The preferred fallback: a node server runs anywhere\n\t\tpkg: \"@torpor/adapter-node\",\n\t\tplatforms: [] as string[],\n\t},\n\t{\n\t\tpkg: \"@torpor/adapter-cloudflare\",\n\t\t// Set when building in a Cloudflare Pages environment. More markers\n\t\t// can be added as adapters are (e.g. `VERCEL` for an adapter-vercel)\n\t\tplatforms: [\"CF_PAGES\"],\n\t},\n];\n\n/**\n * Loads an adapter package, returning undefined when it isn't installed.\n * The import deliberately uses a variable specifier so that bundlers never\n * try to resolve adapter packages from @torpor/build.\n */\nasync function loadAdapterPackage(pkg: string): Promise<Adapter | undefined> {\n\ttry {\n\t\treturn (await import(/* @vite-ignore */ pkg)).default;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport type AdapterResolution = {\n\t/** The resolved adapter, or undefined when none could be found */\n\tadapter: Adapter | undefined;\n\t/** The package the adapter was resolved from */\n\tpkg: string | undefined;\n\t/** Why the adapter was chosen, for logging */\n\treason: string;\n};\n\nexport type ResolveAdapterOptions = {\n\t/** The environment to check for platform markers (defaults to process.env) */\n\tenv?: Record<string, string | undefined>;\n\t/** Loads an adapter package by name (defaults to a dynamic import) */\n\tload?: (pkg: string) => Promise<Adapter | undefined>;\n};\n\n/**\n * Finds an adapter to use when the site doesn't set one explicitly:\n *\n * 1. A platform build environment (e.g. `CF_PAGES` for Cloudflare Pages)\n * selects its adapter, when the adapter package is installed.\n * 2. Otherwise an installed adapter is used, preferring `adapter-node`\n * (a node server runs anywhere).\n * 3. Otherwise nothing is found, and the caller decides what to do (warn,\n * or serve on the current runtime).\n */\nexport async function resolveAdapter(\n\toptions: ResolveAdapterOptions = {},\n): Promise<AdapterResolution> {\n\tconst env = options.env ?? process.env;\n\tconst load = options.load ?? loadAdapterPackage;\n\n\t// Import each package at most once\n\tconst loaded = new Map<string, Adapter | undefined>();\n\tconst loadOnce = async (pkg: string) => {\n\t\tif (!loaded.has(pkg)) loaded.set(pkg, await load(pkg));\n\t\treturn loaded.get(pkg);\n\t};\n\n\t// 1. A deployment environment selects its adapter\n\tfor (const candidate of ADAPTER_PACKAGES) {\n\t\tfor (const marker of candidate.platforms) {\n\t\t\tif (env[marker] === undefined) continue;\n\t\t\tconst adapter = await loadOnce(candidate.pkg);\n\t\t\tif (adapter) {\n\t\t\t\treturn { adapter, pkg: candidate.pkg, reason: `${marker} detected` };\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. An installed adapter (the list is in preference order)\n\tfor (const candidate of ADAPTER_PACKAGES) {\n\t\tconst adapter = await loadOnce(candidate.pkg);\n\t\tif (adapter) {\n\t\t\treturn { adapter, pkg: candidate.pkg, reason: \"installed\" };\n\t\t}\n\t}\n\n\treturn { adapter: undefined, pkg: undefined, reason: \"none found\" };\n}\n\n/**\n * The current runtime, when preview can serve a fetch handler without an\n * adapter package. (Node's request conversion lives in adapter-node, so\n * node is deliberately not handled here.)\n */\nfunction currentRuntime(): \"bun\" | \"deno\" | undefined {\n\tconst global = globalThis as any;\n\tif (global.Bun) return \"bun\";\n\tif (global.Deno) return \"deno\";\n\treturn undefined;\n}\n\n/**\n * Serves the built output on the current runtime, for when no adapter\n * package could be found. Returns false when the runtime isn't supported.\n */\nfunction serveOnCurrentRuntime(server: Server): boolean {\n\tconst runtime = currentRuntime();\n\tif (!runtime) return false;\n\n\tconst global = globalThis as any;\n\tconst port = parseInt(process.env.PORT ?? \"7059\");\n\tconst hostname = process.env.HOST ?? \"localhost\";\n\tconsole.log(`[torpor] Serving on the ${runtime} runtime at ${hostname}:${port}`);\n\n\tif (runtime === \"bun\") {\n\t\tglobal.Bun.serve({ port, hostname, fetch: (req: Request) => server.fetch(req) });\n\t} else {\n\t\tglobal.Deno.serve({ port, hostname }, (req: Request) => server.fetch(req));\n\t}\n\treturn true;\n}\n\n// The resolution is cached per process, and the \"Using ...\" message is only\n// logged once\nlet cache: Promise<AdapterResolution> | undefined;\nlet loggedPkg: string | undefined;\n\nfunction getCachedResolution(): Promise<AdapterResolution> {\n\treturn (cache ??= resolveAdapter());\n}\n\nfunction logAdapter(pkg: string, reason: string): void {\n\tif (loggedPkg === pkg) return;\n\tloggedPkg = pkg;\n\tconsole.log(`[torpor] Using the ${pkg.replace(\"@torpor/adapter-\", \"\")} adapter (${reason})`);\n}\n\n/**\n * The adapter used when the site doesn't set one explicitly. Rather than\n * being a real adapter, it resolves one at the time it's needed (see\n * `resolveAdapter`), and as a last resort serves the built output on the\n * current runtime -- Bun and Deno can serve a fetch handler natively, while\n * node needs `@torpor/adapter-node`.\n *\n * Dev mode is not affected: with no `dev` hook, the framework's default\n * Node-runtime dev plugin is used.\n */\nconst defaultAdapter: Adapter = {\n\tasync serve(server, site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (adapter && pkg) {\n\t\t\tlogAdapter(pkg, reason);\n\t\t\tawait adapter.serve(server, site);\n\t\t\treturn;\n\t\t}\n\t\tif (serveOnCurrentRuntime(server)) return;\n\t\tconsole.log(\n\t\t\t\"[torpor] No adapter found -- install one (e.g. `pnpm add @torpor/adapter-node`) or set `site.adapter` in site.config.ts\",\n\t\t);\n\t},\n\tasync prebuild(site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (!adapter || !pkg) return;\n\t\tlogAdapter(pkg, reason);\n\t\tawait adapter.prebuild?.(site);\n\t},\n\tasync postbuild(site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (!adapter || !pkg) return;\n\t\tlogAdapter(pkg, reason);\n\t\tawait adapter.postbuild?.(site);\n\t},\n};\n\nexport default defaultAdapter;\n","import { promises as fs } from \"node:fs\";\nimport fpath from \"node:path\";\nimport { type Plugin, type UserConfig } from \"vite\";\nimport type Adapter from \"../types/Adapter\";\nimport type { SitemapOptions } from \"../discovery/sitemap\";\nimport type MiddlewareFunction from \"../server/types/MiddlewareFunction\";\nimport type { StandardSchemaV1 } from \"../types/StandardSchema\";\nimport type SitePlugin from \"../types/SitePlugin\";\nimport type { InlineEndPoint } from \"../types/Route\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport type Route from \"../types/Route\";\nimport type ServerEndPoint from \"../types/ServerEndPoint\";\nimport type ServerHook from \"../types/ServerHook\";\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\tRouteType,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport defaultAdapter from \"./defaultAdapter\";\n\n// 1. The user sets this up\n// 2. It is passed into serverEntry and clientEntry through a Vite plugin\n// (defined in manifest.ts)\n// 3. In those files, it is used to build a Router\n\n/**\n * The Site class contains the information necessary to setup a @torpor/build\n * site, including routes, plugins, and options.\n */\nexport default class Site {\n\troot: string;\n\troutes: Route[] = [];\n\t/**\n\t * Torpor site plugins, run when the site config is loaded (for dev and\n\t * build) and when the server starts up. Use these to register extra\n\t * routes (e.g. `openApi()` from `@torpor/build/openapi`) or add other\n\t * framework-level functionality\n\t */\n\tplugins: SitePlugin[] = [];\n\t/**\n\t * Vite plugins to add to the client and server builds\n\t */\n\tvitePlugins: Plugin[] = [];\n\t/**\n\t * The site's adapter, e.g. from `@torpor/adapter-node` or\n\t * `@torpor/adapter-cloudflare`. When not set, one is resolved when it's\n\t * needed: a deployment environment (e.g. `CF_PAGES`) picks the platform's\n\t * adapter when installed, an installed adapter is used otherwise, and\n\t * preview falls back to serving on the current runtime. See\n\t * defaultAdapter.ts\n\t */\n\tadapter: Adapter = defaultAdapter;\n\t/**\n\t * Extra inputs, as absolute file paths, that will be compiled with the\n\t * output. What you do with them after that is up to you. File paths ending\n\t * with server.ts/js will only be compiled with the server output\n\t */\n\tinputs: string[] = [];\n\t/**\n\t * Vite config options to merge with the standard Torpor build options.\n\t * `plugins` and `build.rollupOptions.input` will be overridden, so you\n\t * should set `Site.vitePlugins` and `Site.inputs` instead. Other options may be\n\t * overridden or incompatible, so experimentation may be required\n\t */\n\tviteConfig?: UserConfig;\n\t/**\n\t * The path to the site.config file. Set automatically by the CLI; used by\n\t * the manifest plugin to import inline endpoints for server builds.\n\t */\n\tconfigFile?: string;\n\t/**\n\t * A state map for plugins to store their configuration and state on the\n\t * site, so that framework internals (e.g. the manifest plugin) and other\n\t * plugins can read them back:\n\t *\n\t * ```ts\n\t * const myKey = Symbol.for(\"my-plugin\");\n\t * site.pluginState.set(myKey, options);\n\t * ```\n\t *\n\t * Prefer `Symbol.for(\"...\")` keys (or plain strings) over `Symbol()`,\n\t * because the user's config file and framework internals can be loaded as\n\t * separate module instances -- registry symbols are shared across\n\t * instances, `Symbol()` ones are not.\n\t */\n\tpluginState: Map<PropertyKey, unknown> = new Map();\n\t/**\n\t * The path the site is mounted under, e.g. \"/app\". Incoming server\n\t * requests that don't carry it are not found; everything the framework\n\t * generates (HTML attributes, redirect locations, paths from `route()`)\n\t * gets it added. Server code and markup stay base-free.\n\t */\n\tbasePath: string = \"\";\n\t/**\n\t * Prerendering, applied to every page route that doesn't have (or\n\t * inherit) a `prerender` flag of its own. `true` prerenders everything;\n\t * a `Record<string, boolean>` maps route paths -- exact (`/about`) or\n\t * prefix (`/blog/**` for a path and everything below it) -- to flags,\n\t * with the most specific matching key winning. Route endpoint and\n\t * layout flags always take precedence over this.\n\t */\n\tprerender?: boolean | Record<string, boolean>;\n\t/**\n\t * The site's absolute origin, e.g. \"https://example.com\". Required for\n\t * a build-time sitemap (see `sitemap`), since there is no request to\n\t * take the host from.\n\t */\n\torigin?: string;\n\t/**\n\t * Global middleware, run for every request before routing -- including\n\t * requests that won't match a route (maintenance mode, legacy url\n\t * redirects, etc). Each middleware's `enter` runs in order and may\n\t * return a Response to short-circuit the request; `exit` hooks run in\n\t * reverse after the handler. Middleware see the raw request url.\n\t *\n\t * Route middleware (scoped to a single route) is set on the route's\n\t * server endpoint instead, e.g. `middleware: [...]` in\n\t * `+page.server.ts` or `+server.ts`.\n\t */\n\tmiddleware: MiddlewareFunction[] = [];\n\t/**\n\t * Writes a sitemap.xml listing the prerendered pages at build time\n\t * (see `prerender`). Pass a custom path (e.g. \"/blog/sitemap.xml\") or\n\t * `true` for \"/sitemap.xml\"; requires `origin` to be set.\n\t *\n\t * For a runtime sitemap -- one that reads the database and keeps up with\n\t * content that isn't prerendered -- pass a config instead, e.g.\n\t * `sitemap = { get: async () => [\"/posts/a\", \"/posts/b\"] }`, which serves\n\t * the XML live at that path (customizable with `path`).\n\t */\n\tsitemap?: SitemapOptions | boolean | string;\n\t/**\n\t * A Standard Schema (zod, valibot, arktype, etc) used to validate (and\n\t * parse) the server environment. When set, `env()` from\n\t * `@torpor/build/env` checks the environment on first use per request and\n\t * throws with the schema's issues -- so a missing or invalid key fails\n\t * immediately instead of passing `undefined` along. The schema must\n\t * validate synchronously.\n\t */\n\tenv?: StandardSchemaV1<unknown, TorporEnv>;\n\t/**\n\t * Inline endpoints keyed by `\"path:type\"`. Populated by `addRoute` when\n\t * the user passes an inline endpoint object instead of a file path.\n\t */\n\tinlineEndPoints: Record<string, InlineEndPoint> = {};\n\n\tconstructor() {\n\t\tthis.root = process.cwd();\n\t}\n\n\t/**\n\t * Adds a folder of routes, based on the names of the files in the folder\n\t * @param folder The folder containing the routes\n\t * @param subFolder If a subFolder is set, all routes in the folder will be\n\t * placed under the subFolder, and only hooks, layouts etc will be used if\n\t * they have the same subFolder. This can be used to create e.g. an `api`\n\t * set of routes with their own hook for authorization from various clients\n\t */\n\tasync addRouteFolder(folder: string, subFolder?: string): Promise<void> {\n\t\tconst routeFolder = fpath.join(this.root, folder);\n\t\tconst routeFiles = await fs.readdir(routeFolder, { recursive: true });\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tfor (let file of routeFiles) {\n\t\t\t// The file must start with `+` or `_` and end with `.js` or `.ts`\n\t\t\tif (/^(\\+|_).+(\\.js|\\.ts)$/.test(fpath.basename(file))) {\n\t\t\t\tlet routePath = this.#routePath(file);\n\t\t\t\tif (subFolder !== undefined) {\n\t\t\t\t\troutePath = subFolder + routePath;\n\t\t\t\t}\n\t\t\t\tlet type = this.#routeType(file);\n\t\t\t\tfile = fpath.relative(this.root, fpath.resolve(routeFolder, file));\n\t\t\t\tthis.routes.push({\n\t\t\t\t\tpath: routePath,\n\t\t\t\t\tfile,\n\t\t\t\t\ttype,\n\t\t\t\t\tsubFolder: subFolder,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Adds a file route, which can have a standard name (e.g. +page.ts) or any\n\t * name if you pass the type\n\t * @param path The route path\n\t * @param file The file\n\t * @param type The file type (if the file name is non-standard)\n\t */\n\taddRouteFile(\n\t\tpath: string,\n\t\tfile: string,\n\t\ttype?:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t\tsubFolder?: string,\n\t): void {\n\t\tlet routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));\n\t\tlet routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tthis.routes.push({\n\t\t\tpath: routePath,\n\t\t\tfile,\n\t\t\ttype: routeType,\n\t\t\tsubFolder: subFolder,\n\t\t});\n\t\tthis.#sortRoutes();\n\t}\n\n\t#routePath(file: string): string {\n\t\tlet routePath = file\n\t\t\t.replace(/^\\//, \"\")\n\t\t\t.replace(/(\\.ts|\\.js)$/, \"\")\n\t\t\t.replace(/_hook.server$/, \"_hook/~server\")\n\t\t\t.replace(/_layout.server$/, \"_layout/~server\")\n\t\t\t.replace(/\\+page.server$/, \"~server\")\n\t\t\t.replace(/\\+server$/, \"\")\n\t\t\t.replace(/\\+page$/, \"\")\n\t\t\t.replace(/\\/$/, \"\");\n\t\treturn routePath.length > 0 ? `/${routePath}` : \"/\";\n\t}\n\n\t#routeType(file: string): RouteType {\n\t\tlet routePath = file.replace(/^\\//, \"\").replace(/(\\.ts|\\.js)$/, \"\");\n\t\tif (routePath.endsWith(\"+page\")) {\n\t\t\treturn PAGE_ROUTE;\n\t\t} else if (routePath.endsWith(\"+page.server\")) {\n\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"+server\")) {\n\t\t\treturn SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout\")) {\n\t\t\treturn LAYOUT_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout.server\")) {\n\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook\")) {\n\t\t\treturn HOOK_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook.server\")) {\n\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_error\")) {\n\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t#routeTypeFromString(\n\t\ttype:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t) {\n\t\tswitch (type) {\n\t\t\tcase \"+page\":\n\t\t\t\treturn PAGE_ROUTE;\n\t\t\tcase \"+page.server\":\n\t\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t\tcase \"+server\":\n\t\t\t\treturn SERVER_ROUTE;\n\t\t\tcase \"_layout\":\n\t\t\t\treturn LAYOUT_ROUTE;\n\t\t\tcase \"_layout.server\":\n\t\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t\tcase \"_hook\":\n\t\t\t\treturn HOOK_ROUTE;\n\t\t\tcase \"_hook.server\":\n\t\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t\tcase \"_error\":\n\t\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t}\n\n\t/**\n\t * Adds a route in code, without needing the standard file naming\n\t * conventions (+page.ts, +page.server.ts, etc). This is useful for small\n\t * sites with one or two pages.\n\t *\n\t * Any combination of options may be provided; each maps to the\n\t * corresponding file-route type:\n\t *\n\t * - `page` — a `+page` (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t * - `pageServer` — a `+page.server` (`PageServerEndPoint`, file or inline)\n\t * - `server` — a `+server` HTTP endpoint (`ServerEndPoint`, file or inline)\n\t * - `layout` — a `_layout` (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t * - `layoutServer` — a `_layout.server` (`PageServerEndPoint`, file or inline)\n\t * - `hookServer` — a `_hook.server` (`ServerHook`, file or inline)\n\t * - `error` — an `_error` page (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t *\n\t * Options that need a component (`page`, `layout`, `error`) must be file\n\t * paths so the component is included in the client bundle. Server-only\n\t * options (`pageServer`, `server`, `layoutServer`, `hookServer`) accept\n\t * either a file path or an inline object; inline server code is kept out\n\t * of the client bundle automatically.\n\t *\n\t * @example\n\t * // A page with an inline server action\n\t * site.addRoute(\"/\", {\n\t * page: \"./src/Counter.torp\",\n\t * pageServer: { actions: { set: async ({ request }) => ok() } },\n\t * });\n\t * @example\n\t * // A JSON API endpoint\n\t * site.addRoute(\"/api/time\", {\n\t * server: { get: async () => ok({ time: Date.now() }) },\n\t * });\n\t * @example\n\t * // A root layout, server hook, and error page\n\t * site.addRoute(\"/\", {\n\t * layout: \"./src/Layout.torp\",\n\t * hookServer: { enter: async (event) => {} },\n\t * error: \"./src/ErrorPage.torp\",\n\t * });\n\t *\n\t * @param path The route path, e.g. `/` or `/about`\n\t * @param options File paths and/or inline endpoints for the route\n\t * @param subFolder An optional subFolder for grouping routes\n\t */\n\taddRoute(\n\t\tpath: string,\n\t\toptions: {\n\t\t\tpage?: string;\n\t\t\tpageServer?: string | PageServerEndPoint;\n\t\t\tserver?: string | ServerEndPoint;\n\t\t\tlayout?: string;\n\t\t\tlayoutServer?: string | PageServerEndPoint;\n\t\t\thookServer?: string | ServerHook;\n\t\t\terror?: string;\n\t\t},\n\t\tsubFolder?: string,\n\t): void {\n\t\tlet normalizedSubFolder = subFolder;\n\t\tif (normalizedSubFolder !== undefined && !normalizedSubFolder.startsWith(\"/\")) {\n\t\t\tnormalizedSubFolder = \"/\" + normalizedSubFolder;\n\t\t}\n\n\t\t// The base path with any trailing slash stripped, so that we can\n\t\t// append \"/_layout\", \"/~server\" etc. For the root \"/\" this is \"\".\n\t\tlet base = path.replace(/\\/$/, \"\");\n\n\t\tif (options.page !== undefined) {\n\t\t\tthis.#pushRoute(path, PAGE_ROUTE, options.page, normalizedSubFolder);\n\t\t}\n\t\tif (options.pageServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/~server`,\n\t\t\t\tPAGE_SERVER_ROUTE,\n\t\t\t\toptions.pageServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.server !== undefined) {\n\t\t\tthis.#pushRoute(path, SERVER_ROUTE, options.server, normalizedSubFolder);\n\t\t}\n\t\tif (options.layout !== undefined) {\n\t\t\tthis.#pushRoute(`${base}/_layout`, LAYOUT_ROUTE, options.layout, normalizedSubFolder);\n\t\t}\n\t\tif (options.layoutServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/_layout/~server`,\n\t\t\t\tLAYOUT_SERVER_ROUTE,\n\t\t\t\toptions.layoutServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.hookServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/_hook/~server`,\n\t\t\t\tHOOK_SERVER_ROUTE,\n\t\t\t\toptions.hookServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.error !== undefined) {\n\t\t\tthis.#pushRoute(`${base}/_error`, ERROR_ROUTE, options.error, normalizedSubFolder);\n\t\t}\n\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Pushes a single route entry, handling both file-path and inline-endpoint\n\t * targets. File paths are resolved relative to the site root; inline\n\t * endpoints are also stored in `inlineEndPoints` keyed by `\"path:type\"`\n\t * so the manifest plugin can resolve them at build time.\n\t *\n\t * If a route with the same path and type was already added, it is\n\t * replaced, so that running a plugin twice (config load and server\n\t * startup) doesn't add duplicate routes.\n\t */\n\t#pushRoute(\n\t\troutePath: string,\n\t\ttype: RouteType,\n\t\ttarget: string | InlineEndPoint,\n\t\tsubFolder?: string,\n\t): void {\n\t\tconst index = this.routes.findIndex((r) => r.path === routePath && r.type === type);\n\t\tif (typeof target === \"string\") {\n\t\t\tlet file = fpath.relative(this.root, fpath.resolve(this.root, target));\n\t\t\tif (index >= 0) {\n\t\t\t\tthis.routes[index] = { path: routePath, file, type, subFolder };\n\t\t\t} else {\n\t\t\t\tthis.routes.push({ path: routePath, file, type, subFolder });\n\t\t\t}\n\t\t} else {\n\t\t\tlet key = `${routePath}:${type}`;\n\t\t\tthis.inlineEndPoints[key] = target;\n\t\t\tif (index >= 0) {\n\t\t\t\tthis.routes[index] = { path: routePath, endPoint: target, type, subFolder };\n\t\t\t} else {\n\t\t\t\tthis.routes.push({ path: routePath, endPoint: target, type, subFolder });\n\t\t\t}\n\t\t}\n\t}\n\n\t#sortRoutes() {\n\t\tthis.routes = this.routes.sort((a, b) => {\n\t\t\t// Sort [param]s after paths\n\t\t\t// There might be a quicker/easier way to do this\n\t\t\tfor (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {\n\t\t\t\tif (a.path[i] === \"[\" && b.path[i] !== \"[\") {\n\t\t\t\t\treturn 1;\n\t\t\t\t} else if (b.path[i] === \"[\" && a.path[i] !== \"[\") {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else if (a.path[i] === b.path[i]) {\n\t\t\t\t\t// Keep going...\n\t\t\t\t} else {\n\t\t\t\t\treturn a.path[i].localeCompare(b.path[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn a.path.length - b.path.length;\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["fs","#routePath","#routeType","#sortRoutes","#routeTypeFromString","#pushRoute"],"sources":["../src/site/defaultAdapter.ts","../src/site/Site.ts"],"sourcesContent":["import type Server from \"../server/Server\";\nimport type Adapter from \"../types/Adapter\";\n\n/**\n * The known adapter packages, in preference order, with the platform env\n * markers that select them when the site is built in a deployment\n * environment. Only packages that are actually installed (somewhere in the\n * site's node_modules) can be resolved.\n */\nconst ADAPTER_PACKAGES = [\n\t{\n\t\t// The preferred fallback: a node server runs anywhere\n\t\tpkg: \"@torpor/adapter-node\",\n\t\tplatforms: [] as string[],\n\t},\n\t{\n\t\tpkg: \"@torpor/adapter-cloudflare\",\n\t\t// Set when building in a Cloudflare Pages environment. More markers\n\t\t// can be added as adapters are (e.g. `VERCEL` for an adapter-vercel)\n\t\tplatforms: [\"CF_PAGES\"],\n\t},\n];\n\n/**\n * Loads an adapter package, returning undefined when it isn't installed.\n * The import deliberately uses a variable specifier so that bundlers never\n * try to resolve adapter packages from @torpor/build.\n */\nasync function loadAdapterPackage(pkg: string): Promise<Adapter | undefined> {\n\ttry {\n\t\treturn (await import(/* @vite-ignore */ pkg)).default;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport type AdapterResolution = {\n\t/** The resolved adapter, or undefined when none could be found */\n\tadapter: Adapter | undefined;\n\t/** The package the adapter was resolved from */\n\tpkg: string | undefined;\n\t/** Why the adapter was chosen, for logging */\n\treason: string;\n};\n\nexport type ResolveAdapterOptions = {\n\t/** The environment to check for platform markers (defaults to process.env) */\n\tenv?: Record<string, string | undefined>;\n\t/** Loads an adapter package by name (defaults to a dynamic import) */\n\tload?: (pkg: string) => Promise<Adapter | undefined>;\n};\n\n/**\n * Finds an adapter to use when the site doesn't set one explicitly:\n *\n * 1. A platform build environment (e.g. `CF_PAGES` for Cloudflare Pages)\n * selects its adapter, when the adapter package is installed.\n * 2. Otherwise an installed adapter is used, preferring `adapter-node`\n * (a node server runs anywhere).\n * 3. Otherwise nothing is found, and the caller decides what to do (warn,\n * or serve on the current runtime).\n */\nexport async function resolveAdapter(\n\toptions: ResolveAdapterOptions = {},\n): Promise<AdapterResolution> {\n\tconst env = options.env ?? process.env;\n\tconst load = options.load ?? loadAdapterPackage;\n\n\t// Import each package at most once\n\tconst loaded = new Map<string, Adapter | undefined>();\n\tconst loadOnce = async (pkg: string) => {\n\t\tif (!loaded.has(pkg)) loaded.set(pkg, await load(pkg));\n\t\treturn loaded.get(pkg);\n\t};\n\n\t// 1. A deployment environment selects its adapter\n\tfor (const candidate of ADAPTER_PACKAGES) {\n\t\tfor (const marker of candidate.platforms) {\n\t\t\tif (env[marker] === undefined) continue;\n\t\t\tconst adapter = await loadOnce(candidate.pkg);\n\t\t\tif (adapter) {\n\t\t\t\treturn { adapter, pkg: candidate.pkg, reason: `${marker} detected` };\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. An installed adapter (the list is in preference order)\n\tfor (const candidate of ADAPTER_PACKAGES) {\n\t\tconst adapter = await loadOnce(candidate.pkg);\n\t\tif (adapter) {\n\t\t\treturn { adapter, pkg: candidate.pkg, reason: \"installed\" };\n\t\t}\n\t}\n\n\treturn { adapter: undefined, pkg: undefined, reason: \"none found\" };\n}\n\n/**\n * The current runtime, when preview can serve a fetch handler without an\n * adapter package. (Node's request conversion lives in adapter-node, so\n * node is deliberately not handled here.)\n */\nfunction currentRuntime(): \"bun\" | \"deno\" | undefined {\n\tconst global = globalThis as any;\n\tif (global.Bun) return \"bun\";\n\tif (global.Deno) return \"deno\";\n\treturn undefined;\n}\n\n/**\n * Serves the built output on the current runtime, for when no adapter\n * package could be found. Returns false when the runtime isn't supported.\n */\nfunction serveOnCurrentRuntime(server: Server): boolean {\n\tconst runtime = currentRuntime();\n\tif (!runtime) return false;\n\n\tconst global = globalThis as any;\n\tconst port = parseInt(process.env.PORT ?? \"7059\");\n\tconst hostname = process.env.HOST ?? \"localhost\";\n\tconsole.log(`[torpor] Serving on the ${runtime} runtime at ${hostname}:${port}`);\n\n\tif (runtime === \"bun\") {\n\t\tglobal.Bun.serve({ port, hostname, fetch: (req: Request) => server.fetch(req) });\n\t} else {\n\t\tglobal.Deno.serve({ port, hostname }, (req: Request) => server.fetch(req));\n\t}\n\treturn true;\n}\n\n// The resolution is cached per process, and the \"Using ...\" message is only\n// logged once\nlet cache: Promise<AdapterResolution> | undefined;\nlet loggedPkg: string | undefined;\n\nfunction getCachedResolution(): Promise<AdapterResolution> {\n\treturn (cache ??= resolveAdapter());\n}\n\nfunction logAdapter(pkg: string, reason: string): void {\n\tif (loggedPkg === pkg) return;\n\tloggedPkg = pkg;\n\tconsole.log(`[torpor] Using the ${pkg.replace(\"@torpor/adapter-\", \"\")} adapter (${reason})`);\n}\n\n/**\n * The adapter used when the site doesn't set one explicitly. Rather than\n * being a real adapter, it resolves one at the time it's needed (see\n * `resolveAdapter`), and as a last resort serves the built output on the\n * current runtime -- Bun and Deno can serve a fetch handler natively, while\n * node needs `@torpor/adapter-node`.\n *\n * Dev mode is not affected: with no `dev` hook, the framework's default\n * Node-runtime dev plugin is used.\n */\nconst defaultAdapter: Adapter = {\n\tasync serve(server, site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (adapter && pkg) {\n\t\t\tlogAdapter(pkg, reason);\n\t\t\tawait adapter.serve(server, site);\n\t\t\treturn;\n\t\t}\n\t\tif (serveOnCurrentRuntime(server)) return;\n\t\tconsole.log(\n\t\t\t\"[torpor] No adapter found -- install one (e.g. `pnpm add @torpor/adapter-node`) or set `site.adapter` in site.config.ts\",\n\t\t);\n\t},\n\tasync prebuild(site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (!adapter || !pkg) return;\n\t\tlogAdapter(pkg, reason);\n\t\tawait adapter.prebuild?.(site);\n\t},\n\tasync postbuild(site) {\n\t\tconst { adapter, pkg, reason } = await getCachedResolution();\n\t\tif (!adapter || !pkg) return;\n\t\tlogAdapter(pkg, reason);\n\t\tawait adapter.postbuild?.(site);\n\t},\n};\n\nexport default defaultAdapter;\n","import { promises as fs } from \"node:fs\";\nimport fpath from \"node:path\";\nimport { type Plugin, type UserConfig } from \"vite\";\nimport type Adapter from \"../types/Adapter\";\nimport type { SitemapOptions } from \"../discovery/sitemap\";\nimport type MiddlewareFunction from \"../server/types/MiddlewareFunction\";\nimport type { StandardSchemaV1 } from \"../types/StandardSchema\";\nimport type SitePlugin from \"../types/SitePlugin\";\nimport type { InlineEndPoint } from \"../types/Route\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport type Route from \"../types/Route\";\nimport type ServerEndPoint from \"../types/ServerEndPoint\";\nimport type ServerHook from \"../types/ServerHook\";\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\tRouteType,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport defaultAdapter from \"./defaultAdapter\";\n\n// 1. The user sets this up\n// 2. It is passed into serverEntry and clientEntry through a Vite plugin\n// (defined in manifest.ts)\n// 3. In those files, it is used to build a Router\n\n/**\n * The Site class contains the information necessary to setup a @torpor/build\n * site, including routes, plugins, and options.\n */\nexport default class Site {\n\troot: string;\n\troutes: Route[] = [];\n\t/**\n\t * Torpor site plugins, run when the site config is loaded (for dev and\n\t * build) and when the server starts up. Use these to register extra\n\t * routes (e.g. `openApi()` from `@torpor/build/openapi`) or add other\n\t * framework-level functionality\n\t */\n\tplugins: SitePlugin[] = [];\n\t/**\n\t * Vite plugins to add to the client and server builds\n\t */\n\tvitePlugins: Plugin[] = [];\n\t/**\n\t * The site's adapter, e.g. from `@torpor/adapter-node` or\n\t * `@torpor/adapter-cloudflare`. When not set, one is resolved when it's\n\t * needed: a deployment environment (e.g. `CF_PAGES`) picks the platform's\n\t * adapter when installed, an installed adapter is used otherwise, and\n\t * preview falls back to serving on the current runtime. See\n\t * defaultAdapter.ts\n\t */\n\tadapter: Adapter = defaultAdapter;\n\t/**\n\t * Extra inputs, as absolute file paths, that will be compiled with the\n\t * output. What you do with them after that is up to you. File paths ending\n\t * with server.ts/js will only be compiled with the server output\n\t */\n\tinputs: string[] = [];\n\t/**\n\t * Vite config options to merge with the standard Torpor build options.\n\t * `plugins` and `build.rollupOptions.input` will be overridden, so you\n\t * should set `Site.vitePlugins` and `Site.inputs` instead. Other options may be\n\t * overridden or incompatible, so experimentation may be required\n\t */\n\tviteConfig?: UserConfig;\n\t/**\n\t * The path to the site.config file. Set automatically by the CLI; used by\n\t * the manifest plugin to import inline endpoints for server builds.\n\t */\n\tconfigFile?: string;\n\t/**\n\t * A state map for plugins to store their configuration and state on the\n\t * site, so that framework internals (e.g. the manifest plugin) and other\n\t * plugins can read them back:\n\t *\n\t * ```ts\n\t * const myKey = Symbol.for(\"my-plugin\");\n\t * site.pluginState.set(myKey, options);\n\t * ```\n\t *\n\t * Prefer `Symbol.for(\"...\")` keys (or plain strings) over `Symbol()`,\n\t * because the user's config file and framework internals can be loaded as\n\t * separate module instances -- registry symbols are shared across\n\t * instances, `Symbol()` ones are not.\n\t */\n\tpluginState: Map<PropertyKey, unknown> = new Map();\n\t/**\n\t * The path the site is mounted under, e.g. \"/app\". Incoming server\n\t * requests that don't carry it are not found; everything the framework\n\t * generates (HTML attributes, redirect locations, paths from `route()`)\n\t * gets it added. Server code and markup stay base-free.\n\t */\n\tbasePath: string = \"\";\n\t/**\n\t * Wraps client-side navigations in the View Transitions API -- where the\n\t * browser supports it -- so pages cross-fade by default and can be\n\t * animated with `::view-transition-old/new` CSS. Opt-in: off unless set\n\t * to `true`. The initial hydration never transitions.\n\t */\n\tviewTransitions?: boolean;\n\t/**\n\t * Prerendering, applied to every page route that doesn't have (or\n\t * inherit) a `prerender` flag of its own. `true` prerenders everything;\n\t * a `Record<string, boolean>` maps route paths -- exact (`/about`) or\n\t * prefix (`/blog/**` for a path and everything below it) -- to flags,\n\t * with the most specific matching key winning. Route endpoint and\n\t * layout flags always take precedence over this.\n\t */\n\tprerender?: boolean | Record<string, boolean>;\n\t/**\n\t * The site's absolute origin, e.g. \"https://example.com\". Required for\n\t * a build-time sitemap (see `sitemap`), since there is no request to\n\t * take the host from.\n\t */\n\torigin?: string;\n\t/**\n\t * Global middleware, run for every request before routing -- including\n\t * requests that won't match a route (maintenance mode, legacy url\n\t * redirects, etc). Each middleware's `enter` runs in order and may\n\t * return a Response to short-circuit the request; `exit` hooks run in\n\t * reverse after the handler. Middleware see the raw request url.\n\t *\n\t * Route middleware (scoped to a single route) is set on the route's\n\t * server endpoint instead, e.g. `middleware: [...]` in\n\t * `+page.server.ts` or `+server.ts`.\n\t */\n\tmiddleware: MiddlewareFunction[] = [];\n\t/**\n\t * Writes a sitemap.xml listing the prerendered pages at build time\n\t * (see `prerender`). Pass a custom path (e.g. \"/blog/sitemap.xml\") or\n\t * `true` for \"/sitemap.xml\"; requires `origin` to be set.\n\t *\n\t * For a runtime sitemap -- one that reads the database and keeps up with\n\t * content that isn't prerendered -- pass a config instead, e.g.\n\t * `sitemap = { get: async () => [\"/posts/a\", \"/posts/b\"] }`, which serves\n\t * the XML live at that path (customizable with `path`).\n\t */\n\tsitemap?: SitemapOptions | boolean | string;\n\t/**\n\t * A Standard Schema (zod, valibot, arktype, etc) used to validate (and\n\t * parse) the server environment. When set, `env()` from\n\t * `@torpor/build/env` checks the environment on first use per request and\n\t * throws with the schema's issues -- so a missing or invalid key fails\n\t * immediately instead of passing `undefined` along. The schema must\n\t * validate synchronously.\n\t */\n\tenv?: StandardSchemaV1<unknown, TorporEnv>;\n\t/**\n\t * Inline endpoints keyed by `\"path:type\"`. Populated by `addRoute` when\n\t * the user passes an inline endpoint object instead of a file path.\n\t */\n\tinlineEndPoints: Record<string, InlineEndPoint> = {};\n\n\tconstructor() {\n\t\tthis.root = process.cwd();\n\t}\n\n\t/**\n\t * Adds a folder of routes, based on the names of the files in the folder\n\t * @param folder The folder containing the routes\n\t * @param subFolder If a subFolder is set, all routes in the folder will be\n\t * placed under the subFolder, and only hooks, layouts etc will be used if\n\t * they have the same subFolder. This can be used to create e.g. an `api`\n\t * set of routes with their own hook for authorization from various clients\n\t */\n\tasync addRouteFolder(folder: string, subFolder?: string): Promise<void> {\n\t\tconst routeFolder = fpath.join(this.root, folder);\n\t\tconst routeFiles = await fs.readdir(routeFolder, { recursive: true });\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tfor (let file of routeFiles) {\n\t\t\t// The file must start with `+` or `_` and end with `.js` or `.ts`\n\t\t\tif (/^(\\+|_).+(\\.js|\\.ts)$/.test(fpath.basename(file))) {\n\t\t\t\tlet routePath = this.#routePath(file);\n\t\t\t\tif (subFolder !== undefined) {\n\t\t\t\t\troutePath = subFolder + routePath;\n\t\t\t\t}\n\t\t\t\tlet type = this.#routeType(file);\n\t\t\t\tfile = fpath.relative(this.root, fpath.resolve(routeFolder, file));\n\t\t\t\tthis.routes.push({\n\t\t\t\t\tpath: routePath,\n\t\t\t\t\tfile,\n\t\t\t\t\ttype,\n\t\t\t\t\tsubFolder: subFolder,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Adds a file route, which can have a standard name (e.g. +page.ts) or any\n\t * name if you pass the type\n\t * @param path The route path\n\t * @param file The file\n\t * @param type The file type (if the file name is non-standard)\n\t */\n\taddRouteFile(\n\t\tpath: string,\n\t\tfile: string,\n\t\ttype?:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t\tsubFolder?: string,\n\t): void {\n\t\tlet routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));\n\t\tlet routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tthis.routes.push({\n\t\t\tpath: routePath,\n\t\t\tfile,\n\t\t\ttype: routeType,\n\t\t\tsubFolder: subFolder,\n\t\t});\n\t\tthis.#sortRoutes();\n\t}\n\n\t#routePath(file: string): string {\n\t\tlet routePath = file\n\t\t\t.replace(/^\\//, \"\")\n\t\t\t.replace(/(\\.ts|\\.js)$/, \"\")\n\t\t\t.replace(/_hook.server$/, \"_hook/~server\")\n\t\t\t.replace(/_layout.server$/, \"_layout/~server\")\n\t\t\t.replace(/\\+page.server$/, \"~server\")\n\t\t\t.replace(/\\+server$/, \"\")\n\t\t\t.replace(/\\+page$/, \"\")\n\t\t\t.replace(/\\/$/, \"\");\n\t\treturn routePath.length > 0 ? `/${routePath}` : \"/\";\n\t}\n\n\t#routeType(file: string): RouteType {\n\t\tlet routePath = file.replace(/^\\//, \"\").replace(/(\\.ts|\\.js)$/, \"\");\n\t\tif (routePath.endsWith(\"+page\")) {\n\t\t\treturn PAGE_ROUTE;\n\t\t} else if (routePath.endsWith(\"+page.server\")) {\n\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"+server\")) {\n\t\t\treturn SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout\")) {\n\t\t\treturn LAYOUT_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout.server\")) {\n\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook\")) {\n\t\t\treturn HOOK_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook.server\")) {\n\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_error\")) {\n\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t#routeTypeFromString(\n\t\ttype:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t) {\n\t\tswitch (type) {\n\t\t\tcase \"+page\":\n\t\t\t\treturn PAGE_ROUTE;\n\t\t\tcase \"+page.server\":\n\t\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t\tcase \"+server\":\n\t\t\t\treturn SERVER_ROUTE;\n\t\t\tcase \"_layout\":\n\t\t\t\treturn LAYOUT_ROUTE;\n\t\t\tcase \"_layout.server\":\n\t\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t\tcase \"_hook\":\n\t\t\t\treturn HOOK_ROUTE;\n\t\t\tcase \"_hook.server\":\n\t\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t\tcase \"_error\":\n\t\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t}\n\n\t/**\n\t * Adds a route in code, without needing the standard file naming\n\t * conventions (+page.ts, +page.server.ts, etc). This is useful for small\n\t * sites with one or two pages.\n\t *\n\t * Any combination of options may be provided; each maps to the\n\t * corresponding file-route type:\n\t *\n\t * - `page` — a `+page` (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t * - `pageServer` — a `+page.server` (`PageServerEndPoint`, file or inline)\n\t * - `server` — a `+server` HTTP endpoint (`ServerEndPoint`, file or inline)\n\t * - `layout` — a `_layout` (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t * - `layoutServer` — a `_layout.server` (`PageServerEndPoint`, file or inline)\n\t * - `hookServer` — a `_hook.server` (`ServerHook`, file or inline)\n\t * - `error` — an `_error` page (`.torp` component or `.ts`/`.js` `PageEndPoint`)\n\t *\n\t * Options that need a component (`page`, `layout`, `error`) must be file\n\t * paths so the component is included in the client bundle. Server-only\n\t * options (`pageServer`, `server`, `layoutServer`, `hookServer`) accept\n\t * either a file path or an inline object; inline server code is kept out\n\t * of the client bundle automatically.\n\t *\n\t * @example\n\t * // A page with an inline server action\n\t * site.addRoute(\"/\", {\n\t * page: \"./src/Counter.torp\",\n\t * pageServer: { actions: { set: async ({ request }) => ok() } },\n\t * });\n\t * @example\n\t * // A JSON API endpoint\n\t * site.addRoute(\"/api/time\", {\n\t * server: { get: async () => ok({ time: Date.now() }) },\n\t * });\n\t * @example\n\t * // A root layout, server hook, and error page\n\t * site.addRoute(\"/\", {\n\t * layout: \"./src/Layout.torp\",\n\t * hookServer: { enter: async (event) => {} },\n\t * error: \"./src/ErrorPage.torp\",\n\t * });\n\t *\n\t * @param path The route path, e.g. `/` or `/about`\n\t * @param options File paths and/or inline endpoints for the route\n\t * @param subFolder An optional subFolder for grouping routes\n\t */\n\taddRoute(\n\t\tpath: string,\n\t\toptions: {\n\t\t\tpage?: string;\n\t\t\tpageServer?: string | PageServerEndPoint;\n\t\t\tserver?: string | ServerEndPoint;\n\t\t\tlayout?: string;\n\t\t\tlayoutServer?: string | PageServerEndPoint;\n\t\t\thookServer?: string | ServerHook;\n\t\t\terror?: string;\n\t\t},\n\t\tsubFolder?: string,\n\t): void {\n\t\tlet normalizedSubFolder = subFolder;\n\t\tif (normalizedSubFolder !== undefined && !normalizedSubFolder.startsWith(\"/\")) {\n\t\t\tnormalizedSubFolder = \"/\" + normalizedSubFolder;\n\t\t}\n\n\t\t// The base path with any trailing slash stripped, so that we can\n\t\t// append \"/_layout\", \"/~server\" etc. For the root \"/\" this is \"\".\n\t\tlet base = path.replace(/\\/$/, \"\");\n\n\t\tif (options.page !== undefined) {\n\t\t\tthis.#pushRoute(path, PAGE_ROUTE, options.page, normalizedSubFolder);\n\t\t}\n\t\tif (options.pageServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/~server`,\n\t\t\t\tPAGE_SERVER_ROUTE,\n\t\t\t\toptions.pageServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.server !== undefined) {\n\t\t\tthis.#pushRoute(path, SERVER_ROUTE, options.server, normalizedSubFolder);\n\t\t}\n\t\tif (options.layout !== undefined) {\n\t\t\tthis.#pushRoute(`${base}/_layout`, LAYOUT_ROUTE, options.layout, normalizedSubFolder);\n\t\t}\n\t\tif (options.layoutServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/_layout/~server`,\n\t\t\t\tLAYOUT_SERVER_ROUTE,\n\t\t\t\toptions.layoutServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.hookServer !== undefined) {\n\t\t\tthis.#pushRoute(\n\t\t\t\t`${base}/_hook/~server`,\n\t\t\t\tHOOK_SERVER_ROUTE,\n\t\t\t\toptions.hookServer,\n\t\t\t\tnormalizedSubFolder,\n\t\t\t);\n\t\t}\n\t\tif (options.error !== undefined) {\n\t\t\tthis.#pushRoute(`${base}/_error`, ERROR_ROUTE, options.error, normalizedSubFolder);\n\t\t}\n\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Pushes a single route entry, handling both file-path and inline-endpoint\n\t * targets. File paths are resolved relative to the site root; inline\n\t * endpoints are also stored in `inlineEndPoints` keyed by `\"path:type\"`\n\t * so the manifest plugin can resolve them at build time.\n\t *\n\t * If a route with the same path and type was already added, it is\n\t * replaced, so that running a plugin twice (config load and server\n\t * startup) doesn't add duplicate routes.\n\t */\n\t#pushRoute(\n\t\troutePath: string,\n\t\ttype: RouteType,\n\t\ttarget: string | InlineEndPoint,\n\t\tsubFolder?: string,\n\t): void {\n\t\tconst index = this.routes.findIndex((r) => r.path === routePath && r.type === type);\n\t\tif (typeof target === \"string\") {\n\t\t\tlet file = fpath.relative(this.root, fpath.resolve(this.root, target));\n\t\t\tif (index >= 0) {\n\t\t\t\tthis.routes[index] = { path: routePath, file, type, subFolder };\n\t\t\t} else {\n\t\t\t\tthis.routes.push({ path: routePath, file, type, subFolder });\n\t\t\t}\n\t\t} else {\n\t\t\tlet key = `${routePath}:${type}`;\n\t\t\tthis.inlineEndPoints[key] = target;\n\t\t\tif (index >= 0) {\n\t\t\t\tthis.routes[index] = { path: routePath, endPoint: target, type, subFolder };\n\t\t\t} else {\n\t\t\t\tthis.routes.push({ path: routePath, endPoint: target, type, subFolder });\n\t\t\t}\n\t\t}\n\t}\n\n\t#sortRoutes() {\n\t\tthis.routes = this.routes.sort((a, b) => {\n\t\t\t// Sort [param]s after paths\n\t\t\t// There might be a quicker/easier way to do this\n\t\t\tfor (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {\n\t\t\t\tif (a.path[i] === \"[\" && b.path[i] !== \"[\") {\n\t\t\t\t\treturn 1;\n\t\t\t\t} else if (b.path[i] === \"[\" && a.path[i] !== \"[\") {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else if (a.path[i] === b.path[i]) {\n\t\t\t\t\t// Keep going...\n\t\t\t\t} else {\n\t\t\t\t\treturn a.path[i].localeCompare(b.path[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn a.path.length - b.path.length;\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,8 @@ const CLIENT_SYMBOL = Symbol.for("torp.Client");
|
|
|
6
6
|
const client = globalThis[CLIENT_SYMBOL] ??= {
|
|
7
7
|
router: null,
|
|
8
8
|
layoutStack: [],
|
|
9
|
-
prefetchedData: {}
|
|
9
|
+
prefetchedData: {},
|
|
10
|
+
viewTransitions: false
|
|
10
11
|
};
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/nav/reload.ts
|
|
@@ -226,7 +227,7 @@ async function navigate(rawUrl, withHydration = false) {
|
|
|
226
227
|
if (stripBaseFromUrl(new URL(document.location.href), getBasePath())?.pathname !== path) window.scrollTo(0, 0);
|
|
227
228
|
}
|
|
228
229
|
};
|
|
229
|
-
if (!withHydration && typeof document.startViewTransition === "function") document.startViewTransition(render);
|
|
230
|
+
if (!withHydration && client.viewTransitions && typeof document.startViewTransition === "function") document.startViewTransition(render);
|
|
230
231
|
else render();
|
|
231
232
|
client.prefetchedData = {};
|
|
232
233
|
return true;
|
|
@@ -242,4 +243,4 @@ async function load(path) {
|
|
|
242
243
|
//#endregion
|
|
243
244
|
export { client as a, reload as i, navigate as n, loadData as r, load as t };
|
|
244
245
|
|
|
245
|
-
//# sourceMappingURL=load-
|
|
246
|
+
//# sourceMappingURL=load-Uyj9I60p.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-Uyj9I60p.mjs","names":[],"sources":["../src/state/client.ts","../src/nav/reload.ts","../src/nav/formSubmit.ts","../src/nav/loadData.ts","../src/nav/navigate.ts","../src/nav/load.ts"],"sourcesContent":["import type ClientState from \"../types/ClientState\";\n\nconst CLIENT_SYMBOL: unique symbol = Symbol.for(\"torp.Client\");\n\nconst client: ClientState =\n\t// @ts-ignore\n\t(globalThis[CLIENT_SYMBOL] ??= {\n\t\t// @ts-ignore This will definitely, 100% get set\n\t\trouter: null,\n\t\tlayoutStack: [],\n\t\t// TODO: Probably expire after 30 seconds or something?\n\t\tprefetchedData: {},\n\t\tviewTransitions: false,\n\t});\n\nexport default client;\n","import navigate from \"./navigate\";\n\n/**\n * Reloads data for the currently loaded page and rerenders it.\n */\nexport default async function reload(): Promise<boolean> {\n\tconst url = new URL(document.location.href);\n\treturn await navigate(url);\n}\n","import $page from \"../state/$page\";\nimport load from \"./load\";\nimport reload from \"./reload\";\n\nexport default async function formSubmit(e: SubmitEvent): Promise<void> {\n\t// We'll take it from here\n\te.preventDefault();\n\n\t// Reset $page on submit and link navigation\n\t// TODO: Should we put data in $page.data??\n\t$page.form = undefined;\n\n\t// Perform a POST fetch to the form's action location\n\tconst form = e.target as HTMLFormElement;\n\tconst button = e.submitter as HTMLButtonElement;\n\t// HACK: submit buttons have their formAction set to the current page if not\n\t// set, so we can't just check whether it's empty and fallback to form action\n\t//const action = button?.formAction ?? form.action;\n\tlet action = form.action || document.URL;\n\tif (button && button.formAction && button.formAction !== document.URL) {\n\t\taction = button.formAction;\n\t}\n\tconst options = {\n\t\tbody: new FormData(form),\n\t\tmethod: \"POST\",\n\t\tmode: \"cors\",\n\t\tcredentials: \"same-origin\",\n\t\t// Add a special header which tells the server that we want the raw\n\t\t// error response (if applicable) rather than the reloaded page that you\n\t\t// would get if submitting a page without javascript\n\t\theaders: {\n\t\t\t\"X-Torpor-Form-Submit\": \"\",\n\t\t},\n\t};\n\tconst response = await fetch(\n\t\taction,\n\t\t// @ts-ignore -- don't know what it's complaining about here\n\t\toptions,\n\t);\n\n\tif (\n\t\tresponse.status === 200 &&\n\t\tresponse.headers.has(\"Content-Disposition\") &&\n\t\t/attachment;\\s*filename=\"(.+?)\"/.test(response.headers.get(\"Content-Disposition\")!)\n\t) {\n\t\t// TODO: Is this enough to check to see if we have a file that should download?\n\t\t// Download the file by creating a dummy <a> and clicking it\n\t\tconst downloadFileName =\n\t\t\tresponse.headers.get(\"Content-Disposition\")?.match(/attachment;\\s*filename=\"(.+?)\"/)![1] ??\n\t\t\t\"file\";\n\t\tconst downloadLink = document.createElement(\"a\");\n\t\tdownloadLink.href = window.URL.createObjectURL(await response.blob());\n\t\tdownloadLink.download = downloadFileName;\n\t\tdownloadLink.click();\n\t} else if (response.status === 200 && response.headers.has(\"X-Torpor-Form-Redirect\")) {\n\t\t// TODO: Should do the correct type of redirect e.g. seeOther etc\n\t\tconst redirect = response.headers.get(\"Location\")!;\n\t\tawait load(redirect);\n\t\twindow.location.href = redirect;\n\t} else if (\n\t\t(response.status >= 200 && response.status <= 299) ||\n\t\t(response.status >= 400 && response.status <= 499)\n\t) {\n\t\t// Put the response into `$page.form`, and it will be put into `$props` in reload\n\t\tif (response.headers.get(\"Content-Type\") === \"application/json\") {\n\t\t\t$page.form = await response.json();\n\t\t}\n\t\tawait reload();\n\t}\n}\n","import client from \"../state/client\";\nimport { getBasePath } from \"../site/basePath\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport type RouteHandler from \"../types/RouteHandler\";\n\nexport default async function loadData(\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\tpath: string,\n\tquery: URLSearchParams,\n\tnewLayoutStack: LayoutPath[],\n\tclientEndPoint: PageEndPoint | undefined,\n\tserverEndPoint: PageServerEndPoint | undefined,\n\tprefetch = false,\n): Promise<Record<string, string> | void> {\n\tlet data = {};\n\tif (handler.layouts) {\n\t\tlet layoutStack = client.layoutStack;\n\t\tfor (let [i, layout] of handler.layouts.entries()) {\n\t\t\tlet layoutPath = layout.path;\n\t\t\tfor (let key in params) {\n\t\t\t\tlayoutPath = layoutPath.replace(`[${key}]`, params[key]);\n\t\t\t}\n\t\t\tif (layoutStack.at(i)?.path === layoutPath) {\n\t\t\t\t// We've already loaded this layout, we can just re-use its data and UI\n\t\t\t\tif (!prefetch) {\n\t\t\t\t\tlayoutStack[i].reuse = true;\n\t\t\t\t}\n\t\t\t\tnewLayoutStack[i] = layoutStack[i];\n\t\t\t\tObject.assign(data, layoutStack[i].data);\n\t\t\t} else {\n\t\t\t\tconst stackLayout = { path: layoutPath, data: {}, reuse: false, slotRegion: null };\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\tstackLayout.data,\n\t\t\t\t\tdocument.location.origin + getBasePath() + layoutPath,\n\t\t\t\t\tquery,\n\t\t\t\t\tparams,\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;\n\t\t\t\t}\n\t\t\t\tObject.assign(data, stackLayout.data);\n\t\t\t\tnewLayoutStack.push(stackLayout);\n\t\t\t}\n\t\t}\n\t}\n\tlet endPointResponse = await loadClientAndServerData(\n\t\tdata,\n\t\tdocument.location.origin + getBasePath() + path,\n\t\tquery,\n\t\tparams,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tif (endPointResponse?.ok === false) {\n\t\treturn;\n\t}\n\treturn data;\n}\n\nasync function loadClientAndServerData(\n\tdata: Record<string, any>,\n\tlocation: string,\n\tquery: URLSearchParams,\n\tparams: Record<string, string>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n): Promise<Response | undefined | void> {\n\tlet prefetchedData = client.prefetchedData;\n\n\tif (clientEndPoint?.load) {\n\t\tconst clientKey = location + (query.size > 0 ? `?${query}` : \"\");\n\t\tif (prefetchedData[clientKey]) {\n\t\t\tObject.assign(data, prefetchedData[clientKey]);\n\t\t} else {\n\t\t\tconst clientUrl = new URL(document.location.href);\n\t\t\tfor (let [name, value] of query) {\n\t\t\t\tclientUrl.searchParams.append(name, value);\n\t\t\t}\n\t\t\tconst clientParams = buildClientParams(clientUrl, params, data);\n\t\t\tconst clientResponse = await clientEndPoint.load(clientParams);\n\t\t\tif (clientResponse) {\n\t\t\t\tif (clientResponse.ok) {\n\t\t\t\t\tif (clientResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\t\tconst clientData = await clientResponse.json();\n\t\t\t\t\t\tObject.assign(data, clientData);\n\t\t\t\t\t\tprefetchedData[clientKey] = clientData;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn clientResponse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (serverEndPoint?.load) {\n\t\tconst serverLocation = location.replace(/\\/$/, \"\") + \"/~server\";\n\t\tconst serverKey = serverLocation + (query.size > 0 ? `?${query}` : \"\");\n\t\tif (prefetchedData[serverKey]) {\n\t\t\tObject.assign(data, prefetchedData[serverKey]);\n\t\t} else {\n\t\t\tconst serverUrl = new URL(serverLocation);\n\t\t\tfor (let [name, value] of query) {\n\t\t\t\tserverUrl.searchParams.append(name, value);\n\t\t\t}\n\t\t\tconst serverResponse = await fetch(serverUrl);\n\t\t\tif (serverResponse) {\n\t\t\t\tif (serverResponse.ok) {\n\t\t\t\t\tif (serverResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\t\tconst serverData = await serverResponse.json();\n\t\t\t\t\t\tObject.assign(data, serverData);\n\t\t\t\t\t\tprefetchedData[serverKey] = serverData;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn serverResponse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction buildClientParams(url: URL, params: Record<string, string>, data: Record<string, any>) {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tdata,\n\t};\n}\n","import { clearLayoutSlot, fillLayoutSlot, hydrate } from \"@torpor/view\";\nimport { type Component, type SlotRender } from \"@torpor/view\";\nimport { mount, unmount } from \"@torpor/view\";\nimport $page from \"../state/$page\";\nimport client from \"../state/client\";\nimport { getBasePath, stripBaseFromUrl } from \"../site/basePath\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport formSubmit from \"./formSubmit\";\nimport loadData from \"./loadData\";\n\n// @ts-ignore\nexport default async function navigate(rawUrl: URL, withHydration = false): Promise<boolean> {\n\tlet parent = document.getElementById(\"app\");\n\tif (!parent) {\n\t\t// TODO: 500\n\t\tconsole.log(\"500\");\n\t\treturn false;\n\t}\n\n\t// The base path is stripped before matching (routes are base-free), but\n\t// kept in browser state: the caller pushes the original URL. When the\n\t// url doesn't carry the base there will be no matching route anyway\n\tconst url = stripBaseFromUrl(rawUrl, getBasePath()) ?? rawUrl;\n\tconst path = url.pathname;\n\tconst query = url.searchParams;\n\n\t//console.log(`navigating to '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\tconst route = client.router.match(path, query);\n\tif (!route) {\n\t\t// TODO: 404\n\t\tconsole.log(\"404\");\n\t\treturn false;\n\t}\n\n\t// Update $page before building the components\n\t$page.url = url;\n\tif (path.endsWith(\"/_error\")) {\n\t\t$page.status = parseInt(query.get(\"status\") ?? \"404\");\n\t\t$page.error = { message: query.get(\"message\") ?? \"\" };\n\t\t// Make it look a bit classier by removing the query -- keeping the\n\t\t// original URL, so the base path stays in the address bar\n\t\twindow.history.replaceState({}, \"\", rawUrl.toString().split(\"?\")[0]);\n\t} else {\n\t\t$page.status = 200;\n\t}\n\tconst handler = route.handler;\n\tconst params = route.params || {};\n\n\t// There must be a client endpoint with a component\n\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\tif (!clientEndPoint?.component) {\n\t\t// TODO: 404\n\t\tconsole.log(\"404\");\n\t\treturn false;\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\tlet newLayoutStack: LayoutPath[] = [];\n\n\t// Pass the data into $props\n\t// TODO: Don't load if this is the first time -- it should have been passed\n\t// to us, somehow...\n\tconst data = await loadData(\n\t\thandler,\n\t\tparams,\n\t\tpath,\n\t\tquery,\n\t\tnewLayoutStack,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tif (data === undefined) {\n\t\t// The data couldn't be loaded -- a load function returned an error\n\t\t// response, or (on a prerendered site with no server) the ~server\n\t\t// request got a 404. Leave the current page alone; the caller\n\t\t// (e.g. the client entry) falls back to a full page load\n\t\treturn false;\n\t}\n\t// We may have form data in a hidden input -- not sure if this is the best\n\t// way to do it\n\tlet formInput = document.getElementById(\"t-form-data\") as HTMLInputElement;\n\tlet form: Record<string, string> | undefined;\n\tif (formInput) {\n\t\tform = JSON.parse(formInput.value);\n\t\t$page.form = form;\n\t\tformInput.remove();\n\t}\n\tlet $props: Record<string, any> = { data };\n\n\t// We may have form data in $page.form, either from the hidden input\n\t// (above), or added via onformsubmit (below)\n\t$props.form = $page.form;\n\n\t// Add some special context for submitting Forms client-side\n\tconst $context = {\n\t\tTorporBuildContext: { onformsubmit: formSubmit },\n\t};\n\n\tclient.layoutStack.push({ path: route.handler.path, data: {}, reuse: false, slotRegion: null });\n\tclient.layoutStack = newLayoutStack;\n\tlet layoutStack = client.layoutStack;\n\n\t// If there are layouts, work our way upwards, pushing each component into\n\t// the default slot of its parent\n\t// TODO: There's probably a nicer way to do this with reducers or something\n\tlet component = clientEndPoint.component as Component;\n\tlet slots: Record<string, SlotRender> | undefined = undefined;\n\tlet reused = false;\n\t// The index of the innermost reused layout. Its slotRegion is the region\n\t// that must be cleared and refilled (it contains the next layout's or the\n\t// page's content). This is usually the last entry of the stack, but not\n\t// when an outer layout is reused while an inner one is new — e.g.\n\t// navigating between sections that share the root layout.\n\tlet reusedIndex = -1;\n\tif (handler.layouts) {\n\t\tlet slotFunctions: SlotRender[] = [];\n\t\t// The last slot function will render the client component\n\t\tslotFunctions[handler.layouts.length] = function clientComponent(parent, anchor) {\n\t\t\tlet i = layoutStack.length - 1;\n\t\t\tlayoutStack[i].slotRegion = fillLayoutSlot(\n\t\t\t\tclientEndPoint.component!,\n\t\t\t\tslotFunctions[i + 1],\n\t\t\t\tparent,\n\t\t\t\tanchor,\n\t\t\t\t$props,\n\t\t\t\t$context,\n\t\t\t);\n\t\t};\n\n\t\t// Each earlier slot function will render a layout\n\t\tfor (let i = handler.layouts.length - 1; i >= 0; i--) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())\n\t\t\t\t?.default;\n\t\t\tif (layoutEndPoint?.component) {\n\t\t\t\tif (layoutStack[i].reuse) {\n\t\t\t\t\t// Reuse this layout — clear and refill its slot (done in\n\t\t\t\t\t// the try block below so a failure doesn't leave the slot\n\t\t\t\t\t// half-cleared)\n\t\t\t\t\tcomponent = slotFunctions[i + 1] as Component;\n\t\t\t\t\treusedIndex = i;\n\t\t\t\t\treused = true;\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (i === 0) {\n\t\t\t\t\tcomponent = layoutEndPoint.component as Component;\n\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t} else {\n\t\t\t\t\tslotFunctions[i] = function layoutComponent(parent, anchor, _, $context) {\n\t\t\t\t\t\tlayoutStack[i - 1].slotRegion = fillLayoutSlot(\n\t\t\t\t\t\t\tlayoutEndPoint.component!,\n\t\t\t\t\t\t\tslotFunctions[i + 1],\n\t\t\t\t\t\t\tparent,\n\t\t\t\t\t\t\tanchor,\n\t\t\t\t\t\t\t$props,\n\t\t\t\t\t\t\t$context,\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\t}\n\n\t// A definite alias, so that the render closure's type checks hold\n\tlet app: HTMLElement = parent;\n\t// The DOM update, wrapped by the view transitions API when navigating\n\t// (but not on the initial hydration)\n\tconst render = () => {\n\t\ttry {\n\t\t\tif (reused) {\n\t\t\t\t// The layout is being reused — clear the old slot content, then\n\t\t\t\t// call the slot function directly to fill it with the new page.\n\t\t\t\t// We must not go through `mount` here: the slot's container still\n\t\t\t\t// holds the layout's own children (e.g. a header), which `mount`\n\t\t\t\t// refuses to mount into. Both the clear and the fill are inside\n\t\t\t\t// the try so that a failure doesn't leave the slot half-cleared.\n\t\t\t\tconst slotRegion = layoutStack[reusedIndex].slotRegion;\n\t\t\t\tapp = slotRegion.startNode!.parentNode as HTMLElement;\n\t\t\t\tclearLayoutSlot(slotRegion);\n\t\t\t\tcomponent(app, null);\n\t\t\t} else if (withHydration) {\n\t\t\t\thydrate(app, component, $props, slots);\n\t\t\t} else {\n\t\t\t\t// The layout chain changed (or there was no previous layout to\n\t\t\t\t// reuse): tear down the previous UI entirely — disposing its\n\t\t\t\t// region tree and clearing `#app` — so `mount` starts fresh.\n\t\t\t\t// Without this, `mount` throws because `#app` still holds the\n\t\t\t\t// previous render's children, and it would reuse a stale root\n\t\t\t\t// region.\n\t\t\t\tunmount(app);\n\t\t\t\tmount(app, component, $props, slots);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// TODO: Show a proper Error component\n\t\t\tapp.innerHTML = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\t\tconsole.log(error);\n\t\t}\n\n\t\tif (!withHydration) {\n\t\t\t// Scroll back to the top when moving to a different page; keep the\n\t\t\t// scroll position for same-page navigations (query changes,\n\t\t\t// re-renders after form actions)\n\t\t\tconst current = stripBaseFromUrl(new URL(document.location.href), getBasePath())?.pathname;\n\t\t\tif (current !== path) {\n\t\t\t\twindow.scrollTo(0, 0);\n\t\t\t}\n\t\t}\n\t};\n\n\tif (\n\t\t!withHydration &&\n\t\tclient.viewTransitions &&\n\t\ttypeof document.startViewTransition === \"function\"\n\t) {\n\t\tdocument.startViewTransition(render);\n\t} else {\n\t\trender();\n\t}\n\n\t// Reset prefetched data on each navigation\n\tclient.prefetchedData = {};\n\n\treturn true;\n}\n","import navigate from \"./navigate\";\n\n/**\n * Loads and renders the page at the supplied path.\n */\nexport default async function load(path: string): Promise<boolean> {\n\tconst url = new URL(path, document.location.href);\n\treturn await navigate(url);\n}\n"],"mappings":"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"}
|
package/dist/nav.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as getBasePath, t as addBaseToPath } from "./basePath-DQnbHc7o.mjs";
|
|
2
|
-
import { i as reload, t as load } from "./load-
|
|
2
|
+
import { i as reload, t as load } from "./load-Uyj9I60p.mjs";
|
|
3
3
|
//#region src/nav/route.ts
|
|
4
4
|
/**
|
|
5
5
|
* Builds a route path in a type-safe manner, filling in dynamic segments, e.g.
|
package/dist/openapi.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as StandardSchemaV1 } from "./StandardSchema-D28L8_zZ.mjs";
|
|
2
|
-
import { h as SitePlugin } from "./Site-
|
|
2
|
+
import { h as SitePlugin } from "./Site-CQ29Opvm.mjs";
|
|
3
3
|
//#region src/openapi/types.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A JSON Schema object, as produced by a schema library's converter (e.g.
|
package/dist/run.d.mts
CHANGED
package/dist/run.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.mts","names":[],"sources":["../src/run/run.ts","../src/run/runBuild.ts","../src/run/runDev.ts","../src/run/runOpenApi.ts","../src/run/runPreview.ts"],"mappings":";;;iBAyD8B,IAC7B,gBACA,oCACE;;;
|
|
1
|
+
{"version":3,"file":"run.d.mts","names":[],"sources":["../src/run/run.ts","../src/run/runBuild.ts","../src/run/runDev.ts","../src/run/runOpenApi.ts","../src/run/runPreview.ts"],"mappings":";;;iBAyD8B,IAC7B,gBACA,oCACE;;;iBC1C2B,SAAS,MAAM,OAAO;;;iBCYtB,OAAO,MAAM,OAAO;;;;;;;;iBChBpB,WAC7B,MAAM,MACN,MAAM,eACN,mBACE;;;iBCR2B,WAAW,MAAM,OAAO"}
|
package/dist/run.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as runDev, i as runPreview, o as runBuild, r as run, t as runOpenApi } from "./runOpenApi-
|
|
1
|
+
import { a as runDev, i as runPreview, o as runBuild, r as run, t as runOpenApi } from "./runOpenApi-DWfPiAv0.mjs";
|
|
2
2
|
export { run, runBuild, runDev, runOpenApi, runPreview };
|
|
@@ -10,10 +10,9 @@ import fs, { existsSync, promises, readFileSync, readdirSync, realpathSync, rmSy
|
|
|
10
10
|
import fpath from "node:path";
|
|
11
11
|
import { build, createServer, defineConfig } from "vite";
|
|
12
12
|
import torpor from "@torpor/unplugin/vite";
|
|
13
|
+
import { configDotenv } from "dotenv";
|
|
13
14
|
import { parse } from "@torpor/view/compile";
|
|
14
15
|
import { pathToFileURL } from "node:url";
|
|
15
|
-
import estorpor from "@torpor/unplugin/esbuild";
|
|
16
|
-
import { configDotenv } from "dotenv";
|
|
17
16
|
import { Readable } from "node:stream";
|
|
18
17
|
import { createHash } from "node:crypto";
|
|
19
18
|
import { writeFile } from "node:fs/promises";
|
|
@@ -566,6 +565,7 @@ ${openApiGlue}
|
|
|
566
565
|
${sitemapGlue}
|
|
567
566
|
export default {
|
|
568
567
|
base: ${JSON.stringify(base)},
|
|
568
|
+
viewTransitions: ${!!site.viewTransitions},
|
|
569
569
|
${serverRequest && hasMiddleware ? "middleware: __site.middleware ?? []," : ""}
|
|
570
570
|
routes: [
|
|
571
571
|
${site.routes.map((r) => {
|
|
@@ -635,8 +635,10 @@ async function __openApiGet() {
|
|
|
635
635
|
* leave raw `.torp` imports that neither Node nor workerd can load.
|
|
636
636
|
*
|
|
637
637
|
* A package is a torpor package when it declares a `torpor` entry in its
|
|
638
|
-
* package.json
|
|
639
|
-
*
|
|
638
|
+
* package.json, or when any of its export targets is a `.torp` file. The
|
|
639
|
+
* entry is usually a path (`"torpor": "./lib/index.js"`, mirroring the
|
|
640
|
+
* `svelte` field convention), but packages that ship compiled output can
|
|
641
|
+
* just mark themselves with `"torpor": true`.
|
|
640
642
|
*
|
|
641
643
|
* @param siteRoot The root folder of the site
|
|
642
644
|
* @returns The names of the torpor packages found (may be empty)
|
|
@@ -690,7 +692,7 @@ function collectTorporPackage(name, require, packages, visited) {
|
|
|
690
692
|
for (const depName of dependencyNames$1(pkg)) collectTorporPackage(depName, depRequire, packages, visited);
|
|
691
693
|
}
|
|
692
694
|
function isTorporPackage(pkg) {
|
|
693
|
-
if (typeof pkg.torpor === "string") return true;
|
|
695
|
+
if (pkg.torpor === true || typeof pkg.torpor === "string") return true;
|
|
694
696
|
return exportsIncludeTorp(pkg.exports);
|
|
695
697
|
}
|
|
696
698
|
function exportsIncludeTorp(exports) {
|
|
@@ -954,6 +956,7 @@ async function responseStatus(response) {
|
|
|
954
956
|
//#endregion
|
|
955
957
|
//#region src/run/runBuild.ts
|
|
956
958
|
async function runBuild(site) {
|
|
959
|
+
configDotenv();
|
|
957
960
|
let errorCount = reportRouteIssues(checkRoutes(site));
|
|
958
961
|
errorCount += reportRouteIssues(checkApiCalls(site));
|
|
959
962
|
errorCount += reportRouteIssues(checkLayoutSlots(site));
|
|
@@ -1337,7 +1340,7 @@ async function runDev(site) {
|
|
|
1337
1340
|
config.optimizeDeps.extensions ??= [];
|
|
1338
1341
|
config.optimizeDeps.extensions.push(".torp");
|
|
1339
1342
|
config.optimizeDeps.rolldownOptions ??= {};
|
|
1340
|
-
config.optimizeDeps.rolldownOptions.plugins ??= [
|
|
1343
|
+
config.optimizeDeps.rolldownOptions.plugins ??= [torpor()];
|
|
1341
1344
|
addTorporPackageConfig(site.root, config);
|
|
1342
1345
|
clearStaleDepCache(site.root, (message) => console.log(`\n${message}`));
|
|
1343
1346
|
reportStaleTorpCopies(site.root, (message) => console.log(`\n${message}`));
|
|
@@ -1622,4 +1625,4 @@ async function runOpenApi(site, vite, outFile = "openapi.json") {
|
|
|
1622
1625
|
//#endregion
|
|
1623
1626
|
export { runDev as a, runPreview as i, loadSite as n, runBuild as o, run as r, runOpenApi as t };
|
|
1624
1627
|
|
|
1625
|
-
//# sourceMappingURL=runOpenApi-
|
|
1628
|
+
//# sourceMappingURL=runOpenApi-DWfPiAv0.mjs.map
|