@torpor/build 0.1.12 → 0.1.14

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{Server-DhJ1nRFR.d.cts → Server-BC_dixZQ.d.cts} +5 -6
  3. package/dist/{Server-DhJ1nRFR.d.ts → Server-BC_dixZQ.d.ts} +5 -6
  4. package/dist/{Site-CM2pZtq6.d.cts → Site-BeRKXeJ4.d.cts} +7 -1
  5. package/dist/{Site-BB6kV7wC.d.ts → Site-D70KrWlY.d.ts} +7 -1
  6. package/dist/bin/index.cjs +14 -23
  7. package/dist/bin/index.cjs.map +1 -1
  8. package/dist/bin/index.js +5 -3
  9. package/dist/bin/index.js.map +1 -1
  10. package/dist/chunk-2QQN3D3K.js +50 -0
  11. package/dist/chunk-2QQN3D3K.js.map +1 -0
  12. package/dist/chunk-65K3R3CP.js +150 -0
  13. package/dist/chunk-65K3R3CP.js.map +1 -0
  14. package/dist/{chunk-VAGHGWM5.js → chunk-D6LHMH2C.js} +5 -47
  15. package/dist/chunk-D6LHMH2C.js.map +1 -0
  16. package/dist/chunk-EVBUHZGK.js +85 -0
  17. package/dist/chunk-EVBUHZGK.js.map +1 -0
  18. package/dist/{chunk-YU2SSD7E.js → chunk-FMRCLIWE.js} +4 -83
  19. package/dist/chunk-FMRCLIWE.js.map +1 -0
  20. package/dist/chunk-WMHM5RGZ.js +15 -0
  21. package/dist/chunk-WMHM5RGZ.js.map +1 -0
  22. package/dist/{chunk-GHXCJ52Z.js → chunk-XLNPB3GH.js} +17 -26
  23. package/dist/chunk-XLNPB3GH.js.map +1 -0
  24. package/dist/index.cjs +6 -0
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +8 -9
  27. package/dist/index.d.ts +8 -9
  28. package/dist/index.js +16 -137
  29. package/dist/index.js.map +1 -1
  30. package/dist/metafile-cjs.json +1 -1
  31. package/dist/metafile-esm.json +1 -1
  32. package/dist/response.cjs.map +1 -1
  33. package/dist/response.js +8 -6
  34. package/dist/run.cjs +14 -23
  35. package/dist/run.cjs.map +1 -1
  36. package/dist/run.d.cts +2 -2
  37. package/dist/run.d.ts +2 -2
  38. package/dist/run.js +5 -3
  39. package/dist/server.cjs.map +1 -1
  40. package/dist/server.d.cts +2 -2
  41. package/dist/server.d.ts +2 -2
  42. package/dist/server.js +6 -4
  43. package/dist/state.cjs.map +1 -1
  44. package/dist/state.d.cts +2 -1
  45. package/dist/state.d.ts +2 -1
  46. package/dist/state.js +3 -10
  47. package/dist/state.js.map +1 -1
  48. package/dist/test.cjs +519 -0
  49. package/dist/test.cjs.map +1 -0
  50. package/dist/test.d.cts +8 -0
  51. package/dist/test.d.ts +8 -0
  52. package/dist/test.js +227 -0
  53. package/dist/test.js.map +1 -0
  54. package/package.json +11 -6
  55. package/src/response/response.ts +1 -1
  56. package/src/server/CookieHelper.ts +2 -2
  57. package/src/server/HeaderHelper.ts +2 -2
  58. package/src/server/Routerx.ts +7 -2
  59. package/src/server/Server.ts +6 -1
  60. package/src/server/ServerEvent.ts +1 -1
  61. package/src/server/contentType.ts +1 -1
  62. package/src/site/Router.ts +9 -3
  63. package/src/site/Site.ts +8 -2
  64. package/src/site/prepareTemplate.ts +1 -1
  65. package/src/site/run.ts +9 -7
  66. package/src/site/runBuild.ts +9 -14
  67. package/src/site/runDev.ts +3 -8
  68. package/src/site/runPreview.ts +1 -1
  69. package/src/site/serverEntry.ts +1 -1
  70. package/src/state/$page.ts +6 -1
  71. package/src/test/runTest.ts +314 -0
  72. package/src/test.ts +3 -0
  73. package/tsup.config.ts +8 -2
  74. package/vitest.config.ts +2 -2
  75. package/dist/chunk-GHXCJ52Z.js.map +0 -1
  76. package/dist/chunk-VAGHGWM5.js.map +0 -1
  77. package/dist/chunk-YU2SSD7E.js.map +0 -1
