miaw-core 0.9.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.
package/USAGE.md ADDED
@@ -0,0 +1,1399 @@
1
+ # Miaw Core - Usage Guide
2
+
3
+ This document covers all current capabilities of Miaw Core. It will be updated as new features are added.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Configuration](#configuration)
10
+ - [Authentication](#authentication)
11
+ - [Sending Messages](#sending-messages)
12
+ - [Advanced Messaging](#advanced-messaging)
13
+ - [Group Management](#group-management)
14
+ - [Profile Management](#profile-management)
15
+ - [Business & Social Features](#business--social-features-v090)
16
+ - [Receiving Messages](#receiving-messages)
17
+ - [Connection Management](#connection-management)
18
+ - [Multiple Instances](#multiple-instances)
19
+ - [Session Management](#session-management)
20
+ - [Event Reference](#event-reference)
21
+ - [Error Handling](#error-handling)
22
+ - [TypeScript Usage](#typescript-usage)
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install miaw-core
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ Here's a minimal example to get started:
33
+
34
+ ```typescript
35
+ import { MiawClient } from "miaw-core";
36
+
37
+ // Create client
38
+ const client = new MiawClient({
39
+ instanceId: "my-bot",
40
+ sessionPath: "./sessions",
41
+ });
42
+
43
+ // Handle QR code
44
+ client.on("qr", (qr) => {
45
+ console.log("Scan this QR code:", qr);
46
+ // Display QR code for WhatsApp scanning
47
+ });
48
+
49
+ // When ready
50
+ client.on("ready", () => {
51
+ console.log("Bot is ready!");
52
+ });
53
+
54
+ // Receive messages
55
+ client.on("message", async (message) => {
56
+ console.log("Received:", message.text);
57
+
58
+ // Reply
59
+ await client.sendText(message.from, "Hello!");
60
+ });
61
+
62
+ // Start
63
+ await client.connect();
64
+ ```
65
+
66
+ ## Configuration
67
+
68
+ ### MiawClientOptions
69
+
70
+ When creating a client, you can configure these options:
71
+
72
+ ```typescript
73
+ const client = new MiawClient({
74
+ // Required
75
+ instanceId: "unique-bot-id",
76
+
77
+ // Optional
78
+ sessionPath: "./sessions", // Default: './sessions'
79
+ debug: true, // Default: false
80
+ autoReconnect: true, // Default: true
81
+ maxReconnectAttempts: 10, // Default: Infinity
82
+ reconnectDelay: 5000, // Default: 3000 (ms)
83
+ });
84
+ ```
85
+
86
+ **Configuration Options:**
87
+
88
+ | Option | Type | Default | Description |
89
+ | ---------------------- | --------- | -------------- | --------------------------------------------------- |
90
+ | `instanceId` | `string` | _required_ | Unique identifier for this WhatsApp instance |
91
+ | `sessionPath` | `string` | `'./sessions'` | Directory path where session data will be stored |
92
+ | `debug` | `boolean` | `false` | Enable verbose logging |
93
+ | `autoReconnect` | `boolean` | `true` | Auto-reconnect on connection loss |
94
+ | `maxReconnectAttempts` | `number` | `Infinity` | Maximum reconnection attempts |
95
+ | `reconnectDelay` | `number` | `3000` | Delay between reconnection attempts in milliseconds |
96
+
97
+ ## Authentication
98
+
99
+ ### QR Code Authentication
100
+
101
+ On first connection, WhatsApp requires QR code scanning:
102
+
103
+ ```typescript
104
+ client.on("qr", (qr) => {
105
+ console.log("QR Code:", qr);
106
+
107
+ // For terminal display, install qrcode-terminal:
108
+ // npm install qrcode-terminal
109
+ // import qrcode from 'qrcode-terminal';
110
+ // qrcode.generate(qr, { small: true });
111
+ });
112
+ ```
113
+
114
+ ### Session Persistence
115
+
116
+ After first authentication, the session is automatically saved and reused:
117
+
118
+ ```typescript
119
+ // First run: QR code required
120
+ await client.connect(); // Will emit 'qr' event
121
+
122
+ // Subsequent runs: No QR code needed
123
+ await client.connect(); // Uses saved session
124
+ ```
125
+
126
+ Sessions are stored in: `{sessionPath}/{instanceId}/`
127
+
128
+ ### Logout
129
+
130
+ To logout and clear session:
131
+
132
+ ```typescript
133
+ await client.disconnect();
134
+ // Then manually delete: ./sessions/{instanceId}/
135
+ ```
136
+
137
+ ## Sending Messages
138
+
139
+ ### Send Text Message
140
+
141
+ Basic text message sending:
142
+
143
+ ```typescript
144
+ const result = await client.sendText(
145
+ "1234567890@s.whatsapp.net",
146
+ "Hello, World!"
147
+ );
148
+
149
+ if (result.success) {
150
+ console.log("Message sent! ID:", result.messageId);
151
+ } else {
152
+ console.error("Failed to send:", result.error);
153
+ }
154
+ ```
155
+
156
+ ### Phone Number Formatting
157
+
158
+ You can use phone numbers or WhatsApp JIDs:
159
+
160
+ ```typescript
161
+ // Both formats work:
162
+ await client.sendText("1234567890", "Hello");
163
+ await client.sendText("1234567890@s.whatsapp.net", "Hello");
164
+
165
+ // Group messages:
166
+ await client.sendText("123456789@g.us", "Hello group!");
167
+ ```
168
+
169
+ ### Send to Groups
170
+
171
+ Same API for individual and group chats:
172
+
173
+ ```typescript
174
+ // Send to group (use group JID)
175
+ await client.sendText("123456789@g.us", "Hello everyone!");
176
+ ```
177
+
178
+ ## Advanced Messaging
179
+
180
+ ### Send Reactions
181
+
182
+ React to messages with emojis:
183
+
184
+ ```typescript
185
+ client.on("message", async (msg) => {
186
+ // React to the message with a heart
187
+ const result = await client.sendReaction(msg, "❤️");
188
+
189
+ if (result.success) {
190
+ console.log("Reaction sent!");
191
+ }
192
+ });
193
+
194
+ // Other common reactions
195
+ await client.sendReaction(msg, "👍"); // Thumbs up
196
+ await client.sendReaction(msg, "😂"); // Laughing
197
+ await client.sendReaction(msg, "😮"); // Surprised
198
+ await client.sendReaction(msg, "😢"); // Sad
199
+ await client.sendReaction(msg, "🙏"); // Pray/Thanks
200
+ ```
201
+
202
+ ### Remove Reactions
203
+
204
+ Remove your reaction from a message:
205
+
206
+ ```typescript
207
+ // Remove reaction (sends empty string)
208
+ await client.removeReaction(msg);
209
+
210
+ // Or equivalently:
211
+ await client.sendReaction(msg, "");
212
+ ```
213
+
214
+ ### Forward Messages
215
+
216
+ Forward a message to another chat:
217
+
218
+ ```typescript
219
+ client.on("message", async (msg) => {
220
+ // Forward this message to another contact
221
+ const result = await client.forwardMessage(msg, "0987654321");
222
+
223
+ if (result.success) {
224
+ console.log("Message forwarded!");
225
+ }
226
+ });
227
+
228
+ // Forward to a group
229
+ await client.forwardMessage(msg, "123456789@g.us");
230
+ ```
231
+
232
+ ### Edit Messages
233
+
234
+ Edit your own sent messages (within WhatsApp's 15-minute window):
235
+
236
+ ```typescript
237
+ // Send a message and keep the reference
238
+ const result = await client.sendText("1234567890", "Hello, Wordl!");
239
+
240
+ // Later, fix the typo by editing
241
+ // Note: You need to store/retrieve the sent message object
242
+ client.on("message", async (msg) => {
243
+ if (msg.fromMe && msg.text === "Hello, Wordl!") {
244
+ await client.editMessage(msg, "Hello, World!");
245
+ }
246
+ });
247
+ ```
248
+
249
+ **Important:** You can only edit your own messages (`fromMe: true`).
250
+
251
+ ### Delete Messages
252
+
253
+ Delete messages for everyone:
254
+
255
+ ```typescript
256
+ client.on("message", async (msg) => {
257
+ // Delete this message for everyone
258
+ const result = await client.deleteMessage(msg);
259
+
260
+ if (result.success) {
261
+ console.log("Message deleted for everyone!");
262
+ }
263
+ });
264
+ ```
265
+
266
+ Delete messages only for yourself:
267
+
268
+ ```typescript
269
+ // Delete message locally (others still see it)
270
+ const success = await client.deleteMessageForMe(msg);
271
+
272
+ // Optionally, also delete associated media files
273
+ await client.deleteMessageForMe(msg, true); // deleteMedia = true (default)
274
+ await client.deleteMessageForMe(msg, false); // keep media files
275
+ ```
276
+
277
+ ### Auto-React Bot Example
278
+
279
+ Bot that automatically reacts to messages:
280
+
281
+ ```typescript
282
+ client.on("message", async (msg) => {
283
+ if (msg.fromMe) return;
284
+
285
+ // React based on keywords
286
+ const text = msg.text?.toLowerCase() || "";
287
+
288
+ if (text.includes("thank")) {
289
+ await client.sendReaction(msg, "🙏");
290
+ } else if (text.includes("love")) {
291
+ await client.sendReaction(msg, "❤️");
292
+ } else if (text.includes("funny") || text.includes("lol")) {
293
+ await client.sendReaction(msg, "😂");
294
+ }
295
+ });
296
+ ```
297
+
298
+ ## Group Management
299
+
300
+ Full group administration capabilities for creating and managing WhatsApp groups.
301
+
302
+ ### Create Group
303
+
304
+ Create a new WhatsApp group:
305
+
306
+ ```typescript
307
+ const result = await client.createGroup("My New Group", [
308
+ "1234567890", // Phone number
309
+ "0987654321",
310
+ ]);
311
+
312
+ if (result.success) {
313
+ console.log("Group created:", result.groupJid);
314
+ console.log("Group name:", result.groupInfo?.name);
315
+ console.log("Participants:", result.groupInfo?.participantCount);
316
+ }
317
+ ```
318
+
319
+ ### Add Participants
320
+
321
+ Add members to an existing group (requires admin):
322
+
323
+ ```typescript
324
+ const results = await client.addParticipants("123456789@g.us", [
325
+ "1234567890",
326
+ "0987654321",
327
+ ]);
328
+
329
+ for (const result of results) {
330
+ if (result.success) {
331
+ console.log(`Added: ${result.jid}`);
332
+ } else {
333
+ console.log(`Failed to add ${result.jid}: ${result.status}`);
334
+ }
335
+ }
336
+ ```
337
+
338
+ ### Remove Participants
339
+
340
+ Remove members from a group (requires admin):
341
+
342
+ ```typescript
343
+ const results = await client.removeParticipants("123456789@g.us", [
344
+ "1234567890",
345
+ ]);
346
+
347
+ results.forEach((r) => console.log(`${r.jid}: ${r.success ? "Removed" : r.status}`));
348
+ ```
349
+
350
+ ### Leave Group
351
+
352
+ Leave a group:
353
+
354
+ ```typescript
355
+ const result = await client.leaveGroup("123456789@g.us");
356
+ if (result.success) {
357
+ console.log("Left the group");
358
+ }
359
+ ```
360
+
361
+ ### Promote/Demote Admins
362
+
363
+ Manage group admin roles:
364
+
365
+ ```typescript
366
+ // Promote member to admin
367
+ const promoteResults = await client.promoteToAdmin("123456789@g.us", [
368
+ "1234567890",
369
+ ]);
370
+
371
+ // Demote admin to member
372
+ const demoteResults = await client.demoteFromAdmin("123456789@g.us", [
373
+ "1234567890",
374
+ ]);
375
+ ```
376
+
377
+ ### Update Group Name
378
+
379
+ Change the group name/subject:
380
+
381
+ ```typescript
382
+ const result = await client.updateGroupName("123456789@g.us", "New Group Name");
383
+ if (result.success) {
384
+ console.log("Group name updated");
385
+ }
386
+ ```
387
+
388
+ ### Update Group Description
389
+
390
+ Set or clear group description:
391
+
392
+ ```typescript
393
+ // Set description
394
+ await client.updateGroupDescription(
395
+ "123456789@g.us",
396
+ "Welcome to our group! Please read the rules."
397
+ );
398
+
399
+ // Clear description (pass undefined)
400
+ await client.updateGroupDescription("123456789@g.us");
401
+ ```
402
+
403
+ ### Update Group Picture
404
+
405
+ Change the group profile picture:
406
+
407
+ ```typescript
408
+ // From file path
409
+ await client.updateGroupPicture("123456789@g.us", "./group-icon.jpg");
410
+
411
+ // From URL
412
+ await client.updateGroupPicture("123456789@g.us", "https://example.com/image.jpg");
413
+
414
+ // From Buffer
415
+ const imageBuffer = fs.readFileSync("./image.png");
416
+ await client.updateGroupPicture("123456789@g.us", imageBuffer);
417
+ ```
418
+
419
+ ### Group Invite Links
420
+
421
+ Manage group invite links:
422
+
423
+ ```typescript
424
+ // Get invite link
425
+ const link = await client.getGroupInviteLink("123456789@g.us");
426
+ console.log("Invite link:", link);
427
+ // Output: https://chat.whatsapp.com/AbCdEfGhIjK
428
+
429
+ // Revoke current link and get new one
430
+ const newLink = await client.revokeGroupInvite("123456789@g.us");
431
+ console.log("New invite link:", newLink);
432
+ ```
433
+
434
+ ### Join Group via Invite
435
+
436
+ Accept a group invitation:
437
+
438
+ ```typescript
439
+ // Accept with full URL
440
+ const groupJid = await client.acceptGroupInvite(
441
+ "https://chat.whatsapp.com/AbCdEfGhIjK"
442
+ );
443
+
444
+ // Or just the code
445
+ const groupJid2 = await client.acceptGroupInvite("AbCdEfGhIjK");
446
+
447
+ if (groupJid) {
448
+ console.log("Joined group:", groupJid);
449
+ }
450
+ ```
451
+
452
+ ### Preview Group from Invite
453
+
454
+ Get group info before joining:
455
+
456
+ ```typescript
457
+ const info = await client.getGroupInviteInfo("AbCdEfGhIjK");
458
+
459
+ if (info) {
460
+ console.log("Group name:", info.name);
461
+ console.log("Description:", info.description);
462
+ console.log("Members:", info.participantCount);
463
+ console.log("Created:", new Date(info.createdAt! * 1000));
464
+ }
465
+ ```
466
+
467
+ ### Group Admin Bot Example
468
+
469
+ Bot that manages group membership:
470
+
471
+ ```typescript
472
+ client.on("message", async (msg) => {
473
+ if (!msg.isGroup || msg.fromMe) return;
474
+
475
+ const command = msg.text?.toLowerCase();
476
+ const groupJid = msg.from;
477
+
478
+ if (command === "!invite") {
479
+ const link = await client.getGroupInviteLink(groupJid);
480
+ await client.sendText(groupJid, `Join link: ${link}`);
481
+ }
482
+
483
+ if (command === "!groupinfo") {
484
+ const info = await client.getGroupInfo(groupJid);
485
+ if (info) {
486
+ await client.sendText(
487
+ groupJid,
488
+ `Group: ${info.name}\nMembers: ${info.participantCount}\nDescription: ${info.description || "None"}`
489
+ );
490
+ }
491
+ }
492
+ });
493
+ ```
494
+
495
+ ## Profile Management
496
+
497
+ Customize your bot's WhatsApp profile.
498
+
499
+ ### Update Profile Picture
500
+
501
+ Change your profile picture:
502
+
503
+ ```typescript
504
+ // From file path
505
+ const result = await client.updateProfilePicture("./my-avatar.jpg");
506
+
507
+ // From URL
508
+ const result2 = await client.updateProfilePicture("https://example.com/avatar.jpg");
509
+
510
+ // From Buffer
511
+ const imageBuffer = fs.readFileSync("./avatar.png");
512
+ const result3 = await client.updateProfilePicture(imageBuffer);
513
+
514
+ if (result.success) {
515
+ console.log("Profile picture updated!");
516
+ }
517
+ ```
518
+
519
+ ### Remove Profile Picture
520
+
521
+ Remove your profile picture:
522
+
523
+ ```typescript
524
+ const result = await client.removeProfilePicture();
525
+
526
+ if (result.success) {
527
+ console.log("Profile picture removed");
528
+ }
529
+ ```
530
+
531
+ ### Update Profile Name
532
+
533
+ Change your display name (push name):
534
+
535
+ ```typescript
536
+ const result = await client.updateProfileName("My Bot Name");
537
+
538
+ if (result.success) {
539
+ console.log("Profile name updated!");
540
+ }
541
+ ```
542
+
543
+ ### Update Profile Status
544
+
545
+ Change your "About" text:
546
+
547
+ ```typescript
548
+ const result = await client.updateProfileStatus("Powered by Miaw Core 🤖");
549
+
550
+ if (result.success) {
551
+ console.log("Profile status updated!");
552
+ }
553
+
554
+ // Clear status
555
+ await client.updateProfileStatus("");
556
+ ```
557
+
558
+ ### Profile Bot Example
559
+
560
+ Bot that updates its profile based on commands:
561
+
562
+ ```typescript
563
+ client.on("message", async (msg) => {
564
+ if (msg.fromMe) return; // Ignore own messages
565
+
566
+ const text = msg.text?.toLowerCase();
567
+
568
+ if (text === "!setstatus online") {
569
+ await client.updateProfileStatus("🟢 Online and ready to help!");
570
+ await client.sendText(msg.from, "Status updated to online!");
571
+ }
572
+
573
+ if (text === "!setstatus busy") {
574
+ await client.updateProfileStatus("🔴 Busy - response may be delayed");
575
+ await client.sendText(msg.from, "Status updated to busy!");
576
+ }
577
+ });
578
+ ```
579
+
580
+ ## Business & Social Features (v0.9.0)
581
+
582
+ This section covers WhatsApp Business features (labels, catalog/products) and social features (newsletters/channels, contacts).
583
+
584
+ > **Note:** Label and Catalog/Product features require a **WhatsApp Business account**.
585
+
586
+ ### Label Operations (WhatsApp Business Only)
587
+
588
+ Labels help organize chats and messages. WhatsApp Business provides 20 label colors and 5 predefined labels.
589
+
590
+ #### Create/Edit a Label
591
+
592
+ ```typescript
593
+ import { LabelColor } from "miaw-core";
594
+
595
+ const result = await client.addLabel({
596
+ id: "vip-customers",
597
+ name: "VIP Customers",
598
+ color: LabelColor.Color5,
599
+ });
600
+
601
+ if (result.success) {
602
+ console.log("Label created:", result.labelId);
603
+ }
604
+ ```
605
+
606
+ #### Add Label to Chat
607
+
608
+ ```typescript
609
+ const result = await client.addChatLabel("6281234567890", "label-id");
610
+
611
+ if (result.success) {
612
+ console.log("Label added to chat");
613
+ }
614
+ ```
615
+
616
+ #### Remove Label from Chat
617
+
618
+ ```typescript
619
+ const result = await client.removeChatLabel("6281234567890", "label-id");
620
+
621
+ if (result.success) {
622
+ console.log("Label removed from chat");
623
+ }
624
+ ```
625
+
626
+ #### Add/Remove Label from Message
627
+
628
+ ```typescript
629
+ // Add label to message
630
+ await client.addMessageLabel("6281234567890", "message-id", "label-id");
631
+
632
+ // Remove label from message
633
+ await client.removeMessageLabel("6281234567890", "message-id", "label-id");
634
+ ```
635
+
636
+ ### Catalog/Product Operations (WhatsApp Business Only)
637
+
638
+ Manage your product catalog and inventory.
639
+
640
+ #### Get Product Catalog
641
+
642
+ ```typescript
643
+ const catalog = await client.getCatalog();
644
+
645
+ if (catalog.success) {
646
+ console.log("Products:", catalog.products);
647
+ console.log("Next page cursor:", catalog.nextCursor);
648
+ }
649
+
650
+ // Get from another business
651
+ const otherCatalog = await client.getCatalog("6289876543210");
652
+
653
+ // With pagination
654
+ const paginated = await client.getCatalog(undefined, 20, catalog.nextCursor);
655
+ ```
656
+
657
+ #### Get Product Collections
658
+
659
+ ```typescript
660
+ const collections = await client.getCollections();
661
+
662
+ collections.forEach(col => {
663
+ console.log("Collection:", col.name);
664
+ console.log("Products:", col.products);
665
+ });
666
+ ```
667
+
668
+ #### Create a Product
669
+
670
+ ```typescript
671
+ const result = await client.createProduct({
672
+ name: "Premium Widget",
673
+ description: "High-quality widget for all your needs",
674
+ price: 1999, // In cents (e.g., $19.99)
675
+ imageUrls: ["https://example.com/product.jpg"],
676
+ isHidden: false,
677
+ retailerId: "SKU-001",
678
+ url: "https://example.com/product",
679
+ });
680
+
681
+ if (result.success) {
682
+ console.log("Product created:", result.productId);
683
+ }
684
+ ```
685
+
686
+ #### Update a Product
687
+
688
+ ```typescript
689
+ const result = await client.updateProduct("product-id", {
690
+ name: "Premium Widget v2",
691
+ price: 2499, // $24.99
692
+ description: "Updated with new features",
693
+ });
694
+
695
+ if (result.success) {
696
+ console.log("Product updated:", result.productId);
697
+ }
698
+ ```
699
+
700
+ #### Delete Products
701
+
702
+ ```typescript
703
+ const result = await client.deleteProducts(["product-id-1", "product-id-2"]);
704
+
705
+ if (result.success) {
706
+ console.log("Deleted count:", result.deletedCount);
707
+ }
708
+ ```
709
+
710
+ ### Newsletter/Channel Features
711
+
712
+ WhatsApp Channels (newsletters) for broadcasting updates.
713
+
714
+ #### Create a Newsletter
715
+
716
+ ```typescript
717
+ const result = await client.createNewsletter(
718
+ "My Tech Updates",
719
+ "Latest technology news and updates"
720
+ );
721
+
722
+ if (result.success) {
723
+ console.log("Newsletter created:", result.newsletterId);
724
+ // Newsletter ID format: "1234567890@newsletter"
725
+ }
726
+ ```
727
+
728
+ #### Get Newsletter Metadata
729
+
730
+ ```typescript
731
+ const meta = await client.getNewsletterMetadata("1234567890@newsletter");
732
+
733
+ if (meta) {
734
+ console.log("Name:", meta.name);
735
+ console.log("Description:", meta.description);
736
+ console.log("Subscribers:", meta.subscribers);
737
+ console.log("Picture:", meta.pictureUrl);
738
+ }
739
+ ```
740
+
741
+ #### Follow/Unfollow Newsletter
742
+
743
+ ```typescript
744
+ // Follow
745
+ const followed = await client.followNewsletter("1234567890@newsletter");
746
+
747
+ // Unfollow
748
+ const unfollowed = await client.unfollowNewsletter("1234567890@newsletter");
749
+ ```
750
+
751
+ #### Mute/Unmute Newsletter
752
+
753
+ ```typescript
754
+ await client.muteNewsletter("1234567890@newsletter");
755
+ await client.unmuteNewsletter("1234567890@newsletter");
756
+ ```
757
+
758
+ #### Update Newsletter
759
+
760
+ ```typescript
761
+ // Update name
762
+ await client.updateNewsletterName("1234567890@newsletter", "New Name");
763
+
764
+ // Update description
765
+ await client.updateNewsletterDescription("1234567890@newsletter", "New description");
766
+
767
+ // Update picture
768
+ await client.updateNewsletterPicture("1234567890@newsletter", "./cover.jpg");
769
+
770
+ // Remove picture
771
+ await client.removeNewsletterPicture("1234567890@newsletter");
772
+ ```
773
+
774
+ #### Fetch Newsletter Messages
775
+
776
+ ```typescript
777
+ const messages = await client.fetchNewsletterMessages(
778
+ "1234567890@newsletter",
779
+ 50, // count
780
+ Date.now(), // since timestamp
781
+ 0 // after cursor (for pagination)
782
+ );
783
+
784
+ if (messages.success) {
785
+ messages.messages?.forEach(msg => {
786
+ console.log("Message:", msg.content);
787
+ console.log("Timestamp:", msg.timestamp);
788
+ });
789
+ }
790
+ ```
791
+
792
+ #### React to Newsletter Message
793
+
794
+ ```typescript
795
+ // Add reaction
796
+ await client.reactToNewsletterMessage("1234567890@newsletter", "msg-id", "👍");
797
+
798
+ // Remove reaction
799
+ await client.reactToNewsletterMessage("1234567890@newsletter", "msg-id", "");
800
+ ```
801
+
802
+ #### Newsletter Subscriber Info
803
+
804
+ ```typescript
805
+ // Get subscriber count
806
+ const info = await client.getNewsletterSubscribers("1234567890@newsletter");
807
+ console.log("Subscribers:", info?.subscribers);
808
+
809
+ // Get admin count
810
+ const adminCount = await client.getNewsletterAdminCount("1234567890@newsletter");
811
+ console.log("Admins:", adminCount);
812
+
813
+ // Subscribe to live updates
814
+ await client.subscribeNewsletterUpdates("1234567890@newsletter");
815
+ ```
816
+
817
+ #### Newsletter Admin Operations
818
+
819
+ ```typescript
820
+ // Change owner
821
+ await client.changeNewsletterOwner("1234567890@newsletter", "new-owner@s.whatsapp.net");
822
+
823
+ // Demote admin
824
+ await client.demoteNewsletterAdmin("1234567890@newsletter", "admin@s.whatsapp.net");
825
+
826
+ // Delete newsletter
827
+ await client.deleteNewsletter("1234567890@newsletter");
828
+ ```
829
+
830
+ ### Contact Management
831
+
832
+ Manage your WhatsApp contacts.
833
+
834
+ #### Add or Edit Contact
835
+
836
+ ```typescript
837
+ const result = await client.addOrEditContact({
838
+ phone: "6281234567890",
839
+ name: "John Doe",
840
+ firstName: "John",
841
+ lastName: "Doe",
842
+ });
843
+
844
+ if (result.success) {
845
+ console.log("Contact saved!");
846
+ }
847
+ ```
848
+
849
+ #### Remove Contact
850
+
851
+ ```typescript
852
+ const result = await client.removeContact("6281234567890");
853
+
854
+ if (result.success) {
855
+ console.log("Contact removed!");
856
+ }
857
+ ```
858
+
859
+ ### Business Bot Example
860
+
861
+ Bot that manages labels and products:
862
+
863
+ ```typescript
864
+ client.on("message", async (msg) => {
865
+ if (msg.fromMe) return;
866
+
867
+ const text = msg.text?.toLowerCase();
868
+
869
+ // Label management
870
+ if (text === "!label vip") {
871
+ const result = await client.addChatLabel(msg.from, "vip-label-id");
872
+ if (result.success) {
873
+ await client.sendText(msg.from, "You've been marked as VIP! ⭐");
874
+ }
875
+ }
876
+
877
+ // Catalog query
878
+ if (text === "!products") {
879
+ const catalog = await client.getCatalog();
880
+ if (catalog.success && catalog.products) {
881
+ let response = "Our products:\n\n";
882
+ catalog.products.forEach(p => {
883
+ response += `${p.name}: $${(p.priceAmount1000! / 100).toFixed(2)}\n`;
884
+ });
885
+ await client.sendText(msg.from, response);
886
+ }
887
+ }
888
+
889
+ // Create product (admin only)
890
+ if (text.startsWith("!addproduct")) {
891
+ const args = text.split(" ");
892
+ // Format: !addproduct <name> <price>
893
+ const name = args.slice(1, -1).join(" ");
894
+ const price = parseInt(args[args.length - 1]) * 100; // Convert to cents
895
+
896
+ const result = await client.createProduct({
897
+ name,
898
+ price,
899
+ });
900
+
901
+ if (result.success) {
902
+ await client.sendText(msg.from, `Product created: ${result.productId}`);
903
+ }
904
+ }
905
+ });
906
+ ```
907
+
908
+ ### Newsletter Bot Example
909
+
910
+ Bot that manages a newsletter:
911
+
912
+ ```typescript
913
+ let newsletterId: string | null = null;
914
+
915
+ // Create newsletter on startup
916
+ client.on("ready", async () => {
917
+ const result = await client.createNewsletter(
918
+ "My Daily Updates",
919
+ "Daily news and updates"
920
+ );
921
+ if (result.success) {
922
+ newsletterId = result.newsletterId || null;
923
+ console.log("Newsletter created:", newsletterId);
924
+ }
925
+ });
926
+
927
+ // Post to newsletter from command
928
+ client.on("message", async (msg) => {
929
+ if (msg.fromMe || !newsletterId) return;
930
+
931
+ const text = msg.text?.toLowerCase();
932
+
933
+ if (text.startsWith("!broadcast ")) {
934
+ const broadcastText = msg.text?.slice(11); // Remove "!broadcast "
935
+ await client.sendText(`${newsletterId}`, broadcastText);
936
+ await client.sendText(msg.from, "Broadcast sent to newsletter!");
937
+ }
938
+
939
+ if (text === "!stats") {
940
+ const info = await client.getNewsletterSubscribers(newsletterId);
941
+ await client.sendText(msg.from, `Subscribers: ${info?.subscribers}`);
942
+ }
943
+ });
944
+ ```
945
+
946
+ ## Receiving Messages
947
+
948
+ ### Message Event
949
+
950
+ Listen for incoming messages:
951
+
952
+ ```typescript
953
+ client.on("message", (message) => {
954
+ console.log("From:", message.from);
955
+ console.log("Text:", message.text);
956
+ console.log("Type:", message.type);
957
+ console.log("Is Group:", message.isGroup);
958
+ console.log("Timestamp:", message.timestamp);
959
+ console.log("From Me:", message.fromMe);
960
+ });
961
+ ```
962
+
963
+ ### Message Structure
964
+
965
+ The `MiawMessage` object contains:
966
+
967
+ ```typescript
968
+ interface MiawMessage {
969
+ id: string; // Unique message ID
970
+ from: string; // Sender WhatsApp ID (JID)
971
+ text?: string; // Message text content
972
+ timestamp: number; // Unix timestamp (seconds)
973
+ isGroup: boolean; // Whether from group chat
974
+ participant?: string; // Group participant ID (if isGroup)
975
+ fromMe: boolean; // Whether sent by bot
976
+ type: string; // Message type: 'text' | 'image' | 'video' | etc.
977
+ raw?: any; // Original Baileys message
978
+ }
979
+ ```
980
+
981
+ ### Filter Messages
982
+
983
+ Common filtering patterns:
984
+
985
+ ```typescript
986
+ client.on("message", async (msg) => {
987
+ // Ignore own messages
988
+ if (msg.fromMe) return;
989
+
990
+ // Only text messages
991
+ if (msg.type !== "text" || !msg.text) return;
992
+
993
+ // Only from specific user
994
+ if (msg.from !== "1234567890@s.whatsapp.net") return;
995
+
996
+ // Only from groups
997
+ if (!msg.isGroup) return;
998
+
999
+ // Process message
1000
+ console.log("Valid message:", msg.text);
1001
+ });
1002
+ ```
1003
+
1004
+ ### Echo Bot Example
1005
+
1006
+ Simple bot that echoes messages:
1007
+
1008
+ ```typescript
1009
+ client.on("message", async (msg) => {
1010
+ if (msg.fromMe || !msg.text) return;
1011
+
1012
+ await client.sendText(msg.from, `Echo: ${msg.text}`);
1013
+ });
1014
+ ```
1015
+
1016
+ ### Command Handler Example
1017
+
1018
+ Bot with command handling:
1019
+
1020
+ ```typescript
1021
+ client.on("message", async (msg) => {
1022
+ if (msg.fromMe || !msg.text) return;
1023
+
1024
+ const text = msg.text.toLowerCase();
1025
+
1026
+ if (text === "/help") {
1027
+ await client.sendText(
1028
+ msg.from,
1029
+ "Available commands:\n" +
1030
+ "/help - Show this message\n" +
1031
+ "/ping - Test bot response\n" +
1032
+ "/time - Get current time"
1033
+ );
1034
+ } else if (text === "/ping") {
1035
+ await client.sendText(msg.from, "Pong! 🏓");
1036
+ } else if (text === "/time") {
1037
+ const time = new Date().toLocaleString();
1038
+ await client.sendText(msg.from, `Current time: ${time}`);
1039
+ }
1040
+ });
1041
+ ```
1042
+
1043
+ ## Connection Management
1044
+
1045
+ ### Connect
1046
+
1047
+ Start the WhatsApp connection:
1048
+
1049
+ ```typescript
1050
+ await client.connect();
1051
+ ```
1052
+
1053
+ ### Disconnect
1054
+
1055
+ Stop the connection and logout:
1056
+
1057
+ ```typescript
1058
+ await client.disconnect();
1059
+ ```
1060
+
1061
+ ### Check Connection State
1062
+
1063
+ ```typescript
1064
+ // Get current state
1065
+ const state = client.getConnectionState();
1066
+ // Returns: 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'qr_required'
1067
+
1068
+ // Check if connected
1069
+ if (client.isConnected()) {
1070
+ console.log("Ready to send messages");
1071
+ }
1072
+ ```
1073
+
1074
+ ### Connection Events
1075
+
1076
+ Monitor connection status:
1077
+
1078
+ ```typescript
1079
+ client.on("connection", (state) => {
1080
+ console.log("Connection state:", state);
1081
+ });
1082
+
1083
+ client.on("ready", () => {
1084
+ console.log("Connected and ready!");
1085
+ });
1086
+
1087
+ client.on("disconnected", (reason) => {
1088
+ console.log("Disconnected:", reason);
1089
+ });
1090
+
1091
+ client.on("reconnecting", (attempt) => {
1092
+ console.log(`Reconnecting... Attempt ${attempt}`);
1093
+ });
1094
+ ```
1095
+
1096
+ ### Auto-Reconnection
1097
+
1098
+ Miaw Core automatically handles reconnection:
1099
+
1100
+ ```typescript
1101
+ const client = new MiawClient({
1102
+ instanceId: "bot",
1103
+ autoReconnect: true, // Enable auto-reconnect
1104
+ maxReconnectAttempts: 10, // Try 10 times
1105
+ reconnectDelay: 5000, // Wait 5s between attempts
1106
+ });
1107
+
1108
+ // Connection drops are handled automatically
1109
+ client.on("reconnecting", (attempt) => {
1110
+ console.log(`Reconnection attempt ${attempt}`);
1111
+ });
1112
+ ```
1113
+
1114
+ ## Multiple Instances
1115
+
1116
+ Run multiple WhatsApp connections in the same process:
1117
+
1118
+ ```typescript
1119
+ import { MiawClient } from "miaw-core";
1120
+
1121
+ // Create multiple instances
1122
+ const bot1 = new MiawClient({
1123
+ instanceId: "customer-support",
1124
+ });
1125
+
1126
+ const bot2 = new MiawClient({
1127
+ instanceId: "sales-bot",
1128
+ });
1129
+
1130
+ const bot3 = new MiawClient({
1131
+ instanceId: "notifications",
1132
+ });
1133
+
1134
+ // Each has separate QR code and session
1135
+ bot1.on("qr", (qr) => console.log("Bot 1 QR:", qr));
1136
+ bot2.on("qr", (qr) => console.log("Bot 2 QR:", qr));
1137
+ bot3.on("qr", (qr) => console.log("Bot 3 QR:", qr));
1138
+
1139
+ // Start all instances
1140
+ await Promise.all([bot1.connect(), bot2.connect(), bot3.connect()]);
1141
+
1142
+ // Each operates independently
1143
+ bot1.on("message", (msg) => {
1144
+ console.log("Bot 1 received:", msg.text);
1145
+ });
1146
+
1147
+ bot2.on("message", (msg) => {
1148
+ console.log("Bot 2 received:", msg.text);
1149
+ });
1150
+ ```
1151
+
1152
+ ## Session Management
1153
+
1154
+ ### Session Storage Location
1155
+
1156
+ Sessions are stored in the filesystem:
1157
+
1158
+ ```
1159
+ sessions/
1160
+ ├── bot-1/
1161
+ │ ├── creds.json
1162
+ │ └── app-state-sync-*.json
1163
+ ├── bot-2/
1164
+ │ ├── creds.json
1165
+ │ └── app-state-sync-*.json
1166
+ └── bot-3/
1167
+ ├── creds.json
1168
+ └── app-state-sync-*.json
1169
+ ```
1170
+
1171
+ ### Custom Session Path
1172
+
1173
+ ```typescript
1174
+ const client = new MiawClient({
1175
+ instanceId: "my-bot",
1176
+ sessionPath: "/var/lib/whatsapp/sessions",
1177
+ });
1178
+ // Session will be stored in: /var/lib/whatsapp/sessions/my-bot/
1179
+ ```
1180
+
1181
+ ### Session Persistence
1182
+
1183
+ Sessions persist across restarts:
1184
+
1185
+ ```typescript
1186
+ // First run
1187
+ const client = new MiawClient({ instanceId: "bot" });
1188
+ await client.connect(); // QR code required
1189
+ // Session saved automatically
1190
+
1191
+ // Next run (restart app)
1192
+ const client = new MiawClient({ instanceId: "bot" });
1193
+ await client.connect(); // No QR code! Uses saved session
1194
+ ```
1195
+
1196
+ ### Clear Session (Logout)
1197
+
1198
+ To logout and start fresh:
1199
+
1200
+ ```bash
1201
+ # Manual deletion
1202
+ rm -rf ./sessions/my-bot/
1203
+
1204
+ # Or programmatically
1205
+ import { rmSync } from 'fs';
1206
+ rmSync('./sessions/my-bot', { recursive: true, force: true });
1207
+ ```
1208
+
1209
+ ## Event Reference
1210
+
1211
+ ### Available Events
1212
+
1213
+ | Event | Parameters | Description |
1214
+ | --------------- | -------------------------- | --------------------------- |
1215
+ | `qr` | `(qrCode: string)` | QR code needs to be scanned |
1216
+ | `ready` | `()` | Client connected and ready |
1217
+ | `message` | `(message: MiawMessage)` | New message received |
1218
+ | `connection` | `(state: ConnectionState)` | Connection state changed |
1219
+ | `disconnected` | `(reason?: string)` | Client disconnected |
1220
+ | `reconnecting` | `(attempt: number)` | Attempting to reconnect |
1221
+ | `error` | `(error: Error)` | Error occurred |
1222
+ | `session_saved` | `()` | Session credentials saved |
1223
+
1224
+ ### Event Examples
1225
+
1226
+ ```typescript
1227
+ // QR Code
1228
+ client.on("qr", (qr) => {
1229
+ console.log("Scan this:", qr);
1230
+ });
1231
+
1232
+ // Ready
1233
+ client.on("ready", () => {
1234
+ console.log("Connected!");
1235
+ });
1236
+
1237
+ // Message
1238
+ client.on("message", (msg) => {
1239
+ console.log("New message:", msg.text);
1240
+ });
1241
+
1242
+ // Connection State
1243
+ client.on("connection", (state) => {
1244
+ console.log("State:", state);
1245
+ });
1246
+
1247
+ // Disconnected
1248
+ client.on("disconnected", (reason) => {
1249
+ console.log("Lost connection:", reason);
1250
+ });
1251
+
1252
+ // Reconnecting
1253
+ client.on("reconnecting", (attempt) => {
1254
+ console.log(`Reconnect attempt #${attempt}`);
1255
+ });
1256
+
1257
+ // Error
1258
+ client.on("error", (error) => {
1259
+ console.error("Error:", error.message);
1260
+ });
1261
+
1262
+ // Session Saved
1263
+ client.on("session_saved", () => {
1264
+ console.log("Session persisted");
1265
+ });
1266
+ ```
1267
+
1268
+ ## Error Handling
1269
+
1270
+ ### Send Message Errors
1271
+
1272
+ ```typescript
1273
+ const result = await client.sendText("1234567890", "Hello");
1274
+
1275
+ if (!result.success) {
1276
+ console.error("Failed to send:", result.error);
1277
+
1278
+ // Handle specific errors
1279
+ if (result.error?.includes("not connected")) {
1280
+ console.log("Wait for connection...");
1281
+ }
1282
+ }
1283
+ ```
1284
+
1285
+ ### Global Error Handler
1286
+
1287
+ ```typescript
1288
+ client.on("error", (error) => {
1289
+ console.error("Client error:", error.message);
1290
+
1291
+ // Log to monitoring service
1292
+ // Send alert
1293
+ // etc.
1294
+ });
1295
+ ```
1296
+
1297
+ ### Connection Errors
1298
+
1299
+ ```typescript
1300
+ client.on("disconnected", (reason) => {
1301
+ if (reason === "loggedOut") {
1302
+ console.log("Need to re-authenticate");
1303
+ // Delete session and restart
1304
+ }
1305
+ });
1306
+ ```
1307
+
1308
+ ### Try-Catch Pattern
1309
+
1310
+ ```typescript
1311
+ try {
1312
+ await client.connect();
1313
+ } catch (error) {
1314
+ console.error("Failed to connect:", error);
1315
+ // Handle startup errors
1316
+ }
1317
+ ```
1318
+
1319
+ ## TypeScript Usage
1320
+
1321
+ Miaw Core is written in TypeScript with full type definitions:
1322
+
1323
+ ### Import Types
1324
+
1325
+ ```typescript
1326
+ import {
1327
+ MiawClient,
1328
+ MiawMessage,
1329
+ MiawClientOptions,
1330
+ ConnectionState,
1331
+ SendMessageResult,
1332
+ } from "miaw-core";
1333
+ ```
1334
+
1335
+ ### Type-Safe Configuration
1336
+
1337
+ ```typescript
1338
+ const options: MiawClientOptions = {
1339
+ instanceId: "bot",
1340
+ sessionPath: "./sessions",
1341
+ debug: true,
1342
+ autoReconnect: true,
1343
+ maxReconnectAttempts: 10,
1344
+ reconnectDelay: 5000,
1345
+ };
1346
+
1347
+ const client = new MiawClient(options);
1348
+ ```
1349
+
1350
+ ### Type-Safe Event Handlers
1351
+
1352
+ ```typescript
1353
+ client.on("message", (msg: MiawMessage) => {
1354
+ // TypeScript knows the structure
1355
+ console.log(msg.text); // string | undefined
1356
+ console.log(msg.timestamp); // number
1357
+ console.log(msg.isGroup); // boolean
1358
+ });
1359
+
1360
+ client.on("connection", (state: ConnectionState) => {
1361
+ // 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'qr_required'
1362
+ if (state === "connected") {
1363
+ console.log("Ready!");
1364
+ }
1365
+ });
1366
+ ```
1367
+
1368
+ ### Type-Safe Result Handling
1369
+
1370
+ ```typescript
1371
+ const result: SendMessageResult = await client.sendText("...", "Hello");
1372
+
1373
+ if (result.success) {
1374
+ // TypeScript knows messageId exists here
1375
+ console.log(result.messageId);
1376
+ } else {
1377
+ // TypeScript knows error exists here
1378
+ console.error(result.error);
1379
+ }
1380
+ ```
1381
+
1382
+ ## Complete Example
1383
+
1384
+ For a full-featured bot demonstrating all current capabilities, see:
1385
+
1386
+ **[examples/simple-bot.ts](./examples/simple-bot.ts)**
1387
+
1388
+ The example includes:
1389
+
1390
+ - QR code authentication handling
1391
+ - Message receiving and command processing
1392
+ - Connection state monitoring
1393
+ - Auto-reconnection handling
1394
+ - Error handling
1395
+ - Graceful shutdown
1396
+
1397
+ ---
1398
+
1399
+ For feature roadmap and planned capabilities, see [ROADMAP.md](./ROADMAP.md).