Skip to content

feat(miner-extension): live-fetch ranked candidates from the local miner UI - #5622

Merged
JSONbored merged 1 commit into
mainfrom
miner-extension-live-fetch
Jul 13, 2026
Merged

feat(miner-extension): live-fetch ranked candidates from the local miner UI#5622
JSONbored merged 1 commit into
mainfrom
miner-extension-live-fetch

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • Adds syncRankedCandidatesFromMinerUi() to background.js: fetches GET {minerUiUrl}/api/ranked-candidates (built in feat(miner): persist ranked-candidates snapshots and serve them locally #5619) and writes the result into the same chrome.storage.local keys (rankedCandidates/rankedCandidatesSavedAt) the manual-paste flow in options.js already writes — so content.js/opportunity-badge.js/toolbar-badge.js need zero changes; they already read from that one shared source regardless of which flow populated it.
  • Triggers: once on service-worker startup/install, then every 10 minutes via chrome.alarms (the MV3-correct primitive — a plain setInterval wouldn't survive the worker being killed and woken between calls), plus a manual "Sync now" button on the options page for an immediate pull.
  • Adds a "Local miner UI URL" field to the options page (default http://localhost:5174, persisted to chrome.storage.sync alongside the existing watchedRepos).
  • A failed sync (miner UI not running, network error, missing auth cookie because the dashboard was never opened in this browser, malformed response) never throws and never touches storage — it leaves whatever's already there untouched, which is exactly Replace the manual copy/paste workflow with a live fetch #4859's "keep paste as a fallback" requirement with no merge logic needed: a stale prior fetch or a manual paste just keeps working.
  • Manifest gains the "alarms" permission (host permissions for localhost were already granted by Resolve the extension's localhost-reachability gap #4860/feat(miner-extension): grant loopback host permissions for local miner-ui access (#4860) #5578).

Closes #4859 — this was sequenced after #5619 (the persisted store + read API prerequisite, merged) specifically so the auth cookie and data source both already existed before this consumer went in.

A note on same-site cookies + extensions

vite-auth.ts's cookie (#4858) is HttpOnly; SameSite=Strict. Verified via research before writing any code that this doesn't block the extension: Chrome (79+) treats an extension-initiated request as same-site when the extension has host_permissions for the target host — which #4860/#5578 already granted for localhost/127.0.0.1. So background.js's plain fetch() call correctly carries the cookie automatically, with no chrome.cookies API or custom-header workaround needed, as long as the user has opened the miner-ui dashboard in their browser at least once (so the cookie exists in the jar in the first place) — a reasonable expectation for someone running the local miner-ui. Confirmed live end-to-end below.

Test plan

  • npm run miner-extension:lint, npm run miner-extension:typecheck, npm run miner-extension:build
  • npm run typecheck, npm run docs:drift-check
  • New test/unit/miner-extension-live-fetch.test.ts (15 cases, using the same node:vm sandbox harness miner-extension-content.test.ts established): the sync function's success/failure/malformed-payload/thrown-fetch paths, the runtime-message handler, the alarm/startup/install wiring (including that the alarm listener only reacts to its own alarm name), and the options-page URL field + Sync-now button (save, normalize-empty-to-default, populate-on-load, success/fallback status messages)
  • Fixed 3 pre-existing tests in test/unit/miner-extension-content.test.ts that broke because options.js now requires two new DOM elements (#minerUiUrl/#syncNow) to consider the form "mounted" — updated their fixtures to match the real options.html shape, plus one assertion that now needs to account for minerUiUrl in the saved payload
  • Manually started a real miner-ui dev server, seeded the ranked-candidates store, and ran the exact fetch/parse code path syncRankedCandidatesFromMinerUi uses (same-origin cookie, same JSON parsing) against it — confirmed { ok: true, count: 1 }

Along the way: caught and fixed a real bug in my own first draft — the catch block's non-Error fallback was a hardcoded generic string instead of String(error) (inconsistent with every other catch block in this file and this session), silently discarding real error detail on a non-Error throw. Caught via a node:vm cross-realm instanceof Error test failure, traced to the actual root cause rather than just adjusting the test to match.

This PR touches apps/gittensory-miner-extension/** only (no src/**/lib/**), so Codecov's patch gate has nothing to measure here — same precedent as every other apps/** PR this session.

…ner UI

Adds syncRankedCandidatesFromMinerUi() to background.js, pulling from
#5619's GET /api/ranked-candidates and writing into the same
chrome.storage.local keys the manual-paste flow already writes -- so
content.js/opportunity-badge.js/toolbar-badge.js need zero changes.
Triggers on startup/install and every 10 minutes via chrome.alarms,
plus a manual "Sync now" button. A failed sync leaves storage
untouched, naturally falling back to whatever's already there (a
stale fetch or a manual paste) with no merge logic needed.

Adds a "Local miner UI URL" field to the options page (default
http://localhost:5174, persisted to chrome.storage.sync alongside
watchedRepos).
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored JSONbored self-assigned this Jul 13, 2026
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.01%. Comparing base (6553b54) to head (7602c86).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5622   +/-   ##
=======================================
  Coverage   95.01%   95.01%           
=======================================
  Files         575      575           
  Lines       45738    45738           
  Branches    14661    14661           
=======================================
  Hits        43459    43459           
  Misses       1528     1528           
  Partials      751      751           
Flag Coverage Δ
shard-1 43.89% <ø> (-0.09%) ⬇️
shard-2 35.75% <ø> (+0.15%) ⬆️
shard-3 32.21% <ø> (-0.09%) ⬇️
shard-4 30.87% <ø> (-1.71%) ⬇️
shard-5 32.57% <ø> (+0.79%) ⬆️
shard-6 44.41% <ø> (+0.34%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 13, 2026
@JSONbored
JSONbored merged commit b51220e into main Jul 13, 2026
17 checks passed
@JSONbored
JSONbored deleted the miner-extension-live-fetch branch July 13, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace the manual copy/paste workflow with a live fetch

1 participant