# Tronbyt Toes App — Implementation Plan ## What This Is A toes app that wraps the Tronbyt Go server (self-hosted Tidbyt replacement) as a managed subprocess. Bun proxies all HTTP and WebSocket traffic to the Go binary over a unix socket. The Tidbyt device talks to `tronbyt.toes.local` and everything chains through. ``` Tidbyt device → tronbyt.toes.local (toes proxy) → Bun app on PORT (this app) → Go binary on unix socket ``` ## File Structure ``` tronbyt/ package.json index.tsx # re-exports src/server src/ server/ index.tsx # Hype app: spawns Go binary, proxies all traffic pages/ index.tsx # Hype page (not needed, Go serves its own UI) bin/ .gitkeep tronbyt-server # pre-built binary (gitignored, per-platform) docs/ PLAN.md # this file ``` ## Implementation Steps ### 1. Binary setup - Download the right binary from https://github.com/tronbyt/server/releases - Mac dev: `tronbyt-server-darwin-arm64` - Pi production: `tronbyt-server-linux-arm64` - Place in `bin/tronbyt-server`, make executable (`chmod +x`) - Add `bin/tronbyt-server` to `.gitignore` - On macOS: System Settings → Privacy & Security → Allow Anyway ### 2. Spawn the Go binary On server startup, spawn `bin/tronbyt-server` with these env vars: | Env Var | Value | Why | |---|---|---| | `TRONBYT_UNIX_SOCKET` | `{DATA_DIR}/tronbyt.sock` | Avoids port conflicts, clean proxying | | `DATA_DIR` | `{DATA_DIR}` | Persists DB, apps, firmware across deploys | | `DB_DSN` | `{DATA_DIR}/tronbyt.db` | Explicit DB path | | `PRODUCTION` | `false` | Skip firmware downloads (set `true` on Pi later) | | `SINGLE_USER_AUTO_LOGIN` | `true` | Home network, no login needed | | `SYSTEM_APPS_AUTO_REFRESH` | `true` | Keep community apps updated | Wait for health by polling the unix socket at `/health` until it returns 200. ### 3. HTTP proxy Proxy all requests from Bun → Go over the unix socket: ```ts app.all('*', async (c) => { const resp = await fetch(socketUrl + c.req.path + search, { method: c.req.method, headers: c.req.raw.headers, body: c.req.raw.body, unix: socketPath, }) return new Response(resp.body, resp) }) ``` Bun's `fetch` supports `unix` option natively — no extra libraries needed. ### 4. WebSocket proxy Two WS endpoints to proxy: - `GET /ws` — dashboard real-time updates - `GET /{deviceId}/ws` — device push connection Use `Bun.serve`'s websocket support to accept the upgrade on the Bun side, then open a WebSocket to the Go server over the unix socket and relay messages bidirectionally. ### 5. Health check ```ts app.get('/ok', async (c) => { const resp = await fetch('http://localhost/health', { unix: socketPath }) return resp.ok ? c.text('ok') : c.text('unhealthy', 503) }) ``` ### 6. Graceful shutdown ```ts process.on('SIGTERM', () => { goProcess.kill('SIGTERM') }) ``` The Go server handles SIGTERM cleanly. Toes gives 10s before SIGKILL. ### 7. Remove Hype pages The scaffolded `src/pages/index.tsx` isn't needed — the Go server serves its own web UI. The Bun app is purely a proxy, no HTML rendering. Can simplify to just `src/server/index.tsx` or even a single `index.ts`. ## Toes Environment Variables These are set automatically by toes on every app: | Var | Description | |---|---| | `PORT` | Port to listen on | | `DATA_DIR` | Per-app persistent data directory | | `APPS_DIR` | Shared apps directory | | `TOES_URL` | Base URL of toes server | | `APP_URL` | This app's subdomain URL | ## Device Configuration Flash the Tidbyt with Tronbyt firmware, then set: ``` Image URL: http://tronbyt.toes.local//next ``` The device ID is assigned by the Tronbyt server when you add the device in its web UI. ## Gotchas 1. **IPv6 binding** — Not an issue with unix socket approach (no TCP binding on Go side) 2. **First boot is slow** — Community apps repo clones on first start (~15s). With `PRODUCTION=false`, firmware download is skipped. Set `PRODUCTION=true` on Pi if you want OTA firmware updates. 3. **macOS unsigned binary** — System Settings → Privacy & Security → Allow Anyway 4. **Device WiFi** — Tidbyt ESP32 is 2.4GHz only 5. **Image URL must be full path** — `http://tronbyt.toes.local//next`, not just the base URL ## Dependencies No new dependencies needed beyond what's already in package.json. Bun's native `fetch` handles unix sockets. The Go binary is self-contained (Pixlet embedded). Can remove `@because/forge` and `@because/howl` from dependencies since this app has no UI of its own.