/** * What is SPECIFIC to this repository in the end-to-end setup: the page that carries the * application, and the name of the wallet its runs mint. * * Everything generic — the wallet lifecycle, the broker crossing, per-run profiles, * bounds, the report shape, the recognition of the known browser failure modes — lives in * `ng-e2e-helpers` and is used, never reimplemented. That package knows nothing about * this one and must keep knowing nothing about it: it talks about NextGraph itself, so it * outlives both the polyfill and this indexing layer. */ import { execSync } from "node:child_process"; import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; import { mintWalletProfile, serveOnEphemeralPort, type RunProfile, type WalletCredentials, } from "ng-e2e-helpers"; const here = path.dirname(fileURLToPath(import.meta.url)); /** * The throwaway credentials each run mints its own wallet with. * * A NAME, not an identity that survives: every run gets a profile of its own and mints * this wallet into it, so two runs sharing the name share nothing else — which is what * lets this suite run beside another repository's at the same time, against the same * broker, without a lock. The password sits here in the clear because it opens a wallet * that exists for the length of one run and is deleted with the profile holding it. */ export const WALLET: WalletCredentials = { name: "ng-helpers-e2e", password: "ng-helpers-e2e", }; /** This run's physical user, in a profile of its own. */ export function mintRunWallet(suite: string): Promise { return mintWalletProfile(suite, WALLET); } /** `bun build` is a local bundle; a minute is already many times what it takes. */ const BUILD_MS = 60_000; const ENTRY = path.resolve(here, "indexing-app.ts"); const BUNDLE_OUT = path.resolve(here, ".dist", "indexing-app.js"); export function buildApp(): void { fs.mkdirSync(path.dirname(BUNDLE_OUT), { recursive: true }); execSync(`bun build ${ENTRY} --outfile ${BUNDLE_OUT} --bundle --format=esm`, { stdio: "pipe", cwd: path.resolve(here, ".."), timeout: BUILD_MS, }); } /** * Serve the application the way a deployment would. * * An unknown path 404s rather than answering with the page: a catch-all makes a request * for a file nobody serves look like a perfectly good download, and hides exactly the * kind of mistake a served asset can carry. */ export function serveApp(): Promise<{ url: string; close: () => void }> { const bundle = fs.readFileSync(BUNDLE_OUT, "utf-8"); const html = `` + `ng-helpers indexing — e2e` + ``; return serveOnEphemeralPort((req, res) => { const route = (req.url ?? "/").split("?")[0]; if (route === "/indexing-app.js") { res.writeHead(200, { "Content-Type": "application/javascript; charset=utf-8" }); res.end(bundle); } else if (route === "/" || route === "/index.html") { res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }); res.end(html); } else { res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" }); res.end("not served"); } }); }