@torpor/build 0.0.1

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 (71) hide show
  1. package/LICENSE.md +5 -0
  2. package/README.md +55 -0
  3. package/dist/bin/index.cjs +137 -0
  4. package/dist/bin/index.cjs.map +1 -0
  5. package/dist/bin/index.d.cts +1 -0
  6. package/dist/bin/index.d.ts +1 -0
  7. package/dist/bin/index.js +114 -0
  8. package/dist/bin/index.js.map +1 -0
  9. package/dist/index.cjs +55 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +150 -0
  12. package/dist/index.d.ts +150 -0
  13. package/dist/index.js +27 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/metafile-cjs.json +1 -0
  16. package/dist/metafile-esm.json +1 -0
  17. package/dist/response.cjs +150 -0
  18. package/dist/response.cjs.map +1 -0
  19. package/dist/response.d.cts +162 -0
  20. package/dist/response.d.ts +162 -0
  21. package/dist/response.js +109 -0
  22. package/dist/response.js.map +1 -0
  23. package/dist/state.cjs +41 -0
  24. package/dist/state.cjs.map +1 -0
  25. package/dist/state.d.cts +6 -0
  26. package/dist/state.d.ts +6 -0
  27. package/dist/state.js +14 -0
  28. package/dist/state.js.map +1 -0
  29. package/package.json +49 -0
  30. package/src/bin/index.ts +41 -0
  31. package/src/index.ts +24 -0
  32. package/src/response/badRequest.ts +14 -0
  33. package/src/response/created.ts +13 -0
  34. package/src/response/forbidden.ts +14 -0
  35. package/src/response/methodNotAllowed.ts +14 -0
  36. package/src/response/moved.ts +16 -0
  37. package/src/response/notFound.ts +17 -0
  38. package/src/response/notModified.ts +14 -0
  39. package/src/response/ok.ts +20 -0
  40. package/src/response/redirect.ts +17 -0
  41. package/src/response/response.ts +22 -0
  42. package/src/response/seeOther.ts +13 -0
  43. package/src/response/serverError.ts +10 -0
  44. package/src/response/transfer.ts +14 -0
  45. package/src/response/unauthorized.ts +12 -0
  46. package/src/response/unprocessable.ts +12 -0
  47. package/src/response.ts +33 -0
  48. package/src/site/FileSystemRouter.ts +24 -0
  49. package/src/site/buildRoutePath.ts +25 -0
  50. package/src/site/clientEntry.ts +191 -0
  51. package/src/site/defineConfig.ts +5 -0
  52. package/src/site/defineSite.ts +74 -0
  53. package/src/site/lazyRoute.ts +72 -0
  54. package/src/site/routeHandlers.ts +113 -0
  55. package/src/site/serverEntry.ts +384 -0
  56. package/src/state/$page.ts +11 -0
  57. package/src/state.ts +3 -0
  58. package/src/types/CookieHelper.ts +7 -0
  59. package/src/types/PageEndPoint.ts +37 -0
  60. package/src/types/PageEvent.ts +14 -0
  61. package/src/types/PageServerEndPoint.ts +18 -0
  62. package/src/types/RouteHandler.ts +12 -0
  63. package/src/types/RouteHandlerCollection.ts +7 -0
  64. package/src/types/RouteLayoutHandler.ts +5 -0
  65. package/src/types/RouteMatchResult.ts +7 -0
  66. package/src/types/ServerEndPoint.ts +37 -0
  67. package/src/types/ServerEvent.ts +27 -0
  68. package/src/types/ServerHook.ts +13 -0
  69. package/src/types/UserConfig.ts +3 -0
  70. package/tsconfig.json +4 -0
  71. package/tsup.config.ts +10 -0
