innovators-bot2 1.0.9 → 1.1.1

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.
Files changed (3) hide show
  1. package/example.js +17 -0
  2. package/index.js +126 -158
  3. package/package.json +17 -4
package/example.js CHANGED
@@ -39,6 +39,23 @@ client.on('disconnected', (error) => {
39
39
  // Connect to WhatsApp
40
40
  client.connect()
41
41
 
42
+ client.on('status', async status => {
43
+
44
+ console.log ('Status Received');
45
+ console.log ('Number:', status.from);
46
+ console.log ('Sender:', status.raw.pushName);
47
+ console.log ('Message:', status.body);
48
+ console.log ('Has Media:', status.hasMedia);
49
+ console.log('ID', status.key)
50
+
51
+ await client.readMessage(status.key)
52
+ await status.reply('Thanks for the status! ❤️');
53
+ await status.like('❤️');
54
+ console.log('Status Seen! and Replied With Emoji')
55
+
56
+
57
+ });
58
+
42
59
  // Listen for incoming messages
43
60
  client.on('message', async msg => {
44
61
  console.log ('Message Received');
package/index.js CHANGED
@@ -145,171 +145,103 @@ class WhatsAppClient extends EventEmitter {
145
145
  * @emits WhatsAppClient#message - When a new message is received
146
146
  * @param {object} update - The message update object
147
147
  */
148
+
148
149
  this.sock.ev.on('messages.upsert', async (update) => {
149
150
  try {
150
- // Skip if no messages or not a notification
151
- if (!update.messages || update.messages.length === 0 || update.type !== 'notify') {
152
- return;
153
- }
154
-
151
+ if (update.type !== 'notify' || !update.messages?.length) return;
155
152
  const [message] = update.messages;
156
-
157
- // Skip messages sent by the bot itself
158
- if (message.key.fromMe) {
159
- return;
160
- }
161
-
162
- /**
163
- * Extract message text from different possible locations in the message object
164
- * @type {string}
165
- */
166
- let messageText = '';
167
- let isButtonResponse = false;
168
-
169
- // Check for list response first
170
- if (message.message?.listResponseMessage) {
171
- messageText = message.message.listResponseMessage.title ||
172
- message.message.listResponseMessage.description || '';
173
- isButtonResponse = true;
174
- }
175
- // Check for button response
176
- else if (message.message?.templateButtonReplyMessage) {
177
- messageText = message.message.templateButtonReplyMessage.selectedDisplayText ||
178
- message.message.templateButtonReplyMessage.selectedId || '';
179
- isButtonResponse = true;
180
- }
181
- // Check for classic button response
182
- else if (message.message?.buttonsResponseMessage) {
183
- messageText = message.message.buttonsResponseMessage.selectedDisplayText ||
184
- message.message.buttonsResponseMessage.selectedButtonId || '';
185
- isButtonResponse = true;
186
- }
187
- // Regular message
188
- else {
189
- messageText = message.message?.conversation ||
190
- message.message?.extendedTextMessage?.text ||
191
- message.message?.imageMessage?.caption ||
192
- message.message?.videoMessage?.caption ||
193
- '';
194
- }
195
-
196
- /** @type {string|null} */
197
- let buttonType = null;
198
- /** @type {string} */
199
- let buttonText = '';
200
-
201
- // Determine message type and extract relevant data
202
- const { message: msg } = message;
203
-
204
- // Check for different types of button messages
205
- if (msg?.buttonsMessage) {
206
- buttonType = 'classic_buttons';
207
- }
208
- // Check for hydrated template messages
209
- else if (msg?.templateMessage?.hydratedTemplate?.hydratedButtons) {
210
- buttonType = 'classic_buttons_hydrated';
211
- }
212
- // Check for different types of hydrated four row templates
213
- else if (msg?.templateMessage?.hydratedFourRowTemplate) {
214
- const template = msg.templateMessage.hydratedFourRowTemplate;
215
-
216
- if (template.hydratedButtons) {
217
- buttonType = 'template_buttons_hydrated';
218
- } else if (template.title) {
219
- buttonType = 'template_text_hydrated';
220
- } else if (template.imageMessage) {
221
- buttonType = 'template_image_hydrated';
222
- } else if (template.videoMessage) {
223
- buttonType = 'template_video_hydrated';
224
- } else if (template.documentMessage) {
225
- buttonType = 'template_document_hydrated';
226
- }
227
- }
228
-
229
- // Handle interactive response messages
230
- if (msg?.interactiveResponseMessage) {
231
- const interactive = msg.interactiveResponseMessage;
232
-
233
- if (interactive.nativeFlowResponse?.response?.reply) {
234
- buttonType = 'interactive_buttons_modern_native_flow';
235
- buttonText = interactive.nativeFlowResponse.response.reply;
236
- } else if (interactive.reply) {
237
- buttonType = 'interactive_buttons_modern_reply';
238
- buttonText = interactive.reply;
239
- } else if (interactive.buttonReplyMessage?.displayText) {
240
- buttonType = 'interactive_buttons_modern_button_reply';
241
- buttonText = interactive.buttonReplyMessage.displayText;
242
- }
243
- }
244
-
245
- // Handle button and list responses
246
- if (msg?.listResponseMessage) {
247
- // Handle list response messages
248
- buttonType = 'list_response';
249
- buttonText = msg.listResponseMessage.title || '';
250
- if (msg.listResponseMessage.description) {
251
- buttonText = buttonText ? `${buttonText} - ${msg.listResponseMessage.description}` : msg.listResponse.description;
252
- }
253
- } else if (msg?.buttonsResponseMessage?.selectedButtonId) {
254
- // Handle classic button responses
255
- buttonType = 'classic_buttons';
256
- buttonText = msg.buttonsResponseMessage.selectedDisplayText ||
257
- msg.buttonsResponseMessage.selectedButtonId || '';
258
- } else if (msg?.templateButtonReplyMessage?.selectedId) {
259
- // Handle template button replies
260
- buttonType = 'template_button_reply';
261
- buttonText = msg.templateButtonReplyMessage.selectedDisplayText ||
262
- msg.templateButtonReplyMessage.selectedId || '';
263
- } else if (msg?.interactiveResponseMessage) {
264
- // Handle interactive responses (including list selections)
265
- const interactive = msg.interactiveResponseMessage;
266
- if (interactive.listResponse) {
267
- buttonType = 'list_selection';
268
- buttonText = interactive.listResponse.title || interactive.listResponse.description || '';
269
- } else if (interactive.nativeFlowResponse?.response?.reply) {
270
- buttonType = 'interactive_buttons_modern_native_flow';
271
- buttonText = interactive.nativeFlowResponse.response.reply;
153
+ if (!message || message.key?.fromMe) return;
154
+
155
+ // 🚫 Ignore revoked/deleted messages (including deleted statuses)
156
+ if (message.message?.protocolMessage?.type === 0) return;
157
+
158
+ const msg = message.message || {};
159
+ const jid = message.key.remoteJid;
160
+ const timestamp = new Date((message.messageTimestamp || Date.now()) * 1000);
161
+
162
+ const getText = () =>
163
+ msg.conversation ||
164
+ msg.extendedTextMessage?.text ||
165
+ msg.imageMessage?.caption ||
166
+ msg.videoMessage?.caption ||
167
+ '';
168
+
169
+ const getButtonText = () => {
170
+ if (msg.listResponseMessage)
171
+ return msg.listResponseMessage.title || msg.listResponseMessage.description || '';
172
+ if (msg.templateButtonReplyMessage)
173
+ return msg.templateButtonReplyMessage.selectedDisplayText || msg.templateButtonReplyMessage.selectedId || '';
174
+ if (msg.buttonsResponseMessage)
175
+ return msg.buttonsResponseMessage.selectedDisplayText || msg.buttonsResponseMessage.selectedButtonId || '';
176
+ if (msg.interactiveResponseMessage) {
177
+ const i = msg.interactiveResponseMessage;
178
+ return i.listResponse?.title ||
179
+ i.listResponse?.description ||
180
+ i.nativeFlowResponse?.response?.reply ||
181
+ i.reply ||
182
+ i.buttonReplyMessage?.displayText || '';
272
183
  }
184
+ return '';
185
+ };
186
+
187
+ const reply = async (text) => this.sock.sendMessage(jid, { text }, { quoted: message });
188
+
189
+ // ✅ Handle status updates (stories)
190
+ if (jid === 'status@broadcast') {
191
+ const from = message.key?.participant || message.participant || message.pushName;
192
+ this.emit('status', {
193
+ from,
194
+ body: getText(),
195
+ hasMedia: Boolean(msg.imageMessage || msg.videoMessage),
196
+ timestamp,
197
+ key: message.key,
198
+ raw: message,
199
+
200
+ // Reply to status
201
+ reply: async (text) => {
202
+ if (!from) throw new Error('Missing participant JID');
203
+ return this.sock.sendMessage(from, { text }, { quoted: message });
204
+ },
205
+
206
+ // 👍 Like (react) to status
207
+ like: async (emoji = '❤️') => {
208
+ if (!from) throw new Error('Missing participant JID');
209
+ return this.sock.sendMessage(from, {
210
+ react: {
211
+ text: emoji,
212
+ key: message.key
213
+ }
214
+ });
215
+ }
216
+ });
217
+ return;
273
218
  }
274
-
275
- // Prepare the message body - prioritize button/list responses over regular text
276
- const messageBody = buttonText || messageText ||
277
- (msg?.listResponseMessage?.singleSelectReply?.selectedRowId) ||
278
- (msg?.listResponseMessage?.title) ||
279
- (msg?.listResponseMessage?.description) ||
280
- '';
281
-
282
- // Emit the message event with all extracted data
219
+
220
+ // Handle normal/chat messages
221
+ const buttonText = getButtonText();
222
+ const body = buttonText || getText() ||
223
+ msg.listResponseMessage?.singleSelectReply?.selectedRowId || '';
224
+
283
225
  this.emit('message', {
284
- from: message.key.remoteJid,
285
- body: messageText,
286
- hasMedia: Boolean(msg?.imageMessage || msg?.videoMessage || msg?.audioMessage || msg?.documentMessage),
287
- isGroup: message.key.remoteJid.endsWith('@g.us'),
288
- timestamp: message.messageTimestamp ? new Date(message.messageTimestamp * 1000) : new Date(),
289
- isButtonResponse: isButtonResponse,
290
- buttonId: message.message?.listResponseMessage?.singleSelectReply?.selectedRowId ||
291
- message.message?.templateButtonReplyMessage?.selectedId ||
292
- message.message?.buttonsResponseMessage?.selectedButtonId || null,
293
- buttonText: messageText,
226
+ from: jid,
227
+ body,
228
+ hasMedia: Boolean(msg.imageMessage || msg.videoMessage || msg.audioMessage || msg.documentMessage),
229
+ isGroup: jid.endsWith('@g.us'),
230
+ timestamp,
231
+ isButtonResponse: Boolean(buttonText),
232
+ buttonId: msg?.listResponseMessage?.singleSelectReply?.selectedRowId ||
233
+ msg?.templateButtonReplyMessage?.selectedId ||
234
+ msg?.buttonsResponseMessage?.selectedButtonId || null,
235
+ buttonText,
294
236
  raw: message,
295
- reply: async (replyText) => {
296
- try {
297
- return await this.sock.sendMessage(
298
- message.key.remoteJid,
299
- { text: replyText },
300
- { quoted: message }
301
- );
302
- } catch (error) {
303
- console.error('Error sending reply:', error);
304
- throw error;
305
- }
306
- },
237
+ reply,
307
238
  });
308
- } catch (error) {
309
- console.error('Error processing message:', error);
239
+ } catch (err) {
240
+ console.error('Error processing message:', err);
310
241
  }
311
242
  });
312
- // Handle incoming calls
243
+
244
+ // Handle incoming calls
313
245
  this.sock.ev.on('call', async (call) => {
314
246
  try {
315
247
  await this.emit('call', call);
@@ -388,7 +320,7 @@ class WhatsAppClient extends EventEmitter {
388
320
  messageContent = {
389
321
  react: {
390
322
  text: message.emoji,
391
- key: message.messageKey
323
+ key: message.messageKey || message.message?.key || message.key
392
324
  }
393
325
  };
394
326
  break;
@@ -757,7 +689,13 @@ class WhatsAppClient extends EventEmitter {
757
689
  return await this.sock.profilePictureUrl(id);
758
690
  } catch (error) {
759
691
  // If the error is because the user has no profile picture, return undefined
760
- if (error.message && error.message.includes('404')) {
692
+ const isStatus = (err, code) => (
693
+ (err && typeof err.message === 'string' && err.message.includes(String(code))) ||
694
+ (err && (err.status === code || err.code === code || err.data === code)) ||
695
+ (err && err.response && err.response.status === code) ||
696
+ (err && err.output && err.output.statusCode === code)
697
+ );
698
+ if (isStatus(error, 404) || isStatus(error, 401)) {
761
699
  return undefined;
762
700
  }
763
701
  console.error('Error getting profile picture:', error);
@@ -791,6 +729,36 @@ class WhatsAppClient extends EventEmitter {
791
729
  return this.sock;
792
730
  }
793
731
 
732
+ /**
733
+ * Send typing indicator to a chat
734
+ * @param {string} jid - The JID of the chat
735
+ * @returns {Promise<void>}
736
+ */
737
+ async sendTypingPresence(jid) {
738
+ if (!this.sock) throw new Error('Not connected to WhatsApp');
739
+ await this.sock.sendPresenceUpdate("composing", jid);
740
+ }
741
+
742
+ /**
743
+ * Send recording indicator to a chat
744
+ * @param {string} jid - The JID of the chat
745
+ * @returns {Promise<void>}
746
+ */
747
+ async sendRecordingPresence(jid) {
748
+ if (!this.sock) throw new Error('Not connected to WhatsApp');
749
+ await this.sock.sendPresenceUpdate("recording", jid);
750
+ }
751
+
752
+ /**
753
+ * Clear typing/recording indicator from a chat
754
+ * @param {string} jid - The JID of the chat
755
+ * @returns {Promise<void>}
756
+ */
757
+ async sendPausedPresence(jid) {
758
+ if (!this.sock) throw new Error('Not connected to WhatsApp');
759
+ await this.sock.sendPresenceUpdate("paused", jid);
760
+ }
761
+
794
762
  /**
795
763
  * Reinitialize the WhatsApp client by clearing the session and reconnecting
796
764
  * @returns {Promise<void>}
@@ -815,7 +783,7 @@ class WhatsAppClient extends EventEmitter {
815
783
  if (this.sock) {
816
784
  try {
817
785
  this.sock.ev.removeAllListeners();
818
- await this.sock.end(undefined);
786
+ this.sock.end(undefined);
819
787
  } catch (e) {
820
788
  console.error('Error while cleaning up socket:', e);
821
789
  }
package/package.json CHANGED
@@ -1,20 +1,33 @@
1
1
  {
2
2
  "name": "innovators-bot2",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "start": "node example.js",
8
8
  "test": "echo \"Error: no test specified\" && exit 1"
9
9
  },
10
- "keywords": ["whatsapp", "bot", "automation", "baileys", "whatsapp-web.js", "messaging", "chat", "nodejs", "api", "group-management", "qr-code", "client" ],
10
+ "keywords": [
11
+ "whatsapp",
12
+ "bot",
13
+ "automation",
14
+ "baileys",
15
+ "whatsapp-web.js",
16
+ "messaging",
17
+ "chat",
18
+ "nodejs",
19
+ "api",
20
+ "group-management",
21
+ "qr-code",
22
+ "client"
23
+ ],
11
24
  "author": "Javed Arshad Bhatti",
12
25
  "license": "ISC",
13
26
  "repository": {
14
27
  "type": "git",
15
- "url": "https://github.com/innovatorssoft/innovators-bot2.git"
28
+ "url": "git+https://github.com/innovatorssoft/WhatsAppAPI.git"
16
29
  },
17
- "homepage": "https://github.com/innovatorssoft/innovators-bot2#readme",
30
+ "homepage": "https://github.com/innovatorssoft/WhatsAppAPI?tab=readme-ov-file#whatsapp-api",
18
31
  "dependencies": {
19
32
  "@itsukichan/baileys": "latest",
20
33
  "link-preview-js": "^3.0.13",