This repo contains the first working RefHub browser extension prototype described in docs/spec.md. It keeps scope narrow, uses one shared source tree, and now emits browser-specific manifests so both Chrome and Firefox builds are loadable from the same codebase.
- reads the current tab URL on user action
- extracts a small metadata bundle from the page using canonical URL, citation meta tags, JSON-LD, Open Graph, and document metadata
- shows a popup preview with page type, DOI, source, and normalized item fields
- lets the user configure a RefHub API key
- lists writable vaults from RefHub and saves a single item with
POST /api/v1/vaults/:vaultId/items - opens the matching RefHub route after save:
/public/:slugfor public vaults,/vault/:idfor private or shared vaults - reports clear setup, extraction, auth, and save errors
npm run buildRelease builds now default to production RefHub endpoints and keep them locked in the options UI. For local or self-hosted work, use the dev build path.
Optional dev build-time overrides:
REFHUB_ALLOW_CUSTOM_URLS=1 \
REFHUB_API_BASE_URL=https://refhub-api.netlify.app \
REFHUB_APP_BASE_URL=https://refhub.io \
npm run buildShortcut:
npm run build:devBuild output:
dist/chromedist/firefox
Manifest strategy:
- Chrome build keeps MV3
background.service_worker - Firefox build swaps to MV3
background.scriptsso it loads as a temporary add-on in Firefox without forking the runtime code
Branding:
- extension icons are derived from the existing RefHub favicon asset, reused as the cleanest available project-owned identity mark for now
Once review completes, install from your browser store:
- Chrome / Chromium: Chrome Web Store (pending approval)
- Firefox: Mozilla Add-ons / AMO (pending approval)
Until store listings are approved, you can load the extension locally for testing.
Important: Do not try to load the release zip directly in Firefox via "Extensions → Load From File". Firefox will reject unsigned packages as unverified. Use the temporary add-on method below instead.
See also: docs/RELEASE_NOTES.md for detailed user-facing install instructions.
- Download the latest release or run
npm run build. - Extract the zip so you have a folder on disk.
- Open
chrome://extensions. - Enable Developer Mode (toggle in the top-right).
- Click Load unpacked.
- Select the extracted
dist/chromefolder.
- Download the latest release or run
npm run build. - Extract the zip so you have a folder on disk.
- Open
about:debugging#/runtime/this-firefox. - Click Load Temporary Add-on....
- Select
dist/firefox/manifest.jsonfrom the extracted folder.
Note: Firefox temporary add-ons are removed on browser restart. This is for preview/testing only, not the long-term user install path.
- Sign in to RefHub web app.
- Open
https://refhub.io/profile-edit. - Switch to the
api_keystab. - Create a key with
vaults:readandvaults:write. - Optionally restrict the key to selected vaults for least-privilege access.
- Open the extension options page.
- Paste the API key.
- Open a supported page and click the extension action.
- Confirm the preview, choose a writable vault, and click
save_to_refhub.
For local or self-hosted testing, build with REFHUB_ALLOW_CUSTOM_URLS=1 and then set:
RefHub API base URLto the backend origin only. Do not append/api/v1.RefHub app URLto the frontend origin used for post-save links.
Important setup details:
- Release builds already bundle the production RefHub API and app URLs.
- Current frontend key-creation path is
/profile-edit→api_keys. - The extension only surfaces writable vaults (
owneroreditoraccess).
Required API-key scopes:
vaults:readto list accessible vaultsvaults:writeto create items in the selected vault
Not required for this extension:
vaults:export
Extension permissions and why they exist:
activeTabso capture only runs after explicit user action on the current tabscriptingso the extension can extract metadata from the active tabstorageso API key and last-used vault are stored locally- production host permissions are narrowed to the bundled RefHub API origin
- dev builds keep broader host access so local override targets still work
Expected v1-supported pages:
- DOI landing pages
- pages with
citation_*metadata - pages with article-like JSON-LD
- generic webpages with usable title and URL fallback
Expected v1 exclusions:
- direct PDF tabs
- multi-item search/index pages
- background crawling or persistent site access
- full auth/token exchange inside the extension
src/js/background.js: background runtime, extraction orchestration, RefHub API calls, vault caching, open-in-app route selectionsrc/js/popup.js: capture preview, vault picker, save flowsrc/js/options.js: API key configuration plus dev-only endpoint overridesscripts/build.mjs: emits browser-specific manifests from one shared source tree
The prototype uses activeTab + scripting.executeScript so capture only happens after explicit user action. It does not keep persistent access to arbitrary sites.
Zotero’s connector architecture is a useful concept reference here: keep the extraction and product logic shared, and isolate browser runtime differences in a thin adapter/build layer instead of forking the whole runtime code. We can follow that same general approach without borrowing code.
Practical same-codebase strategy for RefHub:
- share popup UI, extraction heuristics, normalization, storage schema, and RefHub API client logic
- generate per-browser manifests and keep a small runtime compatibility layer for
chromevsbrowserAPIs - expect browser-specific handling around auth handoff, service worker lifecycle differences, and any APIs that are still uneven in Firefox MV3
- keep capture initiated by user action with
activeTabsemantics in both browsers
Conclusion: same-codebase multi-browser builds are realistic for this extension. Chrome-first is sensible for v1, and Firefox support should be an incremental adapter-and-testing exercise rather than a separate implementation.