@oevery/rsp 4.0.0 → 4.1.0

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,66 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PKG_ROOT
4
+ } from "./chunk-P3KO3GZW.mjs";
5
+
6
+ // src/viewer/runtime.ts
7
+ import { createHash } from "crypto";
8
+ import { readdir, readFile, realpath } from "fs/promises";
9
+ import { homedir } from "os";
10
+ import { join, sep } from "path";
11
+ var VIEWER_PROTOCOL = 1;
12
+ async function viewerRuntime(installation = PKG_ROOT) {
13
+ const root = await realpath(installation);
14
+ const { version } = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
15
+ const build = (await readFile(join(root, "dist/viewer-build.json"), "utf8")).trim();
16
+ const identity = createHash("sha256").update(JSON.stringify({ root, version, build, protocol: VIEWER_PROTOCOL })).digest("hex");
17
+ const directory = join(homedir(), ".cache", "rsp", "viewer");
18
+ return { root, version, build, identity, directory, recordPath: join(directory, `${identity}.json`), lockPath: join(directory, `${identity}.lock`) };
19
+ }
20
+ async function snapshotViewerRuntime(root, identity) {
21
+ const runtime = await viewerRuntime(root);
22
+ if (runtime.identity !== identity)
23
+ throw new Error("Viewer build changed during startup; retry");
24
+ const hash = createHash("sha256");
25
+ const assets = /* @__PURE__ */ new Map();
26
+ for (const file of (await readdir(join(root, "dist"), { recursive: true })).map((file2) => file2.split(sep).join("/")).sort()) {
27
+ if (!/\.(?:mjs|js|css)$/.test(file))
28
+ continue;
29
+ const content = await readFile(join(root, "dist", file));
30
+ hash.update(file).update(content);
31
+ if (file === "viewer/app.js" || file === "viewer/app.css")
32
+ assets.set(`/${file.slice("viewer/".length)}`, content);
33
+ }
34
+ if (hash.digest("hex") !== JSON.parse(runtime.build).identity || assets.size !== 2 || (await viewerRuntime(root)).identity !== identity) {
35
+ throw new Error("Viewer assets do not match the startup build; rebuild or reinstall and retry");
36
+ }
37
+ return { version: runtime.version, assets };
38
+ }
39
+ async function serviceRequest(record, path, body, timeoutMs = 2500) {
40
+ const response = await fetch(`http://127.0.0.1:${record.port}${path}`, { method: body === void 0 ? "GET" : "POST", headers: { Authorization: `Bearer ${record.adminToken}`, ...body === void 0 ? {} : { "Content-Type": "application/json" } }, ...body === void 0 ? {} : { body: JSON.stringify(body) }, signal: AbortSignal.timeout(timeoutMs) });
41
+ if (!response.ok)
42
+ throw new Error(await response.text());
43
+ const result = await response.json();
44
+ if (result.identity !== record.identity || result.protocol !== VIEWER_PROTOCOL)
45
+ throw new Error("Viewer identity/protocol mismatch");
46
+ return result;
47
+ }
48
+ async function discoverService(path, identity) {
49
+ try {
50
+ const record = JSON.parse(await readFile(path, "utf8"));
51
+ if (record.identity !== identity || record.protocol !== VIEWER_PROTOCOL || !Number.isInteger(record.port) || record.port < 1 || record.port > 65535 || typeof record.adminToken !== "string")
52
+ return null;
53
+ await serviceRequest(record, "/control/status");
54
+ return record;
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ export {
61
+ VIEWER_PROTOCOL,
62
+ viewerRuntime,
63
+ snapshotViewerRuntime,
64
+ serviceRequest,
65
+ discoverService
66
+ };