@uniflowed/vite 0.0.0-alpha.1 → 0.0.0-alpha.10

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.
@@ -0,0 +1,79 @@
1
+ // @noflow
2
+ //
3
+ // Plain JavaScript: executed by the host that runs Vite, before any transform.
4
+ //
5
+ // Node's request and response objects on one side, the platform's `Request`
6
+ // and `Response` on the other.
7
+ //
8
+ // uf's server contracts are the platform's — a route handler and a middleware
9
+ // both take a `Request` and return a `Response`, because that is what runs
10
+ // unchanged on Node.js, Bun, Deno and a Cloudflare Worker. Node's dev server
11
+ // speaks `IncomingMessage` and `ServerResponse`, so exactly one place has to
12
+ // translate.
13
+ //
14
+ // It is a module rather than two functions in `driver.js` because there are
15
+ // two dev servers: `driver.js` is what `uf dev` spawns, and the `uf:flow`
16
+ // plugin's own `configureServer` is what a project using Vite directly gets.
17
+ // Both have to run the same middleware before the same request, and a second
18
+ // copy of this translation is how the two would come to disagree about, say,
19
+ // whether a repeated header is joined or appended.
20
+
21
+ /**
22
+ * A Node request as a `Request`.
23
+ *
24
+ * The body is read as a stream where the host supports it, because a handler
25
+ * that accepts an upload should not need the whole thing buffered before it
26
+ * starts.
27
+ *
28
+ * @param {import("node:http").IncomingMessage} incoming
29
+ * @param {{server?: {https?: unknown}} | undefined} config the resolved Vite config
30
+ */
31
+ export async function toRequest(incoming, config) {
32
+ const host = incoming.headers.host ?? "localhost";
33
+ const protocol = config?.server?.https == null ? "http" : "https";
34
+ const url = new URL(incoming.originalUrl ?? incoming.url ?? "/", `${protocol}://${host}`);
35
+
36
+ const headers = new Headers();
37
+ for (const [name, value] of Object.entries(incoming.headers)) {
38
+ if (value == null) continue;
39
+ for (const entry of Array.isArray(value) ? value : [value]) {
40
+ headers.append(name, entry);
41
+ }
42
+ }
43
+
44
+ const method = (incoming.method ?? "GET").toUpperCase();
45
+ const init = { method, headers };
46
+ if (method !== "GET" && method !== "HEAD") {
47
+ // `duplex` is required by the specification whenever a body is a stream,
48
+ // and Node throws without it.
49
+ init.body = incoming;
50
+ init.duplex = "half";
51
+ }
52
+ return new Request(url, init);
53
+ }
54
+
55
+ /**
56
+ * Write a `Response` to a Node response.
57
+ *
58
+ * One implementation, reached late. This was a second copy of the loop in
59
+ * `@uniflowed/server`'s `node.js`, and the two drifted the moment the shared
60
+ * one moved: `uf start` and every adapter lost the socket pacing and the
61
+ * hang-up cancel while `uf dev` and `uf preview` kept them, which is a
62
+ * deployment whose memory profile differs from the one that was checked. See
63
+ * ubugeeei-prod/uf#400.
64
+ *
65
+ * The import is inside the function, and that is not a style choice.
66
+ * `driver.js` imports this module *statically* and registers the Flow loader
67
+ * hooks in its own body, so anything reachable from a static import here is
68
+ * read by Node before there is anything to compile Flow with —
69
+ * `@uniflowed/server/node` is Flow source, and a static re-export of it makes
70
+ * every `uf build` die on `import type` with a `SyntaxError`. `loadBuild` in
71
+ * `internal/serve.js` defers for the same reason and says so.
72
+ *
73
+ * @param {import("node:http").ServerResponse} outgoing
74
+ * @param {Response} result
75
+ */
76
+ export async function send(outgoing, result) {
77
+ const { send: write } = await import("@uniflowed/server/node");
78
+ await write(outgoing, result);
79
+ }