107 lines
3.6 KiB
JavaScript
107 lines
3.6 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
// Build a signed .zxp for the Dragonflight Premiere panel.
|
||
|
|
//
|
||
|
|
// - Reads version from ../CSXS/manifest.xml (<ExtensionBundleVersion>)
|
||
|
|
// - Generates a self-signed cert on first run (cert/dragonflight-selfsigned.p12)
|
||
|
|
// - Stages the panel bundle into stage/ (excludes build/ + dev cruft)
|
||
|
|
// - Calls zxp-sign-cmd to sign + package into dist/
|
||
|
|
//
|
||
|
|
// Usage: node build-zxp.mjs
|
||
|
|
// Output: dist/dragonflight-premiere-panel-<version>.zxp
|
||
|
|
|
||
|
|
import { mkdirSync, existsSync, readFileSync, writeFileSync, rmSync, cpSync, readdirSync, statSync } from 'node:fs';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
import { dirname, join, resolve } from 'node:path';
|
||
|
|
import { randomBytes } from 'node:crypto';
|
||
|
|
import zxp from 'zxp-sign-cmd';
|
||
|
|
|
||
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
||
|
|
const PANEL_DIR = resolve(HERE, '..');
|
||
|
|
const MANIFEST = join(PANEL_DIR, 'CSXS', 'manifest.xml');
|
||
|
|
const CERT_DIR = join(HERE, 'cert');
|
||
|
|
const CERT_FILE = join(CERT_DIR, 'dragonflight-selfsigned.p12');
|
||
|
|
const PASS_FILE = join(CERT_DIR, 'cert-passphrase.txt');
|
||
|
|
const STAGE_DIR = join(HERE, 'stage');
|
||
|
|
const DIST_DIR = join(HERE, 'dist');
|
||
|
|
|
||
|
|
// Files/dirs to exclude from the staged bundle.
|
||
|
|
const EXCLUDE = new Set(['build', 'install-windows.ps1', '.git', '.gitignore', 'node_modules']);
|
||
|
|
|
||
|
|
function readVersion() {
|
||
|
|
const xml = readFileSync(MANIFEST, 'utf8');
|
||
|
|
const m = xml.match(/<ExtensionBundleVersion>([^<]+)<\/ExtensionBundleVersion>/);
|
||
|
|
if (!m) throw new Error(`Could not find <ExtensionBundleVersion> in ${MANIFEST}`);
|
||
|
|
return m[1].trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
function ensureCert() {
|
||
|
|
mkdirSync(CERT_DIR, { recursive: true });
|
||
|
|
if (existsSync(CERT_FILE) && existsSync(PASS_FILE)) {
|
||
|
|
return readFileSync(PASS_FILE, 'utf8').trim();
|
||
|
|
}
|
||
|
|
console.log('No signing cert found — generating self-signed cert (one-time)…');
|
||
|
|
const passphrase = randomBytes(24).toString('base64url');
|
||
|
|
writeFileSync(PASS_FILE, passphrase + '\n', { mode: 0o600 });
|
||
|
|
return new Promise((res, rej) => {
|
||
|
|
zxp.selfSignedCert({
|
||
|
|
country: 'US',
|
||
|
|
province: 'WA',
|
||
|
|
org: 'Wild Dragon LLC',
|
||
|
|
name: 'Wild Dragon LLC',
|
||
|
|
password: passphrase,
|
||
|
|
output: CERT_FILE,
|
||
|
|
validityDays: 365 * 25,
|
||
|
|
}, (err) => {
|
||
|
|
if (err) return rej(err);
|
||
|
|
console.log(` wrote ${CERT_FILE}`);
|
||
|
|
console.log(` wrote ${PASS_FILE}`);
|
||
|
|
console.log(' >> COMMIT both files so future builds reuse them. <<');
|
||
|
|
res(passphrase);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function stageBundle() {
|
||
|
|
if (existsSync(STAGE_DIR)) rmSync(STAGE_DIR, { recursive: true, force: true });
|
||
|
|
mkdirSync(STAGE_DIR, { recursive: true });
|
||
|
|
for (const entry of readdirSync(PANEL_DIR)) {
|
||
|
|
if (EXCLUDE.has(entry)) continue;
|
||
|
|
const src = join(PANEL_DIR, entry);
|
||
|
|
const dst = join(STAGE_DIR, entry);
|
||
|
|
cpSync(src, dst, { recursive: true });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function signZxp(version, passphrase) {
|
||
|
|
mkdirSync(DIST_DIR, { recursive: true });
|
||
|
|
const output = join(DIST_DIR, `dragonflight-premiere-panel-${version}.zxp`);
|
||
|
|
if (existsSync(output)) rmSync(output);
|
||
|
|
return new Promise((res, rej) => {
|
||
|
|
zxp.sign({
|
||
|
|
input: STAGE_DIR,
|
||
|
|
output,
|
||
|
|
cert: CERT_FILE,
|
||
|
|
password: passphrase,
|
||
|
|
}, (err) => {
|
||
|
|
if (err) return rej(err);
|
||
|
|
const bytes = statSync(output).size;
|
||
|
|
console.log(`Built ${output} (${(bytes / 1024).toFixed(1)} KB)`);
|
||
|
|
res(output);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
const version = readVersion();
|
||
|
|
console.log(`Dragonflight Premiere panel — ZXP build v${version}`);
|
||
|
|
const passphrase = await ensureCert();
|
||
|
|
stageBundle();
|
||
|
|
await signZxp(version, passphrase);
|
||
|
|
rmSync(STAGE_DIR, { recursive: true, force: true });
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((err) => {
|
||
|
|
console.error('ZXP build failed:', err);
|
||
|
|
process.exit(1);
|
||
|
|
});
|