// Baut den Prüfstand: node scripts/workers-harness/build.mjs // entry.jsx -> harness.js + harness.css (esbuild, Entwicklungsmodus, damit StrictMode wie in der Entwicklung zweimal einhängt), dazu index.html. // outDir muss ein neuer oder leerer Ordner unter dem Temp-Ordner (TMPDIR, sonst /tmp) oder unter .superpowers/ im Repo sein. // Die Schrift /fonts/* bleibt außen vor: der Server von shot.cjs liefert sie aus public/fonts. // Drei Module der App hängen an Appwrite (Anmeldung, Mitarbeiterliste, Sitzungs-JWT) und werden nur im Prüfstand ausgetauscht, damit die // echte Seite WorkersPage (Reiter Hochhaus, Freigabe und Bot-Leads) samt PultList, ProspectPanel und BotLeadList ohne Netz läuft: AuthContext -> stub-auth.js, // useEmployees -> stub-employees.js, workersClient -> stub-client.js. Am Quelltext der App ändert das nichts. import esbuild from 'esbuild' import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { fileURLToPath } from 'node:url' const here = path.dirname(fileURLToPath(import.meta.url)) const repo = path.resolve(here, '../..') const arg = process.argv[2] if (!arg) { console.error('usage: node scripts/workers-harness/build.mjs ') process.exit(2) } const out = path.resolve(arg) const tmp = path.resolve(process.env.TMPDIR || os.tmpdir()) const allowed = [tmp, path.join(repo, '.superpowers')] if (!allowed.some((base) => out.startsWith(base + path.sep))) { console.error(`refusing: outDir must be below ${allowed.join(' or ')}`) process.exit(2) } if (fs.existsSync(out) && fs.readdirSync(out).length > 0) { console.error('refusing: outDir must be new or empty') process.exit(2) } fs.mkdirSync(out, { recursive: true }) const STUBS = [ { filter: /(^|\/)context\/AuthContext(\.jsx?)?$/, file: 'stub-auth.js' }, { filter: /(^|\/)hooks\/useEmployees(\.jsx?)?$/, file: 'stub-employees.js' }, { filter: /(^|\/)lib\/workersClient(\.jsx?)?$/, file: 'stub-client.js' }, ] const stubPlugin = { name: 'harness-stubs', setup(build) { for (const stub of STUBS) { build.onResolve({ filter: stub.filter }, () => ({ path: path.join(here, stub.file) })) } }, } const result = await esbuild.build({ entryPoints: [path.join(here, 'entry.jsx')], outfile: path.join(out, 'harness.js'), bundle: true, format: 'iife', platform: 'browser', jsx: 'automatic', external: ['/fonts/*'], // Bilder der Pixelwelt (url() in src/styles/hustler/*.css) landen als data:-URI im harness.css loader: { '.png': 'dataurl' }, plugins: [stubPlugin], define: { 'process.env.NODE_ENV': '"development"' }, logLevel: 'warning', metafile: true, }) fs.copyFileSync(path.join(here, 'index.html'), path.join(out, 'index.html')) const sizes = Object.entries(result.metafile.outputs).map(([file, info]) => `${path.basename(file)} ${info.bytes}`) console.log(`built ${sizes.join(', ')} -> ${out}`)