@@ -0,0 +1,384 @@
1
+ import type { ServerComponent, ServerSlotRender } from "@torpor/view";
2
+ import fs from "fs";
3
+ import { IncomingMessage } from "node:http";
4
+ import path from "path";
5
+ import { deleteCookie, eventHandler, getCookie, setCookie } from "vinxi/http";
6
+ import type { CookieSerializeOptions, EventHandlerRequest, H3Event } from "vinxi/http";
7
+ import { getManifest } from "vinxi/manifest";
8
+ import { ServerEndPoint } from "..";
9
+ import notFound from "../response/notFound";
10
+ import ok from "../response/ok";
11
+ import seeOther from "../response/seeOther";
12
+ import serverError from "../response/serverError";
13
+ import $page from "../state/$page";
14
+ import type PageEndPoint from "../types/PageEndPoint";
15
+ import type PageServerEndPoint from "../types/PageServerEndPoint";
16
+ import type RouteHandler from "../types/RouteHandler";
17
+ import type ServerEvent from "../types/ServerEvent";
18
+ import type ServerHook from "../types/ServerHook";
19
+ import routeHandlers from "./routeHandlers";
20
+
21
+ let printedRoutes = false;
22
+
23
+ export default eventHandler(async (event) => {
24
+ const url = new URL(`http://${process.env.HOST ?? "localhost"}${event.node.req.url}`);
25
+ const path = url.pathname;
26
+
27
+ const searchParams = url.searchParams;
28
+
29
+ console.log("handling server", event.method, "for", path, "with", searchParams);
30
+
31
+ if (!printedRoutes) {
32
+ printedRoutes = true;
33
+ console.log(
34
+ "routes:\n " +
35
+ routeHandlers.handlers
36
+ .map((h) => h.path)
37
+ .sort()
38
+ .join("\n "),
39
+ );
40
+ }
41
+
42
+ const route = routeHandlers.match(path, searchParams);
43
+ if (!route) {
44
+ return notFound();
45
+ }
46
+
47
+ // Update $page before building the components
48
+ // TODO: Find somewhere better to put this
49
+ $page.url = url;
50
+
51
+ const handler = route.handler;
52
+ const params = route.routeParams || {};
53
+
54
+ // TODO: Hit the server hook out here
55
+
56
+ // HACK: Support any +server location??
57
+ if (path.startsWith("/api/")) {
58
+ return await loadData(event, url, handler, params);
59
+ } else if (path.endsWith("~server")) {
60
+ // HACK: Is this the best way to signal that we want server data??
61
+ // And can we maybe combine this with the above method, or are they too different?
62
+ if (event.method === "GET") {
63
+ return await loadServerData(event, url, handler, params);
64
+ }
65
+ } else {
66
+ if (event.method === "GET") {
67
+ return await loadView(event, url, handler, params);
68
+ } else if (event.method === "POST") {
69
+ return await runAction(event, url, handler, params, searchParams);
70
+ }
71
+ }
72
+ });
73
+
74
+ async function loadData(
75
+ event: H3Event<EventHandlerRequest>,
76
+ url: URL,
77
+ handler: RouteHandler,
78
+ params: Record<string, string>,
79
+ ) {
80
+ const functionName = event.method.toLowerCase().replace("delete", "del");
81
+
82
+ const serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint).default;
83
+ if (serverEndPoint && serverEndPoint[functionName]) {
84
+ const serverParams = await buildServerParams(event, url, params);
85
+
86
+ if (handler.serverHook) {
87
+ const serverHook: ServerHook | undefined = (await handler.serverHook).default;
88
+ if (serverHook?.handle) {
89
+ await serverHook.handle(serverParams);
90
+ }
91
+ }
92
+
93
+ const result = await serverEndPoint[functionName](serverParams);
94
+ // If there was no response returned from load (such as errors or a
95
+ // redirect), send an ok response
96
+ return result || ok();
97
+ }
98
+ }
99
+
100
+ async function loadServerData(
101
+ event: H3Event<EventHandlerRequest>,
102
+ url: URL,
103
+ handler: RouteHandler,
104
+ params: Record<string, string>,
105
+ ) {
106
+ const serverEndPoint: PageServerEndPoint | undefined = (await handler.endPoint).default;
107
+ if (serverEndPoint?.load) {
108
+ const serverParams = await buildServerParams(event, url, params);
109
+
110
+ if (handler.serverHook) {
111
+ const serverHook: ServerHook | undefined = (await handler.serverHook).default;
112
+ if (serverHook?.handle) {
113
+ await serverHook.handle(serverParams);
114
+ }
115
+ }
116
+
117
+ const result = await serverEndPoint.load(serverParams);
118
+ // If there was no response returned from load (such as errors or a
119
+ // redirect), send an ok response
120
+ return result || ok();
121
+ }
122
+
123
+ // It's ok if there's no load method -- we can't tell whether there will be
124
+ // when loading routes
125
+ //return ok();
126
+ }
127
+
128
+ async function loadView(
129
+ event: H3Event<EventHandlerRequest>,
130
+ url: URL,
131
+ handler: RouteHandler,
132
+ params: Record<string, string>,
133
+ ) {
134
+ // There must be a client endpoint with a component
135
+ const clientEndPoint: PageEndPoint | undefined = (await handler.endPoint).default;
136
+ if (!clientEndPoint?.component) {
137
+ return notFound();
138
+ }
139
+
140
+ // There may be a server endpoint
141
+ const serverEndPoint: PageServerEndPoint | undefined = (await handler.serverEndPoint)?.default;
142
+
143
+ // HACK: wrangle the view into app.html
144
+ // We could instead have an App.torp component with a slot, but you can run
145
+ // into hydration problems that way e.g. if there is a browser plugin that
146
+ // injects elements into <head> or <body>
147
+ const appHtml = loadAppHtml();
148
+ let contentStart = regexIndexOf(appHtml, /\<div\s+id=("app"|'app'|app)\s+/);
149
+ contentStart = appHtml.indexOf(">", contentStart) + 1;
150
+ let contentEnd = appHtml.indexOf("</div>", contentStart);
151
+ if (contentStart === -1 || contentEnd === -1) {
152
+ return serverError;
153
+ }
154
+
155
+ // Build client scripts
156
+ const clientManifest = getManifest("client");
157
+ const clientHandler = clientManifest.inputs[clientManifest.handler];
158
+ const clientScript = clientHandler.output.path;
159
+ const hasClientScript = !!clientScript;
160
+ const manifestJson = JSON.stringify(clientManifest.json());
161
+ const hasManifestJson = manifestJson !== "{}";
162
+
163
+ // Maybe hit the server hook
164
+ const serverParams = await buildServerParams(event, url, params);
165
+ if (handler.serverHook) {
166
+ const serverHook: ServerHook | undefined = (await handler.serverHook).default;
167
+ if (serverHook?.handle) {
168
+ await serverHook.handle(serverParams);
169
+ }
170
+ }
171
+
172
+ // Pass the data into $props
173
+ // TODO: Promise.all
174
+ // 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
175
+ let data = {};
176
+ if (handler.layouts) {
177
+ for (let layout of handler.layouts) {
178
+ const layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint)?.default;
179
+ const layoutServerEndPoint: PageServerEndPoint | undefined = (await layout.serverEndPoint)
180
+ ?.default;
181
+ const layoutData = await loadClientAndServerData(
182
+ url,
183
+ params,
184
+ serverParams,
185
+ data,
186
+ layoutEndPoint,
187
+ layoutServerEndPoint,
188
+ );
189
+ Object.assign(data, layoutData);
190
+ }
191
+ }
192
+ let endPointData = await loadClientAndServerData(
193
+ url,
194
+ params,
195
+ serverParams,
196
+ data,
197
+ clientEndPoint,
198
+ serverEndPoint,
199
+ );
200
+ Object.assign(data, endPointData);
201
+ let $props: Record<string, any> = { data };
202
+
203
+ // If there are layouts, work our way upwards, pushing each component into
204
+ // the default slot of its parent
205
+ // TODO: Also handle layout server data
206
+ // TODO: There's probably a nicer way to do this with reducers or something
207
+ // TODO: Re-use parent layouts
208
+ let component = clientEndPoint.component as ServerComponent;
209
+ let slots: Record<string, ServerSlotRender> | undefined = undefined;
210
+ if (handler.layouts) {
211
+ let slotFunctions: ServerSlotRender[] = [];
212
+ slotFunctions[handler.layouts.length] = (_, context) =>
213
+ (clientEndPoint.component as ServerComponent)($props, context);
214
+ for (let i = handler.layouts.length - 1; i >= 0; i--) {
215
+ const layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint)?.default;
216
+ if (layoutEndPoint?.component) {
217
+ if (i === 0) {
218
+ component = layoutEndPoint.component as ServerComponent;
219
+ slots = { _: slotFunctions[i + 1] };
220
+ } else {
221
+ slotFunctions[i] = (_, context) =>
222
+ (layoutEndPoint.component as ServerComponent)($props, context, {
223
+ _: slotFunctions[i + 1],
224
+ });
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ event.node.res.setHeader("content-type", "text/html");
231
+
232
+ let componentCode = "";
233
+ try {
234
+ componentCode = component($props, undefined, slots);
235
+ } catch (error) {
236
+ // TODO: Show a proper Error component
237
+ componentCode = '<span style="color: red">Script syntax error</span><p>' + error + "</p>";
238
+ }
239
+
240
+ // Put it all together
241
+ let html =
242
+ appHtml.substring(0, contentStart) +
243
+ componentCode +
244
+ appHtml.substring(contentEnd) +
245
+ (hasClientScript ? `<script type="module" src="${clientScript}"></script>` : "") +
246
+ (hasManifestJson ? `<script>window.manifest = ${manifestJson}</script>` : "");
247
+
248
+ //console.log(html);
249
+
250
+ return html;
251
+ }
252
+
253
+ async function runAction(
254
+ event: H3Event<EventHandlerRequest>,
255
+ url: URL,
256
+ handler: RouteHandler,
257
+ params: Record<string, string>,
258
+ searchParams: URLSearchParams,
259
+ ) {
260
+ const actionName = (Array.from(searchParams.keys())[0] || "default").replace(/^\//, "");
261
+ const serverEndPoint: PageServerEndPoint | undefined = (await handler.serverEndPoint).default;
262
+ if (serverEndPoint?.actions) {
263
+ const action = serverEndPoint.actions[actionName];
264
+ if (action) {
265
+ // TODO: form.errors etc
266
+ const serverParams = await buildServerParams(event, url, params);
267
+
268
+ if (handler.serverHook) {
269
+ const serverHook: ServerHook | undefined = (await handler.serverHook).default;
270
+ if (serverHook?.handle) {
271
+ await serverHook.handle(serverParams);
272
+ }
273
+ }
274
+
275
+ const result = await action(serverParams);
276
+ // If there was no response returned from the action (such as errors
277
+ // or a redirect), reload the page by redirecting
278
+ return result || seeOther(url.pathname);
279
+ }
280
+ }
281
+ }
282
+
283
+ async function loadClientAndServerData(
284
+ url: URL,
285
+ params: Record<string, string>,
286
+ serverParams: ServerEvent,
287
+ data: Record<string, any>,
288
+ clientEndPoint?: PageEndPoint,
289
+ serverEndPoint?: PageServerEndPoint,
290
+ ) {
291
+ let newData = {};
292
+ if (clientEndPoint?.load) {
293
+ const clientParams = buildClientParams(url, data, params);
294
+ const clientData = await clientEndPoint.load(clientParams);
295
+ if (clientData) {
296
+ Object.assign(newData, clientData);
297
+ }
298
+ }
299
+ if (serverEndPoint?.load) {
300
+ const serverData = await serverEndPoint.load(serverParams);
301
+ if (serverData?.ok) {
302
+ Object.assign(newData, await serverData.json());
303
+ }
304
+ }
305
+ return newData;
306
+ }
307
+
308
+ function buildClientParams(url: URL, params: Record<string, string>, data: Record<string, any>) {
309
+ return {
310
+ url,
311
+ params,
312
+ data,
313
+ };
314
+ }
315
+
316
+ async function buildServerParams(
317
+ event: H3Event<EventHandlerRequest>,
318
+ url: URL,
319
+ params: Record<string, string>,
320
+ ): Promise<ServerEvent> {
321
+ return {
322
+ url,
323
+ params,
324
+ appData: {},
325
+ request: await incomingMessageToRequest(event.node.req, url),
326
+ response: event.node.res,
327
+ cookies: {
328
+ get: (name: string) => getCookie(event, name),
329
+ set: (name: string, value: string, options?: CookieSerializeOptions) =>
330
+ setCookie(event, name, value, options),
331
+ delete: (name: string, options?: CookieSerializeOptions) =>
332
+ deleteCookie(event, name, options),
333
+ },
334
+ };
335
+ }
336
+
337
+ // From https://stackoverflow.com/a/78849544
338
+ async function incomingMessageToRequest(req: IncomingMessage, url: URL): Promise<Request> {
339
+ const headers = new Headers();
340
+ for (const [key, value] of Object.entries(req.headers)) {
341
+ if (Array.isArray(value)) {
342
+ value.forEach((v) => headers.append(key, v));
343
+ } else if (value !== undefined) {
344
+ headers.set(key, value);
345
+ }
346
+ }
347
+ // Convert body to Buffer if applicable
348
+ const body = req.method !== "GET" && req.method !== "HEAD" ? await getRequestBody(req) : null;
349
+ return new Request(url, {
350
+ method: req.method,
351
+ headers: headers,
352
+ body: body,
353
+ });
354
+ }
355
+
356
+ function getRequestBody(req: IncomingMessage): Promise<Buffer> {
357
+ return new Promise<Buffer>((resolve, reject) => {
358
+ const chunks: Buffer[] = [];
359
+ req.on("data", (chunk: Buffer) => {
360
+ chunks.push(chunk);
361
+ });
362
+ req.on("end", () => {
363
+ resolve(Buffer.concat(chunks));
364
+ });
365
+ req.on("error", (err) => {
366
+ reject(err);
367
+ });
368
+ });
369
+ }
370
+
371
+ let loadedAppHtml = "";
372
+ function loadAppHtml() {
373
+ if (!loadedAppHtml) {
374
+ let file = path.resolve("src/app.html");
375
+ loadedAppHtml = fs.readFileSync(file).toString();
376
+ }
377
+ return loadedAppHtml;
378
+ }
379
+
380
+ // From https://stackoverflow.com/a/274094
381
+ function regexIndexOf(string: string, regex: RegExp, position?: number) {
382
+ var indexOf = string.substring(position || 0).search(regex);
383
+ return indexOf >= 0 ? indexOf + (position || 0) : indexOf;
384
+ }
@@ -0,0 +1,11 @@
1
+ import { $watch } from "@torpor/view";
2
+
3
+ const $page = $watch(
4
+ {
5
+ status: 404,
6
+ url: new URL("http://localhost"),
7
+ },
8
+ { shallow: true },
9
+ );
10
+
11
+ export default $page;
package/src/state.ts ADDED
@@ -0,0 +1,3 @@
1
+ import $page from "./state/$page";
2
+
3
+ export { $page };
@@ -0,0 +1,7 @@
1
+ import { CookieSerializeOptions } from "vinxi/http";
2
+
3
+ export default interface CookieHelper {
4
+ get: (name: string) => string | undefined;
5
+ set: (name: string, value: string, options?: CookieSerializeOptions) => void;
6
+ delete: (name: string, options?: CookieSerializeOptions) => void;
7
+ }
@@ -0,0 +1,37 @@
1
+ import type { Component } from "@torpor/view";
2
+ import type PageEvent from "./PageEvent";
3
+
4
+ /**
5
+ * For +page.
6
+ */
7
+ export default interface PageEndPoint {
8
+ /**
9
+ * Builds the route path for the page in a type-safe manner.
10
+ * TODO: Not sure this is actually the best way to do it...
11
+ */
12
+ route?: (...args: any[]) => string;
13
+ /**
14
+ * Loads data for the page.
15
+ */
16
+ load?: (event: PageEvent) => any;
17
+ /**
18
+ * The component that is displayed for the page.
19
+ */
20
+ component?: Component;
21
+ // TODO: Better typing
22
+ /**
23
+ * The head element data for the page, which may include a <title> and <meta> elements.
24
+ */
25
+ head?: HeadElement[] | ((event: PageEvent) => HeadElement[]);
26
+ }
27
+
28
+ type HeadElement = TitleElement | MetaElement;
29
+
30
+ interface TitleElement {
31
+ title: string;
32
+ }
33
+
34
+ interface MetaElement {
35
+ name: string;
36
+ content: string;
37
+ }
@@ -0,0 +1,14 @@
1
+ export default interface PageEvent {
2
+ /**
3
+ * The URL for the server function.
4
+ */
5
+ url: URL;
6
+ /**
7
+ * Route params from the URL and route path.
8
+ */
9
+ params: Record<string, string>;
10
+ /**
11
+ * Data that is (optionally) loaded from the load function and passed into the page as $props.data.
12
+ */
13
+ data: Record<string, any>;
14
+ }
@@ -0,0 +1,18 @@
1
+ import ServerEvent from "./ServerEvent";
2
+
3
+ /**
4
+ * For +page.server.
5
+ */
6
+ export default interface PageServerEndPoint {
7
+ /**
8
+ * Loads data from the server for a page.
9
+ */
10
+ load?: ServerLoad;
11
+ /**
12
+ * A map of actions that can be performed on the server for a page, generally from a form submit.
13
+ */
14
+ actions?: Record<string, ServerAction>;
15
+ }
16
+
17
+ type ServerLoad = (event: ServerEvent) => Response | Promise<Response | undefined> | void;
18
+ type ServerAction = (event: ServerEvent) => Response | Promise<Response | undefined> | void;
@@ -0,0 +1,12 @@
1
+ import RouteLayoutHandler from "./RouteLayoutHandler";
2
+
3
+ export default interface RouteHandler {
4
+ path: string;
5
+ regex: RegExp;
6
+ endPoint: Promise<any>;
7
+
8
+ loaded: boolean;
9
+ layouts?: RouteLayoutHandler[];
10
+ serverEndPoint?: Promise<any>;
11
+ serverHook?: Promise<any>;
12
+ }
@@ -0,0 +1,7 @@
1
+ import type RouteHandler from "./RouteHandler";
2
+ import type RouteMatchResult from "./RouteMatchResult";
3
+
4
+ export default interface RouteHandlerCollection {
5
+ handlers: RouteHandler[];
6
+ match(path: string, urlParams?: URLSearchParams): RouteMatchResult | undefined;
7
+ }
@@ -0,0 +1,5 @@
1
+ export default interface RouteLayoutHandler {
2
+ path: string;
3
+ endPoint: Promise<any>;
4
+ serverEndPoint?: Promise<any>;
5
+ }
@@ -0,0 +1,7 @@
1
+ import type RouteHandler from "./RouteHandler";
2
+
3
+ export default interface RouteMatchResult {
4
+ handler: RouteHandler;
5
+ routeParams?: Record<string, string>;
6
+ urlParams?: Record<string, string>;
7
+ }
@@ -0,0 +1,37 @@
1
+ import ServerEvent from "./ServerEvent";
2
+
3
+ /**
4
+ * For +server.
5
+ */
6
+ export default interface ServerEndPoint {
7
+ /**
8
+ * Performs a GET.
9
+ */
10
+ get?: ServerRequest;
11
+ /**
12
+ * Perfroms a POST.
13
+ */
14
+ post?: ServerRequest;
15
+ /**
16
+ * Perfroms a PATCH.
17
+ */
18
+ patch?: ServerRequest;
19
+ /**
20
+ * Perfroms a PUT.
21
+ */
22
+ put?: ServerRequest;
23
+ /**
24
+ * Perfroms a DELETE.
25
+ */
26
+ del?: ServerRequest;
27
+ /**
28
+ * Perfroms an OPTIONS request.
29
+ */
30
+ options?: ServerRequest;
31
+ /**
32
+ * Perfroms a HEAD request.
33
+ */
34
+ head?: ServerRequest;
35
+ }
36
+
37
+ type ServerRequest = (event: ServerEvent) => Response | Promise<Response | undefined> | void;
@@ -0,0 +1,27 @@
1
+ import { ServerResponse } from "node:http";
2
+ import CookieHelper from "./CookieHelper";
3
+
4
+ export default interface ServerEvent {
5
+ /**
6
+ * The URL for the server function.
7
+ */
8
+ url: URL;
9
+ /**
10
+ * Route params from the URL and route path.
11
+ */
12
+ params: Record<string, string>;
13
+ // TODO: Maybe we should find a better name for the data that is set set in
14
+ // pages, and just call this data?
15
+ /**
16
+ * Data that is available to functions in +server hooks, layouts, endpoints
17
+ * and pages. It flows down in that order.
18
+ */
19
+ appData: Record<string, any>;
20
+ // TODO: Would be nicer if these were Request/Response?
21
+ request: Request;
22
+ response: ServerResponse;
23
+ /**
24
+ * A helper for getting and setting cookie data.
25
+ */
26
+ cookies: CookieHelper;
27
+ }
@@ -0,0 +1,13 @@
1
+ import ServerEvent from "./ServerEvent";
2
+
3
+ /**
4
+ * For _hook.server.
5
+ */
6
+ export default interface ServerHook {
7
+ /**
8
+ * Called on each server request.
9
+ */
10
+ handle?: ServerLoad;
11
+ }
12
+
13
+ type ServerLoad = (event: ServerEvent) => Promise<void> | void;
@@ -0,0 +1,3 @@
1
+ export default interface UserConfig {
2
+ port?: number;
3
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../tsconfig",
3
+ "include": ["tsup.config.ts"]
4
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts", "src/state.ts", "src/response.ts", "src/bin/index.ts"],
5
+ format: ["esm", "cjs"],
6
+ dts: true,
7
+ clean: true,
8
+ metafile: true,
9
+ sourcemap: true,
10
+ });