Gongyu is a single-tenant bookmark manager inspired by Shaarli. It runs on Cloudflare Workers with a server-rendered React Router application and an Effect-based TypeScript backend.
- Bookmark creation, editing, deletion, search, and public detail pages
- Passkey-only administrator authentication
- Metadata extraction and private R2-backed thumbnails
- Bookmarklet, Atom feed, and Shaarli-compatible redirects
- HTML, JSON, and Shaarli data portability
- Full backups and restore workflows
- Optional Mastodon and Bluesky delivery, plus API or manual X sharing
- Queue-backed background work with retries and job visibility
Browser
|
v
Gongyu Worker
|-- HTTP: React Router SSR, authentication, bookmarks, thumbnails
|-- D1: bookmarks, search, sessions, settings, job state
|-- R2: thumbnails, import sources, exports, backups
|-- Queues: metadata, thumbnails, social delivery
|-- Workflows: imports, exports, backups, restores
`-- Cron: stranded outbox recovery and cleanup
Bookmark mutations commit their Queue intent to the D1 outbox, then dispatch it immediately after the transaction. Metadata consumers stage and dispatch automated social deliveries only after metadata and thumbnail processing finishes, and acknowledge the metadata message after that handoff succeeds. X sharing can instead use a manual Web Intent that requires the user to review and publish the post. The cron trigger recovers abandoned outbox leases; it is not part of the normal processing latency.
The repository is a Bun workspace:
apps/web— React 19, React Router 8 SSR, and the Cloudflare Worker entrypointapps/jobs— reusable queue, scheduled, and Workflow implementationspackages/domain— Effect Schema domain models and contractspackages/data— D1 repositories and persistence adapterspackages/auth— passkey and session servicespackages/integrations— R2, metadata, encryption, Shaarli, and social adapterspackages/ui— shared UI compositionsmigrations— ordered Wrangler D1 migrations
Effect services keep business logic independent from React Router and Cloudflare bindings. Runtime-specific code stays at Worker and route boundaries.
- Bun 1.3.9
- A modern browser with WebAuthn support
- A Cloudflare account for remote deployment
bun install
bunx wrangler d1 migrations apply DB --local --config apps/web/wrangler.jsonc
bun run devOpen http://localhost:5173/setup and use the local bootstrap token configured in apps/web/wrangler.jsonc.
Wrangler stores local D1 and R2 state under .wrangler/. The development configuration uses local bindings and does not access production resources.
bun run format
bun run lint
bun run typecheck
bun run test
bun run build
bun run check
bun run --cwd apps/web test:e2eUse bun run test:unit for fast runtime-neutral tests, bun run test:workerd for binding-dependent tests, and bun run test:watch while iterating. bun run test runs both projects.
bun run check typechecks both apps, builds the production Worker, and performs a Wrangler dry-run deployment.
Gongyu is deployed as one Cloudflare Worker backed by D1, R2, Queues, and Workflows. Apply D1 migrations before deploying the Worker.
See docs/self-hosting.md for resource provisioning, secrets, deployment, and updates.
The checked-in configuration deploys the production environment:
bun run deploy:productionThis command applies production D1 migrations, then builds and deploys the Worker. Review the Wrangler resource names, IDs, hostnames, routes, and secrets before using it for your own installation.
/— public bookmark list/search— full-text search/b/:shortUrl— bookmark detail/shaare/:hash— permanent Shaarli redirect/feed— Atom feed/bookmarklet— quick-add bookmarklet/health— runtime and D1 health