#!/usr/bin/env node // Generates docs/demo-dev.html from docs/demo.html with CDN URLs replaced // by the local asset server so no manual editing of demo.html is ever needed. // // CDN pattern replaced: // https://cdn.jsdelivr.net/npm/@kreuzberg/wasm@*/... // → http://localhost:9000/... // // Also patches pkg/web/kreuzberg_wasm.js (gitignored, wasm-pack generated) to // replace bare specifier imports ("env", "wasi_snapshot_preview1") with inline // browser shims. The local 5.x WASM binary is compiled with WASI syscalls via // tesseract's C layer; the importmap approach does not propagate into Workers // loading cross-origin modules, so we shim the generated JS directly. // // The output file is gitignored and regenerated on every `task demo:dev`. import { readFileSync, writeFileSync, existsSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const root = join(dirname(fileURLToPath(import.meta.url)), "..", ".."); const src = join(root, "docs", "demo.html"); const dest = join(root, "docs", "demo-dev.html"); const ASSET_PORT = process.env.ASSET_PORT ?? "9000"; const cdnRe = /https:\/\/cdn\.jsdelivr\.net\/npm\/@kreuzberg\/wasm@[^/'"]+/g; const patched = readFileSync(src, "utf8") .replace(cdnRe, `http://localhost:${ASSET_PORT}`) .replace(/(.*?)<\/title>/, "<title>$1 [local dev]") .replace( "", `
local dev · assets: localhost:${ASSET_PORT}
\n`, ); writeFileSync(dest, patched, "utf8"); console.log(`patch-demo-dev: docs/demo-dev.html → http://localhost:8001/demo-dev.html`); console.log(` assets served from http://localhost:${ASSET_PORT}`); // Patch pkg/web/kreuzberg_wasm.js — strip bare "env" / "wasi_snapshot_preview1" // import lines and replace with inline browser shims so the module loads in a // Worker without an importmap (importmap inheritance in Workers is unreliable // for bare specifiers in transitive cross-origin dynamic imports). const wasmJs = join(root, "crates", "kreuzberg-wasm", "pkg", "web", "kreuzberg_wasm.js"); if (!existsSync(wasmJs)) { console.warn(`patch-demo-dev: ${wasmJs} not found — skipping WASI shim patch`); } else { const bareImportRe = /^import \* as (import\d+) from "(env|wasi_snapshot_preview1)"\s*$/gm; const original = readFileSync(wasmJs, "utf8"); const envAliases = []; const wasiAliases = []; let m; while ((m = bareImportRe.exec(original)) !== null) { if (m[2] === "env") envAliases.push(m[1]); else wasiAliases.push(m[1]); } if (envAliases.length === 0 && wasiAliases.length === 0) { console.log("patch-demo-dev: kreuzberg_wasm.js already patched, skipping"); } else { const stripped = original.replace(/^import \* as import\d+ from "(env|wasi_snapshot_preview1)"\s*\n/gm, ""); const envShim = `const __env_shim = { system: () => -1, mkstemp: () => -1 };`; const envConsts = envAliases.map((a) => `const ${a} = __env_shim;`).join("\n"); const wasiShim = [ `const __wasi_shim = {`, ` environ_sizes_get: () => 0, environ_get: () => 0,`, ` clock_time_get: () => 52,`, ` fd_close: () => 8, fd_fdstat_get: () => 8, fd_fdstat_set_flags: () => 8,`, ` fd_prestat_get: () => 8, fd_prestat_dir_name: () => 8,`, ` fd_read: () => 8, fd_seek: () => 8, fd_write: () => 8,`, ` path_create_directory: () => 52, path_filestat_get: () => 52,`, ` path_open: () => 52, path_remove_directory: () => 52, path_unlink_file: () => 52,`, ` proc_exit: (code) => { throw new Error("WASI: proc_exit(" + code + ")"); },`, `};`, ].join("\n"); const wasiConsts = wasiAliases.map((a) => `const ${a} = __wasi_shim;`).join("\n"); const shims = [envShim, envConsts, wasiShim, wasiConsts].filter(Boolean).join("\n") + "\n"; const patchedWasmJs = stripped.replace(/^(\/\* @ts-self-types[^\n]*\n)/m, `$1${shims}`); writeFileSync(wasmJs, patchedWasmJs, "utf8"); console.log( `patch-demo-dev: patched kreuzberg_wasm.js` + ` (${envAliases.length} env alias(es), ${wasiAliases.length} wasi alias(es))`, ); } }