import { createHash } from "node:crypto"; import { readFileSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const packageRoot = resolve(root, "node_modules/@rerun-io/web-viewer"); const vendorRoot = resolve(root, "vendor/rerun-web-viewer-0.36.3"); const manifest = JSON.parse(readFileSync(resolve(vendorRoot, "navigation-build.json"), "utf8")); const installed = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8")); const sha = bytes => createHash("sha256").update(bytes).digest("hex"); if (installed.version !== "0.36.3" || manifest.upstreamVersion !== installed.version) { throw new Error("Rerun navigation requires the audited 0.36.3 package; rebase before upgrading"); } if (sha(readFileSync(resolve(vendorRoot, "NODEDC_NAVIGATION.patch"))) !== manifest.patchSha256) { throw new Error("Rerun navigation source patch identity mismatch"); } const eyeType = "{ position: [number, number, number]; lookTarget: [number, number, number]; eyeUp: [number, number, number] } | null"; const additions = { "index.js": { marker: " get_active_recording_id() {", code: ` get_camera_eye() {\n if (!this.#handle) throw new Error("Rerun viewer is stopped");\n return JSON.parse(this.#handle.nodedc_camera_eye() ?? "null");\n }\n`, }, "index.ts": { marker: " get_active_recording_id(): string | null {", code: ` get_camera_eye(): ${eyeType} {\n if (!this.#handle) throw new Error("Rerun viewer is stopped");\n return JSON.parse(this.#handle.nodedc_camera_eye() ?? "null");\n }\n`, }, "index.d.ts": { marker: " get_active_recording_id(): string | null;", code: ` get_camera_eye(): ${eyeType};\n`, }, }; // Validate the complete set before changing any installed file. A package // upgrade, corrupt artifact or independently modified wrapper fails closed. const writes = []; for (const [name, identity] of Object.entries(manifest.files)) { const current = readFileSync(resolve(packageRoot, name)); let output; if (additions[name]) { const { marker, code } = additions[name]; const source = current.toString("utf8"); const original = source.includes(code) ? source.replace(code, "") : source; if (sha(original) !== identity.upstreamSha256 || original.split(marker).length !== 2) { throw new Error(`Unexpected upstream wrapper: ${name}`); } output = Buffer.from(original.replace(marker, code + marker)); } else { output = readFileSync(resolve(vendorRoot, identity.artifact)); if (sha(output) !== identity.sha256) throw new Error(`Corrupt navigation artifact: ${name}`); if (![identity.upstreamSha256, identity.sha256].includes(sha(current))) { throw new Error(`Unexpected installed runtime: ${name}`); } } writes.push([resolve(packageRoot, name), output]); } for (const [path, output] of writes) writeFileSync(path, output); console.log("Installed NODE.DC Rerun 0.36.3 navigation/v1 (native camera, one renderer).");