@peopl-health/nexus 1.0.2

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/lib/index.d.ts ADDED
@@ -0,0 +1,276 @@
1
+ declare module '@peopl/nexus' {
2
+ import { EventEmitter } from 'events';
3
+ import mongoose from 'mongoose';
4
+
5
+ // Core Types
6
+ export interface MessageData {
7
+ id?: string;
8
+ from: string;
9
+ to?: string;
10
+ message?: string;
11
+ fileUrl?: string;
12
+ fileType?: 'text' | 'image' | 'document' | 'audio' | 'video';
13
+ contentSid?: string;
14
+ variables?: Record<string, string>;
15
+ timestamp?: Date;
16
+ interactive?: InteractiveData;
17
+ media?: MediaData;
18
+ command?: CommandData;
19
+ keyword?: string;
20
+ flow?: string;
21
+ type?: 'message' | 'interactive' | 'media' | 'command' | 'keyword' | 'flow';
22
+ }
23
+
24
+ export interface InteractiveData {
25
+ type: 'button' | 'list' | 'flow';
26
+ payload?: string;
27
+ title?: string;
28
+ description?: string;
29
+ data?: any;
30
+ }
31
+
32
+ export interface MediaData {
33
+ url?: string;
34
+ contentType?: string;
35
+ filename?: string;
36
+ type?: string;
37
+ data?: any;
38
+ }
39
+
40
+ export interface CommandData {
41
+ prefix: string;
42
+ command: string;
43
+ args: string[];
44
+ }
45
+
46
+ export interface ScheduledMessage extends MessageData {
47
+ sendTime: string | Date;
48
+ timeZone?: string;
49
+ }
50
+
51
+ export interface ThreadData {
52
+ code: string;
53
+ assistantId: string;
54
+ threadId: string;
55
+ patientId?: string;
56
+ runId?: string;
57
+ nombre?: string;
58
+ active: boolean;
59
+ stopped?: boolean;
60
+ nextSid?: string[];
61
+ createdAt: Date;
62
+ }
63
+
64
+ // Provider Configurations
65
+ export interface TwilioConfig {
66
+ accountSid: string;
67
+ authToken: string;
68
+ whatsappNumber: string;
69
+ }
70
+
71
+ export interface BaileysConfig {
72
+ authState?: string;
73
+ mongoUri?: string;
74
+ userDbMongo?: string;
75
+ }
76
+
77
+ export interface StorageConfig {
78
+ mongoUri: string;
79
+ dbName: string;
80
+ collections?: {
81
+ messages?: string;
82
+ interactions?: string;
83
+ threads?: string;
84
+ };
85
+ }
86
+
87
+ export interface AssistantConfig {
88
+ llmClient?: any;
89
+ assistants?: Record<string, string>;
90
+ handlers?: {
91
+ onRequiresAction?: (result: any, threadData: ThreadData) => Promise<any>;
92
+ onCompleted?: (result: any) => Promise<void>;
93
+ onFailed?: (result: any) => Promise<void>;
94
+ };
95
+ }
96
+
97
+ export interface ParserConfig {
98
+ commandPrefixes?: string[];
99
+ keywords?: (string | { pattern: string; flags?: string })[];
100
+ flowTriggers?: (string | { pattern: string; flags?: string })[];
101
+ }
102
+
103
+ // Handler Types
104
+ export type MessageHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
105
+ export type InteractiveHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
106
+ export type MediaHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
107
+ export type CommandHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
108
+ export type KeywordHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
109
+ export type FlowHandler = (messageData: MessageData, nexus: Nexus) => Promise<void>;
110
+
111
+ export interface MessageHandlers {
112
+ onMessage?: MessageHandler;
113
+ onInteractive?: InteractiveHandler;
114
+ onMedia?: MediaHandler;
115
+ onCommand?: CommandHandler;
116
+ onKeyword?: KeywordHandler;
117
+ onFlow?: FlowHandler;
118
+ }
119
+
120
+ // Core Classes
121
+ export abstract class MessageProvider {
122
+ constructor(config: any);
123
+ abstract initialize(): Promise<void>;
124
+ abstract sendMessage(messageData: MessageData): Promise<any>;
125
+ abstract sendScheduledMessage(scheduledMessage: ScheduledMessage): Promise<void>;
126
+ abstract getConnectionStatus(): boolean;
127
+ abstract disconnect(): Promise<void>;
128
+ }
129
+
130
+ export class TwilioProvider extends MessageProvider {
131
+ constructor(config: TwilioConfig);
132
+ initialize(): Promise<void>;
133
+ sendMessage(messageData: MessageData): Promise<any>;
134
+ sendScheduledMessage(scheduledMessage: ScheduledMessage): Promise<void>;
135
+ getConnectionStatus(): boolean;
136
+ disconnect(): Promise<void>;
137
+ }
138
+
139
+ export class BaileysProvider extends MessageProvider {
140
+ constructor(config: BaileysConfig);
141
+ initialize(): Promise<void>;
142
+ sendMessage(messageData: MessageData): Promise<any>;
143
+ sendScheduledMessage(scheduledMessage: ScheduledMessage): Promise<void>;
144
+ getConnectionStatus(): boolean;
145
+ disconnect(): Promise<void>;
146
+ }
147
+
148
+ export class NexusMessaging {
149
+ constructor(config?: any);
150
+ initializeProvider(providerType: 'twilio' | 'baileys', providerConfig: TwilioConfig | BaileysConfig): Promise<void>;
151
+ setMessageStorage(storage: any): void;
152
+ setHandlers(handlers: MessageHandlers): void;
153
+ sendMessage(messageData: MessageData): Promise<any>;
154
+ sendScheduledMessage(scheduledMessage: ScheduledMessage): Promise<void>;
155
+ processIncomingMessage(messageData: MessageData): Promise<any>;
156
+ isConnected(): boolean;
157
+ disconnect(): Promise<void>;
158
+ }
159
+
160
+ export class MongoStorage {
161
+ constructor(config: StorageConfig);
162
+ connect(): Promise<void>;
163
+ saveMessage(messageData: MessageData): Promise<any>;
164
+ saveInteractive(interactionData: any): Promise<any>;
165
+ getMessages(numero: string, limit?: number): Promise<any[]>;
166
+ getThread(code: string): Promise<ThreadData | null>;
167
+ createThread(threadData: ThreadData): Promise<ThreadData>;
168
+ updateThread(code: string, updateData: Partial<ThreadData>): Promise<ThreadData | null>;
169
+ disconnect(): Promise<void>;
170
+ }
171
+
172
+ export class AssistantManager {
173
+ constructor(config?: AssistantConfig);
174
+ setLLMClient(llmClient: any): void;
175
+ registerAssistants(assistantConfigs: Record<string, string>): void;
176
+ setHandlers(handlers: AssistantConfig['handlers']): void;
177
+ createThread(code: string, assistantId: string, initialMessages?: string[]): Promise<ThreadData>;
178
+ sendMessage(threadData: ThreadData, message: string, runOptions?: any): Promise<string | null>;
179
+ submitToolOutputs(threadId: string, runId: string, toolOutputs: any[]): Promise<any>;
180
+ addInstruction(threadData: ThreadData, instruction: string): Promise<string | null>;
181
+ }
182
+
183
+ export class MessageParser {
184
+ constructor(config?: ParserConfig);
185
+ parseMessage(rawMessage: any): MessageData;
186
+ updateConfig(newConfig: ParserConfig): void;
187
+ }
188
+
189
+ // Main Nexus Class
190
+ export interface NexusConfig {
191
+ messaging?: any;
192
+ }
193
+
194
+ export interface InitializeOptions {
195
+ provider?: 'twilio' | 'baileys';
196
+ providerConfig?: TwilioConfig | BaileysConfig;
197
+ storage?: 'mongo';
198
+ storageConfig?: StorageConfig;
199
+ assistant?: AssistantConfig;
200
+ parser?: boolean;
201
+ parserConfig?: ParserConfig;
202
+ }
203
+
204
+ export class Nexus {
205
+ constructor(config?: NexusConfig);
206
+ initialize(options?: InitializeOptions): Promise<void>;
207
+ setHandlers(handlers: MessageHandlers): void;
208
+ sendMessage(messageData: MessageData): Promise<any>;
209
+ sendScheduledMessage(scheduledMessage: ScheduledMessage): Promise<void>;
210
+ processMessage(rawMessage: any): Promise<any>;
211
+ createAssistantThread(code: string, assistantId: string, initialMessages?: string[]): Promise<ThreadData>;
212
+ sendToAssistant(code: string, message: string, runOptions?: any): Promise<string | null>;
213
+ isConnected(): boolean;
214
+ disconnect(): Promise<void>;
215
+ getMessaging(): NexusMessaging;
216
+ getStorage(): MongoStorage | null;
217
+ getAssistantManager(): AssistantManager | null;
218
+ getMessageParser(): MessageParser | null;
219
+ }
220
+
221
+ // Utility Functions
222
+ export function createLogger(config?: any): any;
223
+ export function delay(ms: number): Promise<void>;
224
+ export function formatCode(codeBase: string): string;
225
+ export function calculateDelay(sendTime: string | Date, timeZone?: string): number;
226
+ export function ensureWhatsAppFormat(phoneNumber: string): string | null;
227
+ export function convertTwilioToInternalFormat(twilioMessage: any): any;
228
+ export function downloadMediaFromTwilio(mediaUrl: string, credentials: any): Promise<Buffer>;
229
+ export function getMediaTypeFromContentType(contentType: string): string;
230
+ export function extractTitle(message: any, mediaType: string): string | null;
231
+ export function useMongoDBAuthState(uri: string, dbName: string, sessionId: string): Promise<any>;
232
+
233
+ // Models
234
+ export const Message: mongoose.Model<any>;
235
+ export const Thread: mongoose.Model<any>;
236
+ export function getMessageValues(message: any, content: string, reply?: string, is_media?: boolean): any;
237
+ export function formatTimestamp(unixTimestamp: number): string;
238
+
239
+ // Module Exports
240
+ export const adapters: {
241
+ TwilioProvider: typeof TwilioProvider;
242
+ BaileysProvider: typeof BaileysProvider;
243
+ };
244
+
245
+ export const core: {
246
+ NexusMessaging: typeof NexusMessaging;
247
+ MessageProvider: typeof MessageProvider;
248
+ };
249
+
250
+ export const storage: {
251
+ MongoStorage: typeof MongoStorage;
252
+ };
253
+
254
+ export const utils: {
255
+ AssistantManager: typeof AssistantManager;
256
+ MessageParser: typeof MessageParser;
257
+ logger: any;
258
+ createLogger: typeof createLogger;
259
+ delay: typeof delay;
260
+ formatCode: typeof formatCode;
261
+ calculateDelay: typeof calculateDelay;
262
+ useMongoDBAuthState: typeof useMongoDBAuthState;
263
+ convertTwilioToInternalFormat: typeof convertTwilioToInternalFormat;
264
+ downloadMediaFromTwilio: typeof downloadMediaFromTwilio;
265
+ getMediaTypeFromContentType: typeof getMediaTypeFromContentType;
266
+ extractTitle: typeof extractTitle;
267
+ ensureWhatsAppFormat: typeof ensureWhatsAppFormat;
268
+ };
269
+
270
+ export const models: {
271
+ Message: typeof Message;
272
+ Thread: typeof Thread;
273
+ getMessageValues: typeof getMessageValues;
274
+ formatTimestamp: typeof formatTimestamp;
275
+ };
276
+ }
package/lib/index.js ADDED
@@ -0,0 +1,204 @@
1
+ const { NexusMessaging } = require('./core/NexusMessaging');
2
+ const { TwilioProvider } = require('./adapters/TwilioProvider');
3
+ const { BaileysProvider } = require('./adapters/BaileysProvider');
4
+ const { MongoStorage } = require('./storage/MongoStorage');
5
+ const { MessageParser } = require('./utils/MessageParser');
6
+ const { DefaultLLMProvider } = require('./utils/DefaultLLMProvider');
7
+
8
+ // Export individual components
9
+ const adapters = require('./adapters');
10
+ const core = require('./core');
11
+ const storage = require('./storage');
12
+ const utils = require('./utils');
13
+ const models = require('./models');
14
+
15
+ /**
16
+ * Main Nexus class that orchestrates all components
17
+ */
18
+ class Nexus {
19
+ constructor(config = {}) {
20
+ this.config = config;
21
+ this.messaging = new NexusMessaging(config.messaging || {});
22
+ this.storage = null;
23
+ this.messageParser = null;
24
+ this.llmProvider = null;
25
+ this.isInitialized = false;
26
+ }
27
+
28
+ /**
29
+ * Initialize Nexus with providers and storage
30
+ * @param {Object} options - Initialization options
31
+ * @param {string} [options.provider='twilio'] - Messaging provider ('twilio' or 'baileys')
32
+ * @param {Object} [options.providerConfig={}] - Provider-specific configuration
33
+ * @param {string} [options.storage='mongo'] - Storage type ('mongo' or false)
34
+ * @param {Object} [options.storageConfig={}] - Storage configuration
35
+ * @param {string} [options.parser='MessageParser'] - Message parser type
36
+ * @param {Object} [options.parserConfig={}] - Parser configuration
37
+ * @param {string} [options.llm='openai'] - LLM provider type
38
+ * @param {Object} [options.llmConfig={}] - LLM configuration
39
+ * @returns {Promise<void>}
40
+ */
41
+ async initialize(options = {}) {
42
+ const {
43
+ provider = 'twilio',
44
+ providerConfig = {},
45
+ storage = 'mongo',
46
+ storageConfig = {},
47
+ parser = 'MessageParser',
48
+ parserConfig = {},
49
+ llm = 'openai',
50
+ llmConfig = {}
51
+ } = options;
52
+
53
+ // Initialize messaging provider
54
+ await this.messaging.initializeProvider(provider, providerConfig);
55
+
56
+ // Initialize storage if provided
57
+ if (storage === 'mongo') {
58
+ this.storage = new MongoStorage(storageConfig);
59
+ await this.storage.connect();
60
+ this.messaging.setMessageStorage(this.storage);
61
+ }
62
+
63
+ // Initialize message parser if provided
64
+ if (parser !== false) {
65
+ this.messageParser = new MessageParser(parserConfig);
66
+ }
67
+
68
+ // Initialize default LLM provider if requested
69
+ if (llm === 'openai') {
70
+ this.llmProvider = new DefaultLLMProvider(llmConfig);
71
+ }
72
+
73
+ this.isInitialized = true;
74
+ }
75
+
76
+ /**
77
+ * Set message handlers for different types
78
+ * @param {Object} handlers - Handler functions
79
+ */
80
+ setHandlers(handlers) {
81
+ this.messaging.setHandlers(handlers);
82
+ }
83
+
84
+ /**
85
+ * Send a message
86
+ * @param {Object} messageData - Message data
87
+ * @param {string} messageData.to - Recipient phone number
88
+ * @param {string} messageData.message - Message text
89
+ * @param {string} [messageData.fileUrl] - Optional file URL
90
+ * @param {string} [messageData.fileType] - File type
91
+ * @param {Object} [messageData.variables] - Template variables
92
+ * @param {string} [messageData.contentSid] - Template content SID
93
+ * @returns {Promise<Object>} Message result
94
+ */
95
+ async sendMessage(messageData) {
96
+ if (!this.isInitialized) {
97
+ throw new Error('Nexus not initialized. Call initialize() first.');
98
+ }
99
+ return await this.messaging.sendMessage(messageData);
100
+ }
101
+
102
+ /**
103
+ * Send a scheduled message
104
+ * @param {Object} scheduledMessage - Scheduled message data
105
+ * @param {string} scheduledMessage.to - Recipient phone number
106
+ * @param {string} scheduledMessage.message - Message text
107
+ * @param {Date|string} scheduledMessage.sendAt - When to send the message
108
+ * @returns {Promise<Object>} Scheduled message result
109
+ */
110
+ async sendScheduledMessage(scheduledMessage) {
111
+ if (!this.isInitialized) {
112
+ throw new Error('Nexus not initialized. Call initialize() first.');
113
+ }
114
+ return await this.messaging.sendScheduledMessage(scheduledMessage);
115
+ }
116
+
117
+ /**
118
+ * Process incoming message
119
+ * @param {Object} rawMessage - Raw message from webhook/event
120
+ * @returns {Promise<void>}
121
+ */
122
+ async processMessage(rawMessage) {
123
+ if (!this.isInitialized) {
124
+ throw new Error('Nexus not initialized. Call initialize() first.');
125
+ }
126
+
127
+ let messageData = rawMessage;
128
+
129
+ // Parse message if parser is available
130
+ if (this.messageParser) {
131
+ messageData = this.messageParser.parseMessage(rawMessage);
132
+ }
133
+
134
+ return await this.messaging.processIncomingMessage(messageData);
135
+ }
136
+
137
+
138
+ /**
139
+ * Get connection status
140
+ * @returns {boolean} Connection status
141
+ */
142
+ isConnected() {
143
+ return this.messaging.isConnected();
144
+ }
145
+
146
+ /**
147
+ * Disconnect all services
148
+ * @returns {Promise<void>}
149
+ */
150
+ async disconnect() {
151
+ await this.messaging.disconnect();
152
+ if (this.storage) {
153
+ await this.storage.disconnect();
154
+ }
155
+ }
156
+
157
+ // Expose individual components for advanced usage
158
+ /**
159
+ * Get messaging instance
160
+ * @returns {NexusMessaging} Messaging instance
161
+ */
162
+ getMessaging() {
163
+ return this.messaging;
164
+ }
165
+
166
+ /**
167
+ * Get storage instance
168
+ * @returns {MongoStorage|null} Storage instance
169
+ */
170
+ getStorage() {
171
+ return this.storage;
172
+ }
173
+
174
+ /**
175
+ * Get message parser instance
176
+ * @returns {MessageParser|null} Parser instance
177
+ */
178
+ getMessageParser() {
179
+ return this.messageParser;
180
+ }
181
+
182
+ /**
183
+ * Get LLM provider instance
184
+ * @returns {DefaultLLMProvider|null} LLM provider instance
185
+ */
186
+ getLLMProvider() {
187
+ return this.llmProvider;
188
+ }
189
+ }
190
+
191
+ // Export main class and individual components
192
+ module.exports = {
193
+ Nexus,
194
+ NexusMessaging,
195
+ TwilioProvider,
196
+ BaileysProvider,
197
+ MongoStorage,
198
+ MessageParser,
199
+ adapters,
200
+ core,
201
+ storage,
202
+ utils,
203
+ models
204
+ };
@@ -0,0 +1,9 @@
1
+ const { Message, getMessageValues, formatTimestamp } = require('./messageModel');
2
+ const { Thread } = require('./threadModel');
3
+
4
+ module.exports = {
5
+ Message,
6
+ Thread,
7
+ getMessageValues,
8
+ formatTimestamp
9
+ };
@@ -0,0 +1,91 @@
1
+ const mongoose = require('mongoose');
2
+ const moment = require('moment-timezone');
3
+
4
+ const messageSchema = new mongoose.Schema({
5
+ nombre_whatsapp: { type: String, required: true },
6
+ numero: { type: String, required: true },
7
+ body: { type: String, required: true },
8
+ timestamp: { type: String, required: true, default: Date.now },
9
+ message_id: { type: String, required: true },
10
+ is_group: { type: Boolean, required: true },
11
+ is_media: { type: Boolean, required: true },
12
+ group_id: { type: String, default: null },
13
+ reply_id: { type: String, default: null },
14
+ processed: { type: Boolean, default: false },
15
+ thread_id: { type: String, default: null },
16
+ assistant_id: { type: String, default: null },
17
+ content_sid: { type: String, default: null },
18
+ from_me: { type: Boolean, default: false },
19
+ media: {
20
+ contentType: { type: String, default: null },
21
+ bucketName: { type: String, default: null },
22
+ key: { type: String, default: null },
23
+ mediaType: { type: String, enum: ['image', 'video', 'audio', 'document', 'sticker', 'other'], default: null },
24
+ fileName: { type: String, default: null },
25
+ fileSize: { type: Number, default: null },
26
+ duration: { type: Number, default: null },
27
+ caption: { type: String, default: null },
28
+ thumbnail: { type: String, default: null },
29
+ metadata: { type: Object, default: null }
30
+ },
31
+ memoryType: {
32
+ type: String,
33
+ enum: ['active', 'archived'],
34
+ default: 'active',
35
+ index: true
36
+ },
37
+ read: {
38
+ type: Boolean,
39
+ default: false
40
+ }
41
+ }, { timestamps: true });
42
+
43
+ messageSchema.index({ message_id: 1, body: 1 }, { unique: true });
44
+
45
+ messageSchema.pre('save', function (next) {
46
+ if (this.timestamp) {
47
+ this.timestamp = moment.tz(this.timestamp, 'America/Mexico_City').toDate();
48
+ }
49
+ next();
50
+ });
51
+
52
+ const Message = mongoose.model('Message', messageSchema);
53
+
54
+ function formatTimestamp(unixTimestamp) {
55
+ const date = new Date(unixTimestamp * 1000);
56
+ return date.toLocaleString('sv-MX', {
57
+ timeZone: 'America/Mexico_City',
58
+ hour12: false,
59
+ }).replace(' ', 'T').slice(0, 19);
60
+ }
61
+
62
+ function getMessageValues(message, content, reply, is_media) {
63
+ const nombre_whatsapp = message.pushName;
64
+ const numero = message.key.participant || message.key.remoteJid;
65
+ const body = content;
66
+ const timestamp = formatTimestamp(message.messageTimestamp);
67
+ const message_id = message.key.id;
68
+ const is_group = message.key.remoteJid.endsWith('@g.us');
69
+ const group_id = is_group ? message.key.remoteJid : null;
70
+ const reply_id = reply || null;
71
+ const from_me = message.key.fromMe;
72
+
73
+ return {
74
+ nombre_whatsapp,
75
+ numero,
76
+ body,
77
+ timestamp,
78
+ message_id,
79
+ is_group,
80
+ is_media,
81
+ group_id,
82
+ reply_id,
83
+ from_me
84
+ };
85
+ }
86
+
87
+ module.exports = {
88
+ Message,
89
+ getMessageValues,
90
+ formatTimestamp
91
+ };
@@ -0,0 +1,20 @@
1
+ const mongoose = require('mongoose');
2
+
3
+ const threadSchema = new mongoose.Schema({
4
+ code: { type: String, required: true },
5
+ assistant_id: { type: String, required: true },
6
+ thread_id: { type: String, required: true },
7
+ patient_id: { type: String, default: null },
8
+ run_id: { type: String, default: null },
9
+ nombre: { type: String, default: null },
10
+ active: { type: Boolean, default: true },
11
+ stopped: { type: Boolean, default: false },
12
+ nextSid: { type: [String], default: [] }
13
+ }, { timestamps: true });
14
+
15
+ threadSchema.index({ code: 1, active: 1 });
16
+ threadSchema.index({ thread_id: 1 });
17
+
18
+ const Thread = mongoose.model('Thread', threadSchema);
19
+
20
+ module.exports = { Thread };