#!/usr/bin/env node /** * Build the updater manifest (latest.json) consumed by tauri-plugin-updater. * * Usage: * node scripts/build-updater-manifest.mjs \ * --version 0.1.1 \ * --notes "Bugfix release" \ * --base-url https://your-cdn.example.com/releases/0.1.1 \ * [--windows-x86_64 ./bundle/heicode_0.1.1_x64-setup.exe] \ * [--darwin-aarch64 ./bundle/heicode_0.1.1_aarch64.app.tar.gz] \ * [--darwin-x86_64 ./bundle/heicode_0.1.1_x64.app.tar.gz] \ * [--linux-x86_64 ./bundle/heicode_0.1.1_amd64.AppImage] \ * --out ../../../website/public/updater/latest.json * * For each platform path supplied, the script reads the sibling `.sig` file * that `tauri build` produced (because `createUpdaterArtifacts: true` is * set in tauri.conf.json) and inlines its contents into the manifest. The * `url` field is built from `--base-url` + basename of the artifact, so the * uploader is free to put artifacts wherever — release CDN, Azure Blob, * GitHub Release assets — as long as `--base-url` matches. */ import { readFileSync, writeFileSync, mkdirSync, statSync } from 'node:fs' import { dirname, basename, resolve } from 'node:path' import { argv } from 'node:process' function parseArgs(rawArgs) { const out = {} for (let i = 0; i < rawArgs.length; i++) { const key = rawArgs[i] if (!key?.startsWith('--')) continue const k = key.slice(2) const next = rawArgs[i + 1] if (!next || next.startsWith('--')) { out[k] = true } else { out[k] = next i++ } } return out } const PLATFORM_KEYS = [ 'windows-x86_64', 'darwin-aarch64', 'darwin-x86_64', 'linux-x86_64', ] const args = parseArgs(argv.slice(2)) if (!args.version || !args['base-url'] || !args.out) { console.error('Required: --version, --base-url, --out') process.exit(2) } const platforms = {} for (const key of PLATFORM_KEYS) { const path = args[key] if (!path || path === true) continue const resolvedPath = resolve(path) try { statSync(resolvedPath) } catch { console.error(`Artifact not found for ${key}: ${resolvedPath}`) process.exit(3) } const sigPath = `${resolvedPath}.sig` let signature try { signature = readFileSync(sigPath, 'utf8').trim() } catch { console.error(`Signature file missing: ${sigPath}`) console.error('Run `bun run tauri build` with TAURI_SIGNING_PRIVATE_KEY set.') process.exit(4) } platforms[key] = { signature, url: `${args['base-url'].replace(/\/$/, '')}/${basename(resolvedPath)}`, } } if (Object.keys(platforms).length === 0) { console.error('No platform artifacts supplied — manifest would be empty.') process.exit(5) } const manifest = { version: args.version, notes: args.notes || `Heicode ${args.version}`, pub_date: new Date().toISOString(), platforms, } const outPath = resolve(args.out) mkdirSync(dirname(outPath), { recursive: true }) writeFileSync(outPath, `${JSON.stringify(manifest, null, 2)}\n`) console.log(`Wrote ${outPath}`) console.log(` version = ${manifest.version}`) console.log(` pub_date = ${manifest.pub_date}`) console.log(` platforms = ${Object.keys(platforms).join(', ')}`)