forkfeed-server
v1.0.0
Published
Lightweight edge-deployed content backend for the forkfeed protocol
Readme
forkfeed.server
Tiny, edge-deployed content server for the forkfeed protocol. Part of forkfeed.link. Runs on Cloudflare Workers + Hono. No database - content is typed TypeScript files bundled into the worker at build time. One runtime dependency, zero cold start.
Forking this repo? See DEPLOY.md for the complete fork-to-deploy guide.
Content Hierarchy
Fork → Feed → Card → Variant- Fork - a curated playlist of feeds (e.g. "Atomic Habits")
- Feed - a named collection of cards (e.g. "The Power of Tiny Changes")
- Card - a single piece of content with one or more visual variants
- Variant - one view of a card: full-screen image, video, or rich content blocks
How Content Works
forks/<id>/fork.ts + <feed>.ts --(npm run deploy)--> Cloudflare Worker
(typed, bundled at build) |
GET /forks/:id (+ /feeds/:fid/cards)
|
app-server --(publish)--> Mobile App- Static feeds (books, guides): a
StaticFeedfile with a fixedcardsarray. - Dynamic feeds (counting sheep): a
<feed>.dynamic.tsfile exporting aDynamicFeedwith agenerate(page, limit, seed)function - infinite, on-demand. - To make a fork visible in the app, POST its URL + id to the app-server's
/api/content/publish(forks start private).
Quick Start
npm install # install dependencies
cp wrangler.toml.example wrangler.toml # set READ_KEY in [vars] (defaults to "read")
npm run typecheck # the TS compiler validates all content under forks/
npm run deploy # deploy to Cloudflare WorkersEnvironment Variables
Set in wrangler.toml [vars] (or via wrangler secret put):
| Variable | Description | Default |
|---|---|---|
| READ_KEY | Bearer token for read routes | read |
| ALLOWED_ORIGINS | Comma-separated CORS origins | * |
For the image/content scripts (shell env): CDN_DOMAIN, S3_BUCKET (used by
scripts/upload-image.sh), and FORKFEED_TOKEN (for publishing to the app).
Common Commands
npm run deploy # deploy the worker (bundles forks/ in)
npm run typecheck # validate all content under forks/
npm run convert # regenerate forks/index.ts (and migrate any manifests/*.json)
npm run dev # local dev serverAfter adding or editing a fork, run npm run convert (regenerates the registry) then
npm run deploy. To register a fork in the app, see DEPLOY.md.
Creating Content
- Manual: write typed files under
forks/- see CONTENT.md for the format reference, all variant/block types, and a template. - From git commits: use the MCP server to generate card files automatically.
API Reference
See PROTOCOL.md - the 2 read endpoints, data model, and the dynamic-feed (generator) pattern.
Architecture
| Path | Purpose |
|---|---|
| src/index.ts | Thin Hono worker: 2 read endpoints + health + single-card lookup |
| src/types.ts | Fork / Feed / Card / CardVariant / ContentBlock types (the schema) |
| forks/index.ts | Generated registry importing every forks/<id>/fork.ts |
| forks/<id>/fork.ts | A fork: metadata + ordered feeds |
| forks/<id>/<feed>.ts | A StaticFeed (fixed cards) |
| forks/<id>/<feed>.dynamic.ts | A DynamicFeed (generator function) |
| scripts/manifest-to-fork.mjs | Convert legacy JSON manifests -> typed files |
Stack: Cloudflare Workers (runtime) + Hono (router). No database, no ORM, no runtime validation library - the TypeScript compiler validates content, and Wrangler bundles it. To change content, edit a file and redeploy.
Example Content
The forks/ directory ships with example forks (book summaries, a city guide, and the
counting-sheep dynamic feed). Their images reference the original author's CDN, so
replace the URLs with your own. The reference dynamic feed lives in
forks/counting-sheep/.
Dynamic Feeds (Generators)
A <feed>.dynamic.ts file exports a DynamicFeed whose generate(page, limit, seed)
returns a page of cards plus hasMore, enabling infinite content with nothing stored.
Generated card IDs should be deterministic (derive a UUID from page+index) so they are
stable across requests. See PROTOCOL.md and the counting-sheep example.
Scripts
| Command | Description |
|---|---|
| npm run deploy | Deploy the worker to Cloudflare |
| npm run typecheck | TypeScript type checking (validates content) |
| npm run convert | Regenerate forks/index.ts / migrate manifests |
| npm run dev | Local development server |
