@peopl-health/nexus 1.6.2 → 1.6.3

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.
@@ -20,7 +20,7 @@ await nexus.sendMessage({ code: 'whatsapp:+521555...', message: 'Hi' });
20
20
  ```
21
21
  After (preferred):
22
22
  ```js
23
- await nexus.sendMessage({ to: '+521555...', message: 'Hi' });
23
+ await nexus.sendMessage({ code: '+521555...', message: 'Hi' });
24
24
  ```
25
25
 
26
26
  ## Templates & Flows (Twilio)
package/README.md CHANGED
@@ -88,10 +88,10 @@ registerFlow('greeting_qr', {
88
88
  type: 'quick-reply', language: 'es', body: 'Hola {{1}}', variables: { '1': 'Nombre' },
89
89
  buttons: [{ text: 'Sí' }, { text: 'No' }]
90
90
  });
91
- await sendInteractive(nexus, { to: '+521555...', id: 'greeting_qr' });
91
+ await sendInteractive(nexus, { code: '+521555...', id: 'greeting_qr' });
92
92
 
93
93
  registerInteractiveHandler({ type: 'button', id: /sí|si/i }, async (msg, messaging) => {
94
- await messaging.sendMessage({ to: msg.from, message: '¡Confirmado!' });
94
+ await messaging.sendMessage({ code: msg.from, message: '¡Confirmado!' });
95
95
  });
96
96
  attachInteractiveRouter(nexus);
97
97
  ```
@@ -51,7 +51,7 @@ async function initializeNexus() {
51
51
  const response = await processTextMessage(messageData);
52
52
  if (response) {
53
53
  await nexus.sendMessage({
54
- to: messageData.from,
54
+ code: messageData.from,
55
55
  message: response
56
56
  });
57
57
  }
@@ -64,7 +64,7 @@ async function initializeNexus() {
64
64
  switch (command) {
65
65
  case 'help':
66
66
  await nexus.sendMessage({
67
- to: messageData.from,
67
+ code: messageData.from,
68
68
  message: `🤖 Available Commands:
69
69
  /help - Show this help
70
70
  /support - Connect to support assistant
@@ -78,7 +78,7 @@ async function initializeNexus() {
78
78
  const supportResponse = await assistants.support.handleMessage(messageData.from, 'Hello, I need support.');
79
79
  if (supportResponse) {
80
80
  await nexus.sendMessage({
81
- to: messageData.from,
81
+ code: messageData.from,
82
82
  message: supportResponse
83
83
  });
84
84
  }
@@ -88,7 +88,7 @@ async function initializeNexus() {
88
88
  const salesResponse = await assistants.sales.handleMessage(messageData.from, 'Hello, I\'m interested in your products.');
89
89
  if (salesResponse) {
90
90
  await nexus.sendMessage({
91
- to: messageData.from,
91
+ code: messageData.from,
92
92
  message: salesResponse
93
93
  });
94
94
  }
@@ -96,7 +96,7 @@ async function initializeNexus() {
96
96
 
97
97
  case 'status':
98
98
  await nexus.sendMessage({
99
- to: messageData.from,
99
+ code: messageData.from,
100
100
  message: `System Status: ${nexus.isConnected() ? '✅ Connected' : '❌ Disconnected'}`
101
101
  });
102
102
  break;
@@ -106,14 +106,14 @@ async function initializeNexus() {
106
106
  await nexus.getStorage().clearThread(messageData.from);
107
107
  }
108
108
  await nexus.sendMessage({
109
- to: messageData.from,
109
+ code: messageData.from,
110
110
  message: 'Conversation reset! You can start fresh now.'
111
111
  });
112
112
  break;
113
113
 
114
114
  default:
115
115
  await nexus.sendMessage({
116
- to: messageData.from,
116
+ code: messageData.from,
117
117
  message: `Unknown command: /${command}. Type /help for available commands.`
118
118
  });
119
119
  }
@@ -136,10 +136,10 @@ app.post('/webhook', async (req, res) => {
136
136
  // API endpoints
137
137
  app.post('/api/send-message', async (req, res) => {
138
138
  try {
139
- const { to, message, fileUrl, fileType } = req.body;
139
+ const { code, message, fileUrl, fileType } = req.body;
140
140
 
141
141
  const result = await nexus.sendMessage({
142
- to,
142
+ code,
143
143
  message,
144
144
  fileUrl,
145
145
  fileType
@@ -153,10 +153,10 @@ app.post('/api/send-message', async (req, res) => {
153
153
 
154
154
  app.post('/api/send-template', async (req, res) => {
155
155
  try {
156
- const { to, contentSid, variables } = req.body;
156
+ const { code, contentSid, variables } = req.body;
157
157
 
158
158
  const result = await nexus.sendMessage({
159
- to,
159
+ code,
160
160
  contentSid,
161
161
  variables
162
162
  });
@@ -84,9 +84,9 @@ class BaileysProvider extends MessageProvider {
84
84
  throw new Error('Baileys provider not connected');
85
85
  }
86
86
 
87
- const { to, message, fileUrl, fileType, hidePreview = false } = messageData;
87
+ const { code, message, fileUrl, fileType, hidePreview = false } = messageData;
88
88
 
89
- if (!to) {
89
+ if (!code) {
90
90
  throw new Error('Recipient is required');
91
91
  }
92
92
 
@@ -94,7 +94,7 @@ class BaileysProvider extends MessageProvider {
94
94
  throw new Error('Message or file URL is required');
95
95
  }
96
96
 
97
- const code = this.formatCode(to);
97
+ const formattedCode = this.formatCode(code);
98
98
  let sendOptions = {};
99
99
  let formattedMessage = this.formatMessage(message || '');
100
100
 
@@ -135,7 +135,7 @@ class BaileysProvider extends MessageProvider {
135
135
  }
136
136
 
137
137
  try {
138
- const result = await this.waSocket.sendMessage(code, sendOptions);
138
+ const result = await this.waSocket.sendMessage(formattedCode, sendOptions);
139
139
  return {
140
140
  success: true,
141
141
  messageId: result?.key?.id,
@@ -156,7 +156,7 @@ class BaileysProvider extends MessageProvider {
156
156
  : async (payload) => await this.sendMessage(payload);
157
157
 
158
158
  console.log('[BaileysProvider] Scheduled message created', {
159
- to: scheduledMessage.to || scheduledMessage.code,
159
+ code: scheduledMessage.code,
160
160
  delay,
161
161
  hasMedia: Boolean(scheduledMessage.fileUrl)
162
162
  });
@@ -166,7 +166,7 @@ class BaileysProvider extends MessageProvider {
166
166
  const payload = { ...scheduledMessage };
167
167
  delete payload.__nexusSend;
168
168
  console.log('[BaileysProvider] Timer fired', {
169
- to: payload.to || payload.code,
169
+ code: payload.to || payload.code,
170
170
  hasMessage: Boolean(payload.message || payload.body),
171
171
  hasMedia: Boolean(payload.fileUrl)
172
172
  });
@@ -47,16 +47,16 @@ class TwilioProvider extends MessageProvider {
47
47
  const { code, message, fileUrl, fileType, variables, contentSid } = messageData;
48
48
 
49
49
  const formattedFrom = this.ensureWhatsAppFormat(this.whatsappNumber);
50
- const formattedTo = this.ensureWhatsAppFormat(code);
50
+ const formattedCode = this.ensureWhatsAppFormat(code);
51
51
 
52
52
 
53
- if (!formattedFrom || !formattedTo) {
53
+ if (!formattedFrom || !formattedCode) {
54
54
  throw new Error('Invalid sender or recipient number');
55
55
  }
56
56
 
57
57
  const messageParams = {
58
58
  from: formattedFrom,
59
- to: formattedTo
59
+ to: formattedCode
60
60
  };
61
61
 
62
62
  // Handle template messages
@@ -83,7 +83,7 @@ class TwilioProvider extends MessageProvider {
83
83
 
84
84
  // Handle media messages
85
85
  if (fileUrl && fileType !== 'text') {
86
- const mediaPrep = await this.prepareOutboundMedia(messageData, formattedTo);
86
+ const mediaPrep = await this.prepareOutboundMedia(messageData, formattedCode);
87
87
  const outboundMediaUrl = mediaPrep.mediaUrl || fileUrl;
88
88
  messageParams.mediaUrl = [outboundMediaUrl];
89
89
  if (!messageParams.body || messageParams.body.trim() === '') {
@@ -91,7 +91,7 @@ class TwilioProvider extends MessageProvider {
91
91
  }
92
92
  if (mediaPrep.uploaded) {
93
93
  console.log('[TwilioProvider] Outbound media uploaded to S3', {
94
- to: formattedTo,
94
+ code: formattedCode,
95
95
  bucket: mediaPrep.bucketName,
96
96
  key: mediaPrep.key
97
97
  });
@@ -108,14 +108,14 @@ class TwilioProvider extends MessageProvider {
108
108
  if (this.messageStorage && typeof this.messageStorage.saveMessage === 'function') {
109
109
  try {
110
110
  console.log('[TwilioProvider] Persisting outbound message', {
111
- to: formattedTo,
111
+ code: formattedCode,
112
112
  from: formattedFrom,
113
113
  hasMedia: Boolean(messageParams.mediaUrl && messageParams.mediaUrl.length),
114
114
  hasTemplate: Boolean(messageParams.contentSid)
115
115
  });
116
116
  await this.messageStorage.saveMessage({
117
117
  ...messageData,
118
- to: formattedTo,
118
+ code: formattedCode,
119
119
  from: formattedFrom,
120
120
  messageId: result.sid,
121
121
  provider: 'twilio',
@@ -147,7 +147,7 @@ class TwilioProvider extends MessageProvider {
147
147
  : async (payload) => await this.sendMessage(payload);
148
148
 
149
149
  console.log('[TwilioProvider] Scheduled message created', {
150
- to: scheduledMessage.code,
150
+ code: scheduledMessage.code,
151
151
  delay,
152
152
  hasContentSid: Boolean(scheduledMessage.contentSid)
153
153
  });
@@ -158,7 +158,7 @@ class TwilioProvider extends MessageProvider {
158
158
  const payload = scheduledMessage.toObject ? scheduledMessage.toObject() : { ...scheduledMessage };
159
159
  delete payload.__nexusSend;
160
160
  console.log('[TwilioProvider] Timer fired', {
161
- to: payload.code,
161
+ code: payload.code,
162
162
  hasMessage: Boolean(payload.message || payload.body),
163
163
  hasMedia: Boolean(payload.fileUrl)
164
164
  });
@@ -176,7 +176,7 @@ class TwilioProvider extends MessageProvider {
176
176
  return true;
177
177
  }
178
178
 
179
- async prepareOutboundMedia(messageData, formattedTo) {
179
+ async prepareOutboundMedia(messageData, formattedCode) {
180
180
  const bucketName = runtimeConfig.get('AWS_S3_BUCKET_NAME') || process.env.AWS_S3_BUCKET_NAME;
181
181
  const fileUrl = messageData.fileUrl;
182
182
 
@@ -221,7 +221,7 @@ class TwilioProvider extends MessageProvider {
221
221
 
222
222
  if (!validation.valid) {
223
223
  console.warn('[TwilioProvider] Outbound media validation warning', {
224
- to: formattedTo,
224
+ code: formattedCode,
225
225
  message: validation.message
226
226
  });
227
227
  }
@@ -270,7 +270,7 @@ class TwilioProvider extends MessageProvider {
270
270
  };
271
271
  } catch (error) {
272
272
  console.error('[TwilioProvider] Failed to upload outbound media to S3. Using original URL.', {
273
- to: formattedTo,
273
+ code: formattedCode,
274
274
  error: error?.message || error
275
275
  });
276
276
 
@@ -27,7 +27,7 @@ class MessageProvider {
27
27
  /**
28
28
  * Send a message
29
29
  * @param {Object} messageData - Message data
30
- * @param {string} messageData.to - Recipient
30
+ * @param {string} messageData.code - Recipient
31
31
  * @param {string} messageData.message - Message text
32
32
  * @param {string} messageData.fileUrl - Optional file URL
33
33
  * @param {string} messageData.fileType - File type (text, image, document, audio)
@@ -270,13 +270,7 @@ class NexusMessaging {
270
270
  throw new Error('No provider initialized');
271
271
  }
272
272
 
273
- // Backward compatibility: accept `code` as destination
274
- const normalized = { ...messageData };
275
- if (!normalized.to && normalized.code) {
276
- normalized.to = normalized.code;
277
- }
278
-
279
- const result = await this.provider.sendMessage(normalized);
273
+ const result = await this.provider.sendMessage(messageData);
280
274
 
281
275
  // Store message only if provider does not handle persistence itself
282
276
  const providerStoresMessage = typeof this.provider.supportsMessageStorage === 'function'
@@ -285,7 +279,7 @@ class NexusMessaging {
285
279
 
286
280
  if (this.messageStorage && !providerStoresMessage) {
287
281
  await this.messageStorage.saveMessage({
288
- ...normalized,
282
+ ...messageData,
289
283
  messageId: result.messageId,
290
284
  provider: result.provider,
291
285
  timestamp: new Date(),
@@ -405,7 +399,7 @@ class NexusMessaging {
405
399
 
406
400
  if (response) {
407
401
  await this.sendMessage({
408
- to: from,
402
+ code: from,
409
403
  message: response
410
404
  });
411
405
  }
@@ -455,7 +449,7 @@ class NexusMessaging {
455
449
 
456
450
  if (response) {
457
451
  await this.sendMessage({
458
- to: from,
452
+ code: from,
459
453
  message: response
460
454
  });
461
455
  }
package/lib/index.d.ts CHANGED
@@ -6,7 +6,7 @@ declare module '@peopl-health/nexus' {
6
6
  export interface MessageData {
7
7
  id?: string;
8
8
  from: string;
9
- to?: string;
9
+ code?: string;
10
10
  message?: string;
11
11
  fileUrl?: string;
12
12
  fileType?: 'text' | 'image' | 'document' | 'audio' | 'video';
package/lib/index.js CHANGED
@@ -198,7 +198,7 @@ class Nexus {
198
198
  /**
199
199
  * Send a message
200
200
  * @param {Object} messageData - Message data
201
- * @param {string} messageData.to - Recipient phone number
201
+ * @param {string} messageData.code - Recipient phone number
202
202
  * @param {string} messageData.message - Message text
203
203
  * @param {string} [messageData.fileUrl] - Optional file URL
204
204
  * @param {string} [messageData.fileType] - File type
@@ -216,7 +216,7 @@ class Nexus {
216
216
  /**
217
217
  * Send a scheduled message
218
218
  * @param {Object} scheduledMessage - Scheduled message data
219
- * @param {string} scheduledMessage.to - Recipient phone number
219
+ * @param {string} scheduledMessage.code - Recipient phone number
220
220
  * @param {string} scheduledMessage.message - Message text
221
221
  * @param {Date|string} scheduledMessage.sendAt - When to send the message
222
222
  * @returns {Promise<Object>} Scheduled message result
@@ -3,7 +3,7 @@ const { toTwilioContent } = require('./twilioMapper');
3
3
  const { registerFlow, getFlow, listFlows, registerInteractiveHandler, listInteractiveHandlers } = require('./registry');
4
4
 
5
5
  async function sendInteractive(nexusOrMessaging, params) {
6
- const { to, spec, id, variables } = params || {};
6
+ const { code, spec, id, variables } = params || {};
7
7
  if (!nexusOrMessaging) throw new Error('sendInteractive requires a Nexus or NexusMessaging instance');
8
8
  const messaging = typeof nexusOrMessaging.getMessaging === 'function' ? nexusOrMessaging.getMessaging() : nexusOrMessaging;
9
9
  const provider = typeof messaging.getProvider === 'function' ? messaging.getProvider() : null;
@@ -14,14 +14,14 @@ async function sendInteractive(nexusOrMessaging, params) {
14
14
 
15
15
  // If user supplied a contentSid directly in spec, just send it
16
16
  if (useSpec.contentSid) {
17
- return await provider.sendMessage({ to, contentSid: useSpec.contentSid, variables });
17
+ return await provider.sendMessage({ code, contentSid: useSpec.contentSid, variables });
18
18
  }
19
19
 
20
20
  // Twilio mapping
21
21
  if (provider.constructor && provider.constructor.name === 'TwilioProvider') {
22
22
  const content = toTwilioContent(useSpec);
23
23
  const created = await provider.createTemplate(content);
24
- return await provider.sendMessage({ to, contentSid: created.sid, variables });
24
+ return await provider.sendMessage({ code, contentSid: created.sid, variables });
25
25
  }
26
26
 
27
27
  // Baileys or others: not supported yet
@@ -62,7 +62,7 @@ class MongoStorage {
62
62
  async saveMessage(messageData) {
63
63
  try {
64
64
  console.log('[MongoStorage] saveMessage called', {
65
- to: messageData?.to || messageData?.code || messageData?.numero,
65
+ code: messageData?.to || messageData?.code || messageData?.numero,
66
66
  from: messageData?.from,
67
67
  provider: messageData?.provider || 'unknown',
68
68
  hasRaw: Boolean(messageData?.raw),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peopl-health/nexus",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "Core messaging and assistant library for WhatsApp communication platforms",
5
5
  "keywords": [
6
6
  "whatsapp",