feat(extension): rewrite browser extension with WXT + SolidJS#327
Merged
SuperCoolPencil merged 61 commits intomainfrom Apr 11, 2026
Merged
feat(extension): rewrite browser extension with WXT + SolidJS#327SuperCoolPencil merged 61 commits intomainfrom
SuperCoolPencil merged 61 commits intomainfrom
Conversation
Member
Author
|
@greptile review |
4 tasks
Single codebase for Chrome and Firefox, replacing duplicated extension-chrome/ and extension-firefox/ directories. - WXT (wxt.dev) for cross-browser MV2/MV3 builds - SolidJS for reactive popup UI (replaces manual DOM manipulation) - TypeScript for full type safety across API contracts - SSE support via /events endpoint for real-time progress - Background service worker with typed message handling Co-Authored-By: Claude Opus 4.6 <[email protected]>
Build both Chrome and Firefox extensions from the single extension/ directory using WXT instead of zipping the old separate directories. Co-Authored-By: Claude Opus 4.6 <[email protected]>
The extension packaging script now requires npm to build with WXT. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add eslint.config.js, lint/check/test scripts to package.json, and a new GitHub workflow (.github/workflows/extension.yml) that runs lint and type-check on PRs/pushes touching extension/**. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Re-add _healthCheckTimer/_syncIntervalTimer declarations that were accidentally removed, and restore serverUrl import in SettingsModal. Also remove unused API_BASE constant. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Embed the ViewSwitch (active/history) directly inside the download list, making it part of the scrollable content area instead of the section header. Fix broken .toggle-row:hover and .toggle CSS rules. Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ing, comments - Fix getBaseUrl() reconnect deadlock by always probing cached URL instead of gating on stale isConnected flag - Fix integration test step 7 curl to properly expect 404 status code - Combine EXIT traps to prevent Surge server process leak - Reduce popup polling from 1s to 15s to avoid redundant requests alongside SSE - Replace section comments in store with meaningful why/context comments Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Prefix unused _removePendingDuplicate to silence ESLint warning - Add type assertions to all browser.runtime.sendMessage returns - Fix browser.downloads.onCreated and storage.onChanged type incompatibilities - Cast browser.runtime.getURL to allow empty path argument - Cast vite-plugin-solid plugins as any to resolve duplicate Vite types - Normalize HistoryEntry to DownloadStatus shape with computed progress/speed/eta - Add handleViewChange to eagerly fetch history on tab switch - Extract sortDownloads() to avoid double evaluation per render - Fix indentation of confirmDuplicate case in handleMessage Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Add npx wxt prepare to CI lint and type-check jobs since .wxt/ is gitignored and tsc cannot find the generated tsconfig without it - Wrap items in createMemo for reactive updates in DownloadList - Initialize pendingDuplicateCounter from persisted IDs after rehydration - Fix unreachable >1 week branch in formatETA Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ads immediately and implement exponential backoff for SSE stream retries
…ecks and URL discovery
…bug logging to popup initialization
…tension-side check
… conditional notification display
…essibility and layout
…e test timeout duration
…tion or class' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
…pty state IDs in DownloadList
…d introduce dedicated extension issue template
…sh on server reconnection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Single codebase for Chrome and Firefox, replacing duplicated
extension-chrome/ and extension-firefox/ directories.
Greptile Summary
This PR rewrites the browser extension from two separate duplicated codebases (
extension-chrome/,extension-firefox/) into a single WXT + SolidJS codebase with TypeScript, SSE support, and a typed message-passing architecture between background service worker and popup UI. The scope is large but the implementation is well-structured: many issues flagged in previous review rounds have been addressed (missing store imports, SSE startup race, health-check reconnection loop, history view rendering, auth error propagation).Confidence Score: 5/5
PR is safe to merge; all remaining findings are minor style/duplication concerns with no blocking correctness issues.
The substantial issues raised in earlier review rounds (SSE startup race, health-check reconnection loop, missing store imports, history view breakage, auth-error propagation, setAuthVerified always-true, HistoryEntry progress crash) are all resolved in the current code. The only new finding is a trivial action-button rendering duplication (P2). The CI pipeline is comprehensive with lint, type-check, unit tests, dual-browser builds, and a 10-step live integration test.
extension/entrypoints/popup/components/DownloadItem.tsx — minor duplicate action rendering at lines 174–186.
Important Files Changed
historyDownloadsfrom the store and maps entries viamapHistoryEntryToDownload(including a computedprogressfield) before passing them toDownloadItem; previous breakage is resolved.renderActionshelper is defined but the expanded non-completed view duplicates the same JSX inline rather than callingrenderActions(false); minor code duplication.setAuthVerifiedalways-true persistence bug from earlier rounds is fixed; token save now only writesVERIFIED: truewhenres?.okis truthy (line 72).reconcileActiveDownloadsdiffing, SSE event handlers, and clean separation of active/history/settings signals.formatETAcorrectly checks> 604800before> 86400, making both branches reachable; earlier ordering concern is resolved.Sequence Diagram
sequenceDiagram participant B as Browser Downloads API participant BG as Background (SW) participant Surge as Surge HTTP API participant SSE as /events SSE Stream participant Popup as Popup UI (SolidJS) B->>BG: onCreated (download intercepted) BG->>B: downloads.cancel + erase BG->>Surge: GET /health BG->>Surge: GET /list (duplicate check) alt Duplicate URL BG->>BG: queueDuplicateDownload() BG->>Popup: sendMessage(promptDuplicate) Popup->>BG: sendMessage(confirmDuplicate / skipDuplicate) end BG->>Surge: POST /download {url, filename, headers, path} note over BG,SSE: SSE stream lifecycle BG->>SSE: GET /events (persistent) SSE-->>BG: event: progress / started / complete / error BG->>Popup: sendMessage(sseEvent) Popup->>Popup: handleSseEvent() → signal update note over BG,Popup: Periodic sync fallback (60s) BG->>Surge: GET /list + GET /history BG->>Popup: sendMessage(syncUpdate)Comments Outside Diff (1)
.github/workflows/extension-integration.yml, line 232-238 (link)curl -sftreats HTTP 4xx as an error exit (code 22). Withset -euo pipefailat the top of the script, when/download?id=nonexistentcorrectly returns 404,curlexits non-zero and the entire script terminates beforeecho "PASS". The test always fails in CI against a correctly behaving backend.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (21): Last reviewed commit: "feat: implement background SSE retry log..." | Re-trigger Greptile