pi-straw-boss 0.10.0 → 0.10.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.
- package/package.json +1 -1
- package/src/gui.ts +10 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-straw-boss",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Straw Boss coordination for pi in Herdr: sessions join a tab's net by choice, the first joiner is its main agent, a workspace tower opens on demand with a live monitoring dashboard, and boss_broadcast reaches the rest",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/gui.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
|
-
import {
|
|
3
|
+
import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { createServer, type IncomingMessage, request, type ServerResponse } from "node:http";
|
|
5
5
|
import type { AddressInfo } from "node:net";
|
|
6
|
-
import { extname, join
|
|
6
|
+
import { extname, join } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { waitsForSecret } from "./ask.ts";
|
|
9
9
|
import { createControl, type Reply } from "./control.ts";
|
|
@@ -49,7 +49,9 @@ export async function startGui({ read, net, call, hub, dir = BUNDLE, port = 0, t
|
|
|
49
49
|
} catch {
|
|
50
50
|
throw new Error(`The GUI bundle is missing (${dir}); build it with npm run gui:build`);
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
// The whole bundle is read once: a package update replaces dist/gui under a running server, whose page names the old assets.
|
|
53
|
+
const bundle = new Map(readdirSync(dir, { recursive: true, encoding: "utf8" }).filter((f) => statSync(join(dir, f)).isFile()).map((f) => [f.split("\\").join("/"), readFileSync(join(dir, f))]));
|
|
54
|
+
const page = bundle.get("index.html")!.toString("utf8").replace("<head>", `<head>\n<base href="/${token}/">\n<meta name="sb-csrf" content="${csrf}">`);
|
|
53
55
|
const files: Files = { lookup: (key) => net?.lookup(key), workspace: (id) => net?.workspace(id) ?? [], readers: readers() };
|
|
54
56
|
// Turning remote access off ends the streams of remote pages; their next request finds the cookie void.
|
|
55
57
|
const clients = new Map<ServerResponse, Watch | undefined>(), remotes = new Set<ServerResponse>(), access = createAccess(token, () => remotes.forEach((c) => c.end()));
|
|
@@ -130,14 +132,14 @@ export async function startGui({ read, net, call, hub, dir = BUNDLE, port = 0, t
|
|
|
130
132
|
if (path[0] === "w") return void res.writeHead(200, { ...HEADERS, "content-type": TYPES[".html"] }).end(page);
|
|
131
133
|
let file: string;
|
|
132
134
|
try {
|
|
133
|
-
file =
|
|
134
|
-
if (!file.startsWith(resolve(dir) + sep) || !statSync(file).isFile()) throw new Error();
|
|
135
|
+
file = decodeURIComponent(path.join("/")) || "index.html";
|
|
135
136
|
} catch {
|
|
136
137
|
return void fail(404);
|
|
137
138
|
}
|
|
138
|
-
if (file ===
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
if (file === "index.html") return void res.writeHead(200, { ...HEADERS, "content-type": TYPES[".html"] }).end(page);
|
|
140
|
+
const body = bundle.get(file);
|
|
141
|
+
if (!body) return void fail(404);
|
|
142
|
+
res.writeHead(200, { ...HEADERS, "content-type": TYPES[extname(file)] ?? "application/octet-stream" }).end(body);
|
|
141
143
|
});
|
|
142
144
|
try {
|
|
143
145
|
await listen(port);
|