The client module provides the browser-side WebSocket client for api-ape. It enables seamless communication with api-ape servers through a proxy-based API that converts method calls like api.users.list() into WebSocket messages.
Key capabilities:
- Proxy-based API — Call server endpoints like local methods (
api.path.method(data)) - Auto-reconnection — Automatically reconnects with exponential backoff on disconnection
- Call buffering — Queues calls made before connection is established
- JSS encoding — Supports Date, RegExp, Error, Set, Map, and undefined over the wire
- HTTP fallback — Falls back to long-polling when WebSocket is blocked
- Binary transfers — Transparent file upload/download handling
- Connection state — Track connection status (offline, connecting, connected, disconnected)
- Pub/sub subscriptions — Subscribe to channels and receive targeted updates
The client works in both browser environments (via <script> tag) and bundled applications (React, Vue, etc.).
Contributing? See
files.mdfor directory structure and file descriptions.
<script src="/api/ape.js"></script>
<script>
// Call server functions (RPC)
api.hello('World').then(result => console.log(result))
// Subscribe to channels (pass a callback function)
const unsub = api.message(data => console.log(data))
// Unsubscribe when done
unsub()
</script>npm i api-apeimport api from 'api-ape'
// Just use it! Calls are buffered until connected.
api.users.list().then(users => console.log(users))
// Subscribe to channels (pass a callback function)
const unsub = api.news.banking(data => {
console.log('Received:', data)
})
// Unsubscribe when done
unsub()
// Track connection state
api.onConnectionChange((state) => {
console.log('Connection:', state)
// 'offline' | 'walled' | 'disconnected' | 'connecting' | 'connected'
})Connection States:
offline— Browser reports no networkwalled— Captive portal detected (WiFi without real internet)disconnected— Had connection, lost itconnecting— Actively connectingconnected— Ready to useclosing— Connection is closing
No async setup needed! The client auto-initializes and buffers calls until connected.
- Proxy-based API —
ape.path.method(data)converts to WebSocket calls - Auto-reconnect — Reconnects on disconnect with queued messages
- Promise-based — All calls return promises with matched responses via queryId
- JSS encoding — Supports Date, RegExp, Error, Set, Map, undefined over the wire
- Request timeout — Configurable timeout (default: 10s)
Binary data is automatically handled. The client fetches binary resources and uploads binary data transparently.
// Server returns Buffer, client receives ArrayBuffer
const result = await api.files.download('image.png')
console.log(result.data) // ArrayBuffer
// Display as image
const blob = new Blob([result.data])
img.src = URL.createObjectURL(blob)const file = input.files[0]
const arrayBuffer = await file.arrayBuffer()
// Binary data is uploaded automatically
await api.files.upload({
name: file.name,
data: arrayBuffer // Sent via HTTP PUT
})Binary transfers use /api/ape/data/:hash endpoints with session verification.
Subscribe to channels using the same chaining syntax as RPC calls. The key difference: pass a callback function to subscribe, pass data to make an RPC call.
// RPC call - passing data
await api.news.banking({ category: 'stocks' }) // Returns Promise<response>
// Subscribe - passing a callback function
const unsub = api.news.banking(data => {
console.log('Received:', data)
})
// Unsubscribe when done
unsub()// Subscribe to nested channels
const unsub1 = api.stock.AAPL(data => {
console.log('AAPL:', data.price)
})
const unsub2 = api.health(data => {
console.log('Health update:', data)
})
// Clean up
unsub1()
unsub2()Behavior:
- On subscribe, you receive the last published message immediately (if any)
- Subscriptions are automatically restored on reconnect
- Subscriptions are automatically cleaned up on disconnect
api-ape includes built-in Cross-Site Request Forgery (CSRF) protection:
- Origin Validation — WebSocket connections validate Origin header against Host
- Automatic Rejection — Mismatched origins are rejected immediately
- Session Verification — Binary transfers verify session cookies
No configuration needed — protection is enabled by default.
