miaw-core 1.0.0 → 1.1.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/CHANGELOG.md +84 -0
- package/README.md +94 -7
- package/babel.config.js +2 -2
- package/dist/client/MiawClient.d.ts +98 -8
- package/dist/client/MiawClient.d.ts.map +1 -1
- package/dist/client/MiawClient.js +1056 -546
- package/dist/client/MiawClient.js.map +1 -1
- package/dist/handlers/AuthHandler.d.ts +5 -0
- package/dist/handlers/AuthHandler.d.ts.map +1 -1
- package/dist/handlers/AuthHandler.js +21 -10
- package/dist/handlers/AuthHandler.js.map +1 -1
- package/dist/handlers/MessageHandler.d.ts +1 -1
- package/dist/handlers/MessageHandler.d.ts.map +1 -1
- package/dist/handlers/MessageHandler.js +21 -25
- package/dist/handlers/MessageHandler.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -7
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +129 -24
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -7
- package/dist/types/index.js.map +1 -1
- package/docs/BAILEYS_MIGRATION_v7.md +220 -0
- package/docs/BAILEYS_VS_MIAW_COMPARISON.md +522 -0
- package/docs/MIGRATION.md +90 -18
- package/docs/TEST_COVERAGE_ANALYSIS.md +256 -0
- package/docs/USAGE.md +68 -11
- package/eslint.config.js +22 -0
- package/package.json +23 -6
- package/tsconfig.json +6 -5
- package/tsconfig.test.json +3 -1
- package/dist/utils/storage.d.ts +0 -25
- package/dist/utils/storage.d.ts.map +0 -1
- package/dist/utils/storage.js +0 -60
- package/dist/utils/storage.js.map +0 -1
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# MiawClient Test Coverage Analysis
|
|
2
|
+
|
|
3
|
+
**Generated:** January 2, 2026
|
|
4
|
+
**Source Files Analyzed:**
|
|
5
|
+
|
|
6
|
+
- `src/client/MiawClient.ts` - Main client implementation
|
|
7
|
+
- `tests/interactive-test.ts` - Interactive manual test suite
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
| Category | Total Methods | Covered | Coverage |
|
|
12
|
+
| ------------------ | ------------- | ------- | -------- |
|
|
13
|
+
| Core Client | 6 | 5 | 83% |
|
|
14
|
+
| Basic GET Ops | 6 | 6 | 100% |
|
|
15
|
+
| Messaging | 12 | 11 | 92% |
|
|
16
|
+
| Contact/Validation | 5 | 5 | 100% |
|
|
17
|
+
| Group Management | 16 | 13 | 81% |
|
|
18
|
+
| Profile Management | 4 | 4 | 100% |
|
|
19
|
+
| Business - Labels | 5 | 4 | 80% |
|
|
20
|
+
| Business - Catalog | 5 | 5 | 100% |
|
|
21
|
+
| Newsletter/Channel | 21 | 6 | 29% |
|
|
22
|
+
| Contact Management | 2 | 2 | 100% |
|
|
23
|
+
| UX Features | 5 | 5 | 100% |
|
|
24
|
+
| LID/JID Utilities | 5 | 0 | 0% |
|
|
25
|
+
| **TOTAL** | **92** | **66** | **72%** |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Detailed Coverage Table
|
|
30
|
+
|
|
31
|
+
### Core Client (83% covered)
|
|
32
|
+
|
|
33
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
34
|
+
| ---------------------- | ---- | --------------------------------------------- | ------------- | -------------- |
|
|
35
|
+
| `constructor()` | - | "Constructor - Create client" | Core Client | ✅ Covered |
|
|
36
|
+
| `connect()` | 173 | "connect() - Connect to WhatsApp" | Core Client | ✅ Covered |
|
|
37
|
+
| `dispose()` | 641 | - | - | ❌ Not Covered |
|
|
38
|
+
| `disconnect()` | 4040 | "disconnect() - Disconnect from WhatsApp" | Final | ✅ Covered |
|
|
39
|
+
| `getConnectionState()` | 4058 | "getConnectionState() - Get connection state" | Core Client | ✅ Covered |
|
|
40
|
+
| `getInstanceId()` | 4065 | "getInstanceId() - Get instance ID" | Core Client | ✅ Covered |
|
|
41
|
+
| `isConnected()` | 4072 | "isConnected() - Check if connected" | Core Client | ✅ Covered |
|
|
42
|
+
|
|
43
|
+
### Basic GET Operations (100% covered)
|
|
44
|
+
|
|
45
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
46
|
+
| -------------------- | ---- | ------------------------------------------ | ------------- | ---------- |
|
|
47
|
+
| `getOwnProfile()` | 1336 | "getOwnProfile() - Get your profile" | Basic GET Ops | ✅ Covered |
|
|
48
|
+
| `fetchAllContacts()` | 1263 | "fetchAllContacts() - Get all contacts" | Basic GET Ops | ✅ Covered |
|
|
49
|
+
| `fetchAllGroups()` | 1284 | "fetchAllGroups() - Get all groups" | Basic GET Ops | ✅ Covered |
|
|
50
|
+
| `fetchAllChats()` | 1483 | "fetchAllChats() - Get all chats" | Basic GET Ops | ✅ Covered |
|
|
51
|
+
| `getChatMessages()` | 1460 | "getChatMessages(jid) - Get chat messages" | Basic GET Ops | ✅ Covered |
|
|
52
|
+
| `fetchAllLabels()` | 1430 | "fetchAllLabels() - Get all labels" | Business | ✅ Covered |
|
|
53
|
+
|
|
54
|
+
### Messaging (92% covered)
|
|
55
|
+
|
|
56
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
57
|
+
| ---------------------- | ---- | --------------------------------------- | ------------- | -------------- |
|
|
58
|
+
| `sendText()` | 723 | "sendText() - Send text message" | Messaging | ✅ Covered |
|
|
59
|
+
| `sendImage()` | 767 | "sendImage() - Send image" | Messaging | ✅ Covered |
|
|
60
|
+
| `sendDocument()` | 822 | "sendDocument() - Send document" | Messaging | ⚠️ Skipped |
|
|
61
|
+
| `sendVideo()` | 892 | "sendVideo() - Send video" | Messaging | ⚠️ Skipped |
|
|
62
|
+
| `sendAudio()` | 949 | "sendAudio() - Send audio" | Messaging | ⚠️ Skipped |
|
|
63
|
+
| `downloadMedia()` | 1009 | "downloadMedia() - Download media" | Messaging | ✅ Covered |
|
|
64
|
+
| `sendReaction()` | 1579 | "sendReaction() - Send reaction" | Messaging | ✅ Covered |
|
|
65
|
+
| `removeReaction()` | 1630 | "removeReaction() - Remove reaction" | Messaging | ✅ Covered |
|
|
66
|
+
| `forwardMessage()` | 1640 | "forwardMessage() - Forward message" | Messaging | ✅ Covered |
|
|
67
|
+
| `editMessage()` | 1686 | "editMessage() - Edit message" | Messaging | ✅ Covered |
|
|
68
|
+
| `deleteMessage()` | 1739 | "deleteMessage() - Delete for everyone" | Messaging | ✅ Covered |
|
|
69
|
+
| `deleteMessageForMe()` | 1785 | - | - | ❌ Not Covered |
|
|
70
|
+
|
|
71
|
+
### Contact & Validation (100% covered)
|
|
72
|
+
|
|
73
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
74
|
+
| ---------------------- | ---- | --------------------------------------------- | ------------- | ---------- |
|
|
75
|
+
| `checkNumber()` | 1054 | "checkNumber() - Check if number on WhatsApp" | Contacts | ✅ Covered |
|
|
76
|
+
| `checkNumbers()` | 1090 | "checkNumbers() - Batch check numbers" | Contacts | ✅ Covered |
|
|
77
|
+
| `getContactInfo()` | 1125 | "getContactInfo() - Get contact info" | Contacts | ✅ Covered |
|
|
78
|
+
| `getBusinessProfile()` | 1183 | "getBusinessProfile() - Get business profile" | Contacts | ✅ Covered |
|
|
79
|
+
| `getProfilePicture()` | 1225 | "getProfilePicture() - Get profile picture" | Contacts | ✅ Covered |
|
|
80
|
+
|
|
81
|
+
### Group Management (81% covered)
|
|
82
|
+
|
|
83
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
84
|
+
| -------------------------- | ---- | ----------------------------------------------------- | ------------- | -------------- |
|
|
85
|
+
| `getGroupInfo()` | 1509 | "getGroupInfo() - Get group metadata" | Group Mgmt | ✅ Covered |
|
|
86
|
+
| `getGroupParticipants()` | 1562 | "getGroupParticipants() - Get group members" | Group Mgmt | ✅ Covered |
|
|
87
|
+
| `createGroup()` | 2027 | "createGroup() - Create new group" | Group Mgmt | ✅ Covered |
|
|
88
|
+
| `addParticipants()` | 2094 | "addParticipants() - Add members to group" | Group Mgmt | ✅ Covered |
|
|
89
|
+
| `removeParticipants()` | 2120 | "removeParticipants() - Remove members (DESTRUCTIVE)" | Group Mgmt | ✅ Covered |
|
|
90
|
+
| `leaveGroup()` | 2145 | "leaveGroup() - Leave group (DESTRUCTIVE)" | Group Mgmt | ✅ Covered |
|
|
91
|
+
| `promoteToAdmin()` | 2179 | "promoteToAdmin() - Promote member to admin" | Group Mgmt | ✅ Covered |
|
|
92
|
+
| `demoteFromAdmin()` | 2205 | "demoteFromAdmin() - Demote admin" | Group Mgmt | ✅ Covered |
|
|
93
|
+
| `updateGroupName()` | 2231 | "updateGroupName() - Change group name" | Group Mgmt | ✅ Covered |
|
|
94
|
+
| `updateGroupDescription()` | 2268 | "updateGroupDescription() - Set group description" | Group Mgmt | ✅ Covered |
|
|
95
|
+
| `updateGroupPicture()` | 2305 | "updateGroupPicture() - Change group picture" | Group Mgmt | ⚠️ Skipped |
|
|
96
|
+
| `getGroupInviteLink()` | 2342 | "getGroupInviteLink() - Get invite link" | Group Mgmt | ✅ Covered |
|
|
97
|
+
| `revokeGroupInvite()` | 2371 | - | - | ❌ Not Covered |
|
|
98
|
+
| `acceptGroupInvite()` | 2400 | "acceptGroupInvite() - Join via invite" | Group Mgmt | ✅ Covered |
|
|
99
|
+
| `getGroupInviteInfo()` | 2431 | - | - | ❌ Not Covered |
|
|
100
|
+
|
|
101
|
+
### Profile Management (100% covered)
|
|
102
|
+
|
|
103
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
104
|
+
| ------------------------ | ---- | --------------------------------------------------------------- | ------------- | ---------- |
|
|
105
|
+
| `updateProfilePicture()` | 2475 | "updateProfilePicture() - Update own profile picture" | Profile Mgmt | ⚠️ Skipped |
|
|
106
|
+
| `removeProfilePicture()` | 2511 | "removeProfilePicture() - Remove profile picture (DESTRUCTIVE)" | Profile Mgmt | ✅ Covered |
|
|
107
|
+
| `updateProfileName()` | 2545 | "updateProfileName() - Update display name" | Profile Mgmt | ✅ Covered |
|
|
108
|
+
| `updateProfileStatus()` | 2578 | "updateProfileStatus() - Update About text" | Profile Mgmt | ✅ Covered |
|
|
109
|
+
|
|
110
|
+
### Business - Labels (80% covered)
|
|
111
|
+
|
|
112
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
113
|
+
| ---------------------- | ---- | -------------------------------------------- | ------------- | -------------- |
|
|
114
|
+
| `addLabel()` | 2612 | "addLabel() - Create new label" | Business | ✅ Covered |
|
|
115
|
+
| `addChatLabel()` | 2676 | "addChatLabel() - Add label to chat" | Business | ✅ Covered |
|
|
116
|
+
| `removeChatLabel()` | 2711 | "removeChatLabel() - Remove label from chat" | Business | ✅ Covered |
|
|
117
|
+
| `addMessageLabel()` | 2747 | "addMessageLabel() - Add label to message" | Business | ⚠️ Skipped |
|
|
118
|
+
| `removeMessageLabel()` | 2784 | - | - | ❌ Not Covered |
|
|
119
|
+
|
|
120
|
+
### Business - Catalog (100% covered)
|
|
121
|
+
|
|
122
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
123
|
+
| ------------------ | ---- | ---------------------------------------------- | ------------- | ---------- |
|
|
124
|
+
| `getCatalog()` | 2825 | "getCatalog() - Fetch product catalog" | Business | ✅ Covered |
|
|
125
|
+
| `getCollections()` | 2887 | "getCollections() - Get catalog collections" | Business | ✅ Covered |
|
|
126
|
+
| `createProduct()` | 2935 | "createProduct() - Add new product" | Business | ✅ Covered |
|
|
127
|
+
| `updateProduct()` | 3002 | "updateProduct() - Modify product" | Business | ✅ Covered |
|
|
128
|
+
| `deleteProducts()` | 3068 | "deleteProducts() - Remove products (CLEANUP)" | Business | ✅ Covered |
|
|
129
|
+
|
|
130
|
+
### Newsletter/Channel (29% covered)
|
|
131
|
+
|
|
132
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
133
|
+
| ------------------------------- | ---- | ------------------------------------------------ | ------------- | -------------- |
|
|
134
|
+
| `sendNewsletterMessage()` | 3110 | "sendNewsletterMessage() - Send text to channel" | Newsletter | ✅ Covered |
|
|
135
|
+
| `sendNewsletterImage()` | 3153 | "sendNewsletterImage() - Send image to channel" | Newsletter | ✅ Covered |
|
|
136
|
+
| `sendNewsletterVideo()` | 3200 | - | - | ❌ Not Covered |
|
|
137
|
+
| `createNewsletter()` | 3245 | "createNewsletter() - Create newsletter/channel" | Newsletter | ✅ Covered |
|
|
138
|
+
| `getNewsletterMetadata()` | 3330 | "getNewsletterMetadata() - Get newsletter info" | Newsletter | ✅ Covered |
|
|
139
|
+
| `followNewsletter()` | 3381 | "followNewsletter() - Follow/subscribe" | Newsletter | ✅ Covered |
|
|
140
|
+
| `unfollowNewsletter()` | 3410 | - | - | ❌ Not Covered |
|
|
141
|
+
| `muteNewsletter()` | 3439 | - | - | ❌ Not Covered |
|
|
142
|
+
| `unmuteNewsletter()` | 3468 | - | - | ❌ Not Covered |
|
|
143
|
+
| `updateNewsletterName()` | 3498 | - | - | ❌ Not Covered |
|
|
144
|
+
| `updateNewsletterDescription()` | 3531 | - | - | ❌ Not Covered |
|
|
145
|
+
| `updateNewsletterPicture()` | 3564 | - | - | ❌ Not Covered |
|
|
146
|
+
| `removeNewsletterPicture()` | 3597 | - | - | ❌ Not Covered |
|
|
147
|
+
| `reactToNewsletterMessage()` | 3628 | - | - | ❌ Not Covered |
|
|
148
|
+
| `fetchNewsletterMessages()` | 3664 | - | - | ❌ Not Covered |
|
|
149
|
+
| `subscribeNewsletterUpdates()` | 3725 | - | - | ❌ Not Covered |
|
|
150
|
+
| `getNewsletterSubscribers()` | 3754 | - | - | ❌ Not Covered |
|
|
151
|
+
| `getNewsletterAdminCount()` | 3789 | - | - | ❌ Not Covered |
|
|
152
|
+
| `changeNewsletterOwner()` | 3819 | - | - | ❌ Not Covered |
|
|
153
|
+
| `demoteNewsletterAdmin()` | 3853 | - | - | ❌ Not Covered |
|
|
154
|
+
| `deleteNewsletter()` | 3886 | "deleteNewsletter() - Delete newsletter" | Newsletter | ✅ Covered |
|
|
155
|
+
|
|
156
|
+
### Contact Management (100% covered)
|
|
157
|
+
|
|
158
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
159
|
+
| -------------------- | ---- | -------------------------------------------- | ------------- | ---------- |
|
|
160
|
+
| `addOrEditContact()` | 3919 | "addOrEditContact() - Add or update contact" | Contacts | ✅ Covered |
|
|
161
|
+
| `removeContact()` | 3965 | "removeContact() - Remove contact" | Contacts | ✅ Covered |
|
|
162
|
+
|
|
163
|
+
### UX Features (100% covered)
|
|
164
|
+
|
|
165
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
166
|
+
| --------------------- | ---- | ----------------------------------------------------- | ------------- | ------------------------------------------ |
|
|
167
|
+
| `markAsRead()` | 1838 | "markAsRead() - Mark message as read" | UX Features | ✅ Covered |
|
|
168
|
+
| `sendTyping()` | 1866 | "sendTyping() - Send typing indicator" | UX Features | ✅ Covered |
|
|
169
|
+
| `sendRecording()` | 1889 | "sendRecording() - Send recording indicator" | UX Features | ✅ Covered |
|
|
170
|
+
| `stopTyping()` | 1912 | - | - | ❌ Not Covered (but tested via sendTyping) |
|
|
171
|
+
| `setPresence()` | 1935 | "setPresence() - Set online/offline status" | UX Features | ✅ Covered |
|
|
172
|
+
| `subscribePresence()` | 1958 | "subscribePresence() - Subscribe to presence updates" | UX Features | ✅ Covered |
|
|
173
|
+
|
|
174
|
+
### LID/JID Utility Methods (0% covered - internal use)
|
|
175
|
+
|
|
176
|
+
| Method | Line | Interactive Test | Test Category | Status |
|
|
177
|
+
| ---------------------- | ---- | ---------------- | ------------- | -------------- |
|
|
178
|
+
| `resolveLidToJid()` | 567 | - | - | ❌ Not Covered |
|
|
179
|
+
| `getPhoneFromJid()` | 579 | - | - | ❌ Not Covered |
|
|
180
|
+
| `registerLidMapping()` | 593 | - | - | ❌ Not Covered |
|
|
181
|
+
| `getLidMappings()` | 605 | - | - | ❌ Not Covered |
|
|
182
|
+
| `getLidCacheSize()` | 617 | - | - | ❌ Not Covered |
|
|
183
|
+
| `clearLidCache()` | 624 | - | - | ❌ Not Covered |
|
|
184
|
+
| `clearSession()` | 634 | - | - | ❌ Not Covered |
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Legend
|
|
189
|
+
|
|
190
|
+
| Status | Description |
|
|
191
|
+
| -------------- | --------------------------------------------------------------- |
|
|
192
|
+
| ✅ Covered | Method has a dedicated test in interactive-test.ts |
|
|
193
|
+
| ⚠️ Skipped | Test exists but auto-skips (requires manual assets/interaction) |
|
|
194
|
+
| ❌ Not Covered | No test exists for this method |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Recommendations
|
|
199
|
+
|
|
200
|
+
### High Priority (Core Functionality)
|
|
201
|
+
|
|
202
|
+
1. **`deleteMessageForMe()`** - Important messaging feature, no test
|
|
203
|
+
2. **`dispose()`** - Resource cleanup, should be tested
|
|
204
|
+
3. **`stopTyping()`** - Related to sendTyping but never explicitly tested
|
|
205
|
+
|
|
206
|
+
### Medium Priority (Group & Newsletter)
|
|
207
|
+
|
|
208
|
+
4. **`revokeGroupInvite()`** - Paired with getGroupInviteLink
|
|
209
|
+
5. **`getGroupInviteInfo()`** - Preview before joining
|
|
210
|
+
6. **Newsletter methods** (15 uncovered) - Low coverage at 29%:
|
|
211
|
+
- `sendNewsletterVideo()`
|
|
212
|
+
- `unfollowNewsletter()`
|
|
213
|
+
- `muteNewsletter()` / `unmuteNewsletter()`
|
|
214
|
+
- `updateNewsletterName()` / `updateNewsletterDescription()`
|
|
215
|
+
- `updateNewsletterPicture()` / `removeNewsletterPicture()`
|
|
216
|
+
- `reactToNewsletterMessage()`
|
|
217
|
+
- `fetchNewsletterMessages()`
|
|
218
|
+
- `subscribeNewsletterUpdates()`
|
|
219
|
+
- `getNewsletterSubscribers()` / `getNewsletterAdminCount()`
|
|
220
|
+
- `changeNewsletterOwner()` / `demoteNewsletterAdmin()`
|
|
221
|
+
|
|
222
|
+
### Low Priority (Labels & Utilities)
|
|
223
|
+
|
|
224
|
+
7. **`removeMessageLabel()`** - Paired with addMessageLabel
|
|
225
|
+
8. **LID/JID utilities** - Internal use, can be covered by unit tests
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Test Categories Summary
|
|
230
|
+
|
|
231
|
+
| Test Category | Tests Count | Methods Covered |
|
|
232
|
+
| ------------- | ----------- | --------------- |
|
|
233
|
+
| Prerequisites | 1 | 0 (setup only) |
|
|
234
|
+
| Core Client | 5 | 5 |
|
|
235
|
+
| Basic GET Ops | 5 | 6 |
|
|
236
|
+
| Messaging | 11 | 11 |
|
|
237
|
+
| Contacts | 7 | 7 |
|
|
238
|
+
| Group Mgmt | 13 | 13 |
|
|
239
|
+
| Profile Mgmt | 4 | 4 |
|
|
240
|
+
| Business | 10 | 9 |
|
|
241
|
+
| Newsletter | 6 | 6 |
|
|
242
|
+
| UX Features | 5 | 5 |
|
|
243
|
+
| Final | 1 | 1 |
|
|
244
|
+
| **TOTAL** | **68** | **66** |
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Conclusion
|
|
249
|
+
|
|
250
|
+
The interactive test suite provides **72% coverage** of MiawClient's public API. The main gap is in **Newsletter/Channel features** (29% coverage), with 15 methods lacking tests. Core functionality (messaging, contacts, groups, profile) has excellent coverage at 80-100%.
|
|
251
|
+
|
|
252
|
+
For production readiness, consider:
|
|
253
|
+
|
|
254
|
+
1. Adding tests for uncovered newsletter methods
|
|
255
|
+
2. Adding unit tests for LID/JID utility methods
|
|
256
|
+
3. Converting skipped tests (sendDocument, sendVideo, sendAudio) to use test fixtures
|
package/docs/USAGE.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
This document covers all current capabilities of Miaw Core. It will be updated as new features are added.
|
|
4
4
|
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- **Node.js** >= 18.0.0
|
|
8
|
+
- **ESM** - This package is ESM-only (uses `"type": "module"`)
|
|
9
|
+
|
|
5
10
|
## Table of Contents
|
|
6
11
|
|
|
7
12
|
- [Installation](#installation)
|
|
@@ -344,7 +349,9 @@ const results = await client.removeParticipants("123456789@g.us", [
|
|
|
344
349
|
"1234567890",
|
|
345
350
|
]);
|
|
346
351
|
|
|
347
|
-
results.forEach((r) =>
|
|
352
|
+
results.forEach((r) =>
|
|
353
|
+
console.log(`${r.jid}: ${r.success ? "Removed" : r.status}`)
|
|
354
|
+
);
|
|
348
355
|
```
|
|
349
356
|
|
|
350
357
|
### Leave Group
|
|
@@ -409,7 +416,10 @@ Change the group profile picture:
|
|
|
409
416
|
await client.updateGroupPicture("123456789@g.us", "./group-icon.jpg");
|
|
410
417
|
|
|
411
418
|
// From URL
|
|
412
|
-
await client.updateGroupPicture(
|
|
419
|
+
await client.updateGroupPicture(
|
|
420
|
+
"123456789@g.us",
|
|
421
|
+
"https://example.com/image.jpg"
|
|
422
|
+
);
|
|
413
423
|
|
|
414
424
|
// From Buffer
|
|
415
425
|
const imageBuffer = fs.readFileSync("./image.png");
|
|
@@ -485,7 +495,9 @@ client.on("message", async (msg) => {
|
|
|
485
495
|
if (info) {
|
|
486
496
|
await client.sendText(
|
|
487
497
|
groupJid,
|
|
488
|
-
`Group: ${info.name}\nMembers: ${info.participantCount}\nDescription: ${
|
|
498
|
+
`Group: ${info.name}\nMembers: ${info.participantCount}\nDescription: ${
|
|
499
|
+
info.description || "None"
|
|
500
|
+
}`
|
|
489
501
|
);
|
|
490
502
|
}
|
|
491
503
|
}
|
|
@@ -505,7 +517,9 @@ Change your profile picture:
|
|
|
505
517
|
const result = await client.updateProfilePicture("./my-avatar.jpg");
|
|
506
518
|
|
|
507
519
|
// From URL
|
|
508
|
-
const result2 = await client.updateProfilePicture(
|
|
520
|
+
const result2 = await client.updateProfilePicture(
|
|
521
|
+
"https://example.com/avatar.jpg"
|
|
522
|
+
);
|
|
509
523
|
|
|
510
524
|
// From Buffer
|
|
511
525
|
const imageBuffer = fs.readFileSync("./avatar.png");
|
|
@@ -659,7 +673,7 @@ const paginated = await client.getCatalog(undefined, 20, catalog.nextCursor);
|
|
|
659
673
|
```typescript
|
|
660
674
|
const collections = await client.getCollections();
|
|
661
675
|
|
|
662
|
-
collections.forEach(col => {
|
|
676
|
+
collections.forEach((col) => {
|
|
663
677
|
console.log("Collection:", col.name);
|
|
664
678
|
console.log("Products:", col.products);
|
|
665
679
|
});
|
|
@@ -711,6 +725,8 @@ if (result.success) {
|
|
|
711
725
|
|
|
712
726
|
WhatsApp Channels (newsletters) for broadcasting updates.
|
|
713
727
|
|
|
728
|
+
> **Limitations:** WhatsApp does not provide APIs to list subscribed/owned newsletters or get channel member lists. Channels are one-way broadcasts - you can only get subscriber count.
|
|
729
|
+
|
|
714
730
|
#### Create a Newsletter
|
|
715
731
|
|
|
716
732
|
```typescript
|
|
@@ -725,6 +741,36 @@ if (result.success) {
|
|
|
725
741
|
}
|
|
726
742
|
```
|
|
727
743
|
|
|
744
|
+
#### Send Message to Newsletter
|
|
745
|
+
|
|
746
|
+
You must be an admin/owner of the newsletter to send messages.
|
|
747
|
+
|
|
748
|
+
```typescript
|
|
749
|
+
// Send text message
|
|
750
|
+
const textResult = await client.sendNewsletterMessage(
|
|
751
|
+
"1234567890@newsletter",
|
|
752
|
+
"Hello subscribers! Here's today's update..."
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
if (textResult.success) {
|
|
756
|
+
console.log("Message sent:", textResult.messageId);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Send image to newsletter
|
|
760
|
+
const imageResult = await client.sendNewsletterImage(
|
|
761
|
+
"1234567890@newsletter",
|
|
762
|
+
"./announcement.jpg",
|
|
763
|
+
"Check out our latest announcement!"
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
// Send video to newsletter
|
|
767
|
+
const videoResult = await client.sendNewsletterVideo(
|
|
768
|
+
"1234567890@newsletter",
|
|
769
|
+
"./update-video.mp4",
|
|
770
|
+
"Watch our weekly update video"
|
|
771
|
+
);
|
|
772
|
+
```
|
|
773
|
+
|
|
728
774
|
#### Get Newsletter Metadata
|
|
729
775
|
|
|
730
776
|
```typescript
|
|
@@ -762,7 +808,10 @@ await client.unmuteNewsletter("1234567890@newsletter");
|
|
|
762
808
|
await client.updateNewsletterName("1234567890@newsletter", "New Name");
|
|
763
809
|
|
|
764
810
|
// Update description
|
|
765
|
-
await client.updateNewsletterDescription(
|
|
811
|
+
await client.updateNewsletterDescription(
|
|
812
|
+
"1234567890@newsletter",
|
|
813
|
+
"New description"
|
|
814
|
+
);
|
|
766
815
|
|
|
767
816
|
// Update picture
|
|
768
817
|
await client.updateNewsletterPicture("1234567890@newsletter", "./cover.jpg");
|
|
@@ -782,7 +831,7 @@ const messages = await client.fetchNewsletterMessages(
|
|
|
782
831
|
);
|
|
783
832
|
|
|
784
833
|
if (messages.success) {
|
|
785
|
-
messages.messages?.forEach(msg => {
|
|
834
|
+
messages.messages?.forEach((msg) => {
|
|
786
835
|
console.log("Message:", msg.content);
|
|
787
836
|
console.log("Timestamp:", msg.timestamp);
|
|
788
837
|
});
|
|
@@ -807,7 +856,9 @@ const info = await client.getNewsletterSubscribers("1234567890@newsletter");
|
|
|
807
856
|
console.log("Subscribers:", info?.subscribers);
|
|
808
857
|
|
|
809
858
|
// Get admin count
|
|
810
|
-
const adminCount = await client.getNewsletterAdminCount(
|
|
859
|
+
const adminCount = await client.getNewsletterAdminCount(
|
|
860
|
+
"1234567890@newsletter"
|
|
861
|
+
);
|
|
811
862
|
console.log("Admins:", adminCount);
|
|
812
863
|
|
|
813
864
|
// Subscribe to live updates
|
|
@@ -818,10 +869,16 @@ await client.subscribeNewsletterUpdates("1234567890@newsletter");
|
|
|
818
869
|
|
|
819
870
|
```typescript
|
|
820
871
|
// Change owner
|
|
821
|
-
await client.changeNewsletterOwner(
|
|
872
|
+
await client.changeNewsletterOwner(
|
|
873
|
+
"1234567890@newsletter",
|
|
874
|
+
"new-owner@s.whatsapp.net"
|
|
875
|
+
);
|
|
822
876
|
|
|
823
877
|
// Demote admin
|
|
824
|
-
await client.demoteNewsletterAdmin(
|
|
878
|
+
await client.demoteNewsletterAdmin(
|
|
879
|
+
"1234567890@newsletter",
|
|
880
|
+
"admin@s.whatsapp.net"
|
|
881
|
+
);
|
|
825
882
|
|
|
826
883
|
// Delete newsletter
|
|
827
884
|
await client.deleteNewsletter("1234567890@newsletter");
|
|
@@ -879,7 +936,7 @@ client.on("message", async (msg) => {
|
|
|
879
936
|
const catalog = await client.getCatalog();
|
|
880
937
|
if (catalog.success && catalog.products) {
|
|
881
938
|
let response = "Our products:\n\n";
|
|
882
|
-
catalog.products.forEach(p => {
|
|
939
|
+
catalog.products.forEach((p) => {
|
|
883
940
|
response += `${p.name}: $${(p.priceAmount1000! / 100).toFixed(2)}\n`;
|
|
884
941
|
});
|
|
885
942
|
await client.sendText(msg.from, response);
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import eslint from "@eslint/js";
|
|
2
|
+
import tseslint from "typescript-eslint";
|
|
3
|
+
|
|
4
|
+
export default tseslint.config(
|
|
5
|
+
eslint.configs.recommended,
|
|
6
|
+
...tseslint.configs.recommended,
|
|
7
|
+
{
|
|
8
|
+
ignores: ["dist/**", "node_modules/**", "coverage/**", "*.js"],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
files: ["src/**/*.ts", "tests/**/*.ts", "examples/**/*.ts"],
|
|
12
|
+
rules: {
|
|
13
|
+
"@typescript-eslint/no-unused-vars": [
|
|
14
|
+
"warn",
|
|
15
|
+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
16
|
+
],
|
|
17
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
18
|
+
"@typescript-eslint/no-require-imports": "off",
|
|
19
|
+
"no-console": "off",
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
);
|
package/package.json
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miaw-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Simplified WhatsApp API wrapper for Baileys - Multiple Instance of App WhatsApp",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"scripts": {
|
|
8
15
|
"build": "tsc",
|
|
9
16
|
"dev": "tsc --watch",
|
|
17
|
+
"lint": "eslint src tests examples",
|
|
18
|
+
"lint:fix": "eslint src tests examples --fix",
|
|
10
19
|
"prepublishOnly": "npm run build",
|
|
11
|
-
"test": "jest",
|
|
12
|
-
"test:watch": "jest --watch",
|
|
13
|
-
"test:coverage": "jest --coverage"
|
|
20
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
21
|
+
"test:watch": "NODE_OPTIONS='--experimental-vm-modules' jest --watch",
|
|
22
|
+
"test:coverage": "NODE_OPTIONS='--experimental-vm-modules' jest --coverage",
|
|
23
|
+
"test:manual": "tsx tests/interactive-test.ts",
|
|
24
|
+
"test:manual:build": "npm run build && node dist/tests/interactive-test.js"
|
|
14
25
|
},
|
|
15
26
|
"keywords": [
|
|
16
27
|
"whatsapp",
|
|
@@ -23,20 +34,26 @@
|
|
|
23
34
|
"license": "MIT",
|
|
24
35
|
"dependencies": {
|
|
25
36
|
"@hapi/boom": "^10.0.1",
|
|
26
|
-
"@whiskeysockets/baileys": "^
|
|
37
|
+
"@whiskeysockets/baileys": "^7.0.0-rc.9",
|
|
27
38
|
"pino": "^8.19.0",
|
|
28
39
|
"qrcode-terminal": "^0.12.0"
|
|
29
40
|
},
|
|
30
41
|
"devDependencies": {
|
|
31
42
|
"@babel/preset-env": "^7.28.5",
|
|
43
|
+
"@eslint/js": "^9.39.2",
|
|
32
44
|
"@types/jest": "^29.5.12",
|
|
33
45
|
"@types/node": "^20.11.19",
|
|
34
46
|
"@types/qrcode-terminal": "^0.12.2",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
48
|
+
"@typescript-eslint/parser": "^8.51.0",
|
|
35
49
|
"babel-jest": "^30.2.0",
|
|
36
50
|
"dotenv": "^16.4.5",
|
|
51
|
+
"eslint": "^9.39.2",
|
|
37
52
|
"jest": "^29.7.0",
|
|
38
53
|
"ts-jest": "^29.1.2",
|
|
39
|
-
"
|
|
54
|
+
"tsx": "^4.7.0",
|
|
55
|
+
"typescript": "^5.3.3",
|
|
56
|
+
"typescript-eslint": "^8.51.0"
|
|
40
57
|
},
|
|
41
58
|
"engines": {
|
|
42
59
|
"node": ">=18.0.0"
|
package/tsconfig.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
5
|
-
"lib": ["
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
6
|
"outDir": "./dist",
|
|
7
7
|
"rootDir": "./src",
|
|
8
8
|
"declaration": true,
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
"esModuleInterop": true,
|
|
13
13
|
"skipLibCheck": true,
|
|
14
14
|
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"moduleResolution": "
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
16
|
"resolveJsonModule": true,
|
|
17
17
|
"noUnusedLocals": true,
|
|
18
18
|
"noUnusedParameters": true,
|
|
19
19
|
"noImplicitReturns": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"verbatimModuleSyntax": false
|
|
21
22
|
},
|
|
22
23
|
"include": ["src/**/*"],
|
|
23
24
|
"exclude": ["node_modules", "dist", "examples", "tests", "**/*.test.ts"]
|
package/tsconfig.test.json
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
"noUnusedLocals": false,
|
|
7
7
|
"noUnusedParameters": false,
|
|
8
8
|
"outDir": "./dist-test",
|
|
9
|
-
"rootDir": "./"
|
|
9
|
+
"rootDir": "./",
|
|
10
|
+
"module": "ESNext",
|
|
11
|
+
"moduleResolution": "bundler"
|
|
10
12
|
},
|
|
11
13
|
"include": ["tests/**/*", "src/**/*"],
|
|
12
14
|
"exclude": ["node_modules", "dist", "examples"]
|
package/dist/utils/storage.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handles file-based session storage for authentication state
|
|
3
|
-
*/
|
|
4
|
-
export declare class SessionStorage {
|
|
5
|
-
private sessionDir;
|
|
6
|
-
private sessionFile;
|
|
7
|
-
constructor(sessionPath: string, instanceId: string);
|
|
8
|
-
/**
|
|
9
|
-
* Check if session file exists
|
|
10
|
-
*/
|
|
11
|
-
exists(): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Load session data from file
|
|
14
|
-
*/
|
|
15
|
-
load(): any;
|
|
16
|
-
/**
|
|
17
|
-
* Save session data to file
|
|
18
|
-
*/
|
|
19
|
-
save(data: any): void;
|
|
20
|
-
/**
|
|
21
|
-
* Get the session file path
|
|
22
|
-
*/
|
|
23
|
-
getFilePath(): string;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAUnD;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,IAAI,IAAI,GAAG;IAcX;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI;IASrB;;OAEG;IACH,WAAW,IAAI,MAAM;CAGtB"}
|
package/dist/utils/storage.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SessionStorage = void 0;
|
|
4
|
-
const fs_1 = require("fs");
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
/**
|
|
7
|
-
* Handles file-based session storage for authentication state
|
|
8
|
-
*/
|
|
9
|
-
class SessionStorage {
|
|
10
|
-
constructor(sessionPath, instanceId) {
|
|
11
|
-
this.sessionDir = sessionPath;
|
|
12
|
-
this.sessionFile = (0, path_1.join)(sessionPath, `${instanceId}.json`);
|
|
13
|
-
// Ensure session directory exists
|
|
14
|
-
if (!(0, fs_1.existsSync)(this.sessionDir)) {
|
|
15
|
-
(0, fs_1.mkdirSync)(this.sessionDir, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Check if session file exists
|
|
20
|
-
*/
|
|
21
|
-
exists() {
|
|
22
|
-
return (0, fs_1.existsSync)(this.sessionFile);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Load session data from file
|
|
26
|
-
*/
|
|
27
|
-
load() {
|
|
28
|
-
try {
|
|
29
|
-
if (!this.exists()) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const data = (0, fs_1.readFileSync)(this.sessionFile, 'utf-8');
|
|
33
|
-
return JSON.parse(data);
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
console.error('Failed to load session:', error);
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Save session data to file
|
|
42
|
-
*/
|
|
43
|
-
save(data) {
|
|
44
|
-
try {
|
|
45
|
-
(0, fs_1.writeFileSync)(this.sessionFile, JSON.stringify(data, null, 2), 'utf-8');
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
console.error('Failed to save session:', error);
|
|
49
|
-
throw error;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Get the session file path
|
|
54
|
-
*/
|
|
55
|
-
getFilePath() {
|
|
56
|
-
return this.sessionFile;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.SessionStorage = SessionStorage;
|
|
60
|
-
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/utils/storage.ts"],"names":[],"mappings":";;;AAAA,2BAAwE;AACxE,+BAA4B;AAE5B;;GAEG;AACH,MAAa,cAAc;IAIzB,YAAY,WAAmB,EAAE,UAAkB;QACjD,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAA,WAAI,EAAC,WAAW,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;QAE3D,kCAAkC;QAClC,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,IAAA,cAAS,EAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAA,eAAU,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;gBACnB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,IAAI,GAAG,IAAA,iBAAY,EAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,IAAS;QACZ,IAAI,CAAC;YACH,IAAA,kBAAa,EAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAChD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF;AAxDD,wCAwDC"}
|