@hdriel/whatsapp-socket 1.2.4 → 1.2.6

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 CHANGED
@@ -48,6 +48,24 @@ The WhatsApp socket connection requires a persistent, stateful connection that s
48
48
  - Docker containers on persistent infrastructure
49
49
  - AWS EC2/ECS, Google Compute Engine, or Azure VM (not Lambda/Cloud Functions)
50
50
 
51
+ ## Demo
52
+
53
+ For fully demo you could see in this project github repository this demos <br>
54
+ Note: to update .env.local in each directory to run on your phone number / mongodb connection
55
+
56
+ * demo-client & demo-server, <br/>
57
+ just run in the demo-server this line, to build and run client and server side
58
+ ```bash
59
+ npm run start
60
+ // open when ready: http://localhost:1010
61
+ ```
62
+
63
+ * demo-script just run the following scripts to run all method function on your phone <br/>
64
+ ```bash
65
+ npm run test:private
66
+ // or
67
+ npm run test:group
68
+ ```
51
69
 
52
70
  ## Installation
53
71
 
@@ -137,21 +155,21 @@ await client.startConnection();
137
155
  ```
138
156
 
139
157
  #### `closeConnection()`
140
- Close the WhatsApp connection.
158
+ Close the WhatsApp connection. (not really needed, the connection closed automatically when unused)
141
159
 
142
160
  ```typescript
143
161
  await client.closeConnection();
144
162
  ```
145
163
 
146
164
  #### `resetConnection(options?)`
147
- Reset the connection and generate a new QR code or use phone pairing.
165
+ Reset the connection and generate a new QR code.
148
166
 
149
167
  ```typescript
150
168
  // Generate new QR code
151
169
  await client.resetConnection();
152
170
 
153
- // Or use phone number pairing
154
- await client.resetConnection({ pairingPhone: '050-000-0000' });
171
+ // Or use phone number pairing (not working for now)
172
+ // await client.resetConnection({ pairingPhone: '050-000-0000' });
155
173
  ```
156
174
 
157
175
  #### `isConnected()`
@@ -162,22 +180,18 @@ const connected = client.isConnected();
162
180
  console.log('Connected:', connected);
163
181
  ```
164
182
 
165
- ### Messaging Methods
166
-
167
- #### `sendTextMessage(jid, text)`
168
- Send a plain text message.
183
+ ### Messaging Methods apis
169
184
 
170
185
  ```typescript
186
+ import fs from 'fs';
187
+
188
+ // Send a plain text message.
171
189
  await client.sendTextMessage(
172
190
  '0500000000',// or 050-000-0000 converted to 972500000000 , or define DEFAULT_COUNTRY to change 972 to your country
173
191
  'Hello, this is a test message!'
174
192
  );
175
- ```
176
193
 
177
- #### `sendButtonsMessage(jid, options)`
178
- Send an interactive message with action buttons.
179
-
180
- ```typescript
194
+ // Send an interactive message with action buttons.
181
195
  await client.sendButtonsMessage('1234567890@s.whatsapp.net', {
182
196
  title: 'Welcome to our service!',
183
197
  subtitle: 'Please choose an action below',
@@ -194,12 +208,8 @@ await client.sendButtonsMessage('1234567890@s.whatsapp.net', {
194
208
  // }
195
209
  ]
196
210
  });
197
- ```
198
211
 
199
- #### `sendReplyButtonsMessage(jid, options)`
200
- Send a message with reply buttons (quick reply options).
201
-
202
- ```typescript
212
+ // Send a message with reply buttons (quick reply options).
203
213
  await client.sendReplyButtonsMessage('1234567890@s.whatsapp.net', {
204
214
  title: 'Choose your preferred time',
205
215
  subtitle: 'Click one of the options below',
@@ -209,62 +219,87 @@ await client.sendReplyButtonsMessage('1234567890@s.whatsapp.net', {
209
219
  'Evening (5-9)'
210
220
  ]
211
221
  });
212
- ```
213
222
 
214
- #### `sendImageMessage(jid, buffer, options?)`
215
- Send an image message.
216
-
217
- ```typescript
218
- import fs from 'fs';
219
223
 
224
+ // Send an image message.
220
225
  const imageBuffer = fs.readFileSync('./photo.jpg');
221
226
  await client.sendImageMessage('050-000-0000', imageBuffer, {
222
227
  caption: 'Check out this photo!',
223
228
  filename: 'photo.jpg'
224
229
  });
225
- ```
226
-
227
- #### `sendVideoMessage(jid, buffer, caption?)`
228
- Send a video message.
229
230
 
230
- ```typescript
231
+ // Send a video message.
231
232
  const videoBuffer = fs.readFileSync('./video.mp4');
232
233
  await client.sendVideoMessage(
233
234
  '050-000-0000',
234
235
  videoBuffer,
235
236
  { caption: 'Amazing video!' }
236
237
  );
237
- ```
238
-
239
- #### `sendAudioMessage(jid, buffer, options?)`
240
- Send an audio message.
241
238
 
242
- ```typescript
239
+ // Send an audio message.
243
240
  const audioBuffer = fs.readFileSync('./audio.mp3');
244
241
  await client.sendAudioMessage('050-000-0000', audioBuffer, {
245
242
  filename: 'audio.mp3',
246
243
  mimetype: 'audio/mpeg'
247
244
  });
248
- ```
249
-
250
- #### `sendFileMessage(jid, buffer, options?)`
251
- Send a document/file message.
252
245
 
253
- ```typescript
246
+ // Send a document/file message.
254
247
  const fileBuffer = fs.readFileSync('./document.pdf');
255
248
  await client.sendFileMessage('050-000-0000', fileBuffer, {
256
249
  filename: 'document.pdf',
257
250
  mimetype: 'application/pdf',
258
- caption: 'Here is the requested document'
251
+ caption: 'Here is the requested document',
252
+ autoMessageClassification: false
259
253
  });
260
- ```
261
254
 
262
- #### `sendStickerMessage(jid, buffer)`
263
- Send a sticker message (must be WebP format).
264
-
265
- ```typescript
255
+ // Send a sticker message (must be WebP format).
266
256
  const stickerBuffer = fs.readFileSync('./sticker.webp');
267
257
  await client.sendStickerMessage('050-000-0000', stickerBuffer);
258
+
259
+ // Send a location message
260
+ const position = await getCurrentLocation();
261
+ await was.sendLocationMessage(
262
+ '050-000-0000',
263
+ positon, // { latitude: 31.4117, longitude: 35.0818},
264
+ 'Place Name',
265
+ 'Full Address'
266
+ );
267
+
268
+ // client side to get current location
269
+ export const getCurrentLocation = async () => {
270
+ try {
271
+ const position: any = await new Promise((resolve, reject) => {
272
+ if (!navigator.geolocation) {
273
+ reject(new Error('Geolocation is not supported by your browser'));
274
+ return;
275
+ }
276
+
277
+ navigator.geolocation.getCurrentPosition(resolve, reject, {
278
+ enableHighAccuracy: true,
279
+ timeout: 60_000,
280
+ maximumAge: 0,
281
+ });
282
+ });
283
+
284
+ const location = {
285
+ latitude: position.coords.latitude,
286
+ longitude: position.coords.longitude,
287
+ accuracy: position.coords.accuracy,
288
+ };
289
+
290
+ return location;
291
+ } catch (err: any) {
292
+ if (err.code === 1) {
293
+ throw Error('Location permission denied');
294
+ } else if (err.code === 2) {
295
+ throw Error('Location unavailable');
296
+ } else if (err.code === 3) {
297
+ throw Error('Location request timed out');
298
+ } else {
299
+ throw Error(err instanceof Error ? err.message : 'Failed to send location');
300
+ }
301
+ }
302
+ };
268
303
  ```
269
304
 
270
305
  ### Utility Methods
@@ -278,17 +313,6 @@ console.log(qrImage); // data:image/png;base64,...
278
313
  // In client side <img src={qrImage} />
279
314
  ```
280
315
 
281
- #### `WhatsappSocket.randomPairingCode(pattern)`
282
- Generate a random pairing code.
283
-
284
- ```typescript
285
- // Generate 6-digit numeric code
286
- const code = WhatsappSocket.randomPairingCode('[0-9]');
287
-
288
- // Generate alphanumeric code
289
- const alphaCode = WhatsappSocket.randomPairingCode('[a-z0-9]');
290
- ```
291
-
292
316
  ## Phone Number Format
293
317
 
294
318
  Support normal format and converters to expected format for example:
@@ -438,8 +462,6 @@ await client.startConnection();
438
462
 
439
463
  ## Group Operations
440
464
 
441
- ### Creating Groups
442
-
443
465
  ```typescript
444
466
  // Create a new group
445
467
  const group = await client.createGroup({
@@ -449,11 +471,7 @@ const group = await client.createGroup({
449
471
  });
450
472
 
451
473
  console.log('Group ID:', group.id);
452
- ```
453
-
454
- ### Group Information
455
474
 
456
- ```typescript
457
475
  // Update group name
458
476
  await client.updateGroupName(groupId, 'New Group Name');
459
477
 
@@ -468,11 +486,7 @@ console.log('Participants:', metadata.participants.length);
468
486
  // Get all groups
469
487
  const allGroups = await client.getAllGroups();
470
488
  console.log('Total groups:', allGroups.length);
471
- ```
472
-
473
- ### Group Settings
474
489
 
475
- ```typescript
476
490
  // Lock group (only admins can send messages)
477
491
  await client.updateGroupSettings(groupId, 'announcement');
478
492
 
@@ -484,11 +498,7 @@ await client.updateGroupSettings(groupId, 'locked');
484
498
 
485
499
  // Unlock group info (everyone can edit)
486
500
  await client.updateGroupSettings(groupId, 'unlocked');
487
- ```
488
-
489
- ### Participant Management
490
501
 
491
- ```typescript
492
502
  // Add participants
493
503
  await client.addParticipants(groupId, '972501234567');
494
504
  // Or add multiple
@@ -505,11 +515,7 @@ await client.demoteFromAdmin(groupId, '972501234567');
505
515
 
506
516
  // Leave group
507
517
  await client.leaveGroup(groupId);
508
- ```
509
518
 
510
- ### Invite Management
511
-
512
- ```typescript
513
519
  // Get group invite code
514
520
  const inviteCode = await client.getGroupInviteCode(groupId);
515
521
  const inviteLink = await client.getGroupInviteCode(groupId, true);
@@ -525,16 +531,7 @@ console.log('New invite code:', newInviteCode);
525
531
 
526
532
  // Join group via invite code
527
533
  const joinedGroupId = await client.joinGroupViaInvite(inviteCode);
528
- ```
529
-
530
- ### Profile Picture Management
531
534
 
532
- **Note:** Requires `sharp` library to be installed:
533
- ```bash
534
- npm install sharp
535
- ```
536
-
537
- ```typescript
538
535
  import fs from 'fs';
539
536
 
540
537
  // Update group profile picture
@@ -549,13 +546,8 @@ const highResUrl = await client.getGroupProfilePicture(groupId, true);
549
546
 
550
547
  // Remove profile picture
551
548
  await client.removeGroupProfilePicture(groupId);
552
- ```
553
-
554
- ### Sending Messages to Groups
555
-
556
- All messaging methods work the same for groups and individual chats:
557
549
 
558
- ```typescript
550
+ // All messaging methods work the same for groups and individual chats:
559
551
  // Send text message to group
560
552
  await client.sendTextMessage(groupId, 'Hello everyone!');
561
553
 
@@ -584,6 +576,86 @@ const imageBuffer = fs.readFileSync('./photo.jpg');
584
576
  await client.sendImageMessage(groupId, imageBuffer, {
585
577
  caption: 'Group photo!'
586
578
  });
579
+
580
+ // Send media
581
+ const imageBuffer = fs.readFileSync('./photo.jpg');
582
+ await client.sendFileMessage(groupId, imageBuffer, {
583
+ caption: 'nice photo!',
584
+ filename: 'my best photo.jpg',
585
+ // autoMessageClassification: true (default)
586
+ // true - send as file type, for example here send as image,
587
+ // false - send image as file message
588
+ });
589
+ ```
590
+
591
+ ## Stream and Buffer params
592
+
593
+ All methods that receive files could get buffer and stream types!
594
+ not stream will converted to buffer data, so will pull all data on your server
595
+ consider not send large files!
596
+
597
+ ```typescript
598
+ router.post('/stream-file/:fileKey', async (req: Request, res: Response, next: NextFunction) => {
599
+ // using in this example with @hdriel/aws-utils pakcage..
600
+ if (!s3Util) return next(new Error('AWS FEATURE NOT SUPPORTED'));
601
+
602
+ try {
603
+ const fileKey = decodeURIComponent(req.params.fileKey);
604
+ const fileStream = await s3Util?.getObjectFileStream(fileKey);
605
+ if (!fileStream) {
606
+ res.status(400).json({ message: 'No document file found' });
607
+ return;
608
+ }
609
+
610
+ // for private phone messages
611
+ const phoneTo = req.query?.phoneTo as string;
612
+ if (!phoneTo) {
613
+ res.status(400).json({ message: 'not retrieved defined, phoneTo number' });
614
+ return;
615
+ }
616
+
617
+ const filename = basename(fileKey);
618
+ logger.info(null, 'Sending message...', { ...req.body, ...req.query, filename });
619
+
620
+ if (phoneTo) {
621
+ const was = new WhatsappSocket({
622
+ mongoURL: USE_MONGODB_STORAGE ? MONGODB_URI : undefined,
623
+ fileAuthStateDirectoryPath: fileAuthPath,
624
+ appName: 'whatsapp-socket-demo',
625
+ debug: true,
626
+ logger,
627
+ });
628
+
629
+ await was.sendFileMessage(phoneTo, fileStream as any, { filename });
630
+ }
631
+
632
+ // for groupId messages
633
+ const groupId = req.query?.groupId as string;
634
+ if (!groupId) {
635
+ res.status(400).json({ message: 'not retrieved defined, groupId number' });
636
+ return;
637
+ }
638
+
639
+ if (groupId) {
640
+ const was = new WhatsappSocketGroup({
641
+ mongoURL: USE_MONGODB_STORAGE ? MONGODB_URI : undefined,
642
+ fileAuthStateDirectoryPath: fileAuthPath,
643
+ appName: 'whatsapp-socket-demo',
644
+ debug: true,
645
+ logger,
646
+ });
647
+
648
+ await was.sendFileMessage(groupId, fileStream as any, { filename });
649
+ }
650
+
651
+
652
+
653
+ res.status(200).json({ message: 'OK' });
654
+ } catch (err: any) {
655
+ logger.error('AWS', 'failed on getObjectFileStream', { errMsg: err.message });
656
+ next(err);
657
+ }
658
+ });
587
659
  ```
588
660
 
589
661
  ## Complete Group Example
@@ -677,24 +749,6 @@ const formattedGroupId = WhatsappSocketGroup.formatGroupId('123456789');
677
749
  // Returns: '123456789@g.us'
678
750
  ```
679
751
 
680
- ## Error Handling
681
-
682
- Always wrap group operations in try-catch blocks:
683
-
684
- ```typescript
685
- try {
686
- await client.addParticipants(groupId, phoneNumber);
687
- } catch (error) {
688
- console.error('Failed to add participant:', error);
689
-
690
- if (error.message.includes('item-not-found')) {
691
- console.log('Group or participant not found');
692
- } else if (error.message.includes('not-authorized')) {
693
- console.log('Bot is not an admin');
694
- }
695
- }
696
- ```
697
-
698
752
  ## Common Use Cases
699
753
 
700
754
  ### Auto-Welcome New Members
@@ -704,10 +758,7 @@ client.onReceiveMessages = async (messages) => {
704
758
  for (const msg of messages) {
705
759
  if (msg.messageType === 'groupParticipantsUpdate') {
706
760
  const groupId = msg.key.remoteJid;
707
- await client.sendTextMessage(
708
- groupId,
709
- 'Welcome to the group! 👋'
710
- );
761
+ await client.sendTextMessage(groupId, 'Welcome to the group! 👋');
711
762
  }
712
763
  }
713
764
  };
@@ -720,23 +771,9 @@ import cron from 'node-cron';
720
771
 
721
772
  // Send daily message at 9 AM
722
773
  cron.schedule('0 9 * * *', async () => {
723
- await client.sendMentionAll(
724
- groupId,
725
- '☀️ Good morning everyone! Have a great day!'
726
- );
774
+ await client.sendMentionAll(groupId, '☀️ Good morning everyone! Have a great day!');
727
775
  });
728
776
  ```
729
-
730
- ### Group Polling System
731
-
732
- ```typescript
733
- await client.sendReplyButtonsMessage(groupId, {
734
- title: '📊 Daily Poll',
735
- subtitle: 'What should we have for lunch?',
736
- buttons: ['🍕 Pizza', '🍔 Burgers', '🍜 Ramen', '🥗 Salad']
737
- });
738
- ```
739
-
740
777
  ## Best Practices
741
778
 
742
779
  1. **Admin Rights**: Many operations require admin rights. Ensure your bot is an admin before performing administrative tasks.
@@ -786,6 +823,11 @@ For MongoDB storage, install the peer dependency:
786
823
  npm install mongodb
787
824
  ```
788
825
 
826
+ ## Known Issues
827
+ * not supported image formats: gif, bmp, and sometime data is corrupted
828
+ * issues to send large videos
829
+ * peering phone not working
830
+
789
831
  ## Best Practices
790
832
 
791
833
  1. **Session Management**: Always store session data securely. For production, use MongoDB or encrypted file storage.
@@ -804,17 +846,7 @@ npm install mongodb
804
846
 
805
847
  ## TypeScript Support
806
848
 
807
- The library is written in TypeScript and includes complete type definitions:
808
-
809
- ```typescript
810
- import { WhatsappSocket } from '@hdriel/whatsapp-socket';
811
-
812
- // All methods and options are fully typed
813
- const client: WhatsappSocket = new WhatsappSocket({
814
- fileAuthStateDirectoryPath: './authState',
815
- debug: true
816
- });
817
- ```
849
+ The library is written in TypeScript and includes complete type definitions
818
850
 
819
851
  ## Troubleshooting
820
852
 
@@ -857,6 +889,11 @@ MIT License - see the [LICENSE](LICENSE) file for details.
857
889
  - [music-metadata](https://www.npmjs.com/package/music-metadata) - Audio metadata extraction
858
890
  - [ms](https://www.npmjs.com/package/ms) - Time string parsing
859
891
 
892
+ ## Peer Dependencies
893
+ - [mongodb](https://www.npmjs.com/package/mongodb) ("^5.8.1") for persist connection on db collection
894
+ - [sharp](https://www.npmjs.com/package/sharp) ("^0.32.6") for profile group operators
895
+
896
+
860
897
  ## Author
861
898
 
862
899
  **Hadriel Benjo**