Files
heicode-win/cc-haha/desktop/scripts/build-updater-manifest.mjs
T
chenchenandClaude Opus 4.7 49be79fb9a feat(desktop,website): wire updater endpoint + release tooling
- tauri.conf.json: endpoints now points at the website-hosted
  manifest (https://<azure-swa>/updater/latest.json) so the
  already-built UpdateChecker actually has somewhere to check.
- website/public/updater/latest.json: placeholder manifest with
  empty platforms map (clients will see "up to date" until a real
  release ships).
- scripts/build-updater-manifest.mjs: helper that ingests signed
  Tauri bundle artifacts and emits the manifest, so future releases
  are one node command instead of hand-edited JSON.
- scripts/UPDATER.md: step-by-step for every release — what to set,
  what to upload, where to commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:18:51 +08:00

102 lines
3.1 KiB
JavaScript

#!/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(', ')}`)