import { builtinModules } from 'node:module'; import { copyFileSync, cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { createHash } from 'node:crypto'; import { build } from 'esbuild'; const out = 'dist'; mkdirSync(out, { recursive: true }); const aliases = { '@libsql/client': '@libsql/client-wasm', // client-wasm 0.18.0 pins libsql-wasm-experimental 0.0.2, which has no vector functions; 0.0.3 has them. '@libsql/libsql-wasm-experimental': './node_modules/@libsql/libsql-wasm-experimental/index.mjs', path: 'path-browserify', }; const builtins = new Set([...builtinModules, ...builtinModules.map(m => `node:${m}`)]); const stubbed = new Set(); // Node stdlib imports that @mastra/core pulls in for features this demo never touches. // Each becomes a module with the same export names: globals where the browser has them, inert stubs otherwise. // The one Node API LibSQLVector itself calls is fs/promises.realpath() (to key its per-file write lock); // the Wasm database lives in an in-memory filesystem, so the path is returned as is. const implemented = { 'fs/promises': { realpath: 'async path => path' } }; const stubNodeBuiltins = { name: 'stub-node-builtins', setup(b) { b.onResolve({ filter: /.*/ }, args => { if (!builtins.has(args.path) || args.path in aliases) return; stubbed.add(args.path); return { path: args.path, namespace: 'node-stub' }; }); b.onLoad({ filter: /.*/, namespace: 'node-stub' }, async args => { const real = await import(args.path); const names = Object.keys(real).filter(n => n !== 'default' && /^[A-Za-z_$][\w$]*$/.test(n)); const contents = [ 'const stub = new Proxy(function () {}, { get: (_t, p) => (p === "prototype" ? {} : p === Symbol.toPrimitive ? () => "" : stub), apply: () => stub, construct: () => ({}) });', ...names.map(n => `export const ${n} = ${implemented[args.path]?.[n] ?? `globalThis.${n} ?? stub`};`), 'export default stub;', ].join('\n'); return { contents, loader: 'js' }; }); }, }; const common = { bundle: true, format: 'esm', platform: 'browser', target: 'es2022', sourcemap: false, minify: true, legalComments: 'none', logLevel: 'warning', }; await build({ ...common, entryPoints: ['src/worker.js'], outfile: `${out}/worker.js`, alias: aliases, inject: ['./src/shims/process.js'], plugins: [stubNodeBuiltins], metafile: true, }).then(r => writeFileSync('worker.meta.json', JSON.stringify(r.metafile))); await build({ ...common, entryPoints: ['src/main.js'], outfile: `${out}/main.js` }); copyFileSync('node_modules/@libsql/libsql-wasm-experimental/sqlite-wasm/jswasm/sqlite3.wasm', `${out}/sqlite3.wasm`); cpSync('public', out, { recursive: true }); cpSync('files', `${out}/files`, { recursive: true }); mkdirSync(`${out}/files/demo-src`, { recursive: true }); for (const [from, to] of [ ['src/worker.js', 'worker.js'], ['src/main.js', 'main.js'], ['build.mjs', 'build.mjs'], ['package.json', 'package.json'], ['vendor/libsql-fix/SOURCE.md', 'SOURCE.md'], ]) { copyFileSync(from, `${out}/files/demo-src/${to}`); } const sha = f => createHash('sha256').update(readFileSync(f)).digest('hex').slice(0, 16); console.log('stubbed node builtins:', [...stubbed].sort().join(', ') || '(none)'); console.log('worker.js sha256:', sha(`${out}/worker.js`), `${(readFileSync(`${out}/worker.js`).length / 1024).toFixed(0)} KiB`);