wexa-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.
@@ -0,0 +1,529 @@
1
+ import mongoose, { Document, Model } from 'mongoose';
2
+ import { Server } from 'http';
3
+ import { Socket, Server as Server$1 } from 'socket.io';
4
+
5
+ type Actor = {
6
+ organizationId: string;
7
+ participantModel: string;
8
+ participantId: string;
9
+ };
10
+
11
+ type MessageCreatedEvent = {
12
+ type: "message:created";
13
+ message: any;
14
+ };
15
+ type ConversationReadEvent = {
16
+ type: "conversation:read";
17
+ conversationId: string;
18
+ messageId: string;
19
+ participantModel: string;
20
+ participantId: string;
21
+ at: string;
22
+ };
23
+ type TypingEvent = {
24
+ type: "typing";
25
+ conversationId: string;
26
+ participantModel: string;
27
+ participantId: string;
28
+ state: "start" | "stop";
29
+ };
30
+ type PresenceEvent = {
31
+ type: "presence:join" | "presence:leave";
32
+ organizationId: string;
33
+ participantModel: string;
34
+ participantId: string;
35
+ at: string;
36
+ };
37
+
38
+ /**
39
+ * Redis configuration type
40
+ */
41
+ type RedisConfig = {
42
+ url?: string;
43
+ host?: string;
44
+ port?: number;
45
+ password?: string;
46
+ db?: number;
47
+ socketConnectTimeout?: number;
48
+ keepAlive?: number;
49
+ };
50
+ /**
51
+ * Environment configuration
52
+ */
53
+ interface EnvironmentConfig {
54
+ /** MongoDB connection URI */
55
+ mongoUri: string;
56
+ /** Redis configuration (optional) */
57
+ redis?: RedisConfig;
58
+ }
59
+ /**
60
+ * Get Redis configuration from provided options
61
+ */
62
+ declare function getRedisConfig(config: {
63
+ redis?: RedisConfig;
64
+ }): RedisConfig | null;
65
+
66
+ type SocketConfig$1 = {
67
+ path?: string;
68
+ cors?: {
69
+ origin?: string | string[];
70
+ methods?: string[];
71
+ };
72
+ };
73
+ type InitOptions = {
74
+ /**
75
+ * Models that can participate in conversations
76
+ */
77
+ participantModels: string[];
78
+ /**
79
+ * Valid roles for conversation participants
80
+ */
81
+ memberRoles: string[];
82
+ /**
83
+ * MongoDB connection URI
84
+ */
85
+ mongoUri: string;
86
+ /**
87
+ * Enable text search for messages
88
+ */
89
+ enableTextSearch?: boolean;
90
+ /**
91
+ * Redis configuration
92
+ */
93
+ redis?: RedisConfig;
94
+ /**
95
+ * Socket.IO configuration
96
+ */
97
+ socket?: SocketConfig$1;
98
+ /**
99
+ * Presence tracking configuration
100
+ */
101
+ presence?: {
102
+ enabled?: boolean;
103
+ heartbeatSec?: number;
104
+ };
105
+ /**
106
+ * Rate limiting configuration
107
+ */
108
+ rateLimit?: {
109
+ sendPerMin?: number;
110
+ typingPerMin?: number;
111
+ };
112
+ };
113
+
114
+ type CreateConversationArgs = {
115
+ organizationId: string;
116
+ a: {
117
+ model: string;
118
+ id: string;
119
+ };
120
+ b: {
121
+ model: string;
122
+ id: string;
123
+ };
124
+ };
125
+ type SendMessageArgs = {
126
+ organizationId: string;
127
+ conversationId: string;
128
+ senderModel: string;
129
+ senderId: string;
130
+ text: string;
131
+ kind?: "text" | "system";
132
+ parentMessageId?: string;
133
+ rootThreadId?: string;
134
+ };
135
+ type ListMessagesArgs = {
136
+ organizationId: string;
137
+ conversationId: string;
138
+ limit?: number;
139
+ cursor?: string;
140
+ };
141
+ type MarkReadArgs = {
142
+ organizationId: string;
143
+ conversationId: string;
144
+ participantModel: string;
145
+ participantId: string;
146
+ messageId: string;
147
+ };
148
+ type SearchMessagesArgs = {
149
+ organizationId: string;
150
+ query?: string;
151
+ conversationId?: string;
152
+ senderModel?: string;
153
+ senderId?: string;
154
+ kind?: "text" | "system";
155
+ dateFrom?: string;
156
+ dateTo?: string;
157
+ threadRootId?: string;
158
+ limit?: number;
159
+ cursor?: string;
160
+ };
161
+ type SearchConversationsArgs = {
162
+ organizationId: string;
163
+ participantModel?: string;
164
+ participantId?: string;
165
+ limit?: number;
166
+ cursor?: string;
167
+ };
168
+
169
+ interface IParticipant {
170
+ entityModel: string;
171
+ entityId: string;
172
+ role: string;
173
+ }
174
+ interface IConversation extends Document {
175
+ organizationId: string;
176
+ participants: IParticipant[];
177
+ lastMessageAt: Date;
178
+ lastMessagePreview?: string;
179
+ lastMessageSenderId?: string;
180
+ lastMessageSenderModel?: string;
181
+ metadata?: Record<string, unknown>;
182
+ createdAt: Date;
183
+ updatedAt: Date;
184
+ }
185
+ /**
186
+ * Create Conversation model
187
+ */
188
+ declare function createConversationModel(options: InitOptions): Model<IConversation>;
189
+
190
+ /**
191
+ * Message document interface
192
+ */
193
+ interface IMessage extends Document {
194
+ organizationId: mongoose.Types.ObjectId;
195
+ conversationId: mongoose.Types.ObjectId;
196
+ senderModel: string;
197
+ senderId: mongoose.Types.ObjectId;
198
+ kind: 'text' | 'system';
199
+ text: string;
200
+ parentMessageId?: mongoose.Types.ObjectId;
201
+ rootThreadId?: mongoose.Types.ObjectId;
202
+ editedAt?: Date;
203
+ deletedAt?: Date;
204
+ createdAt: Date;
205
+ updatedAt: Date;
206
+ }
207
+ /**
208
+ * Create Message model
209
+ */
210
+ declare function createMessageModel(options: InitOptions): Model<IMessage>;
211
+
212
+ /**
213
+ * Pagination result interface
214
+ */
215
+ interface PaginatedResult<T> {
216
+ items: T[];
217
+ nextCursor: string | null;
218
+ hasMore: boolean;
219
+ }
220
+ /**
221
+ * Creates a pagination cursor from a timestamp and ID
222
+ * @param timestamp Timestamp to encode in the cursor
223
+ * @param id ID to encode in the cursor
224
+ * @returns An encoded cursor string
225
+ */
226
+ declare function createCursor(timestamp: number, id: string): string;
227
+ /**
228
+ * Parses a pagination cursor into its timestamp and ID components
229
+ * @param cursor The cursor string to parse
230
+ * @returns An object containing the timestamp and ID, or null if invalid
231
+ */
232
+ declare function parseCursor(cursor: string): {
233
+ timestamp: number;
234
+ id: string;
235
+ } | null;
236
+ /**
237
+ * Creates a paginated response
238
+ * @param items The items for the current page
239
+ * @param limit The requested page size
240
+ * @param getNextCursor Function to get the next cursor from the last item
241
+ * @returns A paginated result object
242
+ */
243
+ declare function createPaginatedResponse<T>(items: T[], limit: number, getNextCursor: (lastItem: T) => string): PaginatedResult<T>;
244
+
245
+ /**
246
+ * Service for managing conversations
247
+ */
248
+ interface ConversationsService {
249
+ createOrFindConversation(args: CreateConversationArgs): Promise<IConversation>;
250
+ getConversation(organizationId: string, conversationId: string): Promise<IConversation | null>;
251
+ searchConversations(args: SearchConversationsArgs): Promise<PaginatedResult<IConversation>>;
252
+ searchByParticipantPair(args: {
253
+ organizationId: string;
254
+ a: {
255
+ model: string;
256
+ id: string;
257
+ };
258
+ b: {
259
+ model: string;
260
+ id: string;
261
+ };
262
+ }): Promise<IConversation | null>;
263
+ }
264
+ /**
265
+ * Create conversations service
266
+ * @param models MongoDB models
267
+ * @returns Conversations service instance
268
+ */
269
+ declare function createConversationsService(models: {
270
+ Conversation: Model<IConversation>;
271
+ Message: Model<IMessage>;
272
+ }): ConversationsService;
273
+
274
+ /**
275
+ * Message service hooks interface
276
+ */
277
+ interface MessageServiceHooks {
278
+ onMessageCreated?: (message: IMessage) => void;
279
+ onMessageRead?: (args: MarkReadArgs & {
280
+ at: Date;
281
+ }) => void;
282
+ }
283
+ /**
284
+ * Service for managing messages
285
+ */
286
+ interface MessagesService {
287
+ sendMessage(args: SendMessageArgs): Promise<IMessage>;
288
+ listMessages(args: ListMessagesArgs): Promise<PaginatedResult<IMessage>>;
289
+ markRead(args: MarkReadArgs): Promise<void>;
290
+ }
291
+ /**
292
+ * Create messages service
293
+ * @param models MongoDB models
294
+ * @param hooks Service hooks
295
+ * @returns Messages service instance
296
+ */
297
+ declare function createMessagesService(models: {
298
+ Conversation: Model<IConversation>;
299
+ Message: Model<IMessage>;
300
+ }, hooks?: MessageServiceHooks): MessagesService;
301
+
302
+ /**
303
+ * In-memory subscription maps for conversations and sockets
304
+ */
305
+ /**
306
+ * Subscribe a socket to a conversation
307
+ * @param conversationId The conversation ID to subscribe to
308
+ * @param socketId The socket ID to subscribe
309
+ */
310
+ declare function subscribeLocal(conversationId: string, socketId: string): void;
311
+ /**
312
+ * Unsubscribe a socket from a conversation
313
+ * @param conversationId The conversation ID to unsubscribe from
314
+ * @param socketId The socket ID to unsubscribe
315
+ */
316
+ declare function unsubscribeLocal(conversationId: string, socketId: string): void;
317
+ /**
318
+ * Clean up all subscriptions for a socket
319
+ * @param socketId The socket ID to clean up
320
+ */
321
+ declare function cleanupLocal(socketId: string): void;
322
+ /**
323
+ * Fan out a message to all local subscribers of a conversation
324
+ * @param conversationId The conversation ID to fan out to
325
+ * @param payload The payload to send
326
+ * @param emitter Function to emit events to socket IDs
327
+ */
328
+ declare function fanoutLocal(conversationId: string, payload: any, emitter: (toSocketId: string, event: any) => void): void;
329
+
330
+ interface SocketConfig {
331
+ path?: string;
332
+ cors?: {
333
+ origin?: string | string[];
334
+ methods?: string[];
335
+ };
336
+ }
337
+ interface SocketUser {
338
+ id: string;
339
+ model: string;
340
+ }
341
+ declare class SocketTransport {
342
+ private io;
343
+ private transport;
344
+ constructor(server: Server, transport: Transport, config?: SocketConfig);
345
+ /**
346
+ * Handle socket authentication
347
+ */
348
+ handleAuth(authenticate: (socket: Socket) => Promise<SocketUser | null>): void;
349
+ /**
350
+ * Initialize socket event handlers
351
+ */
352
+ initialize(): void;
353
+ /**
354
+ * Get Socket.IO server instance
355
+ */
356
+ getIO(): Server$1;
357
+ /**
358
+ * Close Socket.IO server
359
+ */
360
+ close(): Promise<void>;
361
+ }
362
+
363
+ /**
364
+ * Transport configuration type
365
+ */
366
+ interface TransportConfig {
367
+ redis?: InitOptions['redis'];
368
+ socket?: SocketConfig;
369
+ }
370
+ /**
371
+ * Transport instance type
372
+ */
373
+ interface Transport {
374
+ subscribeLocal: typeof subscribeLocal;
375
+ unsubscribeLocal: typeof unsubscribeLocal;
376
+ cleanupLocal: typeof cleanupLocal;
377
+ fanoutLocal: typeof fanoutLocal;
378
+ publishToConversation: (conversationId: string, payload: any) => Promise<number>;
379
+ startRedisListener: (onEvent: (conversationId: string, payload: any) => void) => (() => void) | null;
380
+ }
381
+ /**
382
+ * Create transport system with optional Redis and Socket.IO support
383
+ */
384
+ declare function createTransport(config?: TransportConfig, server?: Server): Transport & {
385
+ socket?: SocketTransport;
386
+ };
387
+
388
+ /**
389
+ * Generates a random string ID with the specified length
390
+ * @param length The length of the ID to generate (default: 24)
391
+ * @returns A random string ID
392
+ */
393
+ declare function generateId(length?: number): string;
394
+ /**
395
+ * Creates a conversation ID from two participant identifiers
396
+ * @param a First participant (model:id)
397
+ * @param b Second participant (model:id)
398
+ * @returns A deterministic conversation ID
399
+ */
400
+ declare function createConversationId(a: {
401
+ model: string;
402
+ id: string;
403
+ }, b: {
404
+ model: string;
405
+ id: string;
406
+ }): string;
407
+ /**
408
+ * Creates a thread ID
409
+ * @returns A unique thread ID
410
+ */
411
+ declare function createThreadId(): string;
412
+ /**
413
+ * Creates a message ID
414
+ * @returns A unique message ID
415
+ */
416
+ declare function createMessageId(): string;
417
+
418
+ /**
419
+ * Validates initialization options
420
+ * @param options Options to validate
421
+ * @returns Validation error message or null if valid
422
+ */
423
+ declare function validateInitOptions(options: InitOptions): string | null;
424
+ /**
425
+ * Validates message sending arguments
426
+ * @param args Message sending arguments to validate
427
+ * @returns Validation error message or null if valid
428
+ */
429
+ declare function validateSendMessageArgs(args: SendMessageArgs): string | null;
430
+ /**
431
+ * Validates conversation creation arguments
432
+ * @param args Conversation creation arguments to validate
433
+ * @returns Validation error message or null if valid
434
+ */
435
+ declare function validateCreateConversationArgs(args: CreateConversationArgs): string | null;
436
+ /**
437
+ * Validates mark read arguments
438
+ * @param args Mark read arguments to validate
439
+ * @returns Validation error message or null if valid
440
+ */
441
+ declare function validateMarkReadArgs(args: MarkReadArgs): string | null;
442
+ /**
443
+ * Validates pagination parameters
444
+ * @param limit Pagination limit
445
+ * @param cursor Pagination cursor
446
+ * @returns Validated limit and cursor
447
+ */
448
+ declare function validatePagination(limit?: number, cursor?: string): {
449
+ limit: number;
450
+ cursor: string | undefined;
451
+ };
452
+
453
+ /**
454
+ * Create Mongoose models with applied configuration
455
+ * @param mongooseInstance Mongoose instance
456
+ * @param options Initialization options
457
+ * @returns Object containing Conversation and Message models
458
+ */
459
+ declare function createModels(mongooseInstance: typeof mongoose, options: InitOptions): {
460
+ Conversation: mongoose.Model<IConversation, {}, {}, {}, mongoose.Document<unknown, {}, IConversation> & IConversation & {
461
+ _id: mongoose.Types.ObjectId;
462
+ }, any>;
463
+ Message: mongoose.Model<IMessage, {}, {}, {}, mongoose.Document<unknown, {}, IMessage> & IMessage & {
464
+ _id: mongoose.Types.ObjectId;
465
+ }, any>;
466
+ };
467
+
468
+ /**
469
+ * Ensure all indexes are created on models
470
+ * @param models Object containing Mongoose models
471
+ */
472
+ declare function ensureIndexes(models: {
473
+ Conversation: Model<IConversation>;
474
+ Message: Model<IMessage>;
475
+ }): Promise<void>;
476
+
477
+ /**
478
+ * Search messages based on various criteria
479
+ * @param model Message model
480
+ * @param params Search parameters
481
+ * @returns Paginated messages with optional text search results
482
+ */
483
+ declare function searchMessages(model: Model<IMessage>, params: SearchMessagesArgs): Promise<PaginatedResult<IMessage>>;
484
+
485
+ /**
486
+ * Search conversations with pagination
487
+ */
488
+ declare function searchConversations(model: Model<IConversation>, params: SearchConversationsArgs): Promise<PaginatedResult<IConversation>>;
489
+ /**
490
+ * Find a conversation between two specific participants
491
+ */
492
+ declare function searchByParticipantPair(model: Model<IConversation>, params: {
493
+ organizationId: string;
494
+ a: {
495
+ model: string;
496
+ id: string;
497
+ };
498
+ b: {
499
+ model: string;
500
+ id: string;
501
+ };
502
+ }): Promise<IConversation | null>;
503
+
504
+ /**
505
+ * Chat services container
506
+ */
507
+ interface ChatServices {
508
+ models: {
509
+ Conversation: mongoose.Model<any>;
510
+ Message: mongoose.Model<any>;
511
+ };
512
+ services: {
513
+ conversations: ConversationsService;
514
+ messages: MessagesService;
515
+ };
516
+ transport: Transport & {
517
+ socket?: SocketTransport;
518
+ };
519
+ }
520
+ /**
521
+ * Initialize the chat system
522
+ * @param mongooseInstance Mongoose instance
523
+ * @param options Initialization options
524
+ * @param server Optional HTTP server for Socket.IO integration
525
+ * @returns Chat services
526
+ */
527
+ declare function initChat(mongooseInstance: typeof mongoose, options: InitOptions, server?: Server): Promise<ChatServices>;
528
+
529
+ export { type Actor, type ChatServices, type ConversationReadEvent, type ConversationsService, type CreateConversationArgs, type EnvironmentConfig, type IConversation, type IMessage, type IParticipant, type InitOptions, type ListMessagesArgs, type MarkReadArgs, type MessageCreatedEvent, type MessageServiceHooks, type MessagesService, type PaginatedResult, type PresenceEvent, type RedisConfig, type SearchConversationsArgs, type SearchMessagesArgs, type SendMessageArgs, type SocketConfig$1 as SocketConfig, type Transport, type TransportConfig, type TypingEvent, createConversationId, createConversationModel, createConversationsService, createCursor, createMessageId, createMessageModel, createMessagesService, createModels, createPaginatedResponse, createThreadId, createTransport, ensureIndexes, generateId, getRedisConfig, initChat, parseCursor, searchByParticipantPair, searchConversations, searchMessages, validateCreateConversationArgs, validateInitOptions, validateMarkReadArgs, validatePagination, validateSendMessageArgs };