import fsp from 'node:fs/promises' import path from 'node:path' import { DEFAULT_BASE_URL, DEFAULT_PRIVATE_KEY, DEFAULT_PUBLIC_KEY, assertOutsideRepo, buildManifestPayload, canonicalNow, createSignedManifest, normalizeBaseUrl, parseOptions, readPrivateKey, readPublicKey, resolvePath, serializeSignedManifest, usageError, verifyReleaseInstaller, verifySignedManifest, writeFileAtomic } from './lib.mjs' const usage = `Usage: node scripts/updates/prepare-release.mjs --installer --version --notes-zh --notes-en [--base-url ] [--published-at ] [--private-key ] [--public-key ] [--output ] This validates the actual EXE ProductVersion, current package.json version, size and SHA-256, then signs exact JSON.stringify(payload) with Ed25519. It never deploys. ` async function main() { const options = parseOptions(process.argv.slice(2), { values: ['installer', 'version', 'notes-zh', 'notes-en', 'base-url', 'published-at', 'private-key', 'public-key', 'output'] }) if (!options.installer || !options.version || !options['notes-zh'] || !options['notes-en']) { throw new Error('--installer, --version, --notes-zh and --notes-en are required') } const baseUrl = normalizeBaseUrl(options['base-url'] || DEFAULT_BASE_URL) const installerPath = resolvePath(options.installer) const installer = await verifyReleaseInstaller(installerPath, options.version) const output = resolvePath(options.output || path.join('.tmp', 'updates', options.version, 'latest.json')) const privateKeyPath = await assertOutsideRepo( resolvePath(options['private-key'] || DEFAULT_PRIVATE_KEY), 'Private key' ) const privateKey = await readPrivateKey(privateKeyPath) const publicKeyPath = resolvePath(options['public-key'] || DEFAULT_PUBLIC_KEY) const publicKey = await readPublicKey(publicKeyPath) const payload = buildManifestPayload({ version: options.version, publishedAt: options['published-at'] || canonicalNow(), notes: { zh: options['notes-zh'], en: options['notes-en'] }, installer, baseUrl }) const document = createSignedManifest({ payload, privateKeyPem: privateKey, publicKeyPem: publicKey, baseUrl }) verifySignedManifest(document, publicKey, { baseUrl }) await writeFileAtomic(output, serializeSignedManifest(document)) await fsp.access(output) console.log(`Manifest: ${output}`) console.log(`Version: ${payload.version}`) console.log(`Installer: ${installer.filename}`) console.log(`Size: ${installer.size}`) console.log(`SHA-256: ${installer.sha256}`) console.log(`URL: ${payload.platforms['windows-x64'].url}`) } main().catch((error) => usageError(usage, error))