Desktop Bridge
HTTP bridge from Celestia Desktop (GPUI) to the Hono backend — the desktop twin of api-client.ts
Desktop Bridge
celestia-bridge is how a GPUI app talks to apps/api. Same
architecture rule as the web stack: the UI never imports the database or Better
Auth server code — it only speaks HTTP.
┌─────────────────────┐ HTTP ┌────────────────────┐
│ celestia-ui (GPUI) │ ──────────────────▶ │ apps/api (Hono) │
│ + celestia-bridge │ CELESTIA_API_URL │ auth + data + DB │
└─────────────────────┘ └─────────┬──────────┘
│ Drizzle
┌─────────▼──────────┐
│ PostgreSQL │
└────────────────────┘The web app uses Hono RPC (hc<AppType>) in apps/web/lib/api-client.ts.
Desktop mirrors the wire shape in Rust DTOs — there is no shared codegen yet.
File overview
| Path | Purpose |
|---|---|
packages/desktop/crates/bridge/ | celestia-bridge crate |
…/bridge/src/client.rs | BridgeClient — health, auth, posts |
…/bridge/src/types.rs | Serde DTOs (Health, Post, …) |
…/bridge/src/run.rs | run() — blocking HTTP off the UI thread |
packages/desktop/crates/starter/src/app.rs | Live Backend page (Ping /api/health) |
Environment variables
| Variable | Default | Where |
|---|---|---|
CELESTIA_API_URL | http://127.0.0.1:4000 | Desktop process env |
PORT / API secrets | see Backend API | apps/api/.env only |
# Terminal A — backendpnpm --filter @workspace/api dev
# Terminal B — starter with the bridge demopnpm desktop:starter# or override the URL:CELESTIA_API_URL=http://127.0.0.1:4000 pnpm desktop:starterNative HTTP clients are not subject to browser CORS. No CORS_ORIGIN change is
required for desktop.
Client usage
use celestia_bridge::{BridgeClient, CreatePost, run};
let bridge = BridgeClient::from_env();
// Always leave the UI thread — run() spawns a worker + applies the result.run(cx, { let bridge = bridge.clone(); move || bridge.health()}, |this, result, cx| { this.health = Some(result); cx.notify();}).detach();Authenticated routes
Blog routes require a Better Auth session. Sign in once; the agent cookie jar
(and optional set_session_cookie) is shared across clones:
bridge.sign_in_email("[email protected]", "password")?;let posts = bridge.list_posts()?;bridge.create_post(&CreatePost { title: "From desktop".into(), content: String::new(), published: false,})?;GPUI pattern
- Keep a
BridgeClienton the view (or in aStoreHandle). - On user action, set a
LoadingUI state andcx.notify(). - Call
celestia_bridge::run(cx, work, apply). - In
apply, writeOk/Errinto entity state andcx.notify()again.
Never call bridge.health() (or any other blocking method) directly inside
Render or a click handler on the UI thread.
Try it in the starter
pnpm desktop:starter → sidebar Backend → Ping /api/health. With the
API running you should see a Success badge (status = "ok"). If the API is
down, the error card tells you how to start it.
Related
- Backend API — Hono app, proxy, env vars
- Desktop (GPUI) — crates, theming, bootstrap
- Desktop State —
StoreHandlefor caching bridge results - Blog —
/api/postscontract the bridge mirrors