c0fd69344b
Seed: l'auto-seed sur wallet vide est désormais OPT-IN, OFF par défaut — ne se déclenche que si FESTIPOD_AUTO_SEED=1 (livré en dev via /festipod-config.json + define build.ts, comme le shared-wallet). Le seed répété bloatait le wallet (lenteurs de lecture). Seed explicite (loadTestData, tests @data) inchangé. Logs: chaque useShapeQuery logge à la réception du set le nombre d'objets + le type + des compteurs globaux cumulés : [FestipodData] set reçu: 9 objets Event (public) en 1234ms [FestipodData] totaux — Event: 9, Participation: 3, UserProfile: 10 (5 sets) (polyfill docs.ts: "N rows" -> "N triple-rows" pour clarifier que ce sont des triplets RDF, pas des objets métier.) Diagnostic bug participantCount (NON corrigé, design-sensible): le propriétaire d'un événement reste à participantCount=0 quand un inscrit d'un AUTRE verifier dépose. Cause: le owner-materializer n'est re-déclenché que par ownedKey, jamais par un push d'inbox — doc_subscribe ne délivre aucun Patch cross-session. Le bloat de wallet MASQUAIT le bug (faux-vert). La théorie "StorageError" était fausse. Scénario réactif @wip = test ROUGE qui documente le bug. Doctrine: knowledge_context-internals (caveat BUG ACTIF + auto-seed opt-in), brief_2026-07-06 (claim D.2 "prouvé vert" REFUTÉ), build-pipeline (nouvelle var). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
174 lines
5.6 KiB
TypeScript
174 lines
5.6 KiB
TypeScript
#!/usr/bin/env bun
|
|
import plugin from "bun-plugin-tailwind";
|
|
import { existsSync } from "fs";
|
|
import { rm } from "fs/promises";
|
|
import path from "path";
|
|
|
|
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
console.log(`
|
|
🏗️ Bun Build Script
|
|
|
|
Usage: bun run build.ts [options]
|
|
|
|
Common Options:
|
|
--outdir <path> Output directory (default: "dist")
|
|
--minify Enable minification (or --minify.whitespace, --minify.syntax, etc)
|
|
--sourcemap <type> Sourcemap type: none|linked|inline|external
|
|
--target <target> Build target: browser|bun|node
|
|
--format <format> Output format: esm|cjs|iife
|
|
--splitting Enable code splitting
|
|
--packages <type> Package handling: bundle|external
|
|
--public-path <path> Public path for assets
|
|
--env <mode> Environment handling: inline|disable|prefix*
|
|
--conditions <list> Package.json export conditions (comma separated)
|
|
--external <list> External packages (comma separated)
|
|
--banner <text> Add banner text to output
|
|
--footer <text> Add footer text to output
|
|
--define <obj> Define global constants (e.g. --define.VERSION=1.0.0)
|
|
--help, -h Show this help message
|
|
|
|
Example:
|
|
bun run build.ts --outdir=dist --minify --sourcemap=linked --external=react,react-dom
|
|
`);
|
|
process.exit(0);
|
|
}
|
|
|
|
const toCamelCase = (str: string): string => str.replace(/-([a-z])/g, g => g[1]!.toUpperCase());
|
|
|
|
const parseValue = (value: string): any => {
|
|
if (value === "true") return true;
|
|
if (value === "false") return false;
|
|
|
|
if (/^\d+$/.test(value)) return parseInt(value, 10);
|
|
if (/^\d*\.\d+$/.test(value)) return parseFloat(value);
|
|
|
|
if (value.includes(",")) return value.split(",").map(v => v.trim());
|
|
|
|
return value;
|
|
};
|
|
|
|
function parseArgs(): Partial<Bun.BuildConfig> {
|
|
const config: Record<string, unknown> = {};
|
|
const args = process.argv.slice(2);
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
|
const arg = args[i];
|
|
if (arg === undefined) continue;
|
|
if (!arg.startsWith("--")) continue;
|
|
|
|
if (arg.startsWith("--no-")) {
|
|
const key = toCamelCase(arg.slice(5));
|
|
config[key] = false;
|
|
continue;
|
|
}
|
|
|
|
if (!arg.includes("=") && (i === args.length - 1 || args[i + 1]?.startsWith("--"))) {
|
|
const key = toCamelCase(arg.slice(2));
|
|
config[key] = true;
|
|
continue;
|
|
}
|
|
|
|
let key: string;
|
|
let value: string;
|
|
|
|
if (arg.includes("=")) {
|
|
[key, value] = arg.slice(2).split("=", 2) as [string, string];
|
|
} else {
|
|
key = arg.slice(2);
|
|
value = args[++i] ?? "";
|
|
}
|
|
|
|
key = toCamelCase(key);
|
|
|
|
if (key.includes(".")) {
|
|
const [parentKey, childKey] = key.split(".");
|
|
if (parentKey && childKey) {
|
|
config[parentKey] = config[parentKey] || {};
|
|
(config[parentKey] as Record<string, unknown>)[childKey] = parseValue(value);
|
|
}
|
|
} else {
|
|
config[key] = parseValue(value);
|
|
}
|
|
}
|
|
|
|
return config as Partial<Bun.BuildConfig>;
|
|
}
|
|
|
|
const formatFileSize = (bytes: number): string => {
|
|
const units = ["B", "KB", "MB", "GB"];
|
|
let size = bytes;
|
|
let unitIndex = 0;
|
|
|
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
size /= 1024;
|
|
unitIndex++;
|
|
}
|
|
|
|
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
};
|
|
|
|
console.log("\n🚀 Starting build process...\n");
|
|
|
|
const cliConfig = parseArgs();
|
|
const outdir = cliConfig.outdir || path.join(process.cwd(), "dist");
|
|
|
|
if (existsSync(outdir)) {
|
|
console.log(`🗑️ Cleaning previous build at ${outdir}`);
|
|
await rm(outdir, { recursive: true, force: true });
|
|
}
|
|
|
|
const start = performance.now();
|
|
|
|
const entrypoints = [...new Bun.Glob("**.html").scanSync("src")]
|
|
.map(a => path.resolve("src", a))
|
|
.filter(dir => !dir.includes("node_modules"));
|
|
console.log(`📄 Found ${entrypoints.length} HTML ${entrypoints.length === 1 ? "file" : "files"} to process\n`);
|
|
|
|
const result = await Bun.build({
|
|
entrypoints,
|
|
outdir,
|
|
plugins: [plugin],
|
|
minify: true,
|
|
target: "browser",
|
|
sourcemap: "linked",
|
|
define: {
|
|
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
// Access gate (ON by default) + shared wallet password, baked into the
|
|
// browser bundle as globals (see src/app/AuthGate.tsx, sharedWallet.ts). The
|
|
// wallet FILE is copied into the outdir below (served at /shared-wallet.ngw).
|
|
"globalThis.__FESTIPOD_ACCESS_GATE_DISABLED__": JSON.stringify(
|
|
process.env.ACCESS_GATE_DISABLED === "1",
|
|
),
|
|
"globalThis.__FESTIPOD_SHARED_WALLET_PASSWORD__": JSON.stringify(
|
|
process.env.FESTIPOD_SHARED_WALLET_PASSWORD ?? "",
|
|
),
|
|
// Auto-seed gate (OFF by default): only seed a genuinely-empty wallet with
|
|
// demo data when FESTIPOD_AUTO_SEED is set (see src/shared/utils/autoSeed.ts).
|
|
"globalThis.__FESTIPOD_AUTO_SEED__": JSON.stringify(
|
|
process.env.FESTIPOD_AUTO_SEED ?? "",
|
|
),
|
|
},
|
|
...cliConfig,
|
|
});
|
|
|
|
// Staging: copy the shared wallet FILE into the bundle so the access gate can
|
|
// offer it for download (served at /shared-wallet.ngw). See sharedWallet.ts.
|
|
if (process.env.FESTIPOD_SHARED_WALLET_FILE) {
|
|
const { copyFileSync } = await import("fs");
|
|
copyFileSync(process.env.FESTIPOD_SHARED_WALLET_FILE, path.join(outdir, "shared-wallet.ngw"));
|
|
console.log(`📦 Copied shared wallet → ${path.join(outdir, "shared-wallet.ngw")}`);
|
|
}
|
|
|
|
const end = performance.now();
|
|
|
|
const outputTable = result.outputs.map(output => ({
|
|
File: path.relative(process.cwd(), output.path),
|
|
Type: output.kind,
|
|
Size: formatFileSize(output.size),
|
|
}));
|
|
|
|
console.table(outputTable);
|
|
const buildTime = (end - start).toFixed(2);
|
|
|
|
console.log(`\n✅ Build completed in ${buildTime}ms\n`);
|