* fix(api): gracefully handle aborted requests When a client closes a connection early (e.g. while `await request.text()` is parsing), it throws a `DOMException` with `name: "AbortError"`. Previously, this hit our catch block, was logged as an unhandled exception to the console via `console.error`, and returned a `500` status. This resulted in an alarming error message which looked like a server crash, but the server actually stayed up. This commit updates `errorResponse` in `src/api.ts` to intercept `AbortError` and handle it properly. If we detect an `AbortError`, we now log a simple `400 Bad Request` instead, without writing out the `DOMException` stack trace. * fix(api): gracefully handle aborted requests When a client closes a connection early (e.g. while `await request.text()` is parsing), it throws a `DOMException` with `name: "AbortError"`. Previously, this hit our catch block, was logged as an unhandled exception to the console via `console.error`, and returned a `500` status. This resulted in an alarming error message which looked like a server crash, but the server actually stayed up. This commit updates `errorResponse` in `src/api.ts` to intercept `AbortError` and handle it properly. If we detect an `AbortError`, we now log a simple `499 Client Closed Request` instead, without writing out the `DOMException` stack trace. --------- Co-authored-by: ruinivist <179396038+ruinivist@users.noreply.github.com>
excali-box
Private self-hosted Excalidraw with Bun, Caddy, and SQLite.
This is bare wrapper around the excalidraw packages that adds autosave and disk-persistence. No auth to keep things simple - you either run in a private network or put it behind Caddy auth or similar solutions.
GPT 5.5 generated
Pull from GHCR and run
Images are published to:
ghcr.io/ruinivist/excalidraw-box:<version>
docker pull ghcr.io/ruinivist/excalidraw-box:latest
docker run --rm -p 127.0.0.1:3000:80 -e PUBLIC_BASE_URL=http://localhost:3000 -v "$PWD/excali-box-data:/data" ghcr.io/ruinivist/excalidraw-box:latest
Run locally
bun install
bun run dev
Open http://localhost:3000.
Test
bun run test
bun run typecheck
Build the image
docker build -t excali .
docker run --rm -p 127.0.0.1:3000:80 -e PUBLIC_BASE_URL=http://localhost:3000 -v "$PWD/excali-box-data:/data" excali
This will make the data persistent in the excali-box-data folder in the current directory, with Caddy serving the browser build on localhost:3000. PUBLIC_BASE_URL is required so MCP tools can return drawing URLs with the public browser origin. You would want it to be the same url you use to access the app in the browser - in case you reverse proxy or use a tailscale alias etc.