# FabledCurator Firefox Extension Self-hosted Firefox extension that pushes session cookies from supported platforms (Patreon, SubscribeStar, Hentai-Foundry, Discord, Pixiv) into FabledCurator, and lets you add a creator as a Source from their page in one click. ## Install (operator) The signed XPI is bundled into the FC Docker image — `:dev` and `:latest` each carry their own channel's build. Open FC → Settings → Maintenance → Browser extension → click "Install Firefox extension". Firefox shows its native install prompt. After installing, open the extension's options page (about:addons → FabledCurator → Preferences) and paste in the FC URL + extension API key shown on the same card. ## Develop ```sh cd extension/ npm install --no-save # web-ext only npm run lint # web-ext lint npm run test:unit # vitest — lib/ logic + packaging/version checks npm run start # launches Firefox with extension loaded npm run build # unsigned XPI in web-ext-artifacts/ ``` ## Smoke checklist (after every release that touches `extension/**`) - [ ] `npm run lint` passes - [ ] `npm run start` loads the extension in a clean Firefox profile - [ ] Options page accepts FC URL + key, indicator turns green - [ ] Cookie export: log into patreon.com, click Patreon card → "X cookies exported" - [ ] Discord token: open discord.com, click Discord card → "Token captured" - [ ] Pixiv OAuth: click Pixiv card → login redirects, token stored - [ ] Add as source: visit patreon.com/, click floating button → toast - [ ] Subscriptions list: popup → "Sources" tab → list renders - [ ] Check now: click play icon on source row → no error toast ## Versioning — don't hand-edit the patch number The shipped version is **derived**, not committed. `scripts/packaging.sh version` returns `MAJOR.MINOR` from `manifest.json` plus a patch component that is the commit *time* of the newest change to a packaged extension file, in minutes since 2020-01-01. `build.yml` computes it and stamps it into both `manifest.json` and `package.json` at build time. The stamp is never committed — the commit carrying it would itself be a change to the extension, which would move the version again. So: - **Editing the patch number does nothing.** It is overwritten before web-ext ever reads it. There is no bump to make, and none to forget. - **MAJOR.MINOR is still yours.** It carries the deliberate meaning, it is read from `manifest.json` alone, and CI fails the `extension-version` lane if the two files disagree on it. - `npm run build` locally produces an XPI labelled with the *committed* version, since nothing stamped it. Fine for loading into a test profile; not what ships. Why commit time and not a commit count: a count is per-branch, so `dev` and `main` count different histories of the same code and their versions end up ordered by which branch accumulated more commits rather than by which is newer. Commit time gives both branches the same number for the same source — which is exactly what lets one AMO signature serve both channels (family rule 149, FC issue #3092). ## Release Nothing to do by hand. Push to `dev`: `build.yml` signs the extension if this change moved the version, caches the signed XPI as a Forgejo `ext-` release, and bundles it into `fabledcurator:dev`. Merging to `main` derives the same version, hits that cache, and bundles the byte-identical XPI into `:latest` with no second AMO call. AMO refuses to re-sign a version it has already issued, so signing is one-shot per version — which is why the cache exists and why the version must never move backwards.