Let the extension update itself, and host the dashboard

Chrome has no update channel for an unpacked extension, so every pull left one
manual step: click reload on its card. The dashboard now publishes the version
its own checkout ships at /api/autobuyer/status, and the extension reloads
itself when it is behind — chrome.runtime.reload() re-reads the folder from
disk, which the update check has already pulled into. It only ever runs code
that is on disk, so a reload that changes nothing is reported and waited out
rather than repeated; a dashboard that is behind is ignored.

Also adds the deploy stack for running the dashboard on the droplet, next to
the autotrader one: it joins that nginx's network and renders a server block
into its conf.d rather than standing up a second ingress. AUTOFIRMER_DB moves
the SQLite file onto a volume, since the working directory in a container is
replaced on every deploy.

And waitFor gained `hidden`: an absent gate matched on DOM presence only, so a
modal that closes by going display:none could never satisfy it. The extension
grew a visibility probe for this — locate cannot answer it, because absent and
hidden are both errors there and a wait gate has to tell them apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-08-31 12:30:59 -05:00
co-authored by Claude Opus 5
parent 1f4459985a
commit d1e8668440
18 changed files with 637 additions and 28 deletions
+6 -2
View File
@@ -1,7 +1,11 @@
import Database from 'better-sqlite3';
import path from 'path';
const db = new Database(path.join(process.cwd(), 'autotrader.sqlite'));
// Next to the checkout by default, which is what every desktop instance wants.
// `AUTOFIRMER_DB` moves it onto a mounted volume for the hosted dashboard, where
// the working directory is inside a container image and is replaced on every
// deploy — a database written there would be a fresh empty one each time.
const db = new Database(process.env.AUTOFIRMER_DB || path.join(process.cwd(), 'autotrader.sqlite'));
db.pragma('foreign_keys = ON');
@@ -627,7 +631,7 @@ export const RUNNER_TIMEOUT_MS = 7000;
/** The runner version this server's step vocabulary requires. A running process
* doesn't reload when the source changes, so an older one silently fails on
* steps it predates — the dashboard warns instead. */
export const RUNNER_EXPECTED_VERSION = '0.17.0';
export const RUNNER_EXPECTED_VERSION = '0.18.0';
export interface RunnerHeartbeat {
at: number;