package/dist/test.js ADDED
@@ -0,0 +1,227 @@
1
+ import {
2
+ HOOK_ROUTE,
3
+ HOOK_SERVER_ROUTE,
4
+ LAYOUT_ROUTE,
5
+ LAYOUT_SERVER_ROUTE,
6
+ PAGE_ROUTE,
7
+ PAGE_SERVER_ROUTE,
8
+ Router,
9
+ SERVER_ROUTE
10
+ } from "./chunk-65K3R3CP.js";
11
+ import {
12
+ page_default
13
+ } from "./chunk-WMHM5RGZ.js";
14
+ import {
15
+ notFound,
16
+ ok,
17
+ seeOther
18
+ } from "./chunk-2QQN3D3K.js";
19
+ import {
20
+ ServerEvent
21
+ } from "./chunk-EVBUHZGK.js";
22
+ import "./chunk-SJVHHGVW.js";
23
+
24
+ // src/test/runTest.ts
25
+ import path from "node:path";
26
+ async function runTest(site, route) {
27
+ if (!route.startsWith("/")) route += "/";
28
+ const req = new Request(`http://localhost${route}`);
29
+ const ev = new ServerEvent(req);
30
+ const router = new Router();
31
+ router.addPages(
32
+ site.routes.map((r) => ({
33
+ path: r.path,
34
+ type: r.type,
35
+ endPoint: () => import(
36
+ /* @vite-ignore */
37
+ path.join(site.root, r.file)
38
+ )
39
+ }))
40
+ );
41
+ return await load(router, ev, "%COMPONENT_HTML%");
42
+ }
43
+ async function load(router, ev, template) {
44
+ const url = new URL(ev.request.url);
45
+ const path2 = url.pathname;
46
+ const query = url.searchParams;
47
+ const route = router.match(path2, query);
48
+ if (!route) {
49
+ return notFound();
50
+ }
51
+ page_default.url = url;
52
+ const handler = route.handler;
53
+ const params = route.params || {};
54
+ switch (handler.type) {
55
+ case PAGE_ROUTE:
56
+ case LAYOUT_ROUTE: {
57
+ if (ev.request.method === "GET") {
58
+ return await loadView(ev, url, handler, params, template);
59
+ } else if (ev.request.method === "POST") {
60
+ return await runAction(ev, url, handler, params, query);
61
+ }
62
+ break;
63
+ }
64
+ case PAGE_SERVER_ROUTE:
65
+ case LAYOUT_SERVER_ROUTE: {
66
+ if (ev.request.method === "GET") {
67
+ return await loadData(ev, url, handler, "load", params);
68
+ }
69
+ break;
70
+ }
71
+ case SERVER_ROUTE: {
72
+ const functionName = ev.request.method.toLowerCase().replace("delete", "del");
73
+ return await loadData(ev, url, handler, functionName, params);
74
+ }
75
+ case HOOK_ROUTE:
76
+ case HOOK_SERVER_ROUTE: {
77
+ break;
78
+ }
79
+ }
80
+ return notFound();
81
+ }
82
+ async function loadData(ev, url, handler, functionName, params) {
83
+ const serverEndPoint = (await handler.endPoint()).default;
84
+ if (serverEndPoint && serverEndPoint[functionName]) {
85
+ const serverParams = buildServerParams(ev, url, params);
86
+ if (handler.serverHook) {
87
+ const serverHook = (await handler.serverHook()).default;
88
+ if (serverHook?.handle) {
89
+ await serverHook.handle(serverParams);
90
+ }
91
+ }
92
+ const result = await serverEndPoint[functionName](serverParams);
93
+ return result || ok();
94
+ }
95
+ return notFound();
96
+ }
97
+ async function loadView(ev, url, handler, params, template) {
98
+ const clientEndPoint = (await handler.endPoint()).default;
99
+ if (!clientEndPoint?.component) {
100
+ return notFound();
101
+ }
102
+ const serverEndPoint = handler.serverEndPoint && (await handler.serverEndPoint())?.default;
103
+ const serverParams = buildServerParams(ev, url, params);
104
+ if (handler.serverHook) {
105
+ const serverHook = (await handler.serverHook()).default;
106
+ if (serverHook?.handle) {
107
+ await serverHook.handle(serverParams);
108
+ }
109
+ }
110
+ let data = {};
111
+ if (handler.layouts) {
112
+ for (let layout of handler.layouts) {
113
+ const layoutEndPoint = (await layout.endPoint())?.default;
114
+ const layoutServerEndPoint = layout.serverEndPoint && (await layout.serverEndPoint())?.default;
115
+ const layoutData = await loadClientAndServerData(
116
+ url,
117
+ params,
118
+ serverParams,
119
+ data,
120
+ layoutEndPoint,
121
+ layoutServerEndPoint
122
+ );
123
+ Object.assign(data, layoutData);
124
+ }
125
+ }
126
+ let endPointData = await loadClientAndServerData(
127
+ url,
128
+ params,
129
+ serverParams,
130
+ data,
131
+ clientEndPoint,
132
+ serverEndPoint
133
+ );
134
+ Object.assign(data, endPointData);
135
+ let $props = { data };
136
+ let component = clientEndPoint.component;
137
+ let slots = void 0;
138
+ if (handler.layouts) {
139
+ let slotFunctions = [];
140
+ slotFunctions[handler.layouts.length] = (_, context) => clientEndPoint.component($props, context);
141
+ for (let i = handler.layouts.length - 1; i >= 0; i--) {
142
+ const layoutEndPoint = (await handler.layouts[i].endPoint())?.default;
143
+ if (layoutEndPoint?.component) {
144
+ if (i === 0) {
145
+ component = layoutEndPoint.component;
146
+ slots = { _: slotFunctions[i + 1] };
147
+ } else {
148
+ slotFunctions[i] = (_, context) => layoutEndPoint.component($props, context, {
149
+ _: slotFunctions[i + 1]
150
+ });
151
+ }
152
+ }
153
+ }
154
+ }
155
+ let html;
156
+ try {
157
+ html = component($props, void 0, slots);
158
+ html = template.replace("%COMPONENT_HTML%", html);
159
+ } catch (error) {
160
+ html = '<span style="color: red">Script syntax error</span><p>' + error + "</p>";
161
+ console.log(error);
162
+ }
163
+ return new Response(html, {
164
+ status: 200,
165
+ headers: {
166
+ "Content-Type": "text/html"
167
+ }
168
+ });
169
+ }
170
+ async function runAction(ev, url, handler, params, query) {
171
+ const actionName = (Array.from(query.keys())[0] || "default").replace(/^\//, "");
172
+ const serverEndPoint = handler.serverEndPoint && (await handler.serverEndPoint()).default;
173
+ if (serverEndPoint?.actions) {
174
+ const action = serverEndPoint.actions[actionName];
175
+ if (action) {
176
+ const serverParams = buildServerParams(ev, url, params);
177
+ if (handler.serverHook) {
178
+ const serverHook = (await handler.serverHook()).default;
179
+ if (serverHook?.handle) {
180
+ await serverHook.handle(serverParams);
181
+ }
182
+ }
183
+ const result = await action(serverParams);
184
+ return result || seeOther(url.pathname);
185
+ }
186
+ }
187
+ return notFound();
188
+ }
189
+ async function loadClientAndServerData(url, params, serverParams, data, clientEndPoint, serverEndPoint) {
190
+ let newData = {};
191
+ if (clientEndPoint?.load) {
192
+ const clientParams = buildClientParams(url, data, params);
193
+ const clientData = await clientEndPoint.load(clientParams);
194
+ if (clientData) {
195
+ Object.assign(newData, clientData);
196
+ }
197
+ }
198
+ if (serverEndPoint?.load) {
199
+ const serverData = await serverEndPoint.load(serverParams);
200
+ if (serverData?.ok) {
201
+ Object.assign(newData, await serverData.json());
202
+ }
203
+ }
204
+ return newData;
205
+ }
206
+ function buildClientParams(url, params, data) {
207
+ return {
208
+ url,
209
+ params,
210
+ data
211
+ };
212
+ }
213
+ function buildServerParams(ev, url, params) {
214
+ return {
215
+ url,
216
+ params,
217
+ appData: {},
218
+ request: ev.request,
219
+ cookies: ev.cookies,
220
+ headers: ev.headers,
221
+ adapter: ev.adapter
222
+ };
223
+ }
224
+ export {
225
+ runTest
226
+ };
227
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/test/runTest.ts"],"sourcesContent":["import { type ServerComponent, type ServerSlotRender } from \"@torpor/view\";\nimport path from \"node:path\";\nimport notFound from \"../response/notFound.ts\";\nimport ok from \"../response/ok.ts\";\nimport seeOther from \"../response/seeOther.ts\";\nimport ServerEvent from \"../server/ServerEvent.ts\";\nimport Router from \"../site/Router.ts\";\nimport Site from \"../site/Site\";\nimport $page from \"../state/$page.ts\";\nimport type PageEndPoint from \"../types/PageEndPoint.ts\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint.ts\";\nimport RouteHandler from \"../types/RouteHandler.ts\";\nimport {\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport type ServerEndPoint from \"../types/ServerEndPoint.ts\";\nimport type ServerHook from \"../types/ServerHook.ts\";\nimport type ServerLoadEvent from \"../types/ServerLoadEvent.ts\";\n\nexport default async function runTest(site: Site, route: string): Promise<Response> {\n\tif (!route.startsWith(\"/\")) route += \"/\";\n\tconst req = new Request(`http://localhost${route}`);\n\tconst ev = new ServerEvent(req);\n\n\t// Build the router from the Site object created by the user\n\tconst router = new Router();\n\trouter.addPages(\n\t\tsite.routes.map((r) => ({\n\t\t\tpath: r.path,\n\t\t\ttype: r.type,\n\t\t\tendPoint: () => import(/* @vite-ignore */ path.join(site.root, r.file)),\n\t\t})),\n\t);\n\n\treturn await load(router, ev, \"%COMPONENT_HTML%\");\n}\n\n// HACK: This is a copy of serverEntry\n// TODO: Make it shared instead!\nasync function load(router: Router, ev: ServerEvent, template: string): Promise<Response> {\n\t//const url = new URL(`http://${process.env.HOST ?? \"localhost\"}${ev.request.url}`);\n\tconst url = new URL(ev.request.url);\n\tconst path = url.pathname;\n\tconst query = url.searchParams;\n\n\t//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\tconst route = router.match(path, query);\n\tif (!route) {\n\t\treturn notFound();\n\t}\n\n\t// Update $page before building the components\n\t// TODO: Find somewhere better to put this\n\t$page.url = url;\n\n\tconst handler = route.handler;\n\tconst params = route.params || {};\n\n\t// TODO: Hit the server hook out here\n\t// We could maybe set data loading up as middleware on a route??????\n\n\tswitch (handler.type) {\n\t\tcase PAGE_ROUTE:\n\t\tcase LAYOUT_ROUTE: {\n\t\t\t// It's a /+page.ts or /_layout.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadView(ev, url, handler, params, template);\n\t\t\t} else if (ev.request.method === \"POST\") {\n\t\t\t\treturn await runAction(ev, url, handler, params, query);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase PAGE_SERVER_ROUTE:\n\t\tcase LAYOUT_SERVER_ROUTE: {\n\t\t\t// It's a /+page.server.ts or /_layout.server.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadData(ev, url, handler, \"load\", params);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase SERVER_ROUTE: {\n\t\t\t// It's a /+server.ts endpoint\n\t\t\tconst functionName = ev.request.method.toLowerCase().replace(\"delete\", \"del\");\n\t\t\treturn await loadData(ev, url, handler, functionName, params);\n\t\t}\n\t\tcase HOOK_ROUTE:\n\t\tcase HOOK_SERVER_ROUTE: {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadData(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tfunctionName: string,\n\tparams: Record<string, string>,\n) {\n\tconst serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint()).default;\n\tif (serverEndPoint && serverEndPoint[functionName]) {\n\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\tif (handler.serverHook) {\n\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\tif (serverHook?.handle) {\n\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t}\n\t\t}\n\n\t\tconst result = await serverEndPoint[functionName](serverParams);\n\n\t\t// If there was no response returned from load (such as errors or a\n\t\t// redirect), send an ok response\n\t\treturn result || ok();\n\t}\n\n\treturn notFound();\n}\n\nasync function loadView(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\ttemplate: string,\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\treturn notFound();\n\t}\n\n\t// There may be a server endpoint\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t// Maybe hit the server hook\n\tconst serverParams = buildServerParams(ev, url, params);\n\tif (handler.serverHook) {\n\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\tif (serverHook?.handle) {\n\t\t\tawait serverHook.handle(serverParams);\n\t\t}\n\t}\n\n\t// Pass the data into $props\n\t// TODO: Promise.all\n\t// NOTE: We're loading data from top to bottom, overriding as we go, and I'm not sure if this is the best way to go\n\tlet data = {};\n\tif (handler.layouts) {\n\t\tfor (let layout of handler.layouts) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;\n\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\tconst layoutData = await loadClientAndServerData(\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tserverParams,\n\t\t\t\tdata,\n\t\t\t\tlayoutEndPoint,\n\t\t\t\tlayoutServerEndPoint,\n\t\t\t);\n\t\t\tObject.assign(data, layoutData);\n\t\t}\n\t}\n\tlet endPointData = await loadClientAndServerData(\n\t\turl,\n\t\tparams,\n\t\tserverParams,\n\t\tdata,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tObject.assign(data, endPointData);\n\tlet $props: Record<string, any> = { data };\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: Also handle layout server data\n\t// TODO: There's probably a nicer way to do this with reducers or something\n\t// TODO: Re-use parent layouts\n\tlet component = clientEndPoint.component as ServerComponent;\n\tlet slots: Record<string, ServerSlotRender> | undefined = undefined;\n\tif (handler.layouts) {\n\t\tlet slotFunctions: ServerSlotRender[] = [];\n\t\tslotFunctions[handler.layouts.length] = (_, context) =>\n\t\t\t(clientEndPoint.component as ServerComponent)($props, context);\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 (i === 0) {\n\t\t\t\t\tcomponent = layoutEndPoint.component as ServerComponent;\n\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t} else {\n\t\t\t\t\tslotFunctions[i] = (_, context) =>\n\t\t\t\t\t\t(layoutEndPoint.component as ServerComponent)($props, context, {\n\t\t\t\t\t\t\t_: slotFunctions[i + 1],\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlet html;\n\ttry {\n\t\thtml = component($props, undefined, slots);\n\t\thtml = template.replace(\"%COMPONENT_HTML%\", html);\n\t} catch (error) {\n\t\t// TODO: Show a proper Error component\n\t\thtml = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\tconsole.log(error);\n\t}\n\n\treturn new Response(html, {\n\t\tstatus: 200,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"text/html\",\n\t\t},\n\t});\n}\n\nasync function runAction(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\tquery: URLSearchParams,\n) {\n\tconst actionName = (Array.from(query.keys())[0] || \"default\").replace(/^\\//, \"\");\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint()).default;\n\tif (serverEndPoint?.actions) {\n\t\tconst action = serverEndPoint.actions[actionName];\n\t\tif (action) {\n\t\t\t// TODO: form.errors etc\n\t\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\t\tif (handler.serverHook) {\n\t\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\t\tif (serverHook?.handle) {\n\t\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = await action(serverParams); // <--\n\n\t\t\t// If there was no response returned from the action (such as errors\n\t\t\t// or a redirect), reload the page by redirecting\n\t\t\treturn result || seeOther(url.pathname);\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadClientAndServerData(\n\turl: URL,\n\tparams: Record<string, string>,\n\tserverParams: ServerLoadEvent,\n\tdata: Record<string, any>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n) {\n\tlet newData = {};\n\tif (clientEndPoint?.load) {\n\t\tconst clientParams = buildClientParams(url, data, params);\n\t\tconst clientData = await clientEndPoint.load(clientParams);\n\t\tif (clientData) {\n\t\t\tObject.assign(newData, clientData);\n\t\t}\n\t}\n\tif (serverEndPoint?.load) {\n\t\tconst serverData = await serverEndPoint.load(serverParams);\n\t\tif (serverData?.ok) {\n\t\t\tObject.assign(newData, await serverData.json());\n\t\t}\n\t}\n\treturn newData;\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\nfunction buildServerParams(\n\tev: ServerEvent,\n\turl: URL,\n\tparams: Record<string, string>,\n): ServerLoadEvent {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tappData: {},\n\t\trequest: ev.request,\n\t\tcookies: ev.cookies,\n\t\theaders: ev.headers,\n\t\tadapter: ev.adapter,\n\t};\n}\n"],"mappings":"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","names":["path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torpor/build",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "A framework for building sites and apps with Torpor",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -32,6 +32,11 @@
32
32
  "import": "./dist/server.js",
33
33
  "require": "./dist/server.cjs"
34
34
  },
35
+ "./test": {
36
+ "types": "./dist/test.d.ts",
37
+ "import": "./dist/test.js",
38
+ "require": "./dist/test.cjs"
39
+ },
35
40
  "./manifest": {
36
41
  "types": "./src/types/manifest.d.ts"
37
42
  }
@@ -48,20 +53,20 @@
48
53
  "dependencies": {
49
54
  "cookie": "^1.0.2",
50
55
  "dotenv": "^16.5.0",
51
- "vite": "^6.2.6",
56
+ "vite": "^6.3.5",
52
57
  "vite-tsconfig-paths": "^5.1.4",
53
58
  "@torpor/view": "^0.0.11",
54
- "@torpor/unplugin": "^0.1.5"
59
+ "@torpor/unplugin": "^0.1.6"
55
60
  },
56
61
  "devDependencies": {
57
62
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
58
63
  "tsup": "^8.4.0",
59
- "tsx": "^4.19.3",
64
+ "tsx": "^4.19.4",
60
65
  "typescript": "^5.8.3",
61
- "vitest": "^3.1.1"
66
+ "vitest": "^3.1.3"
62
67
  },
63
68
  "scripts": {
64
- "build": "tsup",
69
+ "build": "tsc --noEmit && tsup",
65
70
  "build:watch": "tsup --watch",
66
71
  "check": "tsc --noEmit",
67
72
  "test": "vitest"
@@ -5,7 +5,7 @@
5
5
  * header set to "application/json". Otherwise, if the body is a string, the
6
6
  * content-type header will be set to "text/plain".
7
7
  */
8
- export default function response(status: number, body?: object | string) {
8
+ export default function response(status: number, body?: object | string): Response {
9
9
  let headers: Record<string, string> | undefined = undefined;
10
10
  if (body) {
11
11
  if (typeof body === "object") {
@@ -18,7 +18,7 @@ export default class CookieHelper {
18
18
  return parse(header ?? "")[name];
19
19
  }
20
20
 
21
- set(name: string, value: string, options?: SerializeOptions) {
21
+ set(name: string, value: string, options?: SerializeOptions): void {
22
22
  // Set a cookie header with some default values for security
23
23
  options ??= {};
24
24
  options.httpOnly ??= true;
@@ -27,7 +27,7 @@ export default class CookieHelper {
27
27
  this.cookies.set(name, serialize(name, value, options));
28
28
  }
29
29
 
30
- delete(name: string, options?: SerializeOptions) {
30
+ delete(name: string, options?: SerializeOptions): void {
31
31
  // Set a cookie header with an immediate expiry date
32
32
  options ??= {};
33
33
  options.expires = new Date(0);
@@ -15,11 +15,11 @@ export default class HeaderHelper {
15
15
  return this.request.headers.get(name) ?? undefined;
16
16
  }
17
17
 
18
- set(name: string, value: string) {
18
+ set(name: string, value: string): void {
19
19
  this.headers.set(name, value);
20
20
  }
21
21
 
22
- delete(name: string) {
22
+ delete(name: string): void {
23
23
  this.headers.delete(name);
24
24
  }
25
25
  }
@@ -6,7 +6,7 @@ import type ServerFunction from "./types/ServerFunction";
6
6
  // This is not actually used anywhere, for now at least
7
7
 
8
8
  export default class Router {
9
- methods = new Map<HttpMethod, RouteHandler[]>();
9
+ methods: Map<HttpMethod, RouteHandler[]> = new Map<HttpMethod, RouteHandler[]>();
10
10
  middleware: MiddlewareHandler[] = [];
11
11
 
12
12
  constructor() {
@@ -28,7 +28,7 @@ export default class Router {
28
28
  return this;
29
29
  }
30
30
 
31
- match(method: HttpMethod, path: string) {
31
+ match(method: HttpMethod, path: string): Match | undefined {
32
32
  for (let handler of this.methods.get(method)!) {
33
33
  let match = path.match(handler.regex);
34
34
  if (match) {
@@ -65,3 +65,8 @@ class MiddlewareHandler {
65
65
  this.fn = fn;
66
66
  }
67
67
  }
68
+
69
+ type Match = {
70
+ fn: ServerFunction;
71
+ params?: Record<string, string>;
72
+ };
@@ -74,7 +74,7 @@ export default class Server {
74
74
  return this;
75
75
  }
76
76
 
77
- match(path: string) {
77
+ match(path: string): Match | undefined {
78
78
  for (let handler of this.routes) {
79
79
  let match = path.match(handler.regex);
80
80
  if (match) {
@@ -137,3 +137,8 @@ class RouteHandler {
137
137
  // this.fn = fn;
138
138
  // }
139
139
  //}
140
+
141
+ type Match = {
142
+ fn: ServerFunction;
143
+ params?: Record<string, string>;
144
+ };
@@ -23,7 +23,7 @@ export default class ServerEvent {
23
23
  this.adapter = globalThis.adapter;
24
24
  }
25
25
 
26
- addHeaders() {
26
+ addHeaders(): void {
27
27
  if (!this.response) {
28
28
  throw new Error("Response not created yet");
29
29
  }
@@ -1,6 +1,6 @@
1
1
  // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
2
2
 
3
- export default function contentType(extension: string) {
3
+ export default function contentType(extension: string): string {
4
4
  return types[extension] || "application/octet-stream";
5
5
  }
6
6
 
@@ -16,7 +16,7 @@ export default class Router {
16
16
  // this.addPage(route, file);
17
17
  //}
18
18
 
19
- addPages(routes: ManifestRoute[]) {
19
+ addPages(routes: ManifestRoute[]): this {
20
20
  for (let r of routes) {
21
21
  this.routes.push(
22
22
  new Route(r.path, {
@@ -31,7 +31,7 @@ export default class Router {
31
31
  }
32
32
 
33
33
  // TODO: Allow calling with the endpoint itself, so that you can setup an app with no scaffold
34
- addPage(path: string, type: number, endPoint: () => Promise<any>) {
34
+ addPage(path: string, type: number, endPoint: () => Promise<any>): this {
35
35
  this.routes.push(
36
36
  new Route(path, {
37
37
  path,
@@ -53,7 +53,7 @@ export default class Router {
53
53
  }
54
54
  */
55
55
 
56
- match(path: string, query: URLSearchParams) {
56
+ match(path: string, query: URLSearchParams): Match | undefined {
57
57
  for (let route of this.routes) {
58
58
  let match = path.match(route.regex);
59
59
  if (match) {
@@ -157,3 +157,9 @@ class Route {
157
157
  this.handler = handler;
158
158
  }
159
159
  }
160
+
161
+ type Match = {
162
+ handler: RouteHandler;
163
+ params?: Record<string, string>;
164
+ query: URLSearchParams;
165
+ };
package/src/site/Site.ts CHANGED
@@ -33,12 +33,18 @@ export default class Site {
33
33
  plugins: Plugin[] = [tsconfigPaths({ loose: true })];
34
34
  // Is default adapter a bad idea?
35
35
  adapter: Adapter = defaultAdapter;
36
+ /**
37
+ * Extra inputs, as absolute file paths, that will be compiled with the
38
+ * output. What you do with them after that is up to you. File paths ending
39
+ * with server.ts/js will only be compiled with the server output
40
+ */
41
+ inputs: string[] = [];
36
42
 
37
43
  constructor() {
38
44
  this.root = process.cwd();
39
45
  }
40
46
 
41
- async addRouteFolder(folder: string) {
47
+ async addRouteFolder(folder: string): Promise<void> {
42
48
  const routeFolder = path.join(this.root, folder);
43
49
  const routeFiles = await fs.readdir(routeFolder, { recursive: true });
44
50
 
@@ -63,7 +69,7 @@ export default class Site {
63
69
  this.#sortRoutes();
64
70
  }
65
71
 
66
- addRouteFile(path: string, file: string) {
72
+ addRouteFile(path: string, file: string): void {
67
73
  let type = this.#routeType(file);
68
74
  this.routes.push({ path, file, type });
69
75
  this.#sortRoutes();
@@ -1,4 +1,4 @@
1
- export default function prepareTemplate(template: string, clientScript: string) {
1
+ export default function prepareTemplate(template: string, clientScript: string): string {
2
2
  let contentStart = regexIndexOf(template, /\<div\s+id=("app"|'app'|app)\s+/);
3
3
  contentStart = template.indexOf(">", contentStart) + 1;
4
4
  let contentEnd = template.indexOf("</div>", contentStart);
package/src/site/run.ts CHANGED
@@ -6,7 +6,10 @@ import runBuild from "./runBuild";
6
6
  import runDev from "./runDev";
7
7
  import runPreview from "./runPreview";
8
8
 
9
- export default async function run(folder: string, mode: "dev" | "build" | "preview") {
9
+ export default async function run(
10
+ folder: string,
11
+ mode: "dev" | "build" | "preview",
12
+ ): Promise<void> {
10
13
  // Look for and load a site.config.js/ts file in the working directory
11
14
  let configFile = "";
12
15
  let deleteConfigFile = false;
@@ -19,12 +22,11 @@ export default async function run(folder: string, mode: "dev" | "build" | "previ
19
22
  // If it's TS, we need to convert it to JS
20
23
  // TODO: Put the generated file somewhere better (dist?)
21
24
  configFile = path.join(folder, "site.config.temp.js");
22
- let source = (
23
- await transformWithEsbuild(fs.readFileSync(tsConfigFile, "utf-8"), tsConfigFile, {
24
- loader: "ts",
25
- })
26
- ).code;
27
- fs.writeFileSync(configFile, source);
25
+ let source = fs.readFileSync(tsConfigFile, "utf-8");
26
+ let transformed = await transformWithEsbuild(source, tsConfigFile, {
27
+ loader: "ts",
28
+ });
29
+ fs.writeFileSync(configFile, transformed.code);
28
30
  deleteConfigFile = true;
29
31
  } else {
30
32
  throw new Error("site.config file not found");
@@ -10,7 +10,7 @@ import manifest from "./manifest.ts";
10
10
  // TODO: Don't reload layouts during client routing
11
11
  // TODO: Call the correct +page and +server routes when in the same folder
12
12
 
13
- export default async function runBuild(site: Site) {
13
+ export default async function runBuild(site: Site): Promise<void> {
14
14
  // Delete the dist folder if it exists
15
15
  const distFolder = path.resolve(site.root, "dist");
16
16
  if (existsSync(distFolder)) {
@@ -36,12 +36,7 @@ export default async function runBuild(site: Site) {
36
36
  // EXCLUDING anything with `server.js` in the name
37
37
  await build(
38
38
  defineConfig({
39
- plugins: [
40
- manifest(site),
41
- // @ts-ignore
42
- torpor(),
43
- ...site.plugins,
44
- ],
39
+ plugins: [manifest(site), torpor(), ...site.plugins],
45
40
  build: {
46
41
  outDir: clientFolder,
47
42
  rollupOptions: {
@@ -51,6 +46,7 @@ export default async function runBuild(site: Site) {
51
46
  ...site.routes
52
47
  .filter((r) => !/server\.(ts|js)$/.test(r.file))
53
48
  .map((r) => path.resolve(site.root, r.file)),
49
+ ...site.inputs.filter((f) => !/server\.(ts|js)$/.test(f)),
54
50
  ],
55
51
  },
56
52
  ssrManifest: true,
@@ -62,16 +58,15 @@ export default async function runBuild(site: Site) {
62
58
  // files
63
59
  await build(
64
60
  defineConfig({
65
- plugins: [
66
- manifest(site, true),
67
- // @ts-ignore
68
- torpor(),
69
- ...site.plugins,
70
- ],
61
+ plugins: [manifest(site, true), torpor(), ...site.plugins],
71
62
  build: {
72
63
  outDir: serverFolder,
73
64
  rollupOptions: {
74
- input: [serverScript, ...site.routes.map((r) => path.resolve(site.root, r.file))],
65
+ input: [
66
+ serverScript,
67
+ ...site.routes.map((r) => path.resolve(site.root, r.file)),
68
+ ...site.inputs,
69
+ ],
75
70
  },
76
71
  ssr: serverScript,
77
72
  },
@@ -10,7 +10,7 @@ import Site from "./Site.ts";
10
10
  import manifest from "./manifest.ts";
11
11
  import prepareTemplate from "./prepareTemplate.ts";
12
12
 
13
- export default async function runDev(site: Site) {
13
+ export default async function runDev(site: Site): Promise<void> {
14
14
  const server = new Server();
15
15
 
16
16
  // Create the Vite server in middleware mode and configure the app type as
@@ -19,12 +19,7 @@ export default async function runDev(site: Site) {
19
19
  const vite = await createViteServer({
20
20
  server: { middlewareMode: true },
21
21
  appType: "custom",
22
- plugins: [
23
- manifest(site, true),
24
- // @ts-ignore not sure...
25
- torpor(),
26
- ...site.plugins,
27
- ],
22
+ plugins: [manifest(site, true), torpor(), ...site.plugins],
28
23
  });
29
24
 
30
25
  // Read site.html
@@ -46,7 +41,7 @@ export default async function runDev(site: Site) {
46
41
  // Prepare site.html so that we can just splice components into it
47
42
  template = prepareTemplate(template, clientScript);
48
43
 
49
- // Use vite's Connect instance as middleware. We need to wrap it with
44
+ // Use Vite's Connect instance as middleware. We need to wrap it with
50
45
  // createMiddlewareHandler that converts Connect middleware to
51
46
  // Request/Response web handlers
52
47
  server.use(connectMiddleware(vite.middlewares));
@@ -8,7 +8,7 @@ import Site from "./Site";
8
8
  import prepareTemplate from "./prepareTemplate.ts";
9
9
  import runBuild from "./runBuild";
10
10
 
11
- export default async function runPreview(site: Site) {
11
+ export default async function runPreview(site: Site): Promise<void> {
12
12
  // Build the site
13
13
  await runBuild(site);
14
14
 
@@ -28,7 +28,7 @@ router.addPages(manifest.routes);
28
28
 
29
29
  //console.log(`routes:\n ${router.routes.map((r) => r.path).join("\n ")}`);
30
30
 
31
- export async function load(ev: ServerEvent, template: string) {
31
+ export async function load(ev: ServerEvent, template: string): Promise<Response> {
32
32
  //const url = new URL(`http://${process.env.HOST ?? "localhost"}${ev.request.url}`);
33
33
  const url = new URL(ev.request.url);
34
34
  const path = url.pathname;
@@ -1,6 +1,11 @@
1
1
  import { $watch } from "@torpor/view";
2
2
 
3
- const $page = $watch(
3
+ type Page = {
4
+ status: number;
5
+ url: URL;
6
+ };
7
+
8
+ const $page: Page = $watch(
4
9
  {
5
10
  status: 404,
6
11
  url: new URL("http://localhost"),