#!/usr/bin/env node import { createHash } from 'node:crypto'; import { readFileSync, writeFileSync } from 'node:fs'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const sourceFiles = Object.freeze([ 'src/runtime/constants.js', 'src/runtime/diagnostics.js', 'src/runtime/rng.js', 'src/runtime/types.js', 'src/runtime/values.js', 'src/runtime/audio-contract.js', 'src/runtime/audio-graph.js', 'src/runtime/validator.js', 'src/runtime/persistence.js', 'src/runtime/library.js', 'src/runtime/resolution.js', 'src/runtime/actions.js', 'src/runtime/performance.js', 'src/runtime/activation.js', 'src/runtime/audio-engine.js', 'src/runtime/app.js' ]); function normalized(path) { return readFileSync(resolve(repositoryRoot, path), 'utf8').replace(/\r\n/g, '\n'); } function bundleModule(source, path) { const withoutImports = source.replace(/^import\s+[\s\S]*?\s+from\s+['"][^'"]+['"];\s*$/gm, ''); const withoutExports = withoutImports.replace(/\bexport\s+/g, ''); return `\n/* ${path} */\n${withoutExports.trim()}\n`; } export function buildStandalone(outputPath = resolve(repositoryRoot, 'XZBT.html')) { const template = normalized('src/XZBT.template.html'); const styles = normalized('src/styles.css').trim(); const script = `'use strict';\n(() => {\n${sourceFiles.map((path) => bundleModule(normalized(path), path)).join('')}\n})();`; if (!template.includes('/*__XZBT_STYLES__*/') || !template.includes('/*__XZBT_SCRIPT__*/')) { throw new Error('Standalone template is missing a build placeholder.'); } const artifact = template .replace('/*__XZBT_STYLES__*/', () => styles) .replace('/*__XZBT_SCRIPT__*/', () => script) .replace(/\r\n/g, '\n'); writeFileSync(outputPath, artifact, 'utf8'); return { outputPath, bytes: Buffer.byteLength(artifact), sha256: createHash('sha256').update(artifact).digest('hex') }; } if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { const outputIndex = process.argv.indexOf('--output'); const outputPath = outputIndex >= 0 ? resolve(process.argv[outputIndex + 1]) : resolve(repositoryRoot, 'XZBT.html'); const result = buildStandalone(outputPath); console.log(`Built ${result.outputPath}`); console.log(`SHA-256 ${result.sha256} (${result.bytes} bytes)`); }