@torpor/build 0.4.14 → 1.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 (193) hide show
  1. package/README.md +20 -2
  2. package/dist/Jsonify-Dg6gChd3.d.mts +10 -0
  3. package/dist/Jsonify-Dg6gChd3.d.mts.map +1 -0
  4. package/dist/ParseRouteParams-DBmqlmLh.d.mts +42 -0
  5. package/dist/ParseRouteParams-DBmqlmLh.d.mts.map +1 -0
  6. package/dist/{RouteType-B6BMOyYw.mjs → Router-C4ADUfhv.mjs} +30 -42
  7. package/dist/Router-C4ADUfhv.mjs.map +1 -0
  8. package/dist/Server-BnjLJleZ.mjs +104 -0
  9. package/dist/Server-BnjLJleZ.mjs.map +1 -0
  10. package/dist/Server-Cler2w5O.d.mts +61 -0
  11. package/dist/Server-Cler2w5O.d.mts.map +1 -0
  12. package/dist/ServerEvent-CTx3Q-hk.d.mts +48 -0
  13. package/dist/ServerEvent-CTx3Q-hk.d.mts.map +1 -0
  14. package/dist/{ServerEvent-CxPwA4lH.mjs → ServerEvent-Dljn5i7A.mjs} +37 -11
  15. package/dist/ServerEvent-Dljn5i7A.mjs.map +1 -0
  16. package/dist/Site-CE0_o5Ci.d.mts +566 -0
  17. package/dist/Site-CE0_o5Ci.d.mts.map +1 -0
  18. package/dist/StandardSchema-D28L8_zZ.d.mts +100 -0
  19. package/dist/StandardSchema-D28L8_zZ.d.mts.map +1 -0
  20. package/dist/TypedResponse-6lznqN4U.d.mts +22 -0
  21. package/dist/TypedResponse-6lznqN4U.d.mts.map +1 -0
  22. package/dist/{_page-BQs4WvCO.mjs → _page-4cQKs_Dn.mjs} +3 -5
  23. package/dist/_page-4cQKs_Dn.mjs.map +1 -0
  24. package/dist/bin/index.d.mts +1 -1
  25. package/dist/bin/index.js +15 -11
  26. package/dist/bin/index.js.map +1 -1
  27. package/dist/clientEntry.d.mts +1 -0
  28. package/dist/clientEntry.mjs +59 -0
  29. package/dist/clientEntry.mjs.map +1 -0
  30. package/dist/clientEntryDev.d.mts +1 -0
  31. package/dist/clientEntryDev.mjs +7 -0
  32. package/dist/clientEntryDev.mjs.map +1 -0
  33. package/dist/dev.d.mts +3 -0
  34. package/dist/dev.mjs +3 -0
  35. package/dist/endpoint-EULRGCKA.mjs +108 -0
  36. package/dist/endpoint-EULRGCKA.mjs.map +1 -0
  37. package/dist/flattenHeaders-DM5qsSqO.mjs +13 -0
  38. package/dist/flattenHeaders-DM5qsSqO.mjs.map +1 -0
  39. package/dist/form.d.mts +35 -0
  40. package/dist/form.d.mts.map +1 -0
  41. package/dist/form.mjs +48 -0
  42. package/dist/form.mjs.map +1 -0
  43. package/dist/index.d.mts +72 -156
  44. package/dist/index.d.mts.map +1 -1
  45. package/dist/index.mjs +158 -26
  46. package/dist/index.mjs.map +1 -1
  47. package/dist/load-BntzvmwL.mjs +228 -0
  48. package/dist/load-BntzvmwL.mjs.map +1 -0
  49. package/dist/nav.d.mts +58 -5
  50. package/dist/nav.d.mts.map +1 -1
  51. package/dist/nav.mjs +63 -209
  52. package/dist/nav.mjs.map +1 -1
  53. package/dist/openapi.d.mts +144 -0
  54. package/dist/openapi.d.mts.map +1 -0
  55. package/dist/openapi.mjs +2 -0
  56. package/dist/pathTrie-D4Ax2Mu9.mjs +160 -0
  57. package/dist/pathTrie-D4Ax2Mu9.mjs.map +1 -0
  58. package/dist/plugin-D8Www11B.mjs +202 -0
  59. package/dist/plugin-D8Www11B.mjs.map +1 -0
  60. package/dist/{response-C5TtAsh1.mjs → response-Bg4w2S1q.mjs} +16 -39
  61. package/dist/response-Bg4w2S1q.mjs.map +1 -0
  62. package/dist/response.d.mts +309 -289
  63. package/dist/response.d.mts.map +1 -1
  64. package/dist/response.mjs +3 -4
  65. package/dist/run.d.mts +11 -4
  66. package/dist/run.d.mts.map +1 -1
  67. package/dist/run.mjs +2 -8
  68. package/dist/runOpenApi-DlOgF2Il.mjs +1419 -0
  69. package/dist/runOpenApi-DlOgF2Il.mjs.map +1 -0
  70. package/dist/schema.d.mts +32 -0
  71. package/dist/schema.d.mts.map +1 -0
  72. package/dist/schema.mjs +2 -0
  73. package/dist/server/Server.d.mts +2 -0
  74. package/dist/server/Server.mjs +2 -0
  75. package/dist/server.d.mts +11 -8
  76. package/dist/server.d.mts.map +1 -1
  77. package/dist/server.mjs +133 -4
  78. package/dist/server.mjs.map +1 -0
  79. package/dist/serverEntry-1qY3wZig.mjs +351 -0
  80. package/dist/serverEntry-1qY3wZig.mjs.map +1 -0
  81. package/dist/serverEntry-BAO8m03V.d.mts +6 -0
  82. package/dist/serverEntry-BAO8m03V.d.mts.map +1 -0
  83. package/dist/serverEntry.d.mts +2 -0
  84. package/dist/serverEntry.mjs +2 -0
  85. package/dist/state.d.mts.map +1 -1
  86. package/dist/state.mjs +2 -3
  87. package/dist/test.d.mts +8 -10
  88. package/dist/test.d.mts.map +1 -1
  89. package/dist/test.mjs +181 -79
  90. package/dist/test.mjs.map +1 -1
  91. package/dist/{seeOther-B4Yhu9iq.mjs → unprocessable-DAZbrDeR.mjs} +34 -13
  92. package/dist/unprocessable-DAZbrDeR.mjs.map +1 -0
  93. package/dist/validate-Ok4krlkX.mjs +40 -0
  94. package/dist/validate-Ok4krlkX.mjs.map +1 -0
  95. package/package.json +30 -18
  96. package/dist/RouteType-B6BMOyYw.mjs.map +0 -1
  97. package/dist/Server-CF5wDJp6.d.mts +0 -78
  98. package/dist/Server-CF5wDJp6.d.mts.map +0 -1
  99. package/dist/ServerEvent-CxPwA4lH.mjs.map +0 -1
  100. package/dist/Site-DgC6WWn1.d.mts +0 -78
  101. package/dist/Site-DgC6WWn1.d.mts.map +0 -1
  102. package/dist/_page-BQs4WvCO.mjs.map +0 -1
  103. package/dist/connectMiddleware-D7nehjj3.mjs +0 -252
  104. package/dist/connectMiddleware-D7nehjj3.mjs.map +0 -1
  105. package/dist/pathToRegex-TUAMc3zS.mjs +0 -11
  106. package/dist/pathToRegex-TUAMc3zS.mjs.map +0 -1
  107. package/dist/response-C5TtAsh1.mjs.map +0 -1
  108. package/dist/run-BPFtSYA3.mjs +0 -332
  109. package/dist/run-BPFtSYA3.mjs.map +0 -1
  110. package/dist/seeOther-B4Yhu9iq.mjs.map +0 -1
  111. package/src/bin/index.ts +0 -11
  112. package/src/index.ts +0 -30
  113. package/src/nav/formSubmit.ts +0 -56
  114. package/src/nav/load.ts +0 -9
  115. package/src/nav/loadData.ts +0 -134
  116. package/src/nav/navigate.ts +0 -164
  117. package/src/nav/reload.ts +0 -9
  118. package/src/nav.ts +0 -4
  119. package/src/response/badRequest.ts +0 -19
  120. package/src/response/created.ts +0 -20
  121. package/src/response/forbidden.ts +0 -21
  122. package/src/response/found.ts +0 -30
  123. package/src/response/methodNotAllowed.ts +0 -18
  124. package/src/response/movedPermanently.ts +0 -25
  125. package/src/response/notFound.ts +0 -24
  126. package/src/response/notModified.ts +0 -34
  127. package/src/response/ok.ts +0 -29
  128. package/src/response/permanentRedirect.ts +0 -30
  129. package/src/response/response.ts +0 -22
  130. package/src/response/seeOther.ts +0 -19
  131. package/src/response/serverError.ts +0 -24
  132. package/src/response/temporaryRedirect.ts +0 -31
  133. package/src/response/transfer.ts +0 -14
  134. package/src/response/unauthorized.ts +0 -21
  135. package/src/response/unprocessable.ts +0 -18
  136. package/src/response.ts +0 -37
  137. package/src/run/prepareTemplate.ts +0 -39
  138. package/src/run/run.ts +0 -62
  139. package/src/run/runBuild.ts +0 -77
  140. package/src/run/runDev.ts +0 -89
  141. package/src/run/runPreview.ts +0 -93
  142. package/src/run.ts +0 -6
  143. package/src/server/CookieHelper.ts +0 -36
  144. package/src/server/HeaderHelper.ts +0 -25
  145. package/src/server/Routerx.ts +0 -72
  146. package/src/server/Server.ts +0 -144
  147. package/src/server/ServerEvent.ts +0 -39
  148. package/src/server/connect/bufferToArrayBuffer.ts +0 -8
  149. package/src/server/connect/connectMiddleware.ts +0 -81
  150. package/src/server/connect/flattenHeaders.ts +0 -44
  151. package/src/server/connect/nodeMessageToNodeResponse.ts +0 -89
  152. package/src/server/connect/readableToBuffer.ts +0 -16
  153. package/src/server/connect/requestToNodeMessage.ts +0 -26
  154. package/src/server/contentType.ts +0 -85
  155. package/src/server/types/HttpMethod.ts +0 -12
  156. package/src/server/types/MiddlewareFunction.ts +0 -8
  157. package/src/server/types/ServerFunction.ts +0 -7
  158. package/src/server.ts +0 -7
  159. package/src/site/Router.ts +0 -164
  160. package/src/site/Site.ts +0 -214
  161. package/src/site/clientEntry.ts +0 -108
  162. package/src/site/clientEntryDev.ts +0 -3
  163. package/src/site/defaultAdapter.ts +0 -11
  164. package/src/site/manifest.ts +0 -54
  165. package/src/site/serverEntry.ts +0 -439
  166. package/src/state/$page.ts +0 -24
  167. package/src/state/client.ts +0 -15
  168. package/src/state.ts +0 -3
  169. package/src/test/runTest.ts +0 -350
  170. package/src/test.ts +0 -3
  171. package/src/types/Adapter.ts +0 -8
  172. package/src/types/ClientState.ts +0 -8
  173. package/src/types/InternalState.ts +0 -7
  174. package/src/types/LayoutHandler.ts +0 -5
  175. package/src/types/LayoutPath.ts +0 -10
  176. package/src/types/ManifestRoute.ts +0 -6
  177. package/src/types/PageEndPoint.ts +0 -39
  178. package/src/types/PageLoadEvent.ts +0 -14
  179. package/src/types/PageServerAction.ts +0 -7
  180. package/src/types/PageServerEndPoint.ts +0 -16
  181. package/src/types/PageServerLoad.ts +0 -7
  182. package/src/types/PageState.ts +0 -8
  183. package/src/types/Route.ts +0 -11
  184. package/src/types/RouteHandler.ts +0 -16
  185. package/src/types/RouteLayoutHandler.ts +0 -5
  186. package/src/types/RouteMatchResult.ts +0 -7
  187. package/src/types/RouteType.ts +0 -19
  188. package/src/types/ServerEndPoint.ts +0 -37
  189. package/src/types/ServerHook.ts +0 -11
  190. package/src/types/ServerLoadEvent.ts +0 -37
  191. package/src/types/ServerRequest.ts +0 -7
  192. package/src/utils/pathToRegex.ts +0 -15
  193. package/src/vite-env.d.ts +0 -2
