← Files NGS Analysis WorkbenchARCHIVED FILE
scripts/check-release-artifacts.mjs
1.71 KB · Sep 30, 2026 · 23:20 UTC
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { build } from "vite";
const root = fileURLToPath(new URL("../", import.meta.url));
const manifest = await readFile(new URL("../../../manage/blob_data.hashes", import.meta.url), "utf8");
const hashes = new Map(
[...manifest.matchAll(/\[\[file\]\]\s+name = "([^"]+)"\s+hash = "([a-f0-9]{64})"/g)]
.map((match) => [match[1], match[2]]),
);
const mismatches = [];
// Rebuild in memory: a cached HTML file can agree with the release manifest
// while both still implement an obsolete MCP response contract.
for (const [config, filename] of [
["vite.config.ts", "mcp-app.html"],
["vite.inline.config.ts", "mcp-inline.html"],
]) {
const name = `plugins/ngs-analysis-workbench/mcp/${filename}`;
const expected = hashes.get(name);
assert.ok(expected, `Missing release hash for ${name}`);
const result = await build({ root, configFile: `${root}${config}`, build: { write: false } });
const outputs = Array.isArray(result) ? result : [result];
const html = outputs.flatMap((output) => output.output)
.find((output) => output.type === "asset" && output.fileName === filename);
assert.ok(html, `Build did not produce ${filename}`);
const actual = createHash("sha256").update(html.source).digest("hex");
if (actual !== expected) {
mismatches.push(`${name}: source build ${actual}, released blob ${expected}`);
}
}
assert.equal(
mismatches.length,
0,
`NGS App release assets are stale. Rebuild and upload the App assets before releasing.\n${mismatches.join("\n")}`,
);
console.log("Both NGS App release hashes match fresh source builds.");
SHA-256: a95d7269b7c1515e03b3d3ea2e58c6aea3510f45448960f5ca6c1787e103f01a