Aegis is most of the remaining launch cost: ~165 ms of synchronous
activation, then ~610 ms of main-thread work loading its crypto and
WizardConnect deps. It was left on startup because another session
owns bundled-addons/aegis. NOTE-aegis-on-demand.md says exactly what it
needs, measured against 0.27.1:
- addon.json: "activation": "on-demand", plus panels [{id:"main",
title:"Wallet", page:"panel.html"}].
- activate() must return a promise that resolves once deps are loaded
and, only if the vault is already unlocked, wallets are mounted.
vault.derive never rejects on a locked vault, so awaiting
mountAllWallets there would stall every first call for the full 5 s
host wait.
- Persisted WizardConnect pairings (wc/<walletId>/uris) need a relay
listener: call api.startAtLaunch(true) while any exist, false when
none are left.
- Bridge calls, panel open, wiz:// links and Settings calls already wake
it. The dapp globals are injected from the manifest before it runs.
GOTCHAS: an enabled add-on may not be running, so code in main reaches
add-ons through dispatch() rather than checking isActive()/hasHandler().
158 lines
7.1 KiB
Markdown
158 lines
7.1 KiB
Markdown
# 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 `<select>` popup theme
|
||
|
||
Chromium's native `<select>` 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`.
|
||
|
||
## A preload belongs to the WebContents, not the page
|
||
|
||
A view's preload runs for every document that view ever loads. Navigating
|
||
a Settings tab to a website used to hand that site `window.cfg`, which
|
||
covers the vault (`pwGet`), settings and extension installs. Two rules
|
||
follow:
|
||
|
||
- Settings and add-on-file tabs never load anything else. `navigateTab`
|
||
and `will-navigate` open the target in a fresh tab instead.
|
||
- A new IPC channel exposed through `settings-preload.js` **must** be added
|
||
to `SETTINGS_ONLY` (or `SETTINGS_SHARED` if the toolbar's `preload.js`
|
||
calls it too) in [main.js](main.js). The wrapper around `ipcMain.handle`
|
||
only checks the sender for the channels in those sets. Any other channel
|
||
is callable by whatever page ends up in the view.
|
||
|
||
The same applies to `home-preload.js`, which is in *every* tab. Handlers
|
||
behind it check `isHomePageSender` / `isErrorPageSender`, which compare
|
||
the sender against the exact shipped file:// URL.
|
||
|
||
## An enabled add-on is not necessarily running
|
||
|
||
An add-on whose `addon.json` says `"activation": "on-demand"` is listed at
|
||
launch but not started. Its declared `panels`, `toolbar-menu`,
|
||
`context-menu-items` and `page-inject` bridge are live anyway, and
|
||
`AddonHost.dispatch()` starts it on the first call (see `ensureActive` in
|
||
[addons-host.js](addons-host.js)). So in main:
|
||
|
||
- Reach an add-on through `addonHost.dispatch(...)`, never by checking
|
||
`isActive()` / `hasHandler()` first. Both are false for a waiting
|
||
add-on, and the call would never wake it (`routeWizUri` shows the
|
||
pattern for when you really need to check).
|
||
- "Enabled" in the snapshot means running or waiting; `running` tells
|
||
them apart.
|
||
- Settings › Performance › "Start extensions when first used" off makes
|
||
every add-on start at launch again, which is the quickest way to rule
|
||
this out when an add-on "does nothing".
|
||
|
||
## 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.
|