@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
@@ -1,39 +0,0 @@
1
- export default function prepareTemplate(
2
- template: string,
3
- clientScript: string,
4
- clientDevScript?: string,
5
- ): string {
6
- let result = template;
7
-
8
- // Put %COMPONENT_HEAD% before </head>
9
- // This is where styles will go
10
- let headStart = result.indexOf("</head>");
11
- if (headStart === -1) {
12
- throw new Error(`Couldn't find <head> end tag`);
13
- }
14
- result = result.substring(0, headStart) + "%COMPONENT_HEAD%" + result.substring(headStart);
15
-
16
- // Put %COMPONENT_BODY% inside <div id="app"></div>
17
- // This is where the component's HTML will go
18
- let bodyStart = regexIndexOf(result, /<div\s+id=("app"|'app'|app)\s+/);
19
- bodyStart = result.indexOf(">", bodyStart) + 1;
20
- let bodyEnd = result.indexOf("</div>", bodyStart);
21
- if (bodyStart === -1 || bodyEnd === -1) {
22
- throw new Error(`Couldn't find <div id="app"></div>`);
23
- }
24
- result = result.substring(0, bodyStart) + "%COMPONENT_BODY%" + result.substring(bodyEnd);
25
-
26
- // Add the clientEntry script at the very end, for hydrating and navigating
27
- if (clientDevScript) {
28
- result += `<script type="module" src="${clientDevScript}"></script>`;
29
- }
30
- result += `<script type="module" src="${clientScript}"></script>`;
31
-
32
- return result;
33
- }
34
-
35
- // From https://stackoverflow.com/a/274094
36
- function regexIndexOf(string: string, regex: RegExp, position?: number) {
37
- var indexOf = string.substring(position || 0).search(regex);
38
- return indexOf >= 0 ? indexOf + (position || 0) : indexOf;
39
- }
package/src/run/run.ts DELETED
@@ -1,62 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { transformWithEsbuild } from "vite";
4
- import Site from "../site/Site";
5
- import runBuild from "./runBuild";
6
- import runDev from "./runDev";
7
- import runPreview from "./runPreview";
8
-
9
- export default async function run(
10
- folder: string,
11
- mode: "dev" | "build" | "preview",
12
- ): Promise<void> {
13
- // Look for and load a site.config.js/ts file in the working directory
14
- let configFile = "";
15
- let deleteConfigFile = false;
16
- const jsConfigFile = path.join(folder, "site.config.js");
17
- const tsConfigFile = path.join(folder, "site.config.ts");
18
- if (fs.existsSync(jsConfigFile)) {
19
- // If it's JS, we can just import it straight up
20
- configFile = jsConfigFile;
21
- } else if (fs.existsSync(tsConfigFile)) {
22
- // If it's TS, we need to convert it to JS
23
- // TODO: Put the generated file somewhere better (dist?)
24
- configFile = path.join(folder, "site.config.temp.js");
25
- let source = fs.readFileSync(tsConfigFile, "utf-8");
26
- let transformed = await transformWithEsbuild(source, tsConfigFile, {
27
- loader: "ts",
28
- });
29
- fs.writeFileSync(configFile, transformed.code);
30
- deleteConfigFile = true;
31
- } else {
32
- throw new Error("site.config file not found");
33
- }
34
-
35
- const site = (await import(configFile)).default as Site;
36
- if (!site || !site.root || !site.routes) {
37
- throw new Error("Invalid site in config file");
38
- }
39
- if (deleteConfigFile) {
40
- fs.rmSync(configFile);
41
- }
42
-
43
- switch (mode) {
44
- case "dev": {
45
- await runDev(site);
46
- break;
47
- }
48
- case "build": {
49
- await runBuild(site);
50
- break;
51
- }
52
- case "preview": {
53
- await runPreview(site);
54
- break;
55
- }
56
- default: {
57
- console.log("No mode passed, running in dev");
58
- await runDev(site);
59
- break;
60
- }
61
- }
62
- }
@@ -1,77 +0,0 @@
1
- import torpor from "@torpor/unplugin/vite";
2
- import { existsSync, promises as fs } from "node:fs";
3
- import path from "node:path";
4
- import { build, defineConfig } from "vite";
5
- import Site from "../site/Site";
6
- import manifest from "../site/manifest.ts";
7
-
8
- // TODO: Don't cache index.html in dev?
9
- // TODO: Multiple hook.server locations
10
- // TODO: Don't reload layouts during client routing
11
- // TODO: Call the correct +page and +server routes when in the same folder
12
-
13
- export default async function runBuild(site: Site): Promise<void> {
14
- // Delete the dist folder if it exists
15
- const distFolder = path.resolve(site.root, "dist");
16
- if (existsSync(distFolder)) {
17
- await fs.rm(distFolder, { recursive: true });
18
- }
19
- const clientFolder = path.join(distFolder, "client");
20
- const serverFolder = path.join(distFolder, "server");
21
-
22
- // HOOK: Prebuild
23
- if (site.adapter.prebuild) {
24
- await site.adapter.prebuild(site);
25
- }
26
-
27
- // TODO: From a setting
28
- let siteHtml = path.resolve(site.root, "src/site.html");
29
-
30
- const siteFolder = path.resolve(site.root, "./node_modules/@torpor/build/src/site/");
31
- let clientScript = path.join(siteFolder, "clientEntry.ts");
32
- let serverScript = path.join(siteFolder, "serverEntry.ts");
33
-
34
- // Build the client assets, including site.html and the route files
35
- // EXCLUDING anything with `server.js` in the name
36
- const clientConfig = structuredClone(site.viteConfig ?? {});
37
- clientConfig.plugins = [manifest(site), torpor(), ...site.plugins];
38
- clientConfig.build ??= {};
39
- clientConfig.build.outDir = clientFolder;
40
- clientConfig.build.rollupOptions ??= {};
41
- clientConfig.build.rollupOptions.input = [
42
- siteHtml,
43
- clientScript,
44
- ...site.routes
45
- .filter((r) => !/server\.(ts|js)$/.test(r.file))
46
- .map((r) => path.resolve(site.root, r.file)),
47
- ...site.inputs.filter((f) => !/server\.(ts|js)$/.test(f)),
48
- ];
49
- clientConfig.build.ssrManifest = true;
50
- await build(defineConfig(clientConfig));
51
-
52
- // Build the server assets, including the server entry script and the route
53
- // files
54
- const serverConfig = structuredClone(site.viteConfig ?? {});
55
- serverConfig.plugins = [manifest(site, true), torpor(), ...site.plugins];
56
- serverConfig.build ??= {};
57
- serverConfig.build.outDir = serverFolder;
58
- serverConfig.build.rollupOptions ??= {};
59
- serverConfig.build.rollupOptions.input = [
60
- serverScript,
61
- ...site.routes.map((r) => path.resolve(site.root, r.file)),
62
- ...site.inputs,
63
- ];
64
- serverConfig.build.ssr = serverScript;
65
- await build(defineConfig(serverConfig));
66
-
67
- // Move the site.html file into /client
68
- // HACK: Should do this in Rollup if possible?
69
- siteHtml = path.join(clientFolder, "site.html");
70
- await fs.rename(path.join(clientFolder, "src", "site.html"), siteHtml);
71
- await fs.rm(path.join(clientFolder, "src"), { recursive: true });
72
-
73
- // HOOK: Postbuild
74
- if (site.adapter.postbuild) {
75
- await site.adapter.postbuild(site);
76
- }
77
- }
package/src/run/runDev.ts DELETED
@@ -1,89 +0,0 @@
1
- import estorpor from "@torpor/unplugin/esbuild";
2
- import torpor from "@torpor/unplugin/vite";
3
- import { configDotenv } from "dotenv";
4
- import { promises as fs } from "node:fs";
5
- import path from "node:path";
6
- import { createServer as createViteServer } from "vite";
7
- import { serverError } from "../response.ts";
8
- import Server from "../server/Server.ts";
9
- import connectMiddleware from "../server/connect/connectMiddleware.ts";
10
- import Site from "../site/Site.ts";
11
- import manifest from "../site/manifest.ts";
12
- import prepareTemplate from "./prepareTemplate.ts";
13
-
14
- export default async function runDev(site: Site): Promise<void> {
15
- const server = new Server();
16
-
17
- // Create the Vite server in middleware mode and configure the app type as
18
- // "custom", disabling Vite's own HTML serving logic so the parent server
19
- // can take control
20
- const config = structuredClone(site.viteConfig ?? {});
21
- config.server = { middlewareMode: true };
22
- config.appType = "custom";
23
- config.plugins = [manifest(site, true), torpor({ dev: true }), ...site.plugins];
24
-
25
- // HACK: To be able to import `.torp` files from barrel files in
26
- // node_modules, we need to add their libraries to `ssr.noExternal` in
27
- // site.config.ts, and let esbuild know how to compile them here
28
- config.optimizeDeps ??= {};
29
- config.optimizeDeps.extensions ??= [];
30
- config.optimizeDeps.extensions.push(".torp");
31
- config.optimizeDeps.esbuildOptions ??= {};
32
- config.optimizeDeps.esbuildOptions.plugins ??= [];
33
- config.optimizeDeps.esbuildOptions.plugins.push(estorpor());
34
-
35
- const vite = await createViteServer(config);
36
-
37
- // Read site.html
38
- // It's called site.html because @torpor/build builds the site (html, routes
39
- // etc) while the user builds the app (components etc)
40
- const templateFile = path.resolve(site.root, "src/site.html");
41
- let template = await fs.readFile(templateFile, "utf-8");
42
-
43
- // Apply Vite HTML transforms. This injects the Vite HMR client, and also
44
- // applies HTML transforms from Vite plugins. Note that we only support a
45
- // universal transform, not individual transforms for each route
46
- template = await vite.transformIndexHtml("", template);
47
-
48
- const siteFolder = path.resolve(site.root, "./node_modules/@torpor/build/src/site/");
49
- let clientScript = path.join(siteFolder, "clientEntry.ts");
50
- let clientDevScript = path.join(siteFolder, "clientEntryDev.ts");
51
- let serverScript = path.join(siteFolder, "serverEntry.ts");
52
-
53
- // Prepare site.html so that we can just splice components into it
54
- template = prepareTemplate(template, clientScript, clientDevScript);
55
-
56
- // Use Vite's Connect instance as middleware. We need to wrap it with
57
- // createMiddlewareHandler that converts Connect middleware to
58
- // Request/Response web handlers
59
- server.use(connectMiddleware(vite.middlewares));
60
-
61
- // Every request (GET, POST, etc) goes through loadEndPoint
62
- server.add("*", async (ev) => {
63
- try {
64
- // Load the server entry. ssrLoadModule automatically transforms ESM
65
- // source code to be usable in Node.js. No bundling is required, and
66
- // it provides efficient invalidation similar to HMR
67
- const { load } = await vite.ssrLoadModule(serverScript);
68
-
69
- // Render the app HTML (or fetch server data etc) via serverEntry's
70
- // exported `load` function
71
- return await load(ev, template);
72
- } catch (e: any) {
73
- // If an error is caught, let Vite fix the stack trace so it maps
74
- // back to your actual source code
75
- vite.ssrFixStacktrace(e);
76
- return serverError(e);
77
- }
78
- });
79
-
80
- // Load environment variables from a `.env` file, with defaults if not set
81
- configDotenv();
82
-
83
- process.env.PROTOCOL ??= "http:";
84
- process.env.HOST ??= "localhost";
85
- process.env.PORT ??= "7059";
86
-
87
- // Serve the site
88
- site.adapter.serve(server, site);
89
- }
@@ -1,93 +0,0 @@
1
- import { configDotenv } from "dotenv";
2
- import { existsSync, promises as fs } from "node:fs";
3
- import path from "node:path";
4
- import { serverError } from "../response.ts";
5
- import Server from "../server/Server.ts";
6
- import contentType from "../server/contentType.ts";
7
- import Site from "../site/Site";
8
- import prepareTemplate from "./prepareTemplate.ts";
9
- import runBuild from "./runBuild";
10
-
11
- export default async function runPreview(site: Site): Promise<void> {
12
- // Build the site
13
- await runBuild(site);
14
-
15
- const distFolder = path.resolve(site.root, "dist");
16
- const clientFolder = path.join(distFolder, "client");
17
- const serverFolder = path.join(distFolder, "server");
18
-
19
- // Find the client script file in /assets
20
- let clientScript = (await fs.readdir(path.join(clientFolder, "assets"))).find((f) =>
21
- f.startsWith("clientEntry-"),
22
- );
23
- if (!clientScript) {
24
- throw new Error("clientEntry.js not found");
25
- }
26
- clientScript = `/assets/${clientScript}`;
27
-
28
- // Read site.html
29
- // It's called site.html because @torpor/build builds the site (html, routes
30
- // etc) while the user builds the app (components etc)
31
- let siteHtml = path.join(clientFolder, "site.html");
32
- let template = await fs.readFile(siteHtml, "utf-8");
33
-
34
- // Prepare site.html so that we can just splice components into it
35
- template = prepareTemplate(template, clientScript);
36
-
37
- // Configure the server
38
- const server = new Server();
39
-
40
- // Serve dist/client/assets statically
41
- server.add("/assets/*", async (ev) => {
42
- try {
43
- const url = new URL(ev.request.url);
44
- const file = path.join(site.root, "dist", "client", url.pathname);
45
- if (existsSync(file)) {
46
- // TODO: Stream the data?
47
- const body = bufferToArrayBuffer(await fs.readFile(file));
48
- return new Response(body, {
49
- status: 200,
50
- headers: {
51
- "Content-Type": contentType(path.extname(file)),
52
- },
53
- });
54
- }
55
- } catch (e: any) {
56
- return serverError(e);
57
- }
58
- });
59
-
60
- // Every request (GET, POST, etc) goes through loadEndPoint
61
- const serverScript = path.resolve(serverFolder, "serverEntry.js");
62
- server.add("*", async (ev) => {
63
- try {
64
- // Load the server entry
65
- const { load } = await import(serverScript);
66
-
67
- // Render the app HTML (or fetch server data etc) via serverEntry's
68
- // exported `load` function
69
- return await load(ev, template);
70
- } catch (e: any) {
71
- return serverError(e);
72
- }
73
- });
74
-
75
- // Load environment variables from a `.env` file, with defaults if not set
76
- configDotenv();
77
-
78
- process.env.PROTOCOL ??= "http:";
79
- process.env.HOST ??= "localhost";
80
- process.env.PORT ??= "7059";
81
-
82
- // Serve the site
83
- site.adapter.serve(server, site);
84
- }
85
-
86
- // From https://stackoverflow.com/a/79345620
87
- // No idea why it is needed
88
- function bufferToArrayBuffer(buffer: Buffer): ArrayBuffer {
89
- return buffer.buffer.slice(
90
- buffer.byteOffset,
91
- buffer.byteOffset + buffer.byteLength,
92
- ) as ArrayBuffer;
93
- }
package/src/run.ts DELETED
@@ -1,6 +0,0 @@
1
- import run from "./run/run";
2
- import runBuild from "./run/runBuild";
3
- import runDev from "./run/runDev";
4
- import runPreview from "./run/runPreview";
5
-
6
- export { run, runDev, runBuild, runPreview };
@@ -1,36 +0,0 @@
1
- import { SerializeOptions, parse, serialize } from "cookie";
2
-
3
- export default class CookieHelper {
4
- request: Request;
5
- cookies: Map<string, string> = new Map();
6
-
7
- constructor(request: Request) {
8
- this.request = request;
9
- }
10
-
11
- get(name: string): string | undefined {
12
- // If it's been set, return the value from the map
13
- if (this.cookies.has(name)) {
14
- return parse(this.cookies.get(name)!)[name];
15
- }
16
- // Otherwise, return the value from the `cookie` header
17
- const header = this.request.headers.get("cookie");
18
- return parse(header ?? "")[name];
19
- }
20
-
21
- set(name: string, value: string, options?: SerializeOptions): void {
22
- // Set a cookie header with some default values for security
23
- options ??= {};
24
- options.httpOnly ??= true;
25
- options.secure ??= true;
26
- options.sameSite ??= "lax";
27
- this.cookies.set(name, serialize(name, value, options));
28
- }
29
-
30
- delete(name: string, options?: SerializeOptions): void {
31
- // Set a cookie header with an immediate expiry date
32
- options ??= {};
33
- options.expires = new Date(0);
34
- this.cookies.set(name, serialize(name, "", options));
35
- }
36
- }
@@ -1,25 +0,0 @@
1
- export default class HeaderHelper {
2
- request: Request;
3
- headers: Map<string, string> = new Map();
4
-
5
- constructor(request: Request) {
6
- this.request = request;
7
- }
8
-
9
- get(name: string): string | undefined {
10
- // If it's been set, return the updated value
11
- if (this.headers.has(name)) {
12
- return this.headers.get(name);
13
- }
14
- // Otherwise, return the value from the header
15
- return this.request.headers.get(name) ?? undefined;
16
- }
17
-
18
- set(name: string, value: string): void {
19
- this.headers.set(name, value);
20
- }
21
-
22
- delete(name: string): void {
23
- this.headers.delete(name);
24
- }
25
- }
@@ -1,72 +0,0 @@
1
- import pathToRegex from "../utils/pathToRegex";
2
- import type HttpMethod from "./types/HttpMethod";
3
- import type MiddlewareFunction from "./types/MiddlewareFunction";
4
- import type ServerFunction from "./types/ServerFunction";
5
-
6
- // This is not actually used anywhere, for now at least
7
-
8
- export default class Router {
9
- methods: Map<HttpMethod, RouteHandler[]> = new Map<HttpMethod, RouteHandler[]>();
10
- middleware: MiddlewareHandler[] = [];
11
-
12
- constructor() {
13
- // Create all method handlers up front so we don't have to worry about
14
- // checking if they exist. Using a non-standard method will just error
15
- this.methods.set("GET", []);
16
- this.methods.set("HEAD", []);
17
- this.methods.set("PATCH", []);
18
- this.methods.set("POST", []);
19
- this.methods.set("PUT", []);
20
- this.methods.set("DELETE", []);
21
- this.methods.set("OPTIONS", []);
22
- this.methods.set("CONNECT", []);
23
- this.methods.set("TRACE", []);
24
- }
25
-
26
- add(method: HttpMethod, path: string, fn: ServerFunction): Router {
27
- this.methods.get(method)!.push(new RouteHandler(path, fn));
28
- return this;
29
- }
30
-
31
- match(method: HttpMethod, path: string): Match | undefined {
32
- for (let handler of this.methods.get(method)!) {
33
- let match = path.match(handler.regex);
34
- if (match) {
35
- console.log("found", handler);
36
- return {
37
- fn: handler.fn,
38
- params: match.groups,
39
- };
40
- }
41
- }
42
- }
43
- }
44
-
45
- class RouteHandler {
46
- path: string;
47
- regex: RegExp;
48
- fn: ServerFunction;
49
-
50
- constructor(path: string, fn: ServerFunction) {
51
- this.path = path;
52
- this.regex = pathToRegex(path);
53
- this.fn = fn;
54
- }
55
- }
56
-
57
- class MiddlewareHandler {
58
- path: string;
59
- regex: RegExp;
60
- fn: MiddlewareFunction;
61
-
62
- constructor(path: string, fn: MiddlewareFunction) {
63
- this.path = path;
64
- this.regex = pathToRegex(path);
65
- this.fn = fn;
66
- }
67
- }
68
-
69
- interface Match {
70
- fn: ServerFunction;
71
- params?: Record<string, string>;
72
- }
@@ -1,144 +0,0 @@
1
- import pathToRegex from "../utils/pathToRegex";
2
- import ServerEvent from "./ServerEvent";
3
- import type MiddlewareFunction from "./types/MiddlewareFunction";
4
- import type ServerFunction from "./types/ServerFunction";
5
-
6
- const noop = () => {};
7
-
8
- /**
9
- * A Fetch API Request/Response server.
10
- */
11
- export default class Server {
12
- // TODO: We don't use any of the routes, just add("*") in runDev/runBuild...
13
- routes: RouteHandler[] = [];
14
- // TODO: We only use the Vite middleware here
15
- middleware: MiddlewareFunction[] = [];
16
-
17
- constructor() {
18
- this.routes = [];
19
- this.middleware = [];
20
- }
21
-
22
- /**
23
- * The standard Fetch API method that should work in any runtime (including
24
- * Node with polyfills).
25
- * @returns
26
- */
27
- fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
28
- const request = new Request(input, init);
29
- const url = new URL(request.url);
30
- const match = this.match(url.pathname);
31
- let ev = new ServerEvent(request, match?.params);
32
-
33
- if (this.middleware.length) {
34
- // TODO: Get middleware that applies to this route only?
35
- await this.middleware[0](ev, buildNext(this.middleware, 0));
36
- function buildNext(middleware: MiddlewareFunction[], i: number): () => void | Promise<void> {
37
- if (ev.response) {
38
- return noop;
39
- }
40
-
41
- if (i < middleware.length - 1) {
42
- let next = middleware[i + 1];
43
- return async () => next(ev, buildNext(middleware, i + 1));
44
- } else {
45
- return match
46
- ? async () => {
47
- ev.response = await match.fn(ev);
48
- }
49
- : noop;
50
- }
51
- }
52
- } else if (match) {
53
- ev.response = await match.fn(ev);
54
- } else {
55
- return new Response(null, { status: 404 });
56
- }
57
-
58
- // TODO: Should I be returning 200 if there's no response? Because it's not an error??
59
- ev.response ??= new Response(null, { status: 200 });
60
- ev.addHeaders();
61
-
62
- return ev.response;
63
- };
64
-
65
- /**
66
- * Adds a server function at a route path.
67
- * @param path The route path pattern.
68
- * @param fn The function to call when the pattern is matched.
69
- * @returns
70
- */
71
- add(path: string, fn: ServerFunction): Server {
72
- this.routes.push(new RouteHandler(path, fn));
73
- this.#sortRoutes();
74
- return this;
75
- }
76
-
77
- match(path: string): Match | undefined {
78
- for (let handler of this.routes) {
79
- let match = path.match(handler.regex);
80
- if (match) {
81
- return {
82
- fn: handler.fn,
83
- params: match.groups,
84
- };
85
- }
86
- }
87
- console.log(`Server path not found: ${path}`);
88
- }
89
-
90
- // TODO:
91
- //use(path: string, ...fn: MiddlewareFunction[])
92
- use(...fn: MiddlewareFunction[]): Server {
93
- this.middleware = this.middleware.concat(fn);
94
- return this;
95
- }
96
-
97
- #sortRoutes() {
98
- this.routes = this.routes.sort((a, b) => {
99
- // Sort [param]s after paths
100
- // There might be a quicker/easier way to do this
101
- for (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {
102
- if (a.path[i] === "[" && b.path[i] !== "[") {
103
- return 1;
104
- } else if (b.path[i] === "[" && a.path[i] !== "[") {
105
- return -1;
106
- } else if (a.path[i] === b.path[i]) {
107
- // Keep going...
108
- } else {
109
- return a.path[i].localeCompare(b.path[i]);
110
- }
111
- }
112
- return a.path.length - b.path.length;
113
- });
114
- }
115
- }
116
-
117
- class RouteHandler {
118
- path: string;
119
- regex: RegExp;
120
- fn: ServerFunction;
121
-
122
- constructor(path: string, fn: ServerFunction) {
123
- this.path = path;
124
- this.regex = pathToRegex(path);
125
- this.fn = fn;
126
- }
127
- }
128
-
129
- //class MiddlewareHandler {
130
- // path: string;
131
- // regex: RegExp;
132
- // fn: MiddlewareFunction;
133
- //
134
- // constructor(path: string, fn: MiddlewareFunction) {
135
- // this.path = path;
136
- // this.regex = pathToRegex(path);
137
- // this.fn = fn;
138
- // }
139
- //}
140
-
141
- interface Match {
142
- fn: ServerFunction;
143
- params?: Record<string, string>;
144
- }
@@ -1,39 +0,0 @@
1
- import CookieHelper from "./CookieHelper";
2
- import HeaderHelper from "./HeaderHelper";
3
-
4
- export default class ServerEvent {
5
- request: Request;
6
- response: Response | undefined | void;
7
- // TODO: Should we cast types??
8
- params?: Record<string, string>;
9
-
10
- adapter: any;
11
-
12
- cookies: CookieHelper;
13
- headers: HeaderHelper;
14
-
15
- constructor(request: Request, params?: Record<string, string>) {
16
- this.request = request;
17
- this.params = params;
18
- this.cookies = new CookieHelper(request);
19
- this.headers = new HeaderHelper(request);
20
-
21
- // Adapters may have added the `adapter` property to globalThis
22
- // @ts-ignore
23
- this.adapter = globalThis.adapter;
24
- }
25
-
26
- addHeaders(): void {
27
- if (!this.response) {
28
- throw new Error("Response not created yet");
29
- }
30
-
31
- for (let cookie of this.cookies.cookies.values()) {
32
- this.response.headers.append("set-cookie", cookie);
33
- }
34
-
35
- for (let header of this.headers.headers.entries()) {
36
- this.response.headers.append(header[0], header[1]);
37
- }
38
- }
39
- }