#!/usr/bin/env -S deno run --allow-read --allow-write /** * bundle-ui.ts * * Walks `ts_web/` and emits `ts_bundled/bundle.ts`, a single TypeScript * module that exports every UI asset as base64 in order. The daemon's * UI server imports this module at runtime to serve the console without * any external filesystem dependency — the entire browser app ends up * embedded in the `deno compile` binary. * * The output shape matches the `@stack.gallery/registry` convention so * a consumer can loop `files` as `{ path, contentBase64 }` entries. */ import { walk } from 'jsr:@std/fs@^1.0.0/walk'; import { fromFileUrl, join, relative } from 'jsr:@std/path@^1.0.0'; const here = fromFileUrl(new URL('./', import.meta.url)); const repoRoot = join(here, '..'); const sourceDir = join(repoRoot, 'ts_web'); const outDir = join(repoRoot, 'ts_bundled'); const outFile = join(outDir, 'bundle.ts'); async function main(): Promise { const entries: Array<{ path: string; contentBase64: string; size: number }> = []; for await ( const entry of walk(sourceDir, { includeDirs: false, includeSymlinks: false, }) ) { const rel = relative(sourceDir, entry.path).replaceAll('\\', '/'); const bytes = await Deno.readFile(entry.path); entries.push({ path: rel, contentBase64: encodeBase64(bytes), size: bytes.byteLength, }); } entries.sort((a, b) => a.path.localeCompare(b.path)); const generatedAt = new Date().toISOString(); const totalBytes = entries.reduce((sum, e) => sum + e.size, 0); const header = [ '// AUTO-GENERATED — do not edit.', '// Regenerate with: deno task bundle:ui', `// Source: ts_web/ (${entries.length} files, ${totalBytes} bytes)`, `// Generated: ${generatedAt}`, '', 'export interface IBundledFile {', ' path: string;', ' contentBase64: string;', '}', '', 'export const files: IBundledFile[] = [', ].join('\n'); const body = entries.map((e) => ` { path: ${JSON.stringify(e.path)}, contentBase64: ${JSON.stringify(e.contentBase64)} },` ).join('\n'); const footer = '\n];\n'; await Deno.mkdir(outDir, { recursive: true }); await Deno.writeTextFile(outFile, header + '\n' + body + footer); console.log( `bundle-ui: wrote ${entries.length} file(s), ${totalBytes} bytes → ${ relative(repoRoot, outFile) }`, ); } function encodeBase64(bytes: Uint8Array): string { let binary = ''; for (let i = 0; i < bytes.length; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } if (import.meta.main) { await main(); }