Compare commits

...

2 Commits

Author SHA1 Message Date
712c0369d1 readme 2026-03-02 21:28:12 -08:00
519b745ad1 Add README with usage docs 2026-03-02 21:25:14 -08:00

View File

@ -1,4 +1,73 @@
# 👟 sneaker
# sneaker
don't ask
Sneakers sneaks your home server onto the internet by tunneling traffic between a public URL and your private server using WebSockets.
## Install
```sh
bun add @because/sneaker
```
## Server
Run the tunnel server:
```sh
bun run src/server.tsx
```
The server exposes:
- `GET /health` — returns the current git SHA
- `GET /tunnels` — lists active tunnel connections
- `GET /tunnel/:app` — redirects to the app's subdomain
- `GET /tunnel?app=NAME` — WebSocket endpoint for clients to establish a tunnel (optional `subdomain` query param to request a specific subdomain)
Incoming HTTP requests to `SUBDOMAIN.your-server.com` are forwarded through the WebSocket to the connected client and proxied to the local target.
The server adds an `x-sneaker` header with the server's hostname to all proxied requests.
## Client
```ts
import { connect } from "@because/sneaker"
const tunnel = connect({
server: "ws://your-server.com",
app: "my-app",
target: "http://localhost:3000",
subdomain: "my-app", // optional: request a specific subdomain
reconnect: true, // optional: auto-reconnect (default: true)
onOpen(subdomain) {
console.log(`Tunnel open: ${subdomain}.your-server.com`)
},
onClose() {
console.log("Tunnel closed")
},
onRequest(req) {
console.log(`${req.method} ${req.path}`)
},
onError(err) {
console.error(err)
},
})
// Later:
tunnel.close()
```
### Client options
| Option | Type | Description |
|---|---|---|
| `server` | `string` | WebSocket URL of the tunnel server |
| `app` | `string` | App name identifier |
| `target` | `string` | Local URL to proxy requests to |
| `subdomain` | `string?` | Request a specific subdomain |
| `reconnect` | `boolean?` | Auto-reconnect on disconnect (default: `true`) |
| `onOpen` | `(subdomain: string) => void` | Called when tunnel is established |
| `onClose` | `() => void` | Called when tunnel disconnects |
| `onRequest` | `(req) => void` | Called for each proxied request |
| `onError` | `(error: Error) => void` | Called on errors |
Binary responses (images, fonts, etc.) are automatically base64-encoded over the tunnel and decoded by the server.