wiil-web
v0.0.2
Published
Browser SDK for WIIL Platform - OTT chat and voice widget integration
Maintainers
Readme
wiil-web
Browser SDK for the WIIL Platform. Build custom chat and voice experiences with real-time WebSocket messaging and WebRTC-powered voice calls.
Installation
npm install wiil-webQuick Start
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({
configId: 'your-config-id',
routeService: RouteService.NA,
});
// Set contact info (optional)
client.setContactInfo({ email: '[email protected]' });
// Connect to chat
await client.connectChat();
// Listen for messages
client.chat.on('messageChunk', ({ chunk }) => {
console.log('Streaming:', chunk);
});
client.chat.on('messageComplete', ({ content }) => {
console.log('Complete:', content);
});
// Send a message
await client.chat.sendMessage('Hello!');
// Cleanup
await client.destroy();Features
- Chat Client - Real-time WebSocket messaging with streaming support
- Voice Client - WebRTC integration for voice calls
- Message Queue - Offline message buffering with automatic retry
- Auto-Reconnect - Exponential backoff reconnection handling
- Type Safety - Full TypeScript support with Zod runtime validation
- Event-Driven - Typed event system with unsubscribe support
API Reference
WiilClient
Main entry point for the SDK. Provides unified access to chat and voice functionality.
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({
configId: 'your-config-id', // Required
routeService: RouteService.NA, // Required - RouteService.NA or RouteService.EU
debug: false, // Optional - enable console logging
chat: { // Optional - ChatClient options
autoReconnect: true,
maxReconnectAttempts: 5,
reconnectDelay: 1000,
maxQueueSize: 50,
messageExpiryMs: 300000,
},
});WiilClient Methods
| Method | Description |
| -------- | ----------- |
| connectChat() | Fetches chat config and connects to WebSocket |
| disconnectChat() | Disconnects from chat |
| connectVoice() | Fetches voice config and connects to voice channel |
| disconnectVoice() | Disconnects from voice |
| setContactInfo(contact) | Sets contact info for API requests |
| getContactInfo() | Returns current contact info |
| getConnectionStates() | Returns chat and voice connection states |
| getIsOnline() | Returns network online status |
| on(event, listener) | Registers event listener (returns unsubscribe fn) |
| off(event, listener) | Removes event listener |
| destroy() | Cleans up all resources |
WiilClient Properties
| Property | Description |
| ---------- | ----------- |
| chat | ChatClient instance (throws if not connected) |
| voice | VoiceClient instance (throws if not connected) |
| hasChatClient | Returns true if chat client exists |
| hasVoiceClient | Returns true if voice client exists |
WiilClient Events
| Event | Payload | Description |
| ------- | --------- | ----------- |
| chat:stateChanged | { previous, current } | Chat connection state changed |
| voice:stateChanged | { previous, current } | Voice connection state changed |
| network:online | void | Network came online |
| network:offline | void | Network went offline |
ChatClient
WebSocket chat client with message queue and auto-reconnect.
const chat = client.chat;
// Listen for streaming chunks
chat.on('messageChunk', ({ chunk, conversationId, streamId }) => {
appendToUI(chunk);
});
// Listen for complete messages
chat.on('messageComplete', ({ content, conversationId }) => {
finalizeMessage(content);
});
// Send message (queued if offline)
const messageId = await chat.sendMessage('Hello!');
// Send typing indicator
chat.sendTypingIndicator(true);ChatClient Methods
| Method | Description |
| -------- | ----------- |
| connect(config) | Connects to WebSocket |
| disconnect(clearQueue?) | Disconnects (optionally clears queue) |
| sendMessage(content) | Sends message, returns message ID |
| sendTypingIndicator(isTyping) | Sends typing indicator |
| getState() | Returns connection state |
| isConnected() | Returns true if connected |
| getConversationId() | Returns current conversation ID |
| getMessageQueue() | Returns queued messages |
| getQueueSize() | Returns pending queue size |
| clearQueue() | Clears message queue |
| reconnect() | Manually triggers reconnection |
| on(event, listener) | Registers event listener |
| off(event, listener) | Removes event listener |
| destroy() | Cleans up resources |
ChatClient Events
| Event | Payload | Description |
| ------- | --------- | ----------- |
| connecting | void | Connection starting |
| connected | void | Successfully connected |
| disconnected | { code, reason } | Disconnected from server |
| reconnecting | { attempt, maxAttempts } | Reconnection attempt starting |
| reconnected | void | Successfully reconnected |
| reconnectFailed | { error } | All reconnection attempts failed |
| message | OttIncomingMessage | Raw incoming message |
| messageChunk | { chunk, conversationId?, streamId?, timestamp? } | Streaming content chunk |
| messageComplete | { conversationId?, content?, timestamp? } | Message streaming complete |
| thinking | { isThinking } | Assistant thinking state |
| processing | { isProcessing } | Assistant processing state |
| messageSent | { conversationId, messageId? } | Message sent successfully |
| messageQueued | { message } | Message queued (offline) |
| queueProcessed | { sent, expired, failed } | Queue processing complete |
| error | Error | Error occurred |
Options
| Option | Type | Default | Description |
| -------- | ------ | --------- | ----------- |
| autoReconnect | boolean | true | Auto-reconnect on disconnect |
| maxReconnectAttempts | number | 5 | Max reconnection attempts |
| reconnectDelay | number | 1000 | Base reconnect delay (ms) |
| maxQueueSize | number | 50 | Max queued messages |
| messageExpiryMs | number | 300000 | Message expiry time (5 min) |
VoiceClient
WebRTC client for voice calls.
const voice = client.voice;
// Listen for connection
voice.on('connected', () => {
console.log('Voice connected');
});
// Listen for remote audio
voice.on('remoteAudioStarted', ({ user }) => {
console.log('Agent speaking:', user.uid);
});
// Start recording
await voice.startRecording();
// Stop recording
await voice.stopRecording();VoiceClient Methods
| Method | Description |
| -------- | ----------- |
| connect(config) | Connects to voice channel |
| disconnect() | Disconnects from channel |
| startRecording() | Starts microphone and publishes |
| stopRecording() | Stops microphone and unpublishes |
| getState() | Returns connection state |
| isConnected() | Returns true if connected |
| isRecording() | Returns true if recording |
| on(event, listener) | Registers event listener |
| off(event, listener) | Removes event listener |
| destroy() | Cleans up resources |
VoiceClient Events
| Event | Payload | Description |
| ------- | --------- | ----------- |
| connecting | void | Connection starting |
| connected | void | Successfully connected |
| disconnected | void | Disconnected from channel |
| recordingStarted | void | Microphone recording started |
| recordingStopped | void | Microphone recording stopped |
| remoteAudioStarted | { user: { uid } } | Remote user started audio |
| remoteAudioStopped | { user: { uid } } | Remote user stopped audio |
| connectionStateChanged | { current, previous } | Connection state changed |
| error | Error | Error occurred |
RouteService
Select the route service based on your platform's registered business region:
- RouteService.EU - Use if your business is registered in Europe
- RouteService.NA - Default for all other regions
import { RouteService } from 'wiil-web';
// RouteService values
RouteService.NA // 'north-america' (default)
RouteService.EU // 'europe'Connection States
import { ConnectionState } from 'wiil-web';
// ConnectionState values
ConnectionState.DISCONNECTED // 'disconnected'
ConnectionState.CONNECTING // 'connecting'
ConnectionState.CONNECTED // 'connected'
ConnectionState.ERROR // 'error'Voice Connection States
import { VoiceConnectionState } from 'wiil-web';
// VoiceConnectionState values
VoiceConnectionState.DISCONNECTED // 'disconnected'
VoiceConnectionState.CONNECTING // 'connecting'
VoiceConnectionState.CONNECTED // 'connected'
VoiceConnectionState.RECORDING // 'recording'
VoiceConnectionState.ERROR // 'error'Examples
Detailed Example Guides
The complete, split walkthroughs are available in examples/basic-usage:
- Examples Overview
- 01 - Basic Chat Integration
- 02 - Chat With Queue And Reconnect
- 03 - Basic Voice Integration
- 04 - Full Chat + Voice Integration With State Tracking
- 05 - Standalone ChatClient
- 06 - Standalone VoiceClient
- 07 - Custom UI Integration Pattern
Chat with Message Queue
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({
configId: 'config-123',
routeService: RouteService.NA,
chat: {
autoReconnect: true,
maxQueueSize: 100,
messageExpiryMs: 600000, // 10 minutes
},
});
// Track queued messages
client.chat.on('messageQueued', ({ message }) => {
showPendingIndicator(message.id);
});
// Track sent messages
client.chat.on('messageSent', ({ messageId }) => {
markAsSent(messageId);
});
// Track queue processing
client.chat.on('queueProcessed', ({ sent, expired, failed }) => {
console.log(`Processed: ${sent} sent, ${expired} expired, ${failed} failed`);
});
await client.connectChat();
// Messages queue automatically if disconnected
await client.chat.sendMessage('This will queue if offline');Voice Call
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({
configId: 'config-123',
routeService: RouteService.NA,
});
// Listen for remote audio
client.on('voice:stateChanged', ({ current }) => {
updateVoiceUI(current);
});
await client.connectVoice();
client.voice.on('remoteAudioStarted', () => {
showSpeakingIndicator();
});
// Start talking
await client.voice.startRecording();
// Stop talking
await client.voice.stopRecording();
// End call
await client.disconnectVoice();Network Awareness
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({ configId: 'config-123', routeService: RouteService.NA });
client.on('network:offline', () => {
showOfflineBanner();
});
client.on('network:online', () => {
hideOfflineBanner();
// Chat will auto-reconnect and process queued messages
});
// Check network status
if (client.getIsOnline()) {
await client.connectChat();
}Handling Reconnection
import { WiilClient, RouteService } from 'wiil-web';
const client = new WiilClient({
configId: 'config-123',
routeService: RouteService.NA,
chat: {
autoReconnect: true,
maxReconnectAttempts: 10,
reconnectDelay: 2000,
},
});
await client.connectChat();
client.chat.on('reconnecting', ({ attempt, maxAttempts }) => {
showReconnectingUI(`Attempt ${attempt}/${maxAttempts}`);
});
client.chat.on('reconnected', () => {
hideReconnectingUI();
showSuccessToast('Reconnected!');
});
client.chat.on('reconnectFailed', ({ error }) => {
showErrorUI(error.message);
showManualReconnectButton();
});Types
All types are exported for TypeScript users:
import { RouteService } from 'wiil-web';
import type {
// Client options
WiilClientOptions,
WiilClientFullOptions,
ChatClientOptions,
ContactInfo,
// Connection states
ConnectionState,
ConnectionStates,
VoiceConnectionState,
// Events
WiilClientEventType,
WiilClientEventMap,
ChatEventType,
ChatEventMap,
VoiceEventType,
VoiceEventMap,
// Messages
QueuedMessage,
QueuedMessageStatus,
MessageChunkPayload,
MessageCompletePayload,
// OTT types
OttIncomingMessage,
OttChatConfig,
OttVoiceConfig,
} from 'wiil-web';Browser Support
- Chrome 60+
- Firefox 55+
- Safari 11+
- Edge 79+
Requires:
fetchAPIWebSocketAPInavigator.mediaDevices(for voice)
License
MIT
