# Theseus gotchas Non-obvious things sessions keep re-deriving. If you found this file because something broke in a way that felt spooky, the answer is probably here. ## `build.files` in [package.json](package.json) is EXPLICIT electron-builder ships **only what's listed** in `build.files`. Every runtime- loaded HTML/preload/module MUST be there. A missing entry causes the `loadFile("foo.html")` in a WebContentsView to silently open blank in the packaged app — visually indistinguishable from "the button does nothing". `npm start` (dev) never catches this because it reads from the source tree directly. Only a real `npm run dist` + install exposes it. Every time you add a new `WebContentsView` or `loadFile`, add its HTML and preload to the `files` array. Sanity check after building: ``` node -e "const b = require('fs').readFileSync('dist-public/win-unpacked/resources/app.asar'); for (const n of ['engine-picker.html','popover.html','downloads.html','engine-picker-preload.js','popover-preload.js','downloads-preload.js']) console.log(n, b.indexOf(Buffer.from(n)) >= 0 ? 'OK' : 'MISSING');" ``` This has bit us once (search-picker dropdown, shipped `6bbccf9c`, blank picker). Do not let it bite twice. ## Building — admin terminal the first time `npm run dist` needs an **admin** terminal on the machine's first Theseus build so `electron-builder`'s `winCodeSign` package can extract its `darwin/` symlinks (requires `SeCreateSymbolicLink`). Subsequent builds reuse the cache under `$LOCALAPPDATA/electron-builder/Cache/winCodeSign/` and don't need admin. If DNS is misbehaving on the machine, pin these hosts in `C:\Windows\System32\drivers\etc\hosts` before building so electron-builder can fetch: `github.com`, `codeload.github.com`, `objects.githubusercontent.com`, `release-assets.githubusercontent.com`. Strip them after. ## Reproducible builds Set both before `npm run dist`: - `SOURCE_DATE_EPOCH` — freezes timestamps so a rebuild with no content changes produces the same hash. Bump per release, not per rebuild. - `CSC_IDENTITY_AUTO_DISCOVERY=false` — stops electron-builder searching for a signing cert (we don't sign; SECURITY.md rule 2). ## Native `` popup uses the page's `color-scheme`. When it's `"light dark"` (both accepted), Chromium picks by the OS scheme — so a dark-themed app on a light OS shows a light popup and vice versa. Fix, currently in [settings.html](settings.html): ```css :root { color-scheme: dark; } @media (prefers-color-scheme: light) { :root { color-scheme: light; } } ``` `nativeTheme.themeSource` (driven by `settings.theme`) sets `prefers-color-scheme`, so this stays in sync automatically. Do not remove. Chromium also respects `select option { background; color }` in the popup on Windows — a belt-and-braces override alongside `color-scheme`. ## The resolver in Theseus is `resolver-web.mjs`, not `.js` Packaged builds ship `Argus/src/lib/resolver-web.js` as `resolver-web.mjs` (see `extraResources` in [package.json](package.json)). Renamed because `resources/` has no adjacent `package.json` so a `.js` gets treated as CommonJS and its `export`s fail. Dev reads the engine copy directly (Argus is `type: module` so `.js` works there). ## The resolver's electrum WS `directIP` fallback [main.js](main.js) passes `directIP: true` to `resolveHost` so the engine can dial the chipnet electrum servers by pinned IP if system DNS is dead. Do not remove — this is what keeps `.bch` resolution working when the adapter DNS is broken (a real failure mode we've hit). ## Publishing new hashes end-to-end 1. Build (see above). 2. Update `../site/releases-manifest.json` AND `../site/tools/index.html` AND `../site/releases/index.html` with the fresh SHA-256s + release date. All three must match. 3. Deploy: ``` scp dist-public/*.exe ../site/releases-manifest.json silentmode:/opt/silent-mode/dl/ cd ../Argus && node src/lib/sia-upload.js ../site bns/silentmode ``` 4. On-chain (wallet spend, user's action): `releases.silentmode.bch` currently publishes `{"u":"https://dl.silentmode.st/releases-manifest.json"}` — a compact `u` record because on-chain hashes wouldn't fit the 200-byte OP_RETURN. Only re-publish if the URL changes or if we ever put full hashes on-chain. ## Sia upload from this machine fails without a `hosts` pin `node src/lib/sia-upload.js` fails with `getaddrinfo EAI_FAIL coinspectrum.duckdns.org` unless the host is pinned in `C:\Windows\System32\drivers\etc\hosts`: `195.184.247.106 coinspectrum.duckdns.org`. This is a DNS quirk of the machine, not a code bug — related to the strict-resolver behavior the Ariadne daemon's EDNS fix addresses. ## Deploy directory quirks - `/opt/silent-mode/dl/` is served as `dl.silentmode.st` — installers + manifest live here. - `silentmode.st` proxies to Sia (`bns/silentmode/`) — the HTML pages live there. - The `bns` gateway does NOT auto-index directories. `silentmode.st/apps/` is a 404 (`NoSuchKey`); users must hit `/apps/index.html`. Fix upstream in `bnsd.js` if it ever matters. ## Firefox needs a restart after Ariadne CA install/rotation Firefox only reads root CAs at startup. The Ariadne installer offers a `-CloseFirefox` task by default when Firefox is running so this doesn't bite. Chrome/Edge pick up the new root immediately.