package/README.md CHANGED
@@ -4,8 +4,6 @@ A framework for building sites and apps with Torpor.
4
4
 
5
5
  Built on top of [Vite](https://vite.dev).
6
6
 
7
- 🚧 WARNING: WORK IN PROGRESS 🚧
8
-
9
7
  ## Installation
10
8
 
11
9
  Use `npm` (or your preferred package manager) to create a starter project:
@@ -17,6 +15,26 @@ npm install
17
15
  npm run dev
18
16
  ```
19
17
 
18
+ ## Features
19
+
20
+ - Configure the `Site` class in your `site.config.ts` with routes and adapters
21
+ - Setup code-based routing (with `site.addRoute`)
22
+ - Or file-based routing (with `site.addRouteFolder`)
23
+ - Pages and API endpoints, with layouts and error pages
24
+ - A `tb` command line interface:
25
+ - `tb --dev` -- start the dev server
26
+ - `tb --build` -- create a production build
27
+ - `tb --preview` -- preview the production build
28
+ - `tb --openapi [outFile]` -- generate an OpenAPI document
29
+ - Adapters for deployment targets -- see
30
+ [@torpor/adapter-node](../adapters/adapter-node) and
31
+ [@torpor/adapter-cloudflare](../adapters/adapter-cloudflare)
32
+ - Schema validation for endpoints (`@torpor/build/schema`)
33
+ - Form helpers (`@torpor/build/form`) and client side navigation helpers
34
+ (`@torpor/build/nav`)
35
+ - `$page` state for pages (`@torpor/build/state`) and response helpers
36
+ (`@torpor/build/response`)
37
+
20
38
  ## Folder structure
21
39
 
22
40
  - /src
@@ -0,0 +1,10 @@
1
+ //#region src/types/Jsonify.d.ts
2
+ /**
3
+ * The JSON-serialized form of a type: what a value looks like after a
4
+ * JSON.stringify / JSON.parse round trip. Dates become strings, functions and
5
+ * undefined properties are dropped.
6
+ */
7
+ type Jsonify<T> = T extends string | number | boolean | null ? T : T extends undefined | ((...args: any[]) => any) ? never : T extends Date ? string : T extends Array<infer Item> ? Array<Jsonify<Item>> : T extends object ? { [Key in keyof T as T[Key] extends undefined | ((...args: any[]) => any) ? never : Key]: Jsonify<T[Key]>; } : T;
8
+ //#endregion
9
+ export { Jsonify as t };
10
+ //# sourceMappingURL=Jsonify-Dg6gChd3.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Jsonify-Dg6gChd3.d.mts","names":[],"sources":["../src/types/Jsonify.ts"],"mappings":";;;;;;KAKY,QAAQ,KAAK,6CACtB,IACA,2BAA2B,+BAE1B,UAAU,gBAET,UAAU,YAAY,QACrB,MAAM,QAAQ,SACd,sBAEE,aAAa,KAAK,EAAE,8BAA8B,+BAEhD,MAAM,QAAQ,EAAE,WAEnB"}
@@ -0,0 +1,42 @@
1
+ //#region src/types/ParseRouteParams.d.ts
2
+ /**
3
+ * Extracts the params object from a route path string.
4
+ *
5
+ * Dynamic segments (`[id]`) and splat segments (`[...path]`) become string
6
+ * properties; static segments are ignored. For example:
7
+ *
8
+ * ```ts
9
+ * type Params = ParseRouteParams<"/posts/[id]/comments/[commentId]">;
10
+ * // { id: string; commentId: string }
11
+ * ```
12
+ */
13
+ type ParseRouteParams<Route extends string> = ParseSegments<Route, unknown>;
14
+ type ParseSegments<Route extends string, Params> = Route extends `${infer Head}/${infer Rest}` ? ParseSegments<Rest, ParseSegment<Head, Params>> : ParseSegment<Route, Params>;
15
+ type ParseSegment<Segment extends string, Params> = Segment extends `[...${infer Name}]` ? Params & { [Key in Name]: string; } : Segment extends `[${infer Name}]` ? Params & { [Key in Name]: string; } : Params;
16
+ /**
17
+ * Resolves the params for a route annotation: the parsed params for a literal
18
+ * route path, or a loose record when no route (or a non-literal string) is
19
+ * given.
20
+ */
21
+ type RouteParamsOf<Route extends string | undefined> = string extends Route ? Record<string, string> : Route extends string ? ParseRouteParams<Route> : Record<string, string>;
22
+ /**
23
+ * Validates an inferred params object against a route's params shape:
24
+ * resolves to the params type when its keys are exactly the route's keys, and
25
+ * `never` when keys are missing or extra — so wrong keys error at the call
26
+ * site (excess property checks are skipped for deferred conditional rest
27
+ * tuples, but assignability to `never` can't be).
28
+ */
29
+ type ExactRouteParams<Params, Shape> = Params extends Shape ? [Exclude<keyof Params, keyof Shape>] extends [never] ? Params : never : never;
30
+ /**
31
+ * The arguments for building a route path: nothing for static routes, or the
32
+ * route's params object for dynamic routes.
33
+ */
34
+ type RouteArgs<Route extends string> = string extends Route ? [params?: Record<string, string>] : keyof ParseRouteParams<Route> extends never ? [] : [params: ParseRouteParams<Route>];
35
+ /**
36
+ * RouteArgs for an optional route annotation, defaulting to a single optional
37
+ * loose params object.
38
+ */
39
+ type RouteArgsOf<Route extends string | undefined> = Route extends string ? RouteArgs<Route> : [params?: Record<string, string>];
40
+ //#endregion
41
+ export { RouteParamsOf as a, RouteArgsOf as i, ParseRouteParams as n, RouteArgs as r, ExactRouteParams as t };
42
+ //# sourceMappingURL=ParseRouteParams-DBmqlmLh.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParseRouteParams-DBmqlmLh.d.mts","names":[],"sources":["../src/types/ParseRouteParams.ts"],"mappings":";;;;;;;;;;;;KAWY,iBAAiB,wBAAwB,cAAc;KAE9D,cAAc,sBAAsB,UAAU,uBAAuB,cAAc,SACrF,cAAc,MAAM,aAAa,MAAM,WACvC,aAAa,OAAO;KAElB,aAAa,wBAAwB,UAAU,6BAA6B,UAC9E,YAAY,OAAO,mBACnB,0BAA0B,UACzB,YAAY,OAAO,mBACnB;;;;;;KAOQ,cAAc,mDAAmD,QAC1E,yBACA,uBACC,iBAAiB,SACjB;;;;;;;;KASQ,iBAAiB,QAAQ,SAAS,eAAe,SACzD,cAAc,cAAc,0BAC5B;;;;;KAQQ,UAAU,uCAAuC,SACzD,SAAS,gCACJ,iBAAiB,6BAErB,QAAQ,iBAAiB;;;;;KAMlB,YAAY,oCAAoC,uBACzD,UAAU,UACT,SAAS"}
@@ -1,49 +1,44 @@
1
- import { t as pathToRegex } from "./pathToRegex-TUAMc3zS.mjs";
2
-
1
+ import { t as PathTrie } from "./pathTrie-D4Ax2Mu9.mjs";
3
2
  //#region src/site/Router.ts
4
3
  /**
5
4
  * A router that handles file routes with layouts, hooks, etc.
6
5
  */
7
6
  var Router = class {
8
7
  routes = [];
8
+ #trie = new PathTrie();
9
9
  constructor() {}
10
10
  addPages(routes) {
11
- for (let r of routes) this.routes.push(new Route(r.path, {
12
- path: r.path,
13
- type: r.type,
14
- endPoint: r.endPoint,
15
- subFolder: r.subFolder
16
- }));
17
- this.#sortRoutes();
11
+ for (let r of routes) this.addPage(r.path, r.type, r.endPoint, r.subFolder);
18
12
  return this;
19
13
  }
20
14
  addPage(path, type, endPoint, subFolder) {
21
- this.routes.push(new Route(path, {
15
+ let route = new Route(path, {
22
16
  path,
23
17
  type,
24
18
  endPoint,
25
19
  subFolder
26
- }));
20
+ });
21
+ this.routes.push(route);
22
+ this.#trie.insert(path, route);
27
23
  this.#sortRoutes();
28
24
  return this;
29
25
  }
30
26
  match(path, query) {
31
- for (let route of this.routes) {
32
- let match = path.match(route.regex);
33
- if (match) {
34
- if (!route.handler.loaded) this.#loadHandler(route.handler, route.path);
35
- return {
36
- handler: route.handler,
37
- params: match.groups,
38
- query
39
- };
40
- }
27
+ let found = this.#trie.match(path);
28
+ if (found) {
29
+ let route = found.value;
30
+ if (!route.handler.loaded) this.#loadHandler(route.handler, route.path);
31
+ return {
32
+ handler: route.handler,
33
+ params: found.params,
34
+ query
35
+ };
41
36
  }
42
37
  }
43
38
  #loadHandler(handler, path) {
44
39
  handler.layouts = this.#findLayouts(path, handler);
45
40
  handler.serverEndPoint = this.#findServer(path);
46
- handler.serverHook = this.#findServerHook(handler);
41
+ handler.serverHooks = this.#findServerHooks(handler);
47
42
  }
48
43
  #findLayouts(path, handler) {
49
44
  let layouts = [];
@@ -66,11 +61,17 @@ var Router = class {
66
61
  const serverRoute = this.routes.find((r) => r.path === serverPath);
67
62
  return serverRoute && serverRoute.handler.endPoint;
68
63
  }
69
- #findServerHook(handler) {
70
- let serverHookPath = "/_hook/~server";
71
- if (handler.subFolder !== void 0) serverHookPath = handler.subFolder + serverHookPath;
72
- const serverHookRoute = this.routes.find((r) => r.path === serverHookPath);
73
- return serverHookRoute && serverHookRoute.handler.endPoint;
64
+ #findServerHooks(handler) {
65
+ const hooks = [];
66
+ let parts = handler.path.replace(/\/~server$/, "").split("/");
67
+ let basePath = "";
68
+ for (let i = 0; i < parts.length; i++) {
69
+ if (i > 0) basePath += "/" + parts[i];
70
+ const hookPath = basePath + "/_hook/~server";
71
+ const hookRoute = this.routes.find((r) => r.path === hookPath);
72
+ if (hookRoute && hookRoute.handler.subFolder === handler.subFolder) hooks.push(hookRoute.handler.endPoint);
73
+ }
74
+ return hooks.length ? hooks : void 0;
74
75
  }
75
76
  #sortRoutes() {
76
77
  this.routes = this.routes.sort((a, b) => {
@@ -83,26 +84,13 @@ var Router = class {
83
84
  };
84
85
  var Route = class {
85
86
  path;
86
- regex;
87
87
  handler;
88
88
  constructor(path, handler) {
89
89
  this.path = path;
90
- this.regex = pathToRegex(path);
91
90
  this.handler = handler;
92
91
  }
93
92
  };
94
-
95
93
  //#endregion
96
- //#region src/types/RouteType.ts
97
- const PAGE_ROUTE = 0;
98
- const PAGE_SERVER_ROUTE = 1;
99
- const SERVER_ROUTE = 3;
100
- const LAYOUT_ROUTE = 4;
101
- const LAYOUT_SERVER_ROUTE = 5;
102
- const HOOK_ROUTE = 6;
103
- const HOOK_SERVER_ROUTE = 7;
104
- const ERROR_ROUTE = 8;
94
+ export { Router as t };
105
95
 
106
- //#endregion
107
- export { LAYOUT_SERVER_ROUTE as a, SERVER_ROUTE as c, LAYOUT_ROUTE as i, Router as l, HOOK_ROUTE as n, PAGE_ROUTE as o, HOOK_SERVER_ROUTE as r, PAGE_SERVER_ROUTE as s, ERROR_ROUTE as t };
108
- //# sourceMappingURL=RouteType-B6BMOyYw.mjs.map
96
+ //# sourceMappingURL=Router-C4ADUfhv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Router-C4ADUfhv.mjs","names":["#trie","#sortRoutes","#loadHandler","#findLayouts","#findServer","#findServerHooks"],"sources":["../src/site/Router.ts"],"sourcesContent":["import type LayoutHandler from \"../types/LayoutHandler\";\nimport type ManifestRoute from \"../types/ManifestRoute\";\nimport type RouteHandler from \"../types/RouteHandler\";\nimport PathTrie from \"../utils/pathTrie\";\n\n/**\n * A router that handles file routes with layouts, hooks, etc.\n */\nexport default class Router {\n\troutes: Route[] = [];\n\t// Match index for the routes above. The routes list is kept for\n\t// introspection (layouts/hooks lookup, client nav, tests); the trie is\n\t// what `match` walks.\n\t#trie = new PathTrie<Route>();\n\n\tconstructor() {}\n\n\t//add(path: string, file: string) {\n\t//\t// TODO: Call the specific addX method based on the file path\n\t//\tthis.addPage(route, file);\n\t//}\n\n\taddPages(routes: ManifestRoute[]): this {\n\t\tfor (let r of routes) {\n\t\t\tthis.addPage(r.path, r.type, r.endPoint, r.subFolder);\n\t\t}\n\t\treturn this;\n\t}\n\n\t// TODO: Allow calling with the endpoint itself, so that you can setup an app with no scaffold\n\taddPage(path: string, type: number, endPoint: () => Promise<any>, subFolder?: string): this {\n\t\tlet route = new Route(path, {\n\t\t\tpath,\n\t\t\ttype,\n\t\t\tendPoint,\n\t\t\tsubFolder,\n\t\t});\n\t\tthis.routes.push(route);\n\t\tthis.#trie.insert(path, route);\n\t\tthis.#sortRoutes();\n\t\treturn this;\n\t}\n\n\t/*\n\tloadPage(ev: ServerEvent, file: string): Response {\n\t\tlet page = this.pages.get(file);\n\t\tif (!page) {\n\t\t\tpage = {};\n\t\t\tthis.pages.set(file, page);\n\t\t}\n\t}\n\t*/\n\n\tmatch(path: string, query: URLSearchParams): RouteMatch | undefined {\n\t\tlet found = this.#trie.match(path);\n\t\tif (found) {\n\t\t\tlet route = found.value;\n\t\t\t// Lazy load server endpoints and layouts\n\t\t\tif (!route.handler.loaded) {\n\t\t\t\tthis.#loadHandler(route.handler, route.path);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\thandler: route.handler,\n\t\t\t\tparams: found.params,\n\t\t\t\tquery,\n\t\t\t};\n\t\t}\n\t}\n\n\t#loadHandler(handler: RouteHandler, path: string) {\n\t\thandler.layouts = this.#findLayouts(path, handler);\n\t\thandler.serverEndPoint = this.#findServer(path);\n\t\thandler.serverHooks = this.#findServerHooks(handler);\n\t}\n\n\t#findLayouts(path: string, handler: RouteHandler): LayoutHandler[] | undefined {\n\t\tlet layouts: LayoutHandler[] = [];\n\t\tlet parts = path\n\t\t\t// Strip the trailing`~/server` (so we don't look for `~/server/_layout`\n\t\t\t// which will never exist)\n\t\t\t.replace(/\\/~server$/, \"\")\n\t\t\t// The path will always start with / so splitting e.g. `/first/second`\n\t\t\t// will result in ['', 'first', 'second'] and checks for `/_layout`,\n\t\t\t// `/first/_layout` and `/second/_layout`\n\t\t\t.split(\"/\");\n\t\tlet basePath = \"\";\n\t\tfor (let i = 0; i < parts.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tbasePath += \"/\" + parts[i];\n\t\t\t}\n\t\t\tconst layoutPath = basePath + \"/_layout\";\n\t\t\tconst layoutRoute = this.routes.find((r) => r.path === layoutPath);\n\t\t\tif (layoutRoute && layoutRoute.handler.subFolder === handler.subFolder) {\n\t\t\t\tlayouts.push({\n\t\t\t\t\tpath: layoutPath,\n\t\t\t\t\tendPoint: layoutRoute.handler.endPoint,\n\t\t\t\t\tserverEndPoint: this.#findServer(layoutPath),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn layouts.length ? layouts : undefined;\n\t}\n\n\t#findServer(path: string): (() => Promise<any>) | undefined {\n\t\tconst serverPath = path.replace(/\\/$/, \"\") + \"/~server\";\n\t\tconst serverRoute = this.routes.find((r) => r.path === serverPath);\n\t\treturn serverRoute && serverRoute.handler.endPoint;\n\t}\n\n\t#findServerHooks(handler: RouteHandler): (() => Promise<any>)[] | undefined {\n\t\t// Collect the hooks from the root down to the route path, like\n\t\t// layouts. Only hooks with the same subFolder are included, so that\n\t\t// e.g. an `api` set of routes can have its own hooks\n\t\tconst hooks: (() => Promise<any>)[] = [];\n\t\tlet parts = handler.path\n\t\t\t// Strip the trailing `~server` (so we don't look for\n\t\t\t// `~server/_hook/~server` which will never exist)\n\t\t\t.replace(/\\/~server$/, \"\")\n\t\t\t// The path will always start with / so splitting e.g.\n\t\t\t// `/first/second` will result in ['', 'first', 'second'] and\n\t\t\t// checks for `/_hook/~server`, `/first/_hook/~server` and\n\t\t\t// `/second/_hook/~server`\n\t\t\t.split(\"/\");\n\t\tlet basePath = \"\";\n\t\tfor (let i = 0; i < parts.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tbasePath += \"/\" + parts[i];\n\t\t\t}\n\t\t\tconst hookPath = basePath + \"/_hook/~server\";\n\t\t\tconst hookRoute = this.routes.find((r) => r.path === hookPath);\n\t\t\tif (hookRoute && hookRoute.handler.subFolder === handler.subFolder) {\n\t\t\t\thooks.push(hookRoute.handler.endPoint);\n\t\t\t}\n\t\t}\n\t\treturn hooks.length ? hooks : undefined;\n\t}\n\n\t// HACK: We're doing this here as well as in Site, so that you can use the\n\t// Router externally without Site\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\nclass Route {\n\tpath: string;\n\thandler: RouteHandler;\n\n\tconstructor(path: string, handler: RouteHandler) {\n\t\tthis.path = path;\n\t\tthis.handler = handler;\n\t}\n}\n\ninterface RouteMatch {\n\thandler: RouteHandler;\n\tparams?: Record<string, string>;\n\tquery: URLSearchParams;\n}\n"],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import { t as PathTrie } from "./pathTrie-D4Ax2Mu9.mjs";
2
+ import { t as ServerEvent } from "./ServerEvent-Dljn5i7A.mjs";
3
+ //#region src/server/Server.ts
4
+ /**
5
+ * A Fetch API Request/Response server.
6
+ */
7
+ var Server = class {
8
+ routes = [];
9
+ #trie = new PathTrie();
10
+ middleware = [];
11
+ constructor() {
12
+ this.routes = [];
13
+ this.middleware = [];
14
+ }
15
+ /**
16
+ * The standard Fetch API method that should work in any runtime (including
17
+ * Node with polyfills).
18
+ * @returns
19
+ */
20
+ fetch = async (input, init) => {
21
+ const request = input instanceof Request && !init ? input : new Request(input, init);
22
+ const url = new URL(request.url);
23
+ const match = this.match(url.pathname);
24
+ let ev = new ServerEvent(request, match?.params, url);
25
+ if (this.middleware.length) {
26
+ let entered = 0;
27
+ let response = void 0;
28
+ let error = void 0;
29
+ try {
30
+ for (; entered < this.middleware.length && !response; entered++) {
31
+ const result = await this.middleware[entered].enter?.(ev);
32
+ if (result) response = result;
33
+ }
34
+ if (!response && match) {
35
+ const result = await match.fn(ev);
36
+ if (result) response = result;
37
+ }
38
+ } catch (e) {
39
+ error = e;
40
+ ev.error = e;
41
+ } finally {
42
+ if (response) ev.response = response;
43
+ while (entered > 0) {
44
+ entered--;
45
+ const result = await this.middleware[entered].exit?.(ev);
46
+ if (result) {
47
+ response = result;
48
+ ev.response = result;
49
+ }
50
+ }
51
+ }
52
+ if (error && !response) throw error;
53
+ } else if (match) ev.response = await match.fn(ev);
54
+ else return new Response(null, { status: 404 });
55
+ ev.response ??= new Response(null, { status: 200 });
56
+ ev.addHeaders();
57
+ return ev.response;
58
+ };
59
+ /**
60
+ * Adds a server function at a route path.
61
+ * @param path The route path pattern.
62
+ * @param fn The function to call when the pattern is matched.
63
+ * @returns
64
+ */
65
+ add(path, fn) {
66
+ let handler = new RouteHandler(path, fn);
67
+ this.routes.push(handler);
68
+ this.#trie.insert(path, handler);
69
+ this.#sortRoutes();
70
+ return this;
71
+ }
72
+ match(path) {
73
+ const found = this.#trie.match(path);
74
+ if (found) return {
75
+ fn: found.value.fn,
76
+ params: found.params
77
+ };
78
+ console.log(`Server path not found: ${path}`);
79
+ }
80
+ use(...fn) {
81
+ this.middleware = this.middleware.concat(fn);
82
+ return this;
83
+ }
84
+ #sortRoutes() {
85
+ this.routes = this.routes.sort((a, b) => {
86
+ for (let i = 0; i < Math.min(a.path.length, b.path.length); i++) if (a.path[i] === "[" && b.path[i] !== "[") return 1;
87
+ else if (b.path[i] === "[" && a.path[i] !== "[") return -1;
88
+ else if (a.path[i] === b.path[i]) {} else return a.path[i].localeCompare(b.path[i]);
89
+ return a.path.length - b.path.length;
90
+ });
91
+ }
92
+ };
93
+ var RouteHandler = class {
94
+ path;
95
+ fn;
96
+ constructor(path, fn) {
97
+ this.path = path;
98
+ this.fn = fn;
99
+ }
100
+ };
101
+ //#endregion
102
+ export { Server as t };
103
+
104
+ //# sourceMappingURL=Server-BnjLJleZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Server-BnjLJleZ.mjs","names":["#trie","#sortRoutes"],"sources":["../src/server/Server.ts"],"sourcesContent":["import PathTrie from \"../utils/pathTrie\";\nimport ServerEvent from \"./ServerEvent\";\nimport type MiddlewareFunction from \"./types/MiddlewareFunction\";\nimport type ServerFunction from \"./types/ServerFunction\";\n\n/**\n * A Fetch API Request/Response server.\n */\nexport default class Server {\n\t// TODO: We don't use any of the routes, just add(\"*\") in runDev/runBuild...\n\troutes: RouteHandler[] = [];\n\t// Match index for the routes above\n\t#trie = new PathTrie<RouteHandler>();\n\t// TODO: We only use the Vite middleware here\n\tmiddleware: MiddlewareFunction[] = [];\n\n\tconstructor() {\n\t\tthis.routes = [];\n\t\tthis.middleware = [];\n\t}\n\n\t/**\n\t * The standard Fetch API method that should work in any runtime (including\n\t * Node with polyfills).\n\t * @returns\n\t */\n\tfetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n\t\t// Use the request as-is when we were given one, so that the adapter\n\t\t// doesn't pay for constructing it twice\n\t\tconst request = input instanceof Request && !init ? input : new Request(input, init);\n\t\tconst url = new URL(request.url);\n\t\tconst match = this.match(url.pathname);\n\t\tlet ev = new ServerEvent(request, match?.params, url);\n\n\t\tif (this.middleware.length) {\n\t\t\t// TODO: Get middleware that applies to this route only?\n\t\t\tlet entered = 0;\n\t\t\tlet response: Response | undefined = undefined;\n\t\t\tlet error: unknown = undefined;\n\t\t\ttry {\n\t\t\t\tfor (; entered < this.middleware.length && !response; entered++) {\n\t\t\t\t\t// A middleware returns a Response to short-circuit the request\n\t\t\t\t\tconst result = await this.middleware[entered].enter?.(ev);\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tresponse = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!response && match) {\n\t\t\t\t\tconst result = await match.fn(ev);\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tresponse = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\t// Exits can handle the error by returning a Response; if none\n\t\t\t\t// does, it is rethrown below\n\t\t\t\terror = e;\n\t\t\t\tev.error = e;\n\t\t\t} finally {\n\t\t\t\tif (response) {\n\t\t\t\t\tev.response = response;\n\t\t\t\t}\n\t\t\t\t// Run exit hooks in reverse order for the middleware that were\n\t\t\t\t// entered. An exit hook can return a Response to replace the\n\t\t\t\t// response, or to handle ev.error\n\t\t\t\twhile (entered > 0) {\n\t\t\t\t\tentered--;\n\t\t\t\t\tconst result = await this.middleware[entered].exit?.(ev);\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tresponse = result;\n\t\t\t\t\t\tev.response = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (error && !response) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} else if (match) {\n\t\t\tev.response = await match.fn(ev);\n\t\t} else {\n\t\t\treturn new Response(null, { status: 404 });\n\t\t}\n\n\t\t// TODO: Should I be returning 200 if there's no response? Because it's not an error??\n\t\tev.response ??= new Response(null, { status: 200 });\n\t\tev.addHeaders();\n\n\t\treturn ev.response;\n\t};\n\n\t/**\n\t * Adds a server function at a route path.\n\t * @param path The route path pattern.\n\t * @param fn The function to call when the pattern is matched.\n\t * @returns\n\t */\n\tadd(path: string, fn: ServerFunction): Server {\n\t\tlet handler = new RouteHandler(path, fn);\n\t\tthis.routes.push(handler);\n\t\tthis.#trie.insert(path, handler);\n\t\tthis.#sortRoutes();\n\t\treturn this;\n\t}\n\n\tmatch(path: string): Match | undefined {\n\t\tconst found = this.#trie.match(path);\n\t\tif (found) {\n\t\t\treturn {\n\t\t\t\tfn: found.value.fn,\n\t\t\t\tparams: found.params,\n\t\t\t};\n\t\t}\n\t\tconsole.log(`Server path not found: ${path}`);\n\t}\n\n\t// TODO:\n\t//use(path: string, ...fn: MiddlewareFunction[])\n\tuse(...fn: MiddlewareFunction[]): Server {\n\t\tthis.middleware = this.middleware.concat(fn);\n\t\treturn this;\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\nclass RouteHandler {\n\tpath: string;\n\tfn: ServerFunction;\n\n\tconstructor(path: string, fn: ServerFunction) {\n\t\tthis.path = path;\n\t\tthis.fn = fn;\n\t}\n}\n\n//class MiddlewareHandler {\n//\tpath: string;\n//\tregex: RegExp;\n//\tfn: MiddlewareFunction;\n//\n//\tconstructor(path: string, fn: MiddlewareFunction) {\n//\t\tthis.path = path;\n//\t\tthis.regex = pathToRegex(path);\n//\t\tthis.fn = fn;\n//\t}\n//}\n\ninterface Match {\n\tfn: ServerFunction;\n\tparams?: Record<string, string>;\n}\n"],"mappings":";;;;;;AAQA,IAAqB,SAArB,MAA4B;CAE3B,SAAyB,CAAC;CAE1B,QAAQ,IAAI,SAAuB;CAEnC,aAAmC,CAAC;CAEpC,cAAc;EACb,KAAK,SAAS,CAAC;EACf,KAAK,aAAa,CAAC;CACpB;;;;;;CAOA,QAAQ,OAAO,OAA0B,SAA0C;EAGlF,MAAM,UAAU,iBAAiB,WAAW,CAAC,OAAO,QAAQ,IAAI,QAAQ,OAAO,IAAI;EACnF,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;EAC/B,MAAM,QAAQ,KAAK,MAAM,IAAI,QAAQ;EACrC,IAAI,KAAK,IAAI,YAAY,SAAS,OAAO,QAAQ,GAAG;EAEpD,IAAI,KAAK,WAAW,QAAQ;GAE3B,IAAI,UAAU;GACd,IAAI,WAAiC,KAAA;GACrC,IAAI,QAAiB,KAAA;GACrB,IAAI;IACH,OAAO,UAAU,KAAK,WAAW,UAAU,CAAC,UAAU,WAAW;KAEhE,MAAM,SAAS,MAAM,KAAK,WAAW,QAAQ,CAAC,QAAQ,EAAE;KACxD,IAAI,QACH,WAAW;IAEb;IACA,IAAI,CAAC,YAAY,OAAO;KACvB,MAAM,SAAS,MAAM,MAAM,GAAG,EAAE;KAChC,IAAI,QACH,WAAW;IAEb;GACD,SAAS,GAAG;IAGX,QAAQ;IACR,GAAG,QAAQ;GACZ,UAAU;IACT,IAAI,UACH,GAAG,WAAW;IAKf,OAAO,UAAU,GAAG;KACnB;KACA,MAAM,SAAS,MAAM,KAAK,WAAW,QAAQ,CAAC,OAAO,EAAE;KACvD,IAAI,QAAQ;MACX,WAAW;MACX,GAAG,WAAW;KACf;IACD;GACD;GACA,IAAI,SAAS,CAAC,UACb,MAAM;EAER,OAAO,IAAI,OACV,GAAG,WAAW,MAAM,MAAM,GAAG,EAAE;OAE/B,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EAI1C,GAAG,aAAa,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EAClD,GAAG,WAAW;EAEd,OAAO,GAAG;CACX;;;;;;;CAQA,IAAI,MAAc,IAA4B;EAC7C,IAAI,UAAU,IAAI,aAAa,MAAM,EAAE;EACvC,KAAK,OAAO,KAAK,OAAO;EACxB,KAAKA,MAAM,OAAO,MAAM,OAAO;EAC/B,KAAKC,YAAY;EACjB,OAAO;CACR;CAEA,MAAM,MAAiC;EACtC,MAAM,QAAQ,KAAKD,MAAM,MAAM,IAAI;EACnC,IAAI,OACH,OAAO;GACN,IAAI,MAAM,MAAM;GAChB,QAAQ,MAAM;EACf;EAED,QAAQ,IAAI,0BAA0B,MAAM;CAC7C;CAIA,IAAI,GAAG,IAAkC;EACxC,KAAK,aAAa,KAAK,WAAW,OAAO,EAAE;EAC3C,OAAO;CACR;CAEA,cAAc;EACb,KAAK,SAAS,KAAK,OAAO,MAAM,GAAG,MAAM;GAGxC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,GAAG,KAC3D,IAAI,EAAE,KAAK,OAAO,OAAO,EAAE,KAAK,OAAO,KACtC,OAAO;QACD,IAAI,EAAE,KAAK,OAAO,OAAO,EAAE,KAAK,OAAO,KAC7C,OAAO;QACD,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,CAEpC,OACC,OAAO,EAAE,KAAK,EAAE,CAAC,cAAc,EAAE,KAAK,EAAE;GAG1C,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK;EAC/B,CAAC;CACF;AACD;AAEA,IAAM,eAAN,MAAmB;CAClB;CACA;CAEA,YAAY,MAAc,IAAoB;EAC7C,KAAK,OAAO;EACZ,KAAK,KAAK;CACX;AACD"}
@@ -0,0 +1,61 @@
1
+ import { t as ServerEvent } from "./ServerEvent-CTx3Q-hk.mjs";
2
+ //#region src/server/types/MiddlewareFunction.d.ts
3
+ type MiddlewareFunction = {
4
+ /**
5
+ * Called before the route handler. Middleware are run in the order they
6
+ * were added. Return a Response to short-circuit the request; the
7
+ * remaining middleware and the route handler are then skipped.
8
+ */
9
+ enter?: (ev: ServerEvent) => Response | void | Promise<Response | void>;
10
+ /**
11
+ * Called after the route handler (even if it threw), in reverse order.
12
+ * Return a Response to replace the response. Middleware that were skipped
13
+ * by a short-circuit don't get their exit hook run.
14
+ *
15
+ * If the route handler (or a later enter hook) threw, the error is
16
+ * available as `ev.error`; returning a Response handles the error and
17
+ * stops it from propagating.
18
+ */
19
+ exit?: (ev: ServerEvent) => Response | void | Promise<Response | void>;
20
+ };
21
+ //#endregion
22
+ //#region src/server/types/ServerFunction.d.ts
23
+ type ServerFunction = (e: ServerEvent) => Response | undefined | void | Promise<Response | undefined | void>;
24
+ //#endregion
25
+ //#region src/server/Server.d.ts
26
+ /**
27
+ * A Fetch API Request/Response server.
28
+ */
29
+ declare class Server {
30
+ #private;
31
+ routes: RouteHandler[];
32
+ middleware: MiddlewareFunction[];
33
+ constructor();
34
+ /**
35
+ * The standard Fetch API method that should work in any runtime (including
36
+ * Node with polyfills).
37
+ * @returns
38
+ */
39
+ fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
40
+ /**
41
+ * Adds a server function at a route path.
42
+ * @param path The route path pattern.
43
+ * @param fn The function to call when the pattern is matched.
44
+ * @returns
45
+ */
46
+ add(path: string, fn: ServerFunction): Server;
47
+ match(path: string): Match | undefined;
48
+ use(...fn: MiddlewareFunction[]): Server;
49
+ }
50
+ declare class RouteHandler {
51
+ path: string;
52
+ fn: ServerFunction;
53
+ constructor(path: string, fn: ServerFunction);
54
+ }
55
+ interface Match {
56
+ fn: ServerFunction;
57
+ params?: Record<string, string>;
58
+ }
59
+ //#endregion
60
+ export { MiddlewareFunction as n, Server as t };
61
+ //# sourceMappingURL=Server-Cler2w5O.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Server-Cler2w5O.d.mts","names":[],"sources":["../src/server/types/MiddlewareFunction.ts","../src/server/types/ServerFunction.ts","../src/server/Server.ts"],"mappings":";;KAEK;;;;;;EAMJ,SAAS,IAAI,gBAAgB,kBAAkB,QAAQ;;;;;;;;;;EAUvD,QAAQ,IAAI,gBAAgB,kBAAkB,QAAQ;;;;KChBlD,kBACJ,GAAG,gBACC,8BAA8B,QAAQ;;;;;;cCItB;;EAEpB,QAAQ;EAIR,YAAY;EAEZ;;;;;;EAUA,QAAe,OAAO,cAAc,KAAK,OAAO,gBAAc,QAAQ;;;;;;;EAsEtE,IAAI,cAAc,IAAI,iBAAiB;EAQvC,MAAM,eAAe;EAarB,OAAO,IAAI,uBAAuB;;cAyB7B;EACL;EACA,IAAI;EAEJ,YAAY,cAAc,IAAI;;UAkBrB;EACT,IAAI;EACJ,SAAS"}
@@ -0,0 +1,48 @@
1
+ import { SerializeOptions } from "cookie";
2
+ //#region src/server/CookieHelper.d.ts
3
+ declare class CookieHelper {
4
+ request: Request;
5
+ cookies: Map<string, string>;
6
+ constructor(request: Request);
7
+ get(name: string): string | undefined;
8
+ set(name: string, value: string, options?: SerializeOptions): void;
9
+ delete(name: string, options?: SerializeOptions): void;
10
+ }
11
+ //#endregion
12
+ //#region src/server/HeaderHelper.d.ts
13
+ declare class HeaderHelper {
14
+ request: Request;
15
+ headers: Map<string, string>;
16
+ constructor(request: Request);
17
+ get(name: string): string | undefined;
18
+ set(name: string, value: string): void;
19
+ delete(name: string): void;
20
+ }
21
+ //#endregion
22
+ //#region src/server/ServerEvent.d.ts
23
+ declare class ServerEvent {
24
+ #private;
25
+ request: Request;
26
+ response: Response | undefined | void;
27
+ /**
28
+ * Set when the route handler (or a middleware enter hook) threw an
29
+ * error. Exit hooks can return a Response to handle it; if none does,
30
+ * the error is rethrown to the caller.
31
+ */
32
+ error: unknown;
33
+ params?: Record<string, string>;
34
+ adapter: any;
35
+ cookies: CookieHelper;
36
+ headers: HeaderHelper;
37
+ /** The request URL, parsed lazily. */
38
+ get url(): URL;
39
+ constructor(request: Request, params?: Record<string, string>, url?: URL);
40
+ addHeaders(): void;
41
+ /**
42
+ * Reads the request body as JSON.
43
+ */
44
+ json(): Promise<unknown>;
45
+ }
46
+ //#endregion
47
+ export { HeaderHelper as n, CookieHelper as r, ServerEvent as t };
48
+ //# sourceMappingURL=ServerEvent-CTx3Q-hk.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerEvent-CTx3Q-hk.d.mts","names":[],"sources":["../src/server/CookieHelper.ts","../src/server/HeaderHelper.ts","../src/server/ServerEvent.ts"],"mappings":";;cAEqB;EACpB,SAAS;EACT,SAAS;EAET,YAAY,SAAS;EAIrB,IAAI;EAaJ,IAAI,cAAc,eAAe,UAAU;EAU3C,OAAO,cAAc,UAAU;;;;cCjCX;EACpB,SAAS;EACT,SAAS;EAET,YAAY,SAAS;EAIrB,IAAI;EASJ,IAAI,cAAc;EAIlB,OAAO;;;;cClBa;;EACpB,SAAS;EACT,UAAU;;;;;;EAMV;EAEA,SAAS;EAET;EAEA,SAAS;EACT,SAAS;;MAOL,OAAO;EAIX,YAAY,SAAS,SAAS,SAAS,wBAAwB,MAAM;EAYrE;;;;EAiBA,QAAQ"}
@@ -1,5 +1,4 @@
1
- import { parse, serialize } from "cookie";
2
-
1
+ import { parseCookie, stringifySetCookie } from "cookie";
3
2
  //#region src/server/CookieHelper.ts
4
3
  var CookieHelper = class {
5
4
  request;
@@ -8,23 +7,33 @@ var CookieHelper = class {
8
7
  this.request = request;
9
8
  }
10
9
  get(name) {
11
- if (this.cookies.has(name)) return parse(this.cookies.get(name))[name];
12
- return parse(this.request.headers.get("cookie") ?? "")[name];
10
+ if (this.cookies.has(name)) return parseCookie(this.cookies.get(name))[name];
11
+ return parseCookie(this.request.headers.get("Cookie") ?? "")[name];
13
12
  }
14
13
  set(name, value, options) {
15
14
  options ??= {};
16
15
  options.httpOnly ??= true;
17
16
  options.secure ??= true;
18
17
  options.sameSite ??= "lax";
19
- this.cookies.set(name, serialize(name, value, options));
18
+ this.cookies.set(name, stringifySetCookie({
19
+ name,
20
+ value,
21
+ ...options
22
+ }));
20
23
  }
21
24
  delete(name, options) {
22
25
  options ??= {};
26
+ options.httpOnly ??= true;
27
+ options.secure ??= true;
28
+ options.sameSite ??= "lax";
23
29
  options.expires = /* @__PURE__ */ new Date(0);
24
- this.cookies.set(name, serialize(name, "", options));
30
+ this.cookies.set(name, stringifySetCookie({
31
+ name,
32
+ value: "",
33
+ ...options
34
+ }));
25
35
  }
26
36
  };
27
-
28
37
  //#endregion
29
38
  //#region src/server/HeaderHelper.ts
30
39
  var HeaderHelper = class {
@@ -44,19 +53,30 @@ var HeaderHelper = class {
44
53
  this.headers.delete(name);
45
54
  }
46
55
  };
47
-
48
56
  //#endregion
49
57
  //#region src/server/ServerEvent.ts
50
58
  var ServerEvent = class {
51
59
  request;
52
60
  response;
61
+ /**
62
+ * Set when the route handler (or a middleware enter hook) threw an
63
+ * error. Exit hooks can return a Response to handle it; if none does,
64
+ * the error is rethrown to the caller.
65
+ */
66
+ error;
53
67
  params;
54
68
  adapter;
55
69
  cookies;
56
70
  headers;
57
- constructor(request, params) {
71
+ #url;
72
+ /** The request URL, parsed lazily. */
73
+ get url() {
74
+ return this.#url ??= new URL(this.request.url);
75
+ }
76
+ constructor(request, params, url) {
58
77
  this.request = request;
59
78
  this.params = params;
79
+ this.#url = url;
60
80
  this.cookies = new CookieHelper(request);
61
81
  this.headers = new HeaderHelper(request);
62
82
  this.adapter = globalThis.adapter;
@@ -66,8 +86,14 @@ var ServerEvent = class {
66
86
  for (let cookie of this.cookies.cookies.values()) this.response.headers.append("set-cookie", cookie);
67
87
  for (let header of this.headers.headers.entries()) this.response.headers.append(header[0], header[1]);
68
88
  }
89
+ /**
90
+ * Reads the request body as JSON.
91
+ */
92
+ json() {
93
+ return this.request.json();
94
+ }
69
95
  };
70
-
71
96
  //#endregion
72
97
  export { HeaderHelper as n, CookieHelper as r, ServerEvent as t };
73
- //# sourceMappingURL=ServerEvent-CxPwA4lH.mjs.map
98
+
99
+ //# sourceMappingURL=ServerEvent-Dljn5i7A.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerEvent-Dljn5i7A.mjs","names":["#url"],"sources":["../src/server/CookieHelper.ts","../src/server/HeaderHelper.ts","../src/server/ServerEvent.ts"],"sourcesContent":["import { type SerializeOptions, parseCookie, stringifySetCookie } from \"cookie\";\n\nexport default class CookieHelper {\n\trequest: Request;\n\tcookies: Map<string, string> = new Map();\n\n\tconstructor(request: Request) {\n\t\tthis.request = request;\n\t}\n\n\tget(name: string): string | undefined {\n\t\t// If it's been set, return the value from the map\n\t\tif (this.cookies.has(name)) {\n\t\t\t// The stored value is a serialized Set-Cookie header; pull the\n\t\t\t// \"name=value\" prefix off and re-parse to get just the value\n\t\t\treturn parseCookie(this.cookies.get(name)!)[name];\n\t\t}\n\n\t\t// Otherwise, return the value from the `cookie` header\n\t\tconst header = this.request.headers.get(\"Cookie\");\n\t\treturn parseCookie(header ?? \"\")[name];\n\t}\n\n\tset(name: string, value: string, options?: SerializeOptions): void {\n\t\t// Set a cookie header with some default values for security\n\t\toptions ??= {};\n\t\toptions.httpOnly ??= true;\n\t\toptions.secure ??= true;\n\t\toptions.sameSite ??= \"lax\";\n\n\t\tthis.cookies.set(name, stringifySetCookie({ name, value, ...options }));\n\t}\n\n\tdelete(name: string, options?: SerializeOptions): void {\n\t\t// Set a cookie header with an empty value and an immediate expiry date.\n\t\t// Apply the same secure defaults as `set` so a previously-set Secure\n\t\t// cookie is actually overridden by the deletion.\n\t\toptions ??= {};\n\t\toptions.httpOnly ??= true;\n\t\toptions.secure ??= true;\n\t\toptions.sameSite ??= \"lax\";\n\t\toptions.expires = new Date(0);\n\n\t\tthis.cookies.set(name, stringifySetCookie({ name, value: \"\", ...options }));\n\t}\n}\n","export default class HeaderHelper {\n\trequest: Request;\n\theaders: Map<string, string> = new Map();\n\n\tconstructor(request: Request) {\n\t\tthis.request = request;\n\t}\n\n\tget(name: string): string | undefined {\n\t\t// If it's been set, return the updated value\n\t\tif (this.headers.has(name)) {\n\t\t\treturn this.headers.get(name);\n\t\t}\n\t\t// Otherwise, return the value from the header\n\t\treturn this.request.headers.get(name) ?? undefined;\n\t}\n\n\tset(name: string, value: string): void {\n\t\tthis.headers.set(name, value);\n\t}\n\n\tdelete(name: string): void {\n\t\tthis.headers.delete(name);\n\t}\n}\n","import CookieHelper from \"./CookieHelper\";\nimport HeaderHelper from \"./HeaderHelper\";\n\nexport default class ServerEvent {\n\trequest: Request;\n\tresponse: Response | undefined | void;\n\t/**\n\t * Set when the route handler (or a middleware enter hook) threw an\n\t * error. Exit hooks can return a Response to handle it; if none does,\n\t * the error is rethrown to the caller.\n\t */\n\terror: unknown;\n\t// TODO: Should we cast types??\n\tparams?: Record<string, string>;\n\n\tadapter: any;\n\n\tcookies: CookieHelper;\n\theaders: HeaderHelper;\n\n\t// Parsed once per request; Server.fetch passes the URL it already needed\n\t// for matching so it isn't parsed twice\n\t#url: URL | undefined;\n\n\t/** The request URL, parsed lazily. */\n\tget url(): URL {\n\t\treturn (this.#url ??= new URL(this.request.url));\n\t}\n\n\tconstructor(request: Request, params?: Record<string, string>, url?: URL) {\n\t\tthis.request = request;\n\t\tthis.params = params;\n\t\tthis.#url = url;\n\t\tthis.cookies = new CookieHelper(request);\n\t\tthis.headers = new HeaderHelper(request);\n\n\t\t// Adapters may have added the `adapter` property to globalThis\n\t\t// @ts-ignore\n\t\tthis.adapter = globalThis.adapter;\n\t}\n\n\taddHeaders(): void {\n\t\tif (!this.response) {\n\t\t\tthrow new Error(\"Response not created yet\");\n\t\t}\n\n\t\tfor (let cookie of this.cookies.cookies.values()) {\n\t\t\tthis.response.headers.append(\"set-cookie\", cookie);\n\t\t}\n\n\t\tfor (let header of this.headers.headers.entries()) {\n\t\t\tthis.response.headers.append(header[0], header[1]);\n\t\t}\n\t}\n\n\t/**\n\t * Reads the request body as JSON.\n\t */\n\tjson(): Promise<unknown> {\n\t\treturn this.request.json();\n\t}\n}\n"],"mappings":";;AAEA,IAAqB,eAArB,MAAkC;CACjC;CACA,0BAA+B,IAAI,IAAI;CAEvC,YAAY,SAAkB;EAC7B,KAAK,UAAU;CAChB;CAEA,IAAI,MAAkC;EAErC,IAAI,KAAK,QAAQ,IAAI,IAAI,GAGxB,OAAO,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAE,CAAC,CAAC;EAK7C,OAAO,YADQ,KAAK,QAAQ,QAAQ,IAAI,QAChB,KAAK,EAAE,CAAC,CAAC;CAClC;CAEA,IAAI,MAAc,OAAe,SAAkC;EAElE,YAAY,CAAC;EACb,QAAQ,aAAa;EACrB,QAAQ,WAAW;EACnB,QAAQ,aAAa;EAErB,KAAK,QAAQ,IAAI,MAAM,mBAAmB;GAAE;GAAM;GAAO,GAAG;EAAQ,CAAC,CAAC;CACvE;CAEA,OAAO,MAAc,SAAkC;EAItD,YAAY,CAAC;EACb,QAAQ,aAAa;EACrB,QAAQ,WAAW;EACnB,QAAQ,aAAa;EACrB,QAAQ,0BAAU,IAAI,KAAK,CAAC;EAE5B,KAAK,QAAQ,IAAI,MAAM,mBAAmB;GAAE;GAAM,OAAO;GAAI,GAAG;EAAQ,CAAC,CAAC;CAC3E;AACD;;;AC7CA,IAAqB,eAArB,MAAkC;CACjC;CACA,0BAA+B,IAAI,IAAI;CAEvC,YAAY,SAAkB;EAC7B,KAAK,UAAU;CAChB;CAEA,IAAI,MAAkC;EAErC,IAAI,KAAK,QAAQ,IAAI,IAAI,GACxB,OAAO,KAAK,QAAQ,IAAI,IAAI;EAG7B,OAAO,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK,KAAA;CAC1C;CAEA,IAAI,MAAc,OAAqB;EACtC,KAAK,QAAQ,IAAI,MAAM,KAAK;CAC7B;CAEA,OAAO,MAAoB;EAC1B,KAAK,QAAQ,OAAO,IAAI;CACzB;AACD;;;ACrBA,IAAqB,cAArB,MAAiC;CAChC;CACA;;;;;;CAMA;CAEA;CAEA;CAEA;CACA;CAIA;;CAGA,IAAI,MAAW;EACd,OAAQ,KAAKA,SAAS,IAAI,IAAI,KAAK,QAAQ,GAAG;CAC/C;CAEA,YAAY,SAAkB,QAAiC,KAAW;EACzE,KAAK,UAAU;EACf,KAAK,SAAS;EACd,KAAKA,OAAO;EACZ,KAAK,UAAU,IAAI,aAAa,OAAO;EACvC,KAAK,UAAU,IAAI,aAAa,OAAO;EAIvC,KAAK,UAAU,WAAW;CAC3B;CAEA,aAAmB;EAClB,IAAI,CAAC,KAAK,UACT,MAAM,IAAI,MAAM,0BAA0B;EAG3C,KAAK,IAAI,UAAU,KAAK,QAAQ,QAAQ,OAAO,GAC9C,KAAK,SAAS,QAAQ,OAAO,cAAc,MAAM;EAGlD,KAAK,IAAI,UAAU,KAAK,QAAQ,QAAQ,QAAQ,GAC/C,KAAK,SAAS,QAAQ,OAAO,OAAO,IAAI,OAAO,EAAE;CAEnD;;;;CAKA,OAAyB;EACxB,OAAO,KAAK,QAAQ,KAAK;CAC1B;AACD"}