JavaScript SDK
@emitwave/js — the browser client for connecting, subscribing to channels, and receiving realtime events.
Install
npm install @emitwave/js
Requires a modern browser with fetch, WebSocket, and Web Crypto. You need a public application key and an end-user Bearer token — never put a server secret in browser code.
Connect & subscribe
connect() starts the socket handshake and is required for every connection, including public-only ones. The authHeaders callback runs before each token request, so a refreshed token is used without recreating the client.
import { Emitwave } from '@emitwave/js' const emitwave = new Emitwave('ew_pk_live_your_public_key', { authHeaders: async () => ({ Authorization: `Bearer ${await getEndUserToken()}`, }), }) await emitwave.connect() const channel = await emitwave.subscribe('news') channel.bind('article.created', (article) => console.log(article)) channel.bindAll((event, data) => console.log(event, data))
Defaults target production — the EmitWave WebSocket and the connect-token / channel-auth endpoints. Override wsUrl, connectEndpoint, and authEndpoint only when targeting another environment.
Connection state
emitwave.onState((state) => { // 'connecting' | 'connected' | 'disconnected' | 'error' console.log('connection:', state) })
Channel types
The same subscribe() call handles every external channel name; the prefix determines authorization. See Channels for the full table.
| Example | Channel auth |
|---|---|
| news | No |
| private-account.42 | Yes — truthy callback |
| presence-room.lobby | Yes — returns { id, info } |
| private-encrypted-account.42 | Yes — plus per-channel key |
Presence
The members property is only available on presence channels.
const room = await emitwave.subscribe('presence-room.lobby') room.members.each((m) => console.log(m.id, m.info)) console.log(room.members.count, room.members.me) room.member_added((m) => console.log('joined', m)) room.member_removed((m) => console.log('left', m))
Cache & encryption
cache_miss and decryption_error are reserved SDK events and are not passed to bindAll().
channel.bind('cache_miss', () => { // Fetch initial state from your HTTP API }) channel.bind('decryption_error', () => { // Encrypted payload could not be decrypted })
Cleanup
channel.unbind('article.created', handler) emitwave.unsubscribe('news') emitwave.disconnect()