@capixjs/transport-ws
v1.0.0
Published
Capix WebSocket transport
Maintainers
Readme
@capixjs/transport-ws
WebSocket transport for Capix. Exposes your capabilities over a persistent WebSocket connection and delivers server-push events to subscribed clients.
Install
npm install @capixjs/core @capixjs/transport-wsUsage
import { createServer } from '@capixjs/core';
import { wsTransport } from '@capixjs/transport-ws';
createServer({
context: buildContext,
capabilities: {
chat: { sendMessage, getHistory },
},
transports: [wsTransport({ port: 3001 })],
}).start();Message protocol
All messages are JSON. Clients send frames to the server:
{ "id": "msg-1", "capability": "chat.sendMessage", "input": { "text": "hello" } }With headers (for auth):
{
"id": "msg-1",
"capability": "chat.sendMessage",
"input": { "text": "hello" },
"headers": { "authorization": "Bearer token" }
}The id field is optional but recommended — it is echoed back so clients can match responses to requests.
Capability response (success):
{ "id": "msg-1", "ok": true, "status": 200, "data": { "messageId": "abc" } }Capability response (error):
{ "id": "msg-1", "ok": false, "status": 403, "error": "Forbidden", "message": "Forbidden" }Server-push events with createEventBus
createEventBus<TEvents>() creates a typed pub/sub hub. REST capabilities publish events; connected WS clients subscribe to receive them.
1. Define events
// src/events.ts
import { createEventBus } from '@capixjs/transport-ws';
type AppEvents = {
'order:paid': { orderId: string; amount: number };
'task:updated': { id: string; status: string };
};
export const eventBus = createEventBus<AppEvents>();2. Wire into wsTransport
// src/server.ts
import { wsTransport } from '@capixjs/transport-ws';
import { eventBus } from './events.js';
createServer({
context: buildContext,
capabilities,
transports: [
restTransport({ port: 3000 }),
wsTransport({ port: 3001, eventBus }),
],
}).start();3. Publish from any capability
import { eventBus } from '../events.js';
export const payOrder = cap(z.object({ id: z.string() }), async ({ id }, ctx) => {
const order = await ctx.db.orders.markPaid(id);
eventBus.publish('order:paid', { orderId: id, amount: order.total }); // typed
return order;
}, 'mutation').guard(mustBeUser);4. Subscribe from a WS client
{ "id": "2", "action": "subscribe", "event": "order:paid" }Server confirms:
{ "id": "2", "ok": true, "event": "order:paid", "subscribed": true }When the event fires, the server pushes (no id — server-initiated):
{ "event": "order:paid", "data": { "orderId": "abc", "amount": 99 } }Unsubscribe:
{ "id": "3", "action": "unsubscribe", "event": "order:paid" }Client subscriptions are automatically cleaned up on disconnect.
Per-transport capabilities
Pass capabilities directly to the transport to restrict which capabilities are available over WebSocket:
createServer({
context: buildContext,
transports: [
restTransport({ port: 3000, capabilities: publicCapabilities }),
wsTransport({ port: 3001, capabilities: realtimeCapabilities, eventBus }),
],
});Options
wsTransport({
port: 3001, // required
host: '0.0.0.0', // optional
eventBus: createEventBus(), // optional — enables server push
})Exports
| Export | Description |
|---|---|
| wsTransport(opts) | Creates a WebSocket transport |
| createEventBus<TEvents>() | Creates a typed event bus for server push |
| WsTransportOptions | Options type for wsTransport |
| EventBus<TEvents> | Event bus interface |
| EventMap | Base type for event maps |
License
MIT
