import fs from "node:fs"; import crypto from "node:crypto"; const [schemaPath, packageRevisionId, bindingOutput, generatorPath, output] = process.argv.slice(2); if (!schemaPath || !packageRevisionId || !bindingOutput || !generatorPath || !output) throw new Error("Missing candidate check receipt inputs"); const canonical = (value) => Array.isArray(value) ? value.map(canonical) : value && typeof value === "object" ? Object.fromEntries( Object.entries(value) .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) .map(([key, entry]) => [key, canonical(entry)]), ) : value; const hash = (value) => `sha256:${crypto .createHash("sha256") .update(JSON.stringify(canonical(value))) .digest("hex")}`; const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8")); if (!schema.packages.some((entry) => entry.revisionId === packageRevisionId)) throw new Error("Checked binding schema lacks the package"); const generated = fs.readFileSync(bindingOutput, "utf8"); if (generated !== fs.readFileSync(".qx-checked-bindings", "utf8")) throw new Error("Build replaced candidate-generated bindings; its check is not evidence for this candidate"); const receipt = { schemaVersion: 1, packageRevisionId, success: true, bindingSchema: schema, bindingSchemaDigest: hash(schema), generatedDigest: hash(generated), checkerDigest: hash({ generatorPath, compiler: JSON.parse(fs.readFileSync("node_modules/typescript/package.json", "utf8")), lock: fs.readFileSync("yarn.lock", "utf8"), }), }; fs.writeFileSync(output, `${JSON.stringify(receipt, null, 2)}\n`, { flag: "wx" });