Skip to content

Variable port#3

Open
mbaas2 wants to merge 6 commits into
TheBrainTech:mainfrom
mbaas2:variablePort
Open

Variable port#3
mbaas2 wants to merge 6 commits into
TheBrainTech:mainfrom
mbaas2:variablePort

Conversation

@mbaas2
Copy link
Copy Markdown

@mbaas2 mbaas2 commented May 1, 2026

Suddenly TheBrain's API was available on 8003 instead of 8001. With the help of Claude I tweaked the extension to better deal with unavailable port (currently it just hangs). Also it remembers the list of ports that once worked and on failure will go through that list to see if TB is reachable there, again.

Michael Baas added 6 commits May 1, 2026 11:53
The Firefox-targeted build (npm run build:firefox) emits to dist-firefox/
and the packaging step produces a top-level .xpi. Both are derived
artifacts and shouldn't live in version control.
TheBrain's desktop app picks a fresh listening port every session, so
the saved endpoint frequently points at a port that's still in TIME_WAIT
or has been claimed by an unrelated process. Without an explicit timeout,
fetch() sits on a half-open socket for tens of seconds and the popup
appears to hang on load.

Add an opt-in timeoutMs option (default 4s) backed by AbortSignal.timeout
and rethrow as NotRunningError, matching the existing connection-refused
path. Also expose getBaseUrl() so callers can record which origin
actually worked — needed by the upcoming port-discovery probe.
Browser extensions can't enumerate listening sockets the way a
PowerShell script can, so when the saved endpoint goes silent (typical
after TheBrain's desktop app restarts) the only signal available is
'does an HTTP request to localhost:<port>/api/app/state succeed'.

discoverEndpoint() fans out to every candidate in parallel with a 700ms
per-probe timeout, capped by AbortSignal.timeout, and returns the first
ok winner along with all settled results so callers can distinguish
'nothing answered' from 'port answered but key was rejected'.

buildCandidates() composes the candidate list deterministically: the
current endpoint first, then MRU history, then a small set of fallback
ports (8001, 52341, 8081). Order matters because we want a tie to go
to the user's last-known-good port, not whichever race we won by 2ms.

Tests cover candidate construction, the auth-vs-no-answer split, and
the empty-input edge case. fetch is injected for testability so we
don't need a real network.
The port-discovery probe needs a list of likely candidate ports to try.
Hard-coding them is brittle: TheBrain's desktop app appears to pick
ports from a small but session-dependent pool, and after a few
launches the user's distribution becomes specific to their machine.

Track an MRU list of ports that have actually answered (cap 8). The
popup will push to it on every successful connect and seed candidate
generation from it. Stored in chrome.storage.local alongside the rest
of the settings; existing users default to [].
When the popup opens and the saved endpoint doesn't answer, fan out a
parallel probe to the candidate set (last-used + recentPorts MRU + a
few defaults) and rotate onto the first port that actually responds.
The new origin is persisted to settings, and its port is pushed to the
recent-ports MRU so the next launch starts on a known-good candidate.

Two specific cases the failure path now distinguishes:

- Nothing answers → 'TheBrain isn't reachable on any known port' with
  a hint to copy the Local API URL from the desktop app's widget.

- A port answers but rejects the API key → InvalidKeyError, so the user
  knows it's a credential problem, not a port problem (otherwise we'd
  silently ignore the 401 and report 'not running').

After every successful probe (whether on the saved port or a rotated
one) we also push the active port to the MRU, so the history grows
even for users whose port rarely changes.
Port-discovery probe + per-request timeout. See preceding commits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant