@torpor/build 1.0.0 → 1.0.2

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 (174) hide show
  1. package/dist/{flattenHeaders-C_YYLdOq.mjs → Server-BnjLJleZ.mjs} +2 -12
  2. package/dist/Server-BnjLJleZ.mjs.map +1 -0
  3. package/dist/{Server-C_IKav_e.d.mts → Server-Cler2w5O.d.mts} +3 -48
  4. package/dist/Server-Cler2w5O.d.mts.map +1 -0
  5. package/dist/ServerEvent-CTx3Q-hk.d.mts +48 -0
  6. package/dist/ServerEvent-CTx3Q-hk.d.mts.map +1 -0
  7. package/dist/{Site-CMa153FA.d.mts → Site-CE0_o5Ci.d.mts} +3 -2
  8. package/dist/Site-CE0_o5Ci.d.mts.map +1 -0
  9. package/dist/bin/index.js +1 -1
  10. package/dist/clientEntry.d.mts +1 -0
  11. package/dist/clientEntry.mjs +59 -0
  12. package/dist/clientEntry.mjs.map +1 -0
  13. package/dist/clientEntryDev.d.mts +1 -0
  14. package/dist/clientEntryDev.mjs +7 -0
  15. package/dist/clientEntryDev.mjs.map +1 -0
  16. package/dist/dev.d.mts +3 -0
  17. package/dist/dev.mjs +3 -0
  18. package/dist/endpoint-EULRGCKA.mjs +108 -0
  19. package/dist/endpoint-EULRGCKA.mjs.map +1 -0
  20. package/dist/flattenHeaders-DM5qsSqO.mjs +13 -0
  21. package/dist/flattenHeaders-DM5qsSqO.mjs.map +1 -0
  22. package/dist/index.d.mts +1 -1
  23. package/dist/load-BntzvmwL.mjs +228 -0
  24. package/dist/load-BntzvmwL.mjs.map +1 -0
  25. package/dist/nav.mjs +1 -225
  26. package/dist/nav.mjs.map +1 -1
  27. package/dist/openapi.d.mts +1 -1
  28. package/dist/run.d.mts +1 -1
  29. package/dist/run.d.mts.map +1 -1
  30. package/dist/run.mjs +1 -1
  31. package/dist/{runOpenApi-BUi1RH1l.mjs → runOpenApi-C8eI2Fh0.mjs} +54 -16
  32. package/dist/runOpenApi-C8eI2Fh0.mjs.map +1 -0
  33. package/dist/server/Server.d.mts +2 -0
  34. package/dist/server/Server.mjs +2 -0
  35. package/dist/server.d.mts +2 -1
  36. package/dist/server.d.mts.map +1 -1
  37. package/dist/server.mjs +2 -1
  38. package/dist/server.mjs.map +1 -1
  39. package/dist/serverEntry-1qY3wZig.mjs +351 -0
  40. package/dist/serverEntry-1qY3wZig.mjs.map +1 -0
  41. package/dist/serverEntry-BAO8m03V.d.mts +6 -0
  42. package/dist/serverEntry-BAO8m03V.d.mts.map +1 -0
  43. package/dist/serverEntry.d.mts +2 -0
  44. package/dist/serverEntry.mjs +2 -0
  45. package/dist/test.d.mts +2 -2
  46. package/dist/test.mjs +2 -104
  47. package/dist/test.mjs.map +1 -1
  48. package/package.json +9 -8
  49. package/dist/Server-C_IKav_e.d.mts.map +0 -1
  50. package/dist/Site-CMa153FA.d.mts.map +0 -1
  51. package/dist/flattenHeaders-C_YYLdOq.mjs.map +0 -1
  52. package/dist/runOpenApi-BUi1RH1l.mjs.map +0 -1
  53. package/src/bin/index.ts +0 -22
  54. package/src/dev.ts +0 -10
  55. package/src/form/formDataToRecord.ts +0 -23
  56. package/src/form/readForm.ts +0 -71
  57. package/src/form.ts +0 -4
  58. package/src/index.ts +0 -82
  59. package/src/nav/api.test-d.ts +0 -79
  60. package/src/nav/api.ts +0 -104
  61. package/src/nav/formSubmit.ts +0 -70
  62. package/src/nav/load.ts +0 -9
  63. package/src/nav/loadData.ts +0 -134
  64. package/src/nav/navigate.ts +0 -189
  65. package/src/nav/reload.ts +0 -9
  66. package/src/nav/route.ts +0 -38
  67. package/src/nav.ts +0 -6
  68. package/src/openapi/docsHtml.ts +0 -25
  69. package/src/openapi/document.ts +0 -154
  70. package/src/openapi/plugin.ts +0 -78
  71. package/src/openapi/types.ts +0 -82
  72. package/src/openapi.ts +0 -14
  73. package/src/response/TypedResponse.ts +0 -17
  74. package/src/response/badRequest.ts +0 -31
  75. package/src/response/created.ts +0 -31
  76. package/src/response/forbidden.ts +0 -21
  77. package/src/response/found.ts +0 -30
  78. package/src/response/methodNotAllowed.ts +0 -18
  79. package/src/response/movedPermanently.ts +0 -25
  80. package/src/response/notFound.ts +0 -24
  81. package/src/response/notModified.ts +0 -34
  82. package/src/response/ok.ts +0 -38
  83. package/src/response/permanentRedirect.ts +0 -30
  84. package/src/response/response.ts +0 -22
  85. package/src/response/seeOther.ts +0 -19
  86. package/src/response/serverError.ts +0 -24
  87. package/src/response/temporaryRedirect.ts +0 -31
  88. package/src/response/transfer.ts +0 -14
  89. package/src/response/unauthorized.ts +0 -21
  90. package/src/response/unprocessable.ts +0 -30
  91. package/src/response.ts +0 -37
  92. package/src/run/depCache.ts +0 -175
  93. package/src/run/devPlugin.ts +0 -128
  94. package/src/run/prepareTemplate.ts +0 -42
  95. package/src/run/run.ts +0 -86
  96. package/src/run/runBuild.ts +0 -128
  97. package/src/run/runDev.ts +0 -177
  98. package/src/run/runOpenApi.ts +0 -52
  99. package/src/run/runPreview.ts +0 -84
  100. package/src/run/staleTorpCopies.ts +0 -100
  101. package/src/run.ts +0 -7
  102. package/src/schema.ts +0 -7
  103. package/src/server/CookieHelper.ts +0 -46
  104. package/src/server/HeaderHelper.ts +0 -25
  105. package/src/server/Server.ts +0 -168
  106. package/src/server/ServerEvent.ts +0 -62
  107. package/src/server/connect/connectMiddleware.ts +0 -85
  108. package/src/server/connect/flattenHeaders.ts +0 -22
  109. package/src/server/connect/nodeMessageToNodeResponse.ts +0 -89
  110. package/src/server/connect/requestToNodeMessage.ts +0 -29
  111. package/src/server/contentType.ts +0 -85
  112. package/src/server/types/HttpMethod.ts +0 -12
  113. package/src/server/types/MiddlewareFunction.ts +0 -22
  114. package/src/server/types/ServerFunction.ts +0 -7
  115. package/src/server.ts +0 -7
  116. package/src/site/Router.ts +0 -175
  117. package/src/site/Site.ts +0 -388
  118. package/src/site/checkLayoutSlots.ts +0 -114
  119. package/src/site/checkRoutes.ts +0 -435
  120. package/src/site/clientEntry.ts +0 -121
  121. package/src/site/clientEntryDev.ts +0 -3
  122. package/src/site/defaultAdapter.ts +0 -11
  123. package/src/site/layoutSlots.ts +0 -53
  124. package/src/site/manifest.ts +0 -173
  125. package/src/site/serverEntry.ts +0 -648
  126. package/src/state/$page.ts +0 -25
  127. package/src/state/$serverPage.ts +0 -22
  128. package/src/state/client.ts +0 -15
  129. package/src/state.ts +0 -3
  130. package/src/test/runTest.ts +0 -538
  131. package/src/test.ts +0 -3
  132. package/src/types/Adapter.ts +0 -20
  133. package/src/types/ClientState.ts +0 -8
  134. package/src/types/InternalState.ts +0 -7
  135. package/src/types/Jsonify.ts +0 -20
  136. package/src/types/LayoutHandler.ts +0 -5
  137. package/src/types/LayoutPath.ts +0 -10
  138. package/src/types/ManifestRoute.ts +0 -6
  139. package/src/types/PageData.test-d.ts +0 -136
  140. package/src/types/PageData.ts +0 -35
  141. package/src/types/PageEndPoint.ts +0 -55
  142. package/src/types/PageForm.test-d.ts +0 -78
  143. package/src/types/PageForm.ts +0 -29
  144. package/src/types/PageLoadEvent.ts +0 -26
  145. package/src/types/PageLoadReturn.ts +0 -13
  146. package/src/types/PageProps.ts +0 -14
  147. package/src/types/PageServerAction.ts +0 -13
  148. package/src/types/PageServerEndPoint.test-d.ts +0 -105
  149. package/src/types/PageServerEndPoint.ts +0 -110
  150. package/src/types/PageServerLoad.ts +0 -15
  151. package/src/types/PageState.ts +0 -8
  152. package/src/types/ParseRouteParams.test-d.ts +0 -84
  153. package/src/types/ParseRouteParams.ts +0 -64
  154. package/src/types/Route.ts +0 -30
  155. package/src/types/RouteHandler.ts +0 -23
  156. package/src/types/RouteLayoutHandler.ts +0 -5
  157. package/src/types/RouteMatchResult.ts +0 -7
  158. package/src/types/RouteType.ts +0 -19
  159. package/src/types/ServerEndPoint.test-d.ts +0 -77
  160. package/src/types/ServerEndPoint.ts +0 -169
  161. package/src/types/ServerHook.ts +0 -18
  162. package/src/types/ServerLoadEvent.ts +0 -82
  163. package/src/types/ServerRequest.ts +0 -15
  164. package/src/types/SitePlugin.ts +0 -24
  165. package/src/types/StandardSchema.ts +0 -109
  166. package/src/utils/pathToRegex.ts +0 -17
  167. package/src/utils/pathTrie.ts +0 -182
  168. package/src/utils/searchParamsToRecord.ts +0 -18
  169. package/src/utils/torporPackages.ts +0 -150
  170. package/src/utils/tsconfigAliases.ts +0 -90
  171. package/src/validation/ValidationError.ts +0 -18
  172. package/src/validation/endpoint.ts +0 -83
  173. package/src/validation/validate.ts +0 -26
  174. package/src/vite-env.d.ts +0 -2
@@ -1,15 +0,0 @@
1
- import type ClientState from "../types/ClientState";
2
-
3
- const CLIENT_SYMBOL: unique symbol = Symbol.for("torp.Client");
4
-
5
- const client: ClientState =
6
- // @ts-ignore
7
- (globalThis[CLIENT_SYMBOL] ??= {
8
- // @ts-ignore This will definitely, 100% get set
9
- router: null,
10
- layoutStack: [],
11
- // TODO: Probably expire after 30 seconds or something?
12
- prefetchedData: {},
13
- });
14
-
15
- export default client;
package/src/state.ts DELETED
@@ -1,3 +0,0 @@
1
- import $page from "./state/$page";
2
-
3
- export { $page };
@@ -1,538 +0,0 @@
1
- import { type ServerComponent, type ServerSlotRender } from "@torpor/view/ssr";
2
- import path from "node:path";
3
- import formDataToRecord from "../form/formDataToRecord.ts";
4
- import notFound from "../response/notFound.ts";
5
- import ok from "../response/ok.ts";
6
- import seeOther from "../response/seeOther.ts";
7
- import ServerEvent from "../server/ServerEvent.ts";
8
- import Router from "../site/Router.ts";
9
- import Site from "../site/Site";
10
- import $page from "../state/$serverPage.ts";
11
- import type PageEndPoint from "../types/PageEndPoint.ts";
12
- import type PageServerEndPoint from "../types/PageServerEndPoint.ts";
13
- import type RouteHandler from "../types/RouteHandler.ts";
14
- import type ServerRequest from "../types/ServerRequest.ts";
15
- import {
16
- ERROR_ROUTE,
17
- HOOK_ROUTE,
18
- HOOK_SERVER_ROUTE,
19
- LAYOUT_ROUTE,
20
- LAYOUT_SERVER_ROUTE,
21
- PAGE_ROUTE,
22
- PAGE_SERVER_ROUTE,
23
- SERVER_ROUTE,
24
- } from "../types/RouteType";
25
- import type ServerEndPoint from "../types/ServerEndPoint.ts";
26
- import type ServerHook from "../types/ServerHook.ts";
27
- import type ServerLoadEvent from "../types/ServerLoadEvent.ts";
28
- import searchParamsToRecord from "../utils/searchParamsToRecord.ts";
29
- import validate from "../validation/validate.ts";
30
- import ValidationError from "../validation/ValidationError.ts";
31
- import {
32
- endpointSchema,
33
- validateEndpointParams,
34
- validateHandlerInput,
35
- validationErrorResponse,
36
- } from "../validation/endpoint.ts";
37
-
38
- /**
39
- * Runs a site route in test mode
40
- * @param site The site configuration, with routing configured
41
- * @param route The route path e.g. `/home`
42
- * @param ev An optional ServerEvent, which you can use to set test cookies and headers
43
- * @returns An HTTP response containing the requested data, HTML, or error status
44
- */
45
- export default async function runTest(
46
- site: Site,
47
- route: string,
48
- ev?: ServerEvent,
49
- ): Promise<Response> {
50
- if (!route.startsWith("/")) route += "/";
51
- if (!ev) {
52
- const req = new Request(`http://localhost${route}`);
53
- ev = new ServerEvent(req);
54
- }
55
-
56
- // Build the router from the Site object created by the user
57
- const router = new Router();
58
- router.addPages(
59
- site.routes.map((r) => ({
60
- path: r.path,
61
- type: r.type,
62
- endPoint: async () => {
63
- if (r.file) {
64
- const mod = await import(/* @vite-ignore */ path.join(site.root, r.file));
65
- // A .torp file's default export is a component, so wrap it as
66
- // a PageEndPoint ({ component }) for the entries
67
- if (r.file.endsWith(".torp")) {
68
- return { default: { component: mod.default } };
69
- }
70
- return mod;
71
- }
72
- // Inline endpoint (no file) — return directly from memory
73
- return { default: r.endPoint };
74
- },
75
- subFolder: r.subFolder,
76
- })),
77
- );
78
-
79
- return await load(router, ev, "%COMPONENT_BODY%");
80
- }
81
-
82
- // HACK: This is a copy of serverEntry
83
- // TODO: Make it shared instead!
84
- async function load(router: Router, ev: ServerEvent, template: string): Promise<Response> {
85
- //const url = new URL(`http://${process.env.HOST ?? "localhost"}${ev.request.url}`);
86
- const url = ev.url;
87
- const path = url.pathname;
88
- const query = url.searchParams;
89
-
90
- //console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : ""}`);
91
-
92
- const route = router.match(path, query);
93
- if (!route) {
94
- return notFound();
95
- }
96
-
97
- // Update $page before building the components
98
- // TODO: Find somewhere better to put this
99
- $page.url = url;
100
- if (path.endsWith("/_error")) {
101
- $page.status = parseInt(query.get("status") ?? "404");
102
- $page.error = { message: query.get("message") ?? "" };
103
- } else {
104
- $page.status = 200;
105
- }
106
-
107
- const handler = route.handler;
108
- const params = route.params || {};
109
-
110
- // TODO: Hit the server hook out here
111
- // We could maybe set data loading up as middleware on a route??????
112
-
113
- switch (handler.type) {
114
- case PAGE_ROUTE:
115
- case LAYOUT_ROUTE: {
116
- // It's a /+page.ts or /_layout.ts endpoint
117
- if (ev.request.method === "GET") {
118
- return await loadView(ev, url, handler, params, template);
119
- } else if (ev.request.method === "POST") {
120
- const serverEndPoint: PageServerEndPoint | undefined =
121
- handler.serverEndPoint && (await handler.serverEndPoint()).default;
122
- return await runAction(ev, url, handler, serverEndPoint, params, query);
123
- }
124
- break;
125
- }
126
- case PAGE_SERVER_ROUTE:
127
- case LAYOUT_SERVER_ROUTE: {
128
- // It's a /+page.server.ts or /_layout.server.ts endpoint
129
- if (ev.request.method === "GET") {
130
- return await loadData(ev, url, handler, "load", params);
131
- } else if (ev.request.method === "POST") {
132
- const serverEndPoint: PageServerEndPoint | undefined =
133
- handler.endPoint && (await handler.endPoint()).default;
134
- return await runAction(ev, url, handler, serverEndPoint, params, query);
135
- }
136
- break;
137
- }
138
- case SERVER_ROUTE: {
139
- // It's a /+server.ts endpoint
140
- const functionName = ev.request.method.toLowerCase().replace("delete", "del");
141
- return await loadData(ev, url, handler, functionName, params);
142
- }
143
- case ERROR_ROUTE: {
144
- return await loadView(ev, url, handler, params, template);
145
- }
146
- case HOOK_ROUTE:
147
- case HOOK_SERVER_ROUTE: {
148
- break;
149
- }
150
- }
151
-
152
- return notFound();
153
- }
154
-
155
- async function loadData(
156
- ev: ServerEvent,
157
- url: URL,
158
- handler: RouteHandler,
159
- functionName: string,
160
- params: Record<string, any>,
161
- ) {
162
- const serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint()).default;
163
- // `functionName` is computed from the request method, so the handlers are
164
- // accessed through a loose record
165
- const handlers = serverEndPoint as unknown as Record<string, ServerRequest | undefined>;
166
- const handlerFn: ServerRequest | undefined = handlers?.[functionName];
167
- if (serverEndPoint && handlerFn) {
168
- // Route params come from the URL, so a failed validation means the
169
- // resource doesn't exist
170
- try {
171
- params = await validateEndpointParams(serverEndPoint, params);
172
- } catch (error) {
173
- if (error instanceof ValidationError) return notFound();
174
- throw error;
175
- }
176
-
177
- try {
178
- // If the endpoint declares a schema for this handler, validate its
179
- // input up front and reject with 422 if it fails. get/head schemas
180
- // validate the query string; other schemas validate the json body
181
- const schema = endpointSchema(serverEndPoint, functionName);
182
- const values = await validateHandlerInput(schema, functionName, url, ev);
183
-
184
- const serverParams = buildServerParams(ev, url, params, values);
185
-
186
- const serverHooks = await loadServerHooks(handler);
187
- let entered = 0;
188
- let enterResponse: Response | undefined = undefined;
189
- try {
190
- // Hooks run from the root down; a hook's enter can return a
191
- // Response to short-circuit the request
192
- for (; entered < serverHooks.length && !enterResponse; entered++) {
193
- const hookResult = await serverHooks[entered].enter?.(serverParams);
194
- if (hookResult) {
195
- enterResponse = hookResult;
196
- }
197
- }
198
-
199
- const result = enterResponse || (await handlerFn(serverParams));
200
-
201
- // If there was no response returned from load (such as errors or a
202
- // redirect), send an ok response
203
- return result || ok();
204
- } finally {
205
- // Run exit hooks in reverse order for hooks that were entered
206
- while (entered > 0) {
207
- entered--;
208
- await serverHooks[entered].exit?.(serverParams);
209
- }
210
- }
211
- } catch (error) {
212
- const response = validationErrorResponse(error);
213
- if (response) return response;
214
- throw error;
215
- }
216
- }
217
-
218
- return notFound();
219
- }
220
-
221
- async function loadView(
222
- ev: ServerEvent,
223
- url: URL,
224
- handler: RouteHandler,
225
- params: Record<string, any>,
226
- template: string,
227
- ) {
228
- // There must be a client endpoint with a component
229
- const clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;
230
- if (!clientEndPoint?.component) {
231
- return notFound();
232
- }
233
-
234
- // There may be a server endpoint
235
- const serverEndPoint: PageServerEndPoint | undefined =
236
- handler.serverEndPoint && (await handler.serverEndPoint())?.default;
237
-
238
- // Validate the route params and the load query against the server
239
- // endpoint's schemas, if it declares any. Params come from the URL, so a
240
- // failed validation means the resource doesn't exist; a failed query
241
- // returns like any other load failure
242
- let query: unknown;
243
- if (serverEndPoint) {
244
- try {
245
- params = await validateEndpointParams(serverEndPoint, params);
246
- } catch (error) {
247
- if (error instanceof ValidationError) return notFound();
248
- throw error;
249
- }
250
- const loadSchema = endpointSchema(serverEndPoint, "load");
251
- if (loadSchema) {
252
- try {
253
- query = await validate(loadSchema, searchParamsToRecord(url.searchParams));
254
- } catch (error) {
255
- const response = validationErrorResponse(error);
256
- if (response) return response;
257
- throw error;
258
- }
259
- }
260
- }
261
-
262
- // Maybe hit the server hooks
263
- const serverParams = buildServerParams(ev, url, params, query ? { query } : {});
264
- const serverHooks = await loadServerHooks(handler);
265
- let entered = 0;
266
- let enterResponse: Response | undefined = undefined;
267
- try {
268
- // Hooks run from the root down; a hook's enter can return a Response
269
- // to short-circuit the request
270
- for (; entered < serverHooks.length && !enterResponse; entered++) {
271
- const hookResult = await serverHooks[entered].enter?.(serverParams);
272
- if (hookResult) {
273
- enterResponse = hookResult;
274
- }
275
- }
276
- if (enterResponse) {
277
- return enterResponse;
278
- }
279
-
280
- // Pass the data into $props
281
- // TODO: Promise.all
282
- // 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
283
- let data = {};
284
- if (handler.layouts) {
285
- for (let layout of handler.layouts) {
286
- const layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;
287
- const layoutServerEndPoint: PageServerEndPoint | undefined =
288
- layout.serverEndPoint && (await layout.serverEndPoint())?.default;
289
- const layoutResponse = await loadClientAndServerData(
290
- url,
291
- params,
292
- serverParams,
293
- data,
294
- layoutEndPoint,
295
- layoutServerEndPoint,
296
- );
297
- if (layoutResponse?.ok === false) {
298
- return layoutResponse;
299
- }
300
- }
301
- }
302
- let endPointResponse = await loadClientAndServerData(
303
- url,
304
- params,
305
- serverParams,
306
- data,
307
- clientEndPoint,
308
- serverEndPoint,
309
- );
310
- if (endPointResponse?.ok === false) {
311
- return endPointResponse;
312
- }
313
- let $props: Record<string, any> = { data };
314
-
315
- let styles = "";
316
-
317
- // If there are layouts, work our way upwards, pushing each component into
318
- // the default slot of its parent
319
- // TODO: Also handle layout server data
320
- // TODO: There's probably a nicer way to do this with reducers or something
321
- let component = clientEndPoint.component as ServerComponent;
322
- let slots: Record<string, ServerSlotRender> | undefined = undefined;
323
- if (handler.layouts) {
324
- let slotFunctions: ServerSlotRender[] = [];
325
- slotFunctions[handler.layouts.length] = (_, $context) => {
326
- let { body, head } = (clientEndPoint.component as ServerComponent)($props, $context);
327
- styles += head;
328
- return body;
329
- };
330
- for (let i = handler.layouts.length - 1; i >= 0; i--) {
331
- const layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())
332
- ?.default;
333
- if (layoutEndPoint?.component) {
334
- if (i === 0) {
335
- component = layoutEndPoint.component as ServerComponent;
336
- slots = { _: slotFunctions[i + 1] };
337
- } else {
338
- slotFunctions[i] = (_, $context) => {
339
- let { body, head } = (layoutEndPoint.component as ServerComponent)($props, $context, {
340
- _: slotFunctions[i + 1],
341
- });
342
- styles += head;
343
- return body;
344
- };
345
- }
346
- }
347
- }
348
- }
349
-
350
- let html;
351
- try {
352
- let { body, head } = component($props, undefined, slots);
353
- styles += head;
354
- html = template.replace("%COMPONENT_BODY%", body).replace("%COMPONENT_HEAD%", styles);
355
- } catch (error) {
356
- // TODO: Show a proper Error component
357
- html = '<span style="color: red">Script syntax error</span><p>' + error + "</p>";
358
- console.log(error);
359
- }
360
-
361
- return new Response(html, {
362
- status: 200,
363
- headers: {
364
- "Content-Type": "text/html",
365
- },
366
- });
367
- } finally {
368
- // Run exit hooks in reverse order for hooks that were entered
369
- while (entered > 0) {
370
- entered--;
371
- await serverHooks[entered].exit?.(serverParams);
372
- }
373
- }
374
- }
375
-
376
- async function runAction(
377
- ev: ServerEvent,
378
- url: URL,
379
- handler: RouteHandler,
380
- serverEndPoint: PageServerEndPoint | undefined,
381
- params: Record<string, any>,
382
- query: URLSearchParams,
383
- ) {
384
- const actionName = (Array.from(query.keys())[0] || "default").replace(/^\//, "");
385
- if (serverEndPoint?.actions) {
386
- const action = serverEndPoint.actions[actionName];
387
- if (action) {
388
- if (actionName === "load" || actionName === "params") {
389
- // These names are reserved in the endpoint's schema map: `load`
390
- // validates the query string and `params` the route params, so
391
- // an action with one of these names would get the wrong schema
392
- // applied to its form data
393
- throw new Error(
394
- `The action name "${actionName}" is reserved. ` +
395
- `Rename the action (and its schema key, if any), e.g. to "save".`,
396
- );
397
- }
398
- // TODO: form.errors etc
399
- // Route params come from the URL, so a failed validation means the
400
- // resource doesn't exist
401
- try {
402
- params = await validateEndpointParams(serverEndPoint, params);
403
- } catch (error) {
404
- if (error instanceof ValidationError) return notFound();
405
- throw error;
406
- }
407
-
408
- let result: Response | undefined | void;
409
- try {
410
- // If the endpoint declares a schema for this action, validate the
411
- // submitted form data up front and reject with 422 if it fails
412
- const schema = endpointSchema(serverEndPoint, actionName);
413
- const form = schema
414
- ? await validate(schema, await formDataToRecord(ev.request))
415
- : undefined;
416
-
417
- const serverParams = buildServerParams(ev, url, params, form ? { form } : {});
418
-
419
- const serverHooks = await loadServerHooks(handler);
420
- let entered = 0;
421
- let enterResponse: Response | undefined = undefined;
422
- try {
423
- // Hooks run from the root down; a hook's enter can return a
424
- // Response to short-circuit the action
425
- for (; entered < serverHooks.length && !enterResponse; entered++) {
426
- const hookResult = await serverHooks[entered].enter?.(serverParams);
427
- if (hookResult) {
428
- enterResponse = hookResult;
429
- }
430
- }
431
-
432
- result = enterResponse || (await action(serverParams));
433
- } finally {
434
- // Run exit hooks in reverse order for hooks that were entered
435
- while (entered > 0) {
436
- entered--;
437
- await serverHooks[entered].exit?.(serverParams);
438
- }
439
- }
440
- } catch (error) {
441
- const response = validationErrorResponse(error);
442
- if (response) return response;
443
- throw error;
444
- }
445
-
446
- // If there was no response returned from the action (such as errors
447
- // or a redirect), reload the page by redirecting
448
- return result || seeOther(url.pathname);
449
- }
450
- }
451
-
452
- return notFound();
453
- }
454
-
455
- async function loadClientAndServerData(
456
- url: URL,
457
- params: Record<string, any>,
458
- serverParams: ServerLoadEvent,
459
- data: Record<string, any>,
460
- clientEndPoint?: PageEndPoint,
461
- serverEndPoint?: PageServerEndPoint,
462
- ) {
463
- if (clientEndPoint?.load) {
464
- const clientParams = buildClientParams(url, params, data);
465
- const clientResponse = await clientEndPoint.load(clientParams);
466
- if (clientResponse) {
467
- if (clientResponse.ok) {
468
- if (clientResponse.headers.get("Content-Type")?.includes("application/json")) {
469
- Object.assign(data, await clientResponse.json());
470
- }
471
- } else {
472
- return clientResponse;
473
- }
474
- }
475
- }
476
- if (serverEndPoint?.load) {
477
- const serverResponse = await serverEndPoint.load(serverParams);
478
- if (serverResponse) {
479
- if (serverResponse.ok) {
480
- if (serverResponse.headers.get("Content-Type")?.includes("application/json")) {
481
- Object.assign(data, await serverResponse.json());
482
- }
483
- } else {
484
- return serverResponse;
485
- }
486
- }
487
- }
488
- }
489
-
490
- function buildClientParams(url: URL, params: Record<string, any>, data: Record<string, any>) {
491
- return {
492
- url,
493
- params,
494
- data,
495
- };
496
- }
497
-
498
- /**
499
- * Loads the route's server hooks, from the root down
500
- */
501
- async function loadServerHooks(handler: RouteHandler): Promise<ServerHook[]> {
502
- const hooks: ServerHook[] = [];
503
- if (handler.serverHooks) {
504
- for (let serverHook of handler.serverHooks) {
505
- hooks.push((await serverHook()).default);
506
- }
507
- }
508
- return hooks;
509
- }
510
-
511
- function buildServerParams(
512
- ev: ServerEvent,
513
- url: URL,
514
- params: Record<string, any>,
515
- values: { json?: unknown; form?: unknown; query?: unknown } = {},
516
- ): ServerLoadEvent {
517
- return {
518
- url,
519
- params,
520
- appData: {},
521
- request: ev.request,
522
- // The inputs may have been validated already, in which case the request
523
- // body has been consumed and the parsed values are returned instead.
524
- // Their types come from the endpoint's schemas, so they are loosely
525
- // typed here
526
- json: (): Promise<any> =>
527
- values.json !== undefined ? Promise.resolve(values.json) : ev.json(),
528
- form: (): Promise<any> =>
529
- values.form !== undefined ? Promise.resolve(values.form) : formDataToRecord(ev.request),
530
- query: (): Promise<any> =>
531
- values.query !== undefined
532
- ? Promise.resolve(values.query)
533
- : Promise.resolve(searchParamsToRecord(url.searchParams)),
534
- cookies: ev.cookies,
535
- headers: ev.headers,
536
- adapter: ev.adapter,
537
- };
538
- }
package/src/test.ts DELETED
@@ -1,3 +0,0 @@
1
- import runTest from "./test/runTest";
2
-
3
- export { runTest };
@@ -1,20 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import Server from "../server/Server";
3
- import Site from "../site/Site";
4
-
5
- export default interface Adapter {
6
- prebuild?: (site: Site) => Promise<void> | void;
7
- postbuild?: (site: Site) => Promise<void> | void;
8
- /**
9
- * Vite plugin(s) used to drive dev mode. The adapter owns where server code
10
- * runs (e.g. the default Node runtime, or workerd via miniflare) and how
11
- * requests reach it. When omitted, the framework's default Node-runtime dev
12
- * plugin is used.
13
- */
14
- dev?: (site: Site) => Plugin | Plugin[] | void;
15
- /**
16
- * Serve the built output (preview). Receives a torpor Server configured to
17
- * load the built server entry.
18
- */
19
- serve: (server: Server, site: Site) => void;
20
- }
@@ -1,8 +0,0 @@
1
- import Router from "../site/Router";
2
- import type LayoutPath from "./LayoutPath";
3
-
4
- export default interface ClientState {
5
- router: Router;
6
- layoutStack: LayoutPath[];
7
- prefetchedData: Record<string, any>;
8
- }
@@ -1,7 +0,0 @@
1
- import type ClientState from "./ClientState";
2
- import type PageState from "./PageState";
3
-
4
- export default interface InternalState {
5
- $page: PageState;
6
- client: ClientState;
7
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * The JSON-serialized form of a type: what a value looks like after a
3
- * JSON.stringify / JSON.parse round trip. Dates become strings, functions and
4
- * undefined properties are dropped.
5
- */
6
- export type Jsonify<T> = T extends string | number | boolean | null
7
- ? T
8
- : T extends undefined | ((...args: any[]) => any)
9
- ? never
10
- : T extends Date
11
- ? string
12
- : T extends Array<infer Item>
13
- ? Array<Jsonify<Item>>
14
- : T extends object
15
- ? {
16
- [Key in keyof T as T[Key] extends undefined | ((...args: any[]) => any)
17
- ? never
18
- : Key]: Jsonify<T[Key]>;
19
- }
20
- : T;
@@ -1,5 +0,0 @@
1
- export default interface LayoutHandler {
2
- path: string;
3
- endPoint: () => Promise<any>;
4
- serverEndPoint?: () => Promise<any>;
5
- }
@@ -1,10 +0,0 @@
1
- // Store the current layout stack, so that we can re-use parts of it as necessary
2
- export default interface LayoutPath {
3
- path: string;
4
- /** Whether to re-use this layout */
5
- reuse: boolean;
6
- /** Data loaded from endpoints that should be re-used */
7
- data: any;
8
- /** The range of the UI in this layout's slot */
9
- slotRegion: any;
10
- }
@@ -1,6 +0,0 @@
1
- export default interface ManifestRoute {
2
- path: string;
3
- type: number;
4
- endPoint: () => Promise<any>;
5
- subFolder: string | undefined;
6
- }