/* * Single-file binary entry point (compiled with `bun build --compile`). * * Not part of upstream. Copied to the server submodule root by scripts/apply.sh. * The built UI is embedded into the binary as `ui.tar.gz` (created by * scripts/build.sh) and extracted to a temp dir on first run. * * Usage: httptoolkit [--port 8080] [--server-port 45457] [--mockttp-port 45456] [--no-open] */ // Bun global is present at runtime in the compiled binary: declare const Bun: { file(path: string): { arrayBuffer(): Promise } }; import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import * as fsp from 'fs/promises'; import { x as extractTar } from 'tar'; import { startHtkApp } from './src/htk-app'; import { SERVER_VERSION } from './src/constants'; // Embedded UI bundle. Resolves to a path Bun can read from the compiled binary: import uiArchive from './ui.tar.gz' with { type: 'file' }; function printHelp() { console.log(`HTTP Toolkit (self-hosted single binary) v${SERVER_VERSION} Usage: httptoolkit [options] Options: -p, --port Port to serve the web UI on (default: 8080) --server-port HTK management API port (default: 45457) --mockttp-port Mockttp admin port (default: 45456) --no-open Don't open a browser automatically -h, --help Show this help `); } function parseArgs(argv: string[]) { const opts = { port: 8080, serverPort: 45457, mockttpPort: 45456, open: true }; for (let i = 0; i < argv.length; i++) { const a = argv[i]; const eq = a.indexOf('='); const inlineVal = eq !== -1 ? a.slice(eq + 1) : undefined; const key = eq !== -1 ? a.slice(0, eq) : a; const val = () => inlineVal ?? argv[++i]; switch (key) { case '-p': case '--port': opts.port = parseInt(val(), 10); break; case '--server-port': opts.serverPort = parseInt(val(), 10); break; case '--mockttp-port': opts.mockttpPort = parseInt(val(), 10); break; case '--no-open': opts.open = false; break; case '-h': case '--help': printHelp(); process.exit(0); default: console.error(`Unknown option: ${a}`); printHelp(); process.exit(1); } } if (!Number.isInteger(opts.port) || opts.port <= 0 || opts.port > 65535) { console.error(`Invalid --port value`); process.exit(1); } return opts; } async function extractUi(): Promise { const dir = path.join(os.tmpdir(), `httptoolkit-ui-${SERVER_VERSION}`); const marker = path.join(dir, '.extracted'); if (fs.existsSync(marker)) return dir; // already extracted for this version await fsp.rm(dir, { recursive: true, force: true }); await fsp.mkdir(dir, { recursive: true }); const bytes = new Uint8Array(await Bun.file(uiArchive).arrayBuffer()); const tmpArchive = path.join(dir, 'ui.tar.gz'); await fsp.writeFile(tmpArchive, bytes); await extractTar({ file: tmpArchive, cwd: dir }); await fsp.unlink(tmpArchive).catch(() => {}); await fsp.writeFile(marker, ''); return dir; } async function main() { const opts = parseArgs(process.argv.slice(2)); const uiDir = await extractUi(); await startHtkApp({ ...opts, uiDir }); } main().catch((e) => { console.error('Failed to start HTTP Toolkit:', e); process.exit(1); });