#!/usr/bin/env node
/**
* Production build: one Node bundle (all deps inlined) + minified single-file Web UI.
*
* Outputs:
* dist/server.js — main app (Torznab, qBt, MCP, UI API)
* dist/mcp.js — optional MCP-only process
* dist/ui/index.html — Search/Queue UI (CSS+JS inlined)
*/
import * as esbuild from 'esbuild';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const dist = path.join(root, 'dist');
const distUi = path.join(dist, 'ui');
fs.rmSync(dist, { recursive: true, force: true });
fs.mkdirSync(distUi, { recursive: true });
const nodeBundle = {
bundle: true,
platform: 'node',
target: 'node20',
format: 'cjs',
minify: true,
legalComments: 'none',
sourcemap: false,
// Keep Node builtins external; pull npm deps into the file.
packages: 'bundle',
};
async function bundleServer() {
const result = await esbuild.build({
...nodeBundle,
entryPoints: [path.join(root, 'src/index.js')],
outfile: path.join(dist, 'server.js'),
metafile: true,
logLevel: 'info',
});
const out = result.metafile.outputs[Object.keys(result.metafile.outputs)[0]];
console.log(`server.js ${(out.bytes / 1024 / 1024).toFixed(2)} MB`);
}
async function bundleMcp() {
const result = await esbuild.build({
...nodeBundle,
entryPoints: [path.join(root, 'src/mcp.js')],
outfile: path.join(dist, 'mcp.js'),
banner: { js: '#!/usr/bin/env node\n' },
metafile: true,
logLevel: 'info',
});
const out = result.metafile.outputs[Object.keys(result.metafile.outputs)[0]];
console.log(`mcp.js ${(out.bytes / 1024 / 1024).toFixed(2)} MB`);
try {
fs.chmodSync(path.join(dist, 'mcp.js'), 0o755);
} catch {
/* windows */
}
}
async function bundleUi() {
const cssSrc = fs.readFileSync(path.join(root, 'ui/styles.css'), 'utf8');
const jsSrc = fs.readFileSync(path.join(root, 'ui/scripts.js'), 'utf8');
const htmlSrc = fs.readFileSync(path.join(root, 'ui/index.html'), 'utf8');
const css = await esbuild.transform(cssSrc, { loader: 'css', minify: true });
const js = await esbuild.transform(jsSrc, {
loader: 'js',
minify: true,
target: ['es2020'],
});
// Prefer a single HTML payload (no extra static requests) for the tiny UI.
let html = htmlSrc
.replace(/\s*/i, '')
.replace(/\n