@yellowdotai/yellow-chat-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +462 -0
- package/dist/index.d.ts +1623 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.js +2 -0
- package/dist/index.umd.js +2 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# Yellow Chat SDK
|
|
2
|
+
|
|
3
|
+
A TypeScript SDK for integrating Yellow.ai chat functionality into web applications. This SDK provides event-based communication for a clean separation between the data layer and UI layer.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @yellowdotai/yellow-chat-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { YellowChat } from '@yellowdotai/yellow-chat-sdk';
|
|
15
|
+
|
|
16
|
+
// Create SDK instance
|
|
17
|
+
const sdk = new YellowChat();
|
|
18
|
+
|
|
19
|
+
// Subscribe to events BEFORE connecting
|
|
20
|
+
sdk.on('connection:connected', ({ userId }) => {
|
|
21
|
+
console.log('Connected as:', userId);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
sdk.on('message:received', (message) => {
|
|
25
|
+
console.log('New message:', message);
|
|
26
|
+
// message.type = 'text' | 'image' | 'video' | 'audio' | 'file' | 'location' | 'system'
|
|
27
|
+
// message.content = { message: "..." } for text, { url: "..." } for media
|
|
28
|
+
// Render message in your UI based on type
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
sdk.on('agent:assigned', (agentProfile) => {
|
|
32
|
+
// Update UI to show agent info
|
|
33
|
+
console.log('Agent joined:', agentProfile.name);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
sdk.on('agent:left', () => {
|
|
37
|
+
// Agent has left the conversation
|
|
38
|
+
console.log('Agent left the conversation');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Initialize and connect
|
|
42
|
+
await sdk.init({
|
|
43
|
+
bot: 'your-bot-id',
|
|
44
|
+
host: 'https://cloud.yellow.ai'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await sdk.connect();
|
|
48
|
+
|
|
49
|
+
// Send messages
|
|
50
|
+
await sdk.sendMessage('Hello!');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface SDKConfig {
|
|
57
|
+
// Required
|
|
58
|
+
bot: string; // Your bot ID
|
|
59
|
+
|
|
60
|
+
// Server
|
|
61
|
+
host?: string; // API host URL (default: 'https://cloud.yellow.ai')
|
|
62
|
+
|
|
63
|
+
// Message Source (IMPORTANT for live agent integrations)
|
|
64
|
+
source?: string; // 'yellowmessenger' (default) or 'syncApi'
|
|
65
|
+
|
|
66
|
+
// User
|
|
67
|
+
userId?: string; // User ID (auto-generated if not provided)
|
|
68
|
+
name?: string; // User display name
|
|
69
|
+
|
|
70
|
+
// Authentication
|
|
71
|
+
ymAuthenticationToken?: string; // Auth token (if required by your bot)
|
|
72
|
+
|
|
73
|
+
// Custom Payload
|
|
74
|
+
payload?: Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
// Journey Triggers
|
|
77
|
+
triggerJourney?: string;
|
|
78
|
+
|
|
79
|
+
// UTM Parameters
|
|
80
|
+
utmSource?: string;
|
|
81
|
+
utmCampaign?: string;
|
|
82
|
+
utmMedium?: string;
|
|
83
|
+
|
|
84
|
+
// Debug
|
|
85
|
+
debug?: boolean; // Enable debug logging
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Source Configuration
|
|
90
|
+
|
|
91
|
+
The `source` parameter is critical when integrating with live agent functionality:
|
|
92
|
+
|
|
93
|
+
| Source | Use Case | Description |
|
|
94
|
+
|--------|----------|-------------|
|
|
95
|
+
| `yellowmessenger` | **Fully Headless** | Default. Use when SDK is your only communication channel. All messages sent/received via WebSocket. |
|
|
96
|
+
| `syncApi` | **Hybrid Mode (REST + SDK)** | Use when integrating with `/integrations/sync/v1/message` REST API. Required for hybrid architectures. |
|
|
97
|
+
|
|
98
|
+
#### When to use `yellowmessenger` (default)
|
|
99
|
+
|
|
100
|
+
Use this for a **fully headless** approach where the SDK handles all communication:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
await sdk.init({
|
|
104
|
+
bot: 'your-bot-id',
|
|
105
|
+
source: 'yellowmessenger' // or omit - this is the default
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await sdk.connect(userId);
|
|
109
|
+
|
|
110
|
+
// All communication via SDK
|
|
111
|
+
await sdk.sendMessage('Hello');
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### When to use `syncApi`
|
|
115
|
+
|
|
116
|
+
Use this for a **hybrid approach** where you:
|
|
117
|
+
1. Start with REST API calls to `/integrations/sync/v1/message` for bot interactions
|
|
118
|
+
2. Switch to SDK WebSocket connection when a live agent connects
|
|
119
|
+
3. Continue using SDK for real-time agent communication
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Step 1: Initially use REST API for bot messages
|
|
123
|
+
const response = await fetch('/integrations/sync/v1/message', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
botId: 'your-bot-id',
|
|
127
|
+
sender: senderId,
|
|
128
|
+
data: { message: 'Hello' }
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Step 2: When live agent connects, switch to SDK with syncApi source
|
|
133
|
+
if (response.data.includes('live agent connected')) {
|
|
134
|
+
await sdk.init({
|
|
135
|
+
bot: 'your-bot-id',
|
|
136
|
+
source: 'syncApi' // IMPORTANT: Must match REST API source for ticket consistency
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await sdk.connect(senderId); // Use same senderId from REST API
|
|
140
|
+
|
|
141
|
+
// Now receive agent messages via SDK events
|
|
142
|
+
sdk.on('message:received', (msg) => console.log('Agent:', msg));
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
> **Important:** When using hybrid mode, the `source` must be set to `syncApi` to maintain ticket consistency between REST API and WebSocket channels. Using mismatched sources will cause live agent tickets to close unexpectedly.
|
|
147
|
+
|
|
148
|
+
## API
|
|
149
|
+
|
|
150
|
+
### Lifecycle
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Initialize
|
|
154
|
+
await sdk.init(config);
|
|
155
|
+
|
|
156
|
+
// Connect (optionally with a specific user ID)
|
|
157
|
+
await sdk.connect(userId?);
|
|
158
|
+
|
|
159
|
+
// Disconnect
|
|
160
|
+
sdk.disconnect();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Messaging
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Send text message
|
|
167
|
+
await sdk.sendMessage('Hello!');
|
|
168
|
+
|
|
169
|
+
// Send file
|
|
170
|
+
await sdk.sendFile(file);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
> **Note:** Message history is **automatically fetched** when you call `connect()`. Listen to the `history:previousMessages` event to receive it.
|
|
174
|
+
|
|
175
|
+
### State
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Check connection
|
|
179
|
+
const connected = sdk.isConnected();
|
|
180
|
+
|
|
181
|
+
// Get user ID
|
|
182
|
+
const userId = sdk.getUserId();
|
|
183
|
+
|
|
184
|
+
// Get bot info
|
|
185
|
+
const botInfo = sdk.getBotInfo();
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Events
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// Subscribe to events (returns unsubscribe function)
|
|
192
|
+
const unsubscribe = sdk.on('message:received', (message) => {
|
|
193
|
+
console.log(message);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Unsubscribe later
|
|
197
|
+
unsubscribe();
|
|
198
|
+
|
|
199
|
+
// Or use off()
|
|
200
|
+
sdk.off('message:received', handler);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Events
|
|
204
|
+
|
|
205
|
+
### Connection Events
|
|
206
|
+
|
|
207
|
+
| Event | Payload | Description |
|
|
208
|
+
|-------|---------|-------------|
|
|
209
|
+
| `connection:connecting` | - | Connection attempt started |
|
|
210
|
+
| `connection:connected` | `{ userId }` | Successfully connected |
|
|
211
|
+
| `connection:disconnected` | `{ code, message, wasClean }` | Disconnected |
|
|
212
|
+
| `connection:reconnecting` | `{ attempt, delay }` | Reconnecting |
|
|
213
|
+
| `connection:reconnected` | `{ userId }` | Successfully reconnected |
|
|
214
|
+
| `connection:error` | `SDKError` | Connection error |
|
|
215
|
+
|
|
216
|
+
### Message Events
|
|
217
|
+
|
|
218
|
+
| Event | Payload | Description |
|
|
219
|
+
|-------|---------|-------------|
|
|
220
|
+
| `message:received` | `IncomingMessage` | Message from bot/agent |
|
|
221
|
+
| `message:sent` | `{ id, message }` | Message sent successfully |
|
|
222
|
+
| `message:failed` | `{ messageId, error }` | Message failed to send |
|
|
223
|
+
|
|
224
|
+
### Agent Events
|
|
225
|
+
|
|
226
|
+
| Event | Payload | Description |
|
|
227
|
+
|-------|---------|-------------|
|
|
228
|
+
| `agent:assigned` | `AgentProfile` | Live agent joined the conversation |
|
|
229
|
+
| `agent:left` | - | Agent left or ticket closed/resolved |
|
|
230
|
+
| `agent:typing` | `boolean` | Agent is typing |
|
|
231
|
+
|
|
232
|
+
### Ticket Events
|
|
233
|
+
|
|
234
|
+
| Event | Payload | Description |
|
|
235
|
+
|-------|---------|-------------|
|
|
236
|
+
| `ticket:closed` | - | Ticket has been closed |
|
|
237
|
+
| `ticket:resolved` | - | Ticket has been resolved |
|
|
238
|
+
|
|
239
|
+
### History Events
|
|
240
|
+
|
|
241
|
+
| Event | Payload | Description |
|
|
242
|
+
|-------|---------|-------------|
|
|
243
|
+
| `history:previousMessages` | `Message[]` | Previous conversation messages (auto-fetched on connect) |
|
|
244
|
+
|
|
245
|
+
> History is automatically fetched when `connect()` is called. On reconnection, only missed messages are fetched.
|
|
246
|
+
|
|
247
|
+
### Network Events
|
|
248
|
+
|
|
249
|
+
| Event | Payload | Description |
|
|
250
|
+
|-------|---------|-------------|
|
|
251
|
+
| `network:online` | - | Network connection restored |
|
|
252
|
+
| `network:offline` | - | Network connection lost |
|
|
253
|
+
|
|
254
|
+
## Integration Modes
|
|
255
|
+
|
|
256
|
+
### Mode 1: Fully Headless (SDK Only)
|
|
257
|
+
|
|
258
|
+
Use the SDK as your only communication channel. Best for custom chat widgets.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { YellowChat } from 'yellow-chat-sdk';
|
|
262
|
+
|
|
263
|
+
const sdk = new YellowChat();
|
|
264
|
+
|
|
265
|
+
sdk.on('message:received', (message) => {
|
|
266
|
+
console.log('Message:', message);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
await sdk.init({
|
|
270
|
+
bot: 'your-bot-id',
|
|
271
|
+
source: 'yellowmessenger' // Default - can be omitted
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await sdk.connect();
|
|
275
|
+
await sdk.sendMessage('Hello');
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Mode 2: Hybrid Mode (REST API + SDK)
|
|
279
|
+
|
|
280
|
+
Start with REST API for bot interactions, switch to SDK when live agent connects.
|
|
281
|
+
|
|
282
|
+
**Why use Hybrid Mode?**
|
|
283
|
+
- Server-side control over bot conversations
|
|
284
|
+
- Reduced client-side complexity for bot-only flows
|
|
285
|
+
- Real-time WebSocket only when needed (live agent)
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { YellowChat } from 'yellow-chat-sdk';
|
|
289
|
+
|
|
290
|
+
let chatMode = 'rest';
|
|
291
|
+
let sdk = null;
|
|
292
|
+
const senderId = 'unique-user-id';
|
|
293
|
+
|
|
294
|
+
// REST API for bot messages
|
|
295
|
+
async function sendMessageViaREST(message) {
|
|
296
|
+
const response = await fetch('https://cloud.yellow.ai/integrations/sync/v1/message', {
|
|
297
|
+
method: 'POST',
|
|
298
|
+
headers: {
|
|
299
|
+
'Content-Type': 'application/json',
|
|
300
|
+
'x-api-key': 'your-api-key'
|
|
301
|
+
},
|
|
302
|
+
body: JSON.stringify({
|
|
303
|
+
botId: 'your-bot-id',
|
|
304
|
+
sender: senderId,
|
|
305
|
+
data: { message }
|
|
306
|
+
})
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const data = await response.json();
|
|
310
|
+
|
|
311
|
+
// Check if live agent connected
|
|
312
|
+
if (data.data?.messageArray?.some(m =>
|
|
313
|
+
m.message?.toLowerCase().includes('live agent') &&
|
|
314
|
+
m.message?.toLowerCase().includes('connected')
|
|
315
|
+
)) {
|
|
316
|
+
await switchToWebSocketMode();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return data;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Switch to SDK when live agent connects
|
|
323
|
+
async function switchToWebSocketMode() {
|
|
324
|
+
sdk = new YellowChat();
|
|
325
|
+
|
|
326
|
+
sdk.on('message:received', (message) => {
|
|
327
|
+
console.log('Agent message:', message);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
sdk.on('ticket:closed', () => {
|
|
331
|
+
console.log('Ticket closed - switching back to REST');
|
|
332
|
+
chatMode = 'rest';
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
sdk.on('ticket:resolved', () => {
|
|
336
|
+
console.log('Ticket resolved - switching back to REST');
|
|
337
|
+
chatMode = 'rest';
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
await sdk.init({
|
|
341
|
+
bot: 'your-bot-id',
|
|
342
|
+
source: 'syncApi' // CRITICAL: Must be 'syncApi' for hybrid mode!
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
await sdk.connect(senderId); // Use same senderId from REST API
|
|
346
|
+
chatMode = 'websocket';
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Send message based on current mode
|
|
350
|
+
async function sendMessage(message) {
|
|
351
|
+
if (chatMode === 'rest') {
|
|
352
|
+
return sendMessageViaREST(message);
|
|
353
|
+
} else {
|
|
354
|
+
return sdk.sendMessage(message);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
> **Critical:** When using hybrid mode, you **MUST** set `source: 'syncApi'` in the SDK configuration. This ensures that messages sent via the SDK are correctly associated with tickets created via the REST API. Using mismatched sources will cause tickets to close unexpectedly.
|
|
360
|
+
|
|
361
|
+
## Message Types
|
|
362
|
+
|
|
363
|
+
All messages from the SDK follow a **standardized, flattened format**:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
interface IncomingMessage {
|
|
367
|
+
id: string; // Unique message ID
|
|
368
|
+
timestamp: Date; // Message timestamp
|
|
369
|
+
type: MessageType; // Message type
|
|
370
|
+
content: MessageContent; // Flattened content
|
|
371
|
+
sender: 'bot' | 'agent' | 'user' | 'system'; // Who sent the message
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Message types
|
|
375
|
+
type MessageType = 'text' | 'image' | 'video' | 'audio' | 'file' | 'location' | 'system' | 'cards' | 'quickReplies';
|
|
376
|
+
|
|
377
|
+
// Content is FLATTENED based on type:
|
|
378
|
+
// Text: { message: "Hello" }
|
|
379
|
+
// Image: { url: "https://..." }
|
|
380
|
+
// Video: { url: "https://...", controls: true, autoplay: false, ... }
|
|
381
|
+
// Audio: { url: "https://..." }
|
|
382
|
+
// File: { url: "https://...", name: "document.pdf" }
|
|
383
|
+
// Location: { latitude: 12.34, longitude: 56.78 }
|
|
384
|
+
// System: { message: "Agent joined the conversation" }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Example: Handling Different Message Types
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
sdk.on('message:received', (message) => {
|
|
391
|
+
switch (message.type) {
|
|
392
|
+
case 'text':
|
|
393
|
+
console.log('Text:', message.content.message);
|
|
394
|
+
break;
|
|
395
|
+
case 'image':
|
|
396
|
+
console.log('Image URL:', message.content.url);
|
|
397
|
+
break;
|
|
398
|
+
case 'video':
|
|
399
|
+
console.log('Video URL:', message.content.url);
|
|
400
|
+
// Optional: message.content.controls, message.content.autoplay
|
|
401
|
+
break;
|
|
402
|
+
case 'file':
|
|
403
|
+
console.log('File:', message.content.name, message.content.url);
|
|
404
|
+
break;
|
|
405
|
+
case 'system':
|
|
406
|
+
console.log('System:', message.content.message);
|
|
407
|
+
// e.g., "Agent joined the conversation", "Conversation ended"
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Error Handling
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { YellowChatError } from 'yellow-chat-sdk';
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
await sdk.sendMessage('Hello');
|
|
420
|
+
} catch (error) {
|
|
421
|
+
if (error instanceof YellowChatError) {
|
|
422
|
+
console.error('SDK Error:', error.code, error.message);
|
|
423
|
+
if (error.recoverable) {
|
|
424
|
+
// Retry logic
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Or listen for error events
|
|
430
|
+
sdk.on('connection:error', (error) => {
|
|
431
|
+
console.error('Connection error:', error);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
sdk.on('message:failed', ({ messageId, error }) => {
|
|
435
|
+
console.error('Message failed:', messageId, error);
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## TypeScript
|
|
440
|
+
|
|
441
|
+
The SDK is written in TypeScript and includes full type definitions.
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
import type {
|
|
445
|
+
SDKConfig,
|
|
446
|
+
IncomingMessage,
|
|
447
|
+
AgentProfile,
|
|
448
|
+
SDKEvents,
|
|
449
|
+
SDKEventName
|
|
450
|
+
} from 'yellow-chat-sdk';
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Browser Support
|
|
454
|
+
|
|
455
|
+
- Chrome 60+
|
|
456
|
+
- Firefox 55+
|
|
457
|
+
- Safari 11+
|
|
458
|
+
- Edge 79+
|
|
459
|
+
|
|
460
|
+
## License
|
|
461
|
+
|
|
462
|
+
MIT
|