Compare commits
No commits in common. "712c0369d12ee9b46386c31cd7aab8c0a75fa1fe" and "9d04ab1ae5f86845dc44356774e03b7cf4789dad" have entirely different histories.
712c0369d1
...
9d04ab1ae5
73
README.md
73
README.md
|
|
@ -1,73 +1,4 @@
|
||||||
# sneaker
|
# 👟 sneaker
|
||||||
|
|
||||||
Sneakers sneaks your home server onto the internet by tunneling traffic between a public URL and your private server using WebSockets.
|
don't ask
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user