This is the API service that acts as the central hub for FOSSBilling instances. It serves version checks, system-wide alerts, the extensions catalogue, preview builds, and release stats.
Everything is built on Hono, making it lightweight and fast. While we currently deploy this to Cloudflare Workers, the code is designed to be platform-agnostic.
The worker exposes five services:
-
Versions (
/versions/v1) The source of truth for FOSSBilling updates. It fetches release data from GitHub, caches it for performance, and helps instances decide if they need to update. -
Central Alerts (
/central-alerts/v1) Allows the project to push critical notifications to all FOSSBilling installations—useful for security hotfixes or major announcements. -
Extensions (
/extensions/v1,/extensions/v2) Owns the complete Extensions domain and itsDB_EXTENSIONSschema.v2is authoritative;v1is legacy read-only. The separate Extensions site keeps OIDC/session state but accesses this domain through the generated HTTPS API client; it must not bind or migrateDB_EXTENSIONS. Seesrc/services/extensions/v2/README.md. -
Previews (
/previews/v1) Resolves FOSSBilling preview builds — the current main preview and per-PR/per-commit builds produced by FOSSBilling/FOSSBilling's GitHub Actions workflows. Read-only; GitHub Actions and R2 are the sources of truth, not this service. Seesrc/services/previews/v1/README.md. -
Stats (
/stats/v1) Aggregates release data through the versions service's shared releases cache into charts and JSON; a cold cache can trigger a GitHub fetch through that shared path. Seesrc/services/stats/v1/README.md.
We've structured the app to separate the core logic from the specific runtime environment (Cloudflare, Node, etc.).
- Application Logic: Found in
src/services/versions/v1,src/services/central-alerts/v1, etc. These feature modules don't know they are running on Cloudflare. Smaller services are a flatindex.ts+interfaces.ts;src/services/extensions/v2is the reference layout for larger ones, splitting intoroutes/,db/,schemas/, andgithub/. SeeAGENTS.mdfor what belongs in each. - Platform Layer: Located in
src/lib. This defines interfaces for things like Cache, Database, and Environment variables. - Adapters:
src/lib/adapters/cloudflare: Real implementations using KV and D1.src/lib/adapters/node: Reference implementations (useful for testing or alternative deployments).
Cron and Durable Object code lives with its owning service and is wired in src/app/index.ts.
Each service documents its own endpoints and behaviour:
| Service | Base path | Docs |
|---|---|---|
| Versions | /versions/v1 |
src/services/versions/v1/README.md |
| Central Alerts | /central-alerts/v1 |
src/services/central-alerts/v1/README.md |
| Stats | /stats/v1 |
src/services/stats/v1/README.md |
| Extensions | /extensions/v1, /extensions/v2 |
src/services/extensions/v2/README.md |
| Previews | /previews/v1 |
src/services/previews/v1/README.md |
Extensions v2 and Previews v1 also publish a live OpenAPI document (/extensions/v2/docs/openapi.json, /previews/v1/docs/openapi.json) and a reference UI (/extensions/v2/docs, /previews/v1/docs).
If you're running this yourself, you'll need a few things set up.
We use Cloudflare D1 and KV.
- D1 Database (
DB_CENTRAL_ALERTS): Stores the alert messages. - D1 Database (
DB_EXTENSIONS): Stores the complete Extensions domain. Migrations are owned by extensions v2 and applied only from this repository — see its README for the migration and adoption procedure. - KV Namespace (
CACHE_KV): Caches GitHub API responses so we don't hit rate limits. - KV Namespace (
AUTH_KV): Stores theUPDATE_TOKENvalue for/versions/v1/update. - R2 Bucket (
DOWNLOAD_BUCKET): Shared by versions, previews, and stats for release/preview zips — seesrc/services/previews/v1/README.mdand the comment inwrangler.jsoncfor which bucket this points at and why. - Durable Object (
PREVIEW_GITHUB_BUDGET): Token bucket limiting previews GitHub calls. Policy lives insrc/services/previews/v1/budget.ts. - Rate limiters (
EXTENSION_WRITE_RATE_LIMITER,PROFILE_CREATION_RATE_LIMITER): Edge pacing for extension writes and profile creation. Durable quotas are enforced in D1; see extensions v2 README. - Service binding (
EXTENSIONS_FRONTEND): Private binding to the Extensions site worker, used to purge cached catalogue pages after mutations. - Cron (
0 * * * *): Hourly extension resource maintenance. See extensions v2 README.
GITHUB_TOKEN: A GitHub Personal Access Token (classic) with public repo read access.ASSERTION_SIGNING_SECRET: Shared HMAC secret used to verify the short-lived bearer assertions minted by the Extensions site. Configure the same value in both Workers; it is never sent to clients.ASSERTION_SIGNING_SECRET_PREVIOUS: Optional previous HMAC secret accepted during a signing-key rotation.EXTENSIONS_REVALIDATE_SECRET: Bearer token the API sends to the Extensions site'sPOST /api/revalidate(over theEXTENSIONS_FRONTENDservice binding) to purge the site's CDN-cached catalogue pages after content mutations. Configure the same value in both Workers; it is never sent to clients.EXTENSIONS_V2_EMAIL_PROVIDER:mxrouteorresendto send moderator notification emails, or unset/disabledto skip sending.EXTENSIONS_V2_EMAIL_FROM: Sender address for notification emails (defaultnoreply@fossbilling.org).EXTENSIONS_V2_EMAIL_REPLY_TO: Optional Reply-To address for a monitored inbox. Omit when unset (no Reply-To header is sent) — notification emails do not invite replies.EXTENSIONS_V2_MXROUTE_SERVER,EXTENSIONS_V2_MXROUTE_USERNAME,EXTENSIONS_V2_MXROUTE_PASSWORD: Mailbox credentials for the MXroute SMTP API (https://smtpapi.mxroute.com/). Required whenEXTENSIONS_V2_EMAIL_PROVIDER=mxroute.EXTENSIONS_V2_RESEND_API_KEY: API key for Resend. Required whenEXTENSIONS_V2_EMAIL_PROVIDER=resend.EXTENSIONS_RETENTION_MODE:dry-run(report only) orcompact(prune old revision bodies). See extensions v2 README.
Only extensions v2 consumes these. For the assertion format and the rotation procedure, see its README.
Get the dependencies installed:
npm install-
Create a
.dev.varsfile for your secrets:GITHUB_TOKEN="your-token" ASSERTION_SIGNING_SECRET="local-shared-secret" EXTENSIONS_REVALIDATE_SECRET="local-revalidate-secret" # Optional while rotating the shared assertion secret. # ASSERTION_SIGNING_SECRET_PREVIOUS="previous-local-shared-secret"
-
Apply migrations to the local D1 databases:
npm run db:migrate:all:local
-
(Optional) Store an update token in KV for
/versions/v1/update:npx wrangler kv:key put --binding AUTH_KV UPDATE_TOKEN "dev-secret" --local -
Spin up the dev server:
npm run dev
You can now hit endpoints at http://localhost:8787.
We use Vitest. Unit tests run under the Workers pool; Node adapter tests use a separate config.
npm run test # workers pool
npm run test:all # workers + node adaptersnpm run typecheck
npm run lintnpm run cf-deployThis applies remote D1 migrations, then deploys with Wrangler.