#!/usr/bin/env node /** * latest.json 무결성 보장 — 빈 파일·깨진 JSON 방지 (Tauri updater JSON parse 오류 예방) */ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); function arg(name, fallback) { const i = process.argv.indexOf(name); return i >= 0 && process.argv[i + 1] ? process.argv[i + 1] : fallback; } const dir = path.resolve(arg('--dir', 'frontend/public/desktop/updates')); const version = arg('--version', '0.1.0'); const rawBaseUrl = arg('--base-url', 'https://exdev.co.kr/desktop/updates'); const baseUrl = rawBaseUrl.replace(/\/$/, '').replace(/^http:\/\//i, 'https://'); const notes = arg('--notes', `GoldenChart Desktop ${version}`); const latestPath = path.join(dir, 'latest.json'); const generator = path.join(__dirname, 'generate-desktop-latest-json.mjs'); function isValidManifest(obj) { return obj && typeof obj === 'object' && typeof obj.version === 'string' && obj.version.trim().length > 0 && typeof obj.pub_date === 'string' && obj.platforms && typeof obj.platforms === 'object' && !Array.isArray(obj.platforms); } function readManifest() { if (!fs.existsSync(latestPath)) return null; if (fs.statSync(latestPath).size < 8) return null; try { const obj = JSON.parse(fs.readFileSync(latestPath, 'utf8')); return isValidManifest(obj) ? obj : null; } catch { return null; } } function writeManifest(manifest) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); const tmp = `${latestPath}.tmp`; const body = `${JSON.stringify(manifest, null, 2)}\n`; if (body.length < 8) throw new Error('refusing to write empty latest.json'); fs.writeFileSync(tmp, body, 'utf8'); fs.renameSync(tmp, latestPath); } function runGenerate() { const r = spawnSync( process.execPath, [generator, '--version', version, '--dir', dir, '--base-url', baseUrl, '--notes', notes], { encoding: 'utf8' }, ); if (r.status === 0) return readManifest(); return null; } function fallbackManifest(existing) { return { version: existing?.version?.trim() || version, notes: existing?.notes?.trim() || notes, pub_date: new Date().toISOString(), platforms: existing?.platforms && typeof existing.platforms === 'object' ? existing.platforms : {}, }; } if (!fs.existsSync(dir)) { console.error('[ensure-latest] directory not found:', dir); process.exit(1); } let manifest = readManifest(); const platformKeys = manifest ? Object.keys(manifest.platforms) : []; if (manifest && platformKeys.length > 0) { console.log('[ensure-latest] OK v' + manifest.version + ' platforms=' + platformKeys.join(',')); process.exit(0); } const generated = runGenerate(); if (generated && Object.keys(generated.platforms).length > 0) { console.log('[ensure-latest] regenerated v' + generated.version + ' platforms=' + Object.keys(generated.platforms).join(',')); process.exit(0); } manifest = fallbackManifest(manifest); writeManifest(manifest); console.warn('[ensure-latest] fallback v' + manifest.version + ' (platforms empty — Jenkins desktop publish 필요)'); process.exit(2);