57 lines
1.5 KiB
JavaScript
Executable File
57 lines
1.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import process from "node:process";
|
|
import { parse } from "yaml";
|
|
|
|
function fail(message) {
|
|
console.error(`[nani] error: ${message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const [manifestPath, manifestUrl] = process.argv.slice(2);
|
|
if (!manifestPath || !manifestUrl) {
|
|
fail("usage: resolve-upstream.mjs MANIFEST_PATH MANIFEST_URL");
|
|
}
|
|
|
|
let manifest;
|
|
try {
|
|
manifest = parse(fs.readFileSync(manifestPath, "utf8"));
|
|
} catch (error) {
|
|
fail(`could not parse upstream manifest: ${error.message}`);
|
|
}
|
|
|
|
const files = Array.isArray(manifest?.files) ? manifest.files : [];
|
|
const dmgs = files.filter(
|
|
(file) => typeof file?.url === "string" && file.url.toLowerCase().endsWith(".dmg"),
|
|
);
|
|
if (dmgs.length !== 1) {
|
|
fail(`expected exactly one DMG in manifest, found ${dmgs.length}`);
|
|
}
|
|
|
|
const selected = dmgs[0];
|
|
if (typeof manifest.version !== "string" || manifest.version.length === 0) {
|
|
fail("manifest has no version");
|
|
}
|
|
if (typeof selected.sha512 !== "string" || selected.sha512.length === 0) {
|
|
fail("DMG entry has no SHA-512");
|
|
}
|
|
|
|
let resolvedUrl;
|
|
try {
|
|
resolvedUrl = new URL(selected.url, manifestUrl).href;
|
|
} catch (error) {
|
|
fail(`invalid DMG URL: ${error.message}`);
|
|
}
|
|
if (!resolvedUrl.startsWith("https://")) {
|
|
fail("DMG URL must use HTTPS");
|
|
}
|
|
|
|
const filename = path.basename(new URL(resolvedUrl).pathname);
|
|
if (!filename) fail("DMG URL has no filename");
|
|
|
|
process.stdout.write(
|
|
[manifest.version, resolvedUrl, selected.sha512, filename].join("\t") + "\n",
|
|
);
|