A high-performance **HTTP relay**, **WebSocket relay**, and **multi-provider AI proxy** built entirely with Bun's standard library. Zero framework dependencies — no Next.js, no Express, no React, no Vercel Edge Runtime.
Any `OPTIONS` request to any path returns `204 No Content` with permissive CORS headers (`Access-Control-Allow-Origin: *`). Set `CORS_ORIGIN` to restrict.
---
## AI Proxy — Available Models
The proxy routes requests to multiple backends based on the `model` field. All backends are OpenAI-compatible except where noted.
Both `/v1/chat/completions` and `/v1/messages` accept any of these model names. The Anthropic handler translates the request into the backend's OpenAI format, then translates the response back to Anthropic format (tool_use blocks, content_block_delta events, usage metadata, etc.).
### Streaming (SSE)
Both endpoints support `stream: true`. Streaming responses are passed through to the client without buffering (default), preserving the upstream's event timing. Set `STREAM_PASSTHROUGH=false` to fall back to per-chunk transformation.
### DeepSeek Tool Calls (DSML)
DeepSeek models return tool calls embedded as markup (`<tool_calls><invoke name="...">...`). The proxy detects this markup and converts it into standard `tool_calls` (OpenAI format) or `tool_use` content blocks (Anthropic format). DSML detection is **enabled by default** for `deepseek,*` and `codestral,*` models only — for all other models the per-chunk scanning is skipped.
### Response Cache
Non-streaming responses are cached for 5 minutes (default) to reduce upstream bandwidth and latency on repeated identical requests. Cache keys are hash-derived from `(model, sorted messages, stream flag)`. Cache is process-local (in-memory Map with LRU eviction).
The relay handles text frames, binary frames (`Buffer`, `Uint8Array`, `ArrayBuffer`, `Blob`), and forwards close events with status codes. Client backpressure is monitored via `drain()` — when buffered bytes exceed 512 KB, upstream forwarding is paused until the consumer drains back below 64 KB.
---
## Environment Variables
### Server
| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3000` | Server listen port |
| `HOST` | `0.0.0.0` | Bind address |
| `NODE_ENV` / `BUN_ENV` | — | Set to `development` to enable HMR + verbose console |
### Request Limits
| Variable | Default | Description |
|----------|---------|-------------|
| `BODY_MAX_BYTES` | `1048576` | Max request body size in bytes (1 MB) |
| `RATE_LIMIT_MAX` | `100` | Max requests per sliding window per client IP |
| `RATE_LIMIT_WINDOW_MS` | `60000` | Sliding window duration in ms (1 minute) |
### Relay Behavior
| Variable | Default | Description |
|----------|---------|-------------|
| `MAX_RETRIES` | `1` | Max retry attempts (direct first, then proxy fallback if pool loaded) |
| `PROXY_FILE` / `PROXY_LIST` | `./proxy.txt` | Proxy pool source — file path or comma-separated `host:port:user:pass` list |
| `SSRF_DNS_CHECK` | `false` | When `true`, resolve target DNS at relay time to block rebinding attacks (adds latency) |
| `CORS_ORIGIN` | `*` | Restrict CORS to this origin |
### AI Proxy
| Variable | Default | Description |
|----------|---------|-------------|
| `API_KEY` | _(empty)_ | If set, all requests must include matching `Authorization: Bearer <key>` or `x-api-key: <key>` header |
| `CACHE_TTL` | `300000` | Response cache TTL in ms (set `0` to disable cache) |
| `CACHE_MAX_SIZE` | `500` | Max entries in the LRU cache before eviction |
| `CACHE_MODELS` | _(all)_ | Comma-separated model prefixes to cache (e.g. `deepseek,minimax,kimi`) |
| `DSML_DETECTION` | `true` | Global toggle for DeepSeek markup detection on streaming chunks |
| `DSML_MODELS` | `deepseek,codestral` | Comma-separated model prefixes that emit DSML markup |
When `SSRF_DNS_CHECK=true`, the proxy resolves the target hostname at relay time and verifies the resolved IP is not in a blocked range (prevents DNS rebinding attacks — adds latency proportional to upstream DNS).
When `API_KEY` is set, every request must include a matching `Authorization: Bearer <key>` or `x-api-key: <key>` header. Missing or mismatched keys return `401 UNAUTHORIZED`.
In-memory sliding window rate limiter keyed by client IP (default: 100 requests per minute). The `Retry-After` header is set on 429 responses. A periodic cleanup routine prunes expired entries; when the keyspace exceeds 10k entries, the oldest is evicted.
Requests with a `Content-Length` exceeding `BODY_MAX_BYTES` (default 1 MB) are rejected with a 413 response. Requests without `Content-Length` (streaming) are passed through.
The server listens for `SIGTERM` and `SIGINT`. On shutdown it cancels all tracked active stream readers (awaiting upstream cancellation), then calls `server.stop()` and exits cleanly.
---
## Performance Notes
The codebase includes two rounds of performance optimization on top of the architectural baseline: