Files
festipod/src/index.ts
T
Sylvain Duchesne 25b1c033d9 fix(auth): show the shared-wallet flow in dev; hide re-import when already connected
The access barrier's shared-wallet steps are gated on hasSharedWallet(), which
reads a global set only by build.ts's compile-time `define`. The src-served paths
(bun run dev AND bun run start) bundle index.html via Bun's HTML import, which
applies no define and inlines neither `process.env` nor `bun --define` (verified) —
so FESTIPOD_SHARED_WALLET_PASSWORD passed to `bun run dev` never reached the
frontend, and the barrier showed the identifier-only variant.

Expose the config at runtime instead: src/index.ts serves /festipod-config.json
(+ /shared-wallet.ngw), and the entry (frontend.tsx) fetches it, sets the global,
then dynamically imports App so sharedWallet.ts reads it on eval. In a build.ts
bundle the value is inlined via define, so the fetch is skipped (NODE_ENV).
Verified in a headless browser: FESTIPOD_SHARED_WALLET_PASSWORD=1 bun run dev now
renders the download + import steps AND the identifier field, no console errors.

Also: only show the download/import steps when status !== 'connected' — after a
faux-logout the wallet is still open, so re-import must not be offered (just the
identifier). Documents the build-define-vs-runtime-config pitfall in tech-stack.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 15:23:20 +02:00

77 lines
2.2 KiB
TypeScript

import { serve } from "bun";
import index from "./index.html";
const port = process.env.PORT ? parseInt(process.env.PORT) : 3000;
const server = serve({
port,
routes: {
// Serve Cucumber HTML report
"/reports/cucumber": async () => {
const file = Bun.file("reports/cucumber-report.html");
if (await file.exists()) {
return new Response(file, {
headers: { "Content-Type": "text/html" },
});
}
return new Response("No test report found. Run 'bun run test:cucumber' first.", {
status: 404,
});
},
"/api/hello": {
async GET(req) {
return Response.json({
message: "Hello, world!",
method: "GET",
});
},
async PUT(req) {
return Response.json({
message: "Hello, world!",
method: "PUT",
});
},
},
"/api/hello/:name": async req => {
const name = req.params.name;
return Response.json({
message: `Hello, ${name}!`,
});
},
// Shared-wallet config, exposed at RUNTIME for the dev server + `bun run start`
// (both serve from src/, so they miss build.ts's compile-time `define`). The app
// entry (frontend.tsx) fetches this before it loads the app tree, so
// `sharedWallet.ts` sees the password. Empty env → '' → no shared wallet.
"/festipod-config.json": () =>
Response.json({
sharedWalletPassword: process.env.FESTIPOD_SHARED_WALLET_PASSWORD ?? "",
}),
// The shared wallet file (download target of the access barrier), when configured.
"/shared-wallet.ngw": async () => {
const p = process.env.FESTIPOD_SHARED_WALLET_FILE;
if (p) {
const file = Bun.file(p);
if (await file.exists()) return new Response(file);
}
return new Response("No shared wallet file configured.", { status: 404 });
},
// Serve index.html for all unmatched routes (must be last)
"/*": index,
},
development: process.env.NODE_ENV !== "production" && {
// Enable browser hot reloading in development
hmr: true,
// Echo console logs from the browser to the server
console: true,
},
});
console.log(`🚀 Server running at ${server.url}`);