@veroai/chat 0.1.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 ADDED
@@ -0,0 +1,579 @@
1
+ # @veroai/chat
2
+
3
+ Real-time messaging SDK for VeroAI applications. Provides HTTP API client, WebSocket connection management, and React integration for building chat interfaces with AI agents.
4
+
5
+ ## Features
6
+
7
+ - **Real-time messaging** - WebSocket-based with auto-reconnect
8
+ - **Typing indicators** - Show when users are typing
9
+ - **Presence tracking** - Online/away/busy/offline status
10
+ - **Read receipts** - Track message read status
11
+ - **Voice/video calls** - LiveKit integration for WebRTC calls
12
+ - **AI agents** - Built-in support for AI agent conversations
13
+ - **React hooks** - Ready-to-use hooks for React applications
14
+ - **TypeScript** - Full type safety
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @veroai/chat
20
+ # or
21
+ pnpm add @veroai/chat
22
+ # or
23
+ yarn add @veroai/chat
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### Vanilla TypeScript/JavaScript
29
+
30
+ ```typescript
31
+ import { ChatClient } from '@veroai/chat';
32
+
33
+ const chat = new ChatClient({
34
+ apiUrl: 'https://api.veroai.dev',
35
+ wsUrl: 'wss://ws.veroai.dev',
36
+ token: 'your-jwt-token',
37
+ });
38
+
39
+ // Connect to real-time events
40
+ await chat.connect();
41
+
42
+ // Listen for new messages
43
+ chat.on('message:new', ({ message, conversationId }) => {
44
+ console.log('New message:', message.content);
45
+ });
46
+
47
+ // Send a message
48
+ await chat.send(conversationId, 'Hello!');
49
+ ```
50
+
51
+ ### React
52
+
53
+ ```tsx
54
+ import { ChatProvider, useChat, useConversation } from '@veroai/chat/react';
55
+
56
+ function App() {
57
+ return (
58
+ <ChatProvider
59
+ config={{
60
+ apiUrl: 'https://api.veroai.dev',
61
+ wsUrl: 'wss://ws.veroai.dev',
62
+ token: authToken,
63
+ }}
64
+ >
65
+ <ChatApp />
66
+ </ChatProvider>
67
+ );
68
+ }
69
+
70
+ function ChatApp() {
71
+ const { conversations, isConnected } = useChat();
72
+
73
+ return (
74
+ <div>
75
+ <p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
76
+ {conversations.map(conv => (
77
+ <ConversationItem key={conv.id} conversation={conv} />
78
+ ))}
79
+ </div>
80
+ );
81
+ }
82
+
83
+ function ChatRoom({ conversationId }) {
84
+ const { messages, send, typingUsers, startTyping, stopTyping } = useConversation(conversationId);
85
+ const [input, setInput] = useState('');
86
+
87
+ return (
88
+ <div>
89
+ {messages.map(m => <Message key={m.id} message={m} />)}
90
+ {typingUsers.length > 0 && <p>Someone is typing...</p>}
91
+ <input
92
+ value={input}
93
+ onChange={(e) => {
94
+ setInput(e.target.value);
95
+ startTyping();
96
+ }}
97
+ onBlur={stopTyping}
98
+ onKeyDown={(e) => {
99
+ if (e.key === 'Enter') {
100
+ send(input);
101
+ setInput('');
102
+ }
103
+ }}
104
+ />
105
+ </div>
106
+ );
107
+ }
108
+ ```
109
+
110
+ ## Configuration
111
+
112
+ ```typescript
113
+ interface ChatClientConfig {
114
+ /** VeroAI API URL */
115
+ apiUrl: string;
116
+ /** WebSocket URL for real-time events */
117
+ wsUrl?: string;
118
+ /** JWT authentication token */
119
+ token?: string;
120
+ /** Dynamic token getter (for token refresh) */
121
+ getToken?: () => string | null | Promise<string | null>;
122
+ /** Auto-connect to WebSocket on initialization */
123
+ autoConnect?: boolean;
124
+ /** Auto-reconnect on disconnect (default: true) */
125
+ autoReconnect?: boolean;
126
+ /** Reconnect interval in ms (default: 3000) */
127
+ reconnectInterval?: number;
128
+ /** Max reconnect attempts (default: 10) */
129
+ maxReconnectAttempts?: number;
130
+ }
131
+ ```
132
+
133
+ ## API Reference
134
+
135
+ ### ChatClient
136
+
137
+ #### Connection Management
138
+
139
+ ```typescript
140
+ // Connect to WebSocket
141
+ await chat.connect();
142
+
143
+ // Disconnect
144
+ chat.disconnect();
145
+
146
+ // Check connection status
147
+ chat.isConnected();
148
+
149
+ // Update auth token
150
+ chat.setToken(newToken);
151
+ ```
152
+
153
+ #### Conversations
154
+
155
+ ```typescript
156
+ // List all conversations
157
+ const conversations = await chat.listConversations();
158
+
159
+ // Get a specific conversation
160
+ const conversation = await chat.getConversation(conversationId);
161
+
162
+ // Create a new conversation
163
+ const newConv = await chat.createConversation({
164
+ type: 'direct', // 'direct' | 'group' | 'channel'
165
+ participantIds: ['user-id-1', 'user-id-2'],
166
+ name: 'Optional name for groups',
167
+ });
168
+
169
+ // Mark conversation as read
170
+ await chat.markConversationRead(conversationId);
171
+
172
+ // Leave a conversation
173
+ await chat.leaveConversation(conversationId);
174
+
175
+ // Subscribe to real-time updates
176
+ chat.subscribeToConversation(conversationId);
177
+ chat.unsubscribeFromConversation(conversationId);
178
+ ```
179
+
180
+ #### Messages
181
+
182
+ ```typescript
183
+ // Get messages (paginated)
184
+ const { messages, hasMore, total } = await chat.getMessages(conversationId, {
185
+ limit: 50,
186
+ before: 'message-id', // For pagination
187
+ });
188
+
189
+ // Send a message
190
+ const message = await chat.sendMessage(conversationId, {
191
+ content: 'Hello!',
192
+ messageType: 'text', // 'text' | 'system' | 'agent' | 'file'
193
+ metadata: { custom: 'data' },
194
+ });
195
+
196
+ // Convenience method
197
+ await chat.send(conversationId, 'Hello!');
198
+ ```
199
+
200
+ #### Typing Indicators
201
+
202
+ ```typescript
203
+ // Send typing indicator
204
+ chat.sendTypingStart(conversationId);
205
+ chat.sendTypingStop(conversationId);
206
+ ```
207
+
208
+ #### Users & Presence
209
+
210
+ ```typescript
211
+ // List users (contacts)
212
+ const users = await chat.listUsers({ includeVirtual: true });
213
+
214
+ // Get online users
215
+ const onlineUsers = await chat.getOnlineUsers();
216
+
217
+ // Get current user profile
218
+ const me = await chat.getCurrentUser();
219
+
220
+ // Get specific user
221
+ const user = await chat.getUser(userId);
222
+
223
+ // Update presence status
224
+ await chat.updateStatus('online', 'Working on something cool');
225
+ // Status: 'online' | 'away' | 'busy' | 'offline'
226
+ ```
227
+
228
+ #### AI Agents
229
+
230
+ ```typescript
231
+ // List available agents
232
+ const agents = await chat.listAgents();
233
+
234
+ // Add agent to conversation
235
+ await chat.addAgentToConversation(conversationId, agentConfigId);
236
+
237
+ // Remove agent from conversation
238
+ await chat.removeAgentFromConversation(conversationId);
239
+
240
+ // Toggle agent enabled/disabled
241
+ await chat.toggleAgent(conversationId, true);
242
+ ```
243
+
244
+ #### Voice/Video Calls (LiveKit)
245
+
246
+ The SDK integrates with LiveKit for WebRTC voice and video calls. Call signaling (ring, accept, reject, end) is handled via WebSocket, while actual media streams go through LiveKit.
247
+
248
+ ```typescript
249
+ // Create a room
250
+ const room = await chat.createRoom({
251
+ name: 'call-room-123',
252
+ emptyTimeout: 300, // seconds
253
+ maxParticipants: 10,
254
+ });
255
+ // Returns: { name, wsUrl, token }
256
+
257
+ // Join an existing room
258
+ const room = await chat.joinRoom({
259
+ roomName: 'call-room-123',
260
+ participantName: 'John Doe',
261
+ canPublish: true,
262
+ canSubscribe: true,
263
+ });
264
+
265
+ // Start a call (creates room + notifies participants)
266
+ const room = await chat.startCall(conversationId, 'video'); // 'audio' | 'video'
267
+
268
+ // Accept an incoming call
269
+ chat.on('call:ring', async ({ conversationId, roomName, callType }) => {
270
+ const room = await chat.acceptCall(conversationId, roomName, 'My Name');
271
+ // Connect to LiveKit using room.wsUrl and room.token
272
+ });
273
+
274
+ // Reject a call
275
+ chat.rejectCall(conversationId);
276
+
277
+ // End a call
278
+ chat.endCall(conversationId);
279
+ ```
280
+
281
+ ### Events
282
+
283
+ ```typescript
284
+ // Connection events
285
+ chat.on('connected', () => { /* WebSocket connected */ });
286
+ chat.on('disconnected', (reason) => { /* WebSocket disconnected */ });
287
+ chat.on('error', (error) => { /* Error occurred */ });
288
+
289
+ // Message events
290
+ chat.on('message:new', ({ message, conversationId }) => { });
291
+ chat.on('message:updated', (message) => { });
292
+ chat.on('message:deleted', (messageId, conversationId) => { });
293
+
294
+ // Conversation events
295
+ chat.on('conversation:created', (conversation) => { });
296
+ chat.on('conversation:updated', (conversation) => { });
297
+ chat.on('participant:joined', (conversationId, participant) => { });
298
+ chat.on('participant:left', (conversationId, userId) => { });
299
+
300
+ // Presence events
301
+ chat.on('presence:updated', ({ userId, status, statusMessage }) => { });
302
+
303
+ // Typing events
304
+ chat.on('typing:start', ({ conversationId, userId, userName }) => { });
305
+ chat.on('typing:stop', ({ conversationId, userId }) => { });
306
+
307
+ // Read receipt events
308
+ chat.on('read:receipt', ({ conversationId, messageId, userId, readAt }) => { });
309
+
310
+ // Call events
311
+ chat.on('call:ring', ({ conversationId, userId, callType, roomName }) => { });
312
+ chat.on('call:accept', ({ conversationId, userId, roomName }) => { });
313
+ chat.on('call:reject', ({ conversationId, userId }) => { });
314
+ chat.on('call:end', ({ conversationId, userId }) => { });
315
+ ```
316
+
317
+ ## React Hooks
318
+
319
+ ### ChatProvider
320
+
321
+ Wrap your app with `ChatProvider` to enable chat functionality:
322
+
323
+ ```tsx
324
+ import { ChatProvider } from '@veroai/chat/react';
325
+
326
+ <ChatProvider
327
+ config={{
328
+ apiUrl: 'https://api.veroai.dev',
329
+ wsUrl: 'wss://ws.veroai.dev',
330
+ token: authToken,
331
+ }}
332
+ autoFetchConversations={true}
333
+ autoFetchCurrentUser={true}
334
+ >
335
+ {children}
336
+ </ChatProvider>
337
+ ```
338
+
339
+ ### useChat
340
+
341
+ Access chat context and global state:
342
+
343
+ ```tsx
344
+ import { useChat } from '@veroai/chat/react';
345
+
346
+ function MyComponent() {
347
+ const {
348
+ client, // ChatClient instance
349
+ isConnected, // WebSocket connection status
350
+ currentUser, // Current user profile
351
+ conversations, // List of conversations
352
+ isLoadingConversations,
353
+ refreshConversations,
354
+ connect,
355
+ disconnect,
356
+ updateStatus,
357
+ } = useChat();
358
+ }
359
+ ```
360
+
361
+ ### useChatClient
362
+
363
+ Get direct access to the ChatClient:
364
+
365
+ ```tsx
366
+ import { useChatClient } from '@veroai/chat/react';
367
+
368
+ function MyComponent() {
369
+ const client = useChatClient();
370
+ // Use client directly for advanced operations
371
+ }
372
+ ```
373
+
374
+ ### useConversation
375
+
376
+ Manage a single conversation with real-time updates:
377
+
378
+ ```tsx
379
+ import { useConversation } from '@veroai/chat/react';
380
+
381
+ function ChatRoom({ conversationId }) {
382
+ const {
383
+ conversation, // Conversation object
384
+ messages, // Messages array
385
+ isLoading, // Loading state
386
+ hasMore, // More messages available
387
+ typingUsers, // Users currently typing
388
+ sendMessage, // Send message with params
389
+ send, // Send text message (convenience)
390
+ loadMore, // Load older messages
391
+ refresh, // Refresh messages
392
+ markAsRead, // Mark conversation as read
393
+ startTyping, // Send typing indicator
394
+ stopTyping, // Stop typing indicator
395
+ error, // Error if any
396
+ } = useConversation(conversationId, {
397
+ autoFetchMessages: true,
398
+ initialMessageLimit: 50,
399
+ autoSubscribe: true,
400
+ });
401
+ }
402
+ ```
403
+
404
+ ### usePresence
405
+
406
+ Track online users and presence status:
407
+
408
+ ```tsx
409
+ import { usePresence } from '@veroai/chat/react';
410
+
411
+ function OnlineUsers() {
412
+ const {
413
+ onlineUsers, // Array of online users
414
+ isLoading,
415
+ getUserStatus, // Get status for specific user
416
+ refresh,
417
+ error,
418
+ } = usePresence();
419
+
420
+ return (
421
+ <ul>
422
+ {onlineUsers.map(user => (
423
+ <li key={user.id}>
424
+ {user.firstName} - {getUserStatus(user.id)}
425
+ </li>
426
+ ))}
427
+ </ul>
428
+ );
429
+ }
430
+ ```
431
+
432
+ ### useUserPresence
433
+
434
+ Track presence for a specific user:
435
+
436
+ ```tsx
437
+ import { useUserPresence } from '@veroai/chat/react';
438
+
439
+ function UserStatus({ userId }) {
440
+ const { status, isOnline } = useUserPresence(userId);
441
+
442
+ return (
443
+ <span className={isOnline ? 'text-green-500' : 'text-gray-400'}>
444
+ {status}
445
+ </span>
446
+ );
447
+ }
448
+ ```
449
+
450
+ ## Types
451
+
452
+ ```typescript
453
+ // User types
454
+ type PresenceStatus = 'online' | 'away' | 'busy' | 'offline';
455
+
456
+ interface User {
457
+ id: string;
458
+ email?: string;
459
+ firstName?: string;
460
+ lastName?: string;
461
+ isVirtual?: boolean;
462
+ agentConfigId?: string;
463
+ status?: PresenceStatus;
464
+ statusMessage?: string;
465
+ lastSeen?: string;
466
+ }
467
+
468
+ // Conversation types
469
+ type ConversationType = 'direct' | 'group' | 'channel' | 'support';
470
+
471
+ interface Conversation {
472
+ id: string;
473
+ name?: string;
474
+ type: ConversationType;
475
+ isActive: boolean;
476
+ lastMessageAt?: string;
477
+ agentEnabled?: boolean;
478
+ agentConfigId?: string;
479
+ participants?: Participant[];
480
+ unreadCount?: number;
481
+ metadata?: Record<string, unknown>;
482
+ }
483
+
484
+ // Message types
485
+ type MessageType = 'text' | 'system' | 'agent' | 'file' | 'call';
486
+
487
+ interface Message {
488
+ id: string;
489
+ conversationId: string;
490
+ content: string;
491
+ messageType: MessageType;
492
+ senderId?: string;
493
+ sender?: User;
494
+ readBy?: ReadReceipt[];
495
+ metadata?: Record<string, unknown>;
496
+ createdAt?: string;
497
+ }
498
+
499
+ // Call types
500
+ type CallAction = 'ring' | 'accept' | 'reject' | 'end';
501
+ type CallType = 'audio' | 'video';
502
+
503
+ interface CallEvent {
504
+ conversationId: string;
505
+ userId: string;
506
+ action: CallAction;
507
+ callType?: CallType;
508
+ roomName?: string;
509
+ }
510
+
511
+ // Room info (for LiveKit)
512
+ interface RoomInfo {
513
+ name: string;
514
+ wsUrl: string;
515
+ token: string;
516
+ }
517
+ ```
518
+
519
+ ## Advanced Usage
520
+
521
+ ### Custom Token Refresh
522
+
523
+ ```typescript
524
+ const chat = new ChatClient({
525
+ apiUrl: 'https://api.veroai.dev',
526
+ wsUrl: 'wss://ws.veroai.dev',
527
+ getToken: async () => {
528
+ // Check if token is expired
529
+ const token = localStorage.getItem('token');
530
+ if (isExpired(token)) {
531
+ const newToken = await refreshToken();
532
+ localStorage.setItem('token', newToken);
533
+ return newToken;
534
+ }
535
+ return token;
536
+ },
537
+ });
538
+ ```
539
+
540
+ ### Direct API Access
541
+
542
+ For server-side usage or when you don't need WebSocket:
543
+
544
+ ```typescript
545
+ import { ChatApi } from '@veroai/chat';
546
+
547
+ const api = new ChatApi({
548
+ apiUrl: 'https://api.veroai.dev',
549
+ getToken: () => localStorage.getItem('token'),
550
+ });
551
+
552
+ // Use API directly without WebSocket
553
+ const conversations = await api.listConversations();
554
+ const room = await api.createRoom({ name: 'my-room' });
555
+ ```
556
+
557
+ ### Direct WebSocket Access
558
+
559
+ For custom WebSocket handling:
560
+
561
+ ```typescript
562
+ import { WebSocketManager } from '@veroai/chat';
563
+
564
+ const ws = new WebSocketManager({
565
+ url: 'wss://ws.veroai.dev',
566
+ getToken: () => localStorage.getItem('token'),
567
+ autoReconnect: true,
568
+ heartbeatInterval: 30000,
569
+ });
570
+
571
+ await ws.connect();
572
+ ws.on('message:new', handleNewMessage);
573
+ ws.sendTypingStart(conversationId);
574
+ ws.sendCallNotification(conversationId, 'ring', 'video', roomName);
575
+ ```
576
+
577
+ ## License
578
+
579
+ MIT