@crysnovax/baileys 2.6.2 โ 2.6.4
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 +280 -67
- package/lib/Socket/chats.js +23 -1
- package/lib/Socket/{chats.js[past] โ chats.js[old]} +16 -2
- package/lib/Socket/messages-send.js +164 -1
- package/lib/Socket/messages-send.js[old] +1397 -0
- package/lib/Utils/chat-utils.js +14 -0
- package/lib/Utils/chat-utils.js[old] +871 -0
- package/lib/Utils/messages.js +38 -0
- package/lib/Utils/messages.js[old] +1864 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,60 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
<h2 align="center">
|
|
3
|
-
<img src="https://media2.giphy.com/media/QssGEmpkyEOhBCb7e1/giphy.gif?cid=ecf05e47a0n3gi1bfqntqmob8g9aid1oyj2wr3ds3mg700bl&rid=giphy.gif" width="28" />
|
|
4
|
-
About Me
|
|
5
|
-
<img src="https://media2.giphy.com/media/QssGEmpkyEOhBCb7e1/giphy.gif?cid=ecf05e47a0n3gi1bfqntqmob8g9aid1oyj2wr3ds3mg700bl&rid=giphy.gif" width="28" />
|
|
6
|
-
</h2>
|
|
7
|
-
|
|
8
|
-
```javascript
|
|
9
|
-
const crysnova = {
|
|
10
|
-
name: "CRYSNOVA AI",
|
|
11
|
-
location: "๐ Global",
|
|
12
|
-
role: "Full Stack Developer & Bot Creator",
|
|
13
|
-
stack: ["JavaScript", "Node.js", "Cloudflare Workers", "WhatsApp Bot Development"],
|
|
14
|
-
interests: ["AI", "Automation", "Open Source", "Building Cool Stuff"],
|
|
15
|
-
currentFocus: "Building the most powerful WhatsApp bot ecosystem ๐",
|
|
16
|
-
funFact: "My code runs 24/7 on Cloudflare's edge network โก"
|
|
17
|
-
};
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
<br />
|
|
21
|
-
|
|
22
|
-
<h2 align="center">
|
|
23
|
-
<img src="https://media.giphy.com/media/iY8CRBdQXODJSCERIr/giphy.gif" width="28" />
|
|
24
|
-
Tech Stack
|
|
25
|
-
<img src="https://media.giphy.com/media/iY8CRBdQXODJSCERIr/giphy.gif" width="28" />
|
|
26
|
-
</h2>
|
|
27
|
-
|
|
28
|
-
<p align="center">
|
|
29
|
-
<img src="https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black&labelColor=0a0f0a&color=10b981" />
|
|
30
|
-
<img src="https://img.shields.io/badge/Node.js-339933?style=for-the-badge&logo=node.js&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
31
|
-
<img src="https://img.shields.io/badge/Cloudflare-F38020?style=for-the-badge&logo=cloudflare&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
32
|
-
<img src="https://img.shields.io/badge/Workers-F38020?style=for-the-badge&logo=cloudflareworkers&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
33
|
-
<img src="https://img.shields.io/badge/GitHub-181717?style=for-the-badge&logo=github&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
34
|
-
<img src="https://img.shields.io/badge/Baileys-25D366?style=for-the-badge&logo=whatsapp&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
35
|
-
<img src="https://img.shields.io/badge/API-FF6F00?style=for-the-badge&logo=fastapi&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
36
|
-
<img src="https://img.shields.io/badge/KV-FF4F00?style=for-the-badge&logo=cloudflare&logoColor=white&labelColor=0a0f0a&color=10b981" />
|
|
37
|
-
</p>
|
|
38
|
-
<br />
|
|
39
|
-
|
|
40
|
-
<h2 align="center">
|
|
41
|
-
<img src="https://media.giphy.com/media/W5eoZHPpUx9sapR0eu/giphy.gif" width="28" />
|
|
42
|
-
Featured Projects
|
|
43
|
-
<img src="https://media.giphy.com/media/W5eoZHPpUx9sapR0eu/giphy.gif" width="28" />
|
|
44
|
-
</h2>
|
|
45
|
-
|
|
46
|
-
<div align="center">
|
|
47
|
-
|
|
48
|
-
| ๐ Project | โญ Stars | ๐ Description |
|
|
49
|
-
|-----------|---------|---------------|
|
|
50
|
-
| **CRYSNOVA AI** | [](https://github.com/crysnovax/CRYSNOVA_AI) | 550+ Command WhatsApp Bot with AI Integration |
|
|
51
|
-
| **API Gateway** | [](https://github.com/crysnovax/API) | Nexray Endpoints Unified API Gateway |
|
|
52
|
-
| **Economy Engine** | [](https://github.com/crysnovax) | Realistic Virtual Economy with Banking System |
|
|
53
|
-
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
1
|
<p align="center">
|
|
59
2
|
<img src="https://readme-typing-svg.demolab.com?font=Fira+Code&weight=700&size=32&duration=3000&pause=800&color=10B981¢er=true&vCenter=true&width=650&lines=%F0%9F%9A%80+%40crysnovax%2Fbailey%3B+WhatsApp+API+for+Node.js%3B+Rich+Messages+%7C+Meta+AI+Style%3B+Production+Ready+%E2%9C%85" alt="Typing Animation" />
|
|
60
3
|
</p>
|
|
@@ -90,15 +33,18 @@ const crysnova = {
|
|
|
90
33
|
| 10 | [Welcome Flow](#welcome-flow) | Auto-greet new contacts with FAQ menus |
|
|
91
34
|
| 11 | [Payment Messages](#payment-messages) | Invites, invoices, orders, payment requests |
|
|
92
35
|
| 12 | [Message Options](#message-options) | AI icon, ephemeral, spoilers, view once, raw, and more |
|
|
93
|
-
| 13 | [
|
|
94
|
-
| 14 | [
|
|
95
|
-
| 15 | [
|
|
96
|
-
| 16 | [
|
|
97
|
-
| 17 | [
|
|
98
|
-
| 18 | [
|
|
99
|
-
| 19 | [
|
|
100
|
-
| 20 | [
|
|
101
|
-
| 21 | [
|
|
36
|
+
| 13 | [Status & Stories](#status--stories) | Post status updates with text, media, mentions |
|
|
37
|
+
| 14 | [Favorites](#favorites) | Manage WhatsApp Favorites list |
|
|
38
|
+
| 15 | [Newsletter Management](#newsletter-management) | Create, update, follow, react, delete newsletters |
|
|
39
|
+
| 16 | [Group Management](#group-management) | Create, settings, participants, invites, metadata |
|
|
40
|
+
| 17 | [Community Management](#community-management) | Communities, subgroups, linked groups |
|
|
41
|
+
| 18 | [Profile & Business](#profile--business) | Profile pictures, business catalog, products, quick replies |
|
|
42
|
+
| 19 | [Privacy & Security](#privacy--security) | Last seen, online, status, read receipts, calls |
|
|
43
|
+
| 20 | [Utility Methods](#utility-methods) | LID mapping, dirty bits, app state sync, props |
|
|
44
|
+
| 21 | [Events Reference](#events-reference) | Full list of socket event listeners |
|
|
45
|
+
| 22 | [Image Processing](#image-processing) | Sharp, NAPI-RS, Jimp auto-detection |
|
|
46
|
+
| 23 | [Condition of Use](#condition-of-use) | Channel follow agreement |
|
|
47
|
+
| 24 | [Credits](#credits) | Attribution and enhancements |
|
|
102
48
|
|
|
103
49
|
---
|
|
104
50
|
|
|
@@ -113,12 +59,16 @@ const crysnova = {
|
|
|
113
59
|
| Rich Messages | โ
| Code blocks, tables, inline entities, carousel cards |
|
|
114
60
|
| Meta AI Style | โ
| Live thinking indicators without "edited" badges |
|
|
115
61
|
| Welcome Flow | โ
| Auto-greet new contacts with interactive FAQ menus |
|
|
62
|
+
| Status Posting | โ
| Text with colors/fonts, image, video, audio, mentions |
|
|
63
|
+
| Favorites Management | โ
| Add/remove JIDs with local persistence |
|
|
64
|
+
| HD Profile Picture | โ
| Full-size upload with no crop or resize via `{ hd: true }` (max 720px) |
|
|
65
|
+
| LID/PN Resolution | โ
| Cross-resolve LID and phone number JIDs |
|
|
66
|
+
| Member Labels | โ
| Group participant labels |
|
|
116
67
|
| No Obfuscation | โ
| Fully readable, auditable source code |
|
|
117
68
|
| Newsletter Ready | โ
| Full media support, quoting, quiz polls |
|
|
118
69
|
| Image Processing | โ
| Auto-detects `sharp`, `@napi-rs/image`, or `jimp` |
|
|
119
70
|
| Safe FFmpeg | โ
| Uses `spawn` instead of `exec` |
|
|
120
71
|
| In-Memory Store | โ
| Reintroduced with minimal ESM adaptation |
|
|
121
|
-
| HD Profile Picture | โ
| Full-size upload with no crop or resize via `{ hd: true }` (max 720px) |
|
|
122
72
|
|
|
123
73
|
---
|
|
124
74
|
|
|
@@ -771,7 +721,26 @@ sock.sendMessage(jid, {
|
|
|
771
721
|
]
|
|
772
722
|
})
|
|
773
723
|
```
|
|
724
|
+
### Rich preview
|
|
725
|
+
```
|
|
726
|
+
await sock.sendMessage(jid, {
|
|
727
|
+
text: 'https://chat.whatsapp.com/CODE',
|
|
728
|
+
richPreview: true,
|
|
729
|
+
previewTitle: 'My Group',
|
|
730
|
+
previewDescription: '42 members ยท Tap to join',
|
|
731
|
+
previewImage: imageBufferOrUrl // Buffer, or a URL string
|
|
732
|
+
})
|
|
733
|
+
```
|
|
774
734
|
|
|
735
|
+
### WHATSAPP VERIFIED โ๏ธ โ
|
|
736
|
+
send Media messages with verified WhatsApp check โ๏ธ
|
|
737
|
+
```
|
|
738
|
+
await sock.sendMessage(jid, {
|
|
739
|
+
image: buffer,
|
|
740
|
+
caption: 'Hello',
|
|
741
|
+
verifiedMe: true
|
|
742
|
+
})
|
|
743
|
+
```
|
|
775
744
|
---
|
|
776
745
|
|
|
777
746
|
## Meta AI Features
|
|
@@ -1190,6 +1159,161 @@ sock.sendMessage(jid, {
|
|
|
1190
1159
|
|
|
1191
1160
|
---
|
|
1192
1161
|
|
|
1162
|
+
## Status & Stories
|
|
1163
|
+
|
|
1164
|
+
Post WhatsApp status updates with text, media, and targeted mentions.
|
|
1165
|
+
|
|
1166
|
+
### Text Status
|
|
1167
|
+
|
|
1168
|
+
```javascript
|
|
1169
|
+
// Plain text status
|
|
1170
|
+
sock.sendMessage(jid, {
|
|
1171
|
+
text: 'Hello world!',
|
|
1172
|
+
status: true
|
|
1173
|
+
})
|
|
1174
|
+
|
|
1175
|
+
// With background color (named)
|
|
1176
|
+
sock.sendMessage(jid, {
|
|
1177
|
+
text: 'Hello world!',
|
|
1178
|
+
status: true,
|
|
1179
|
+
backgroundColor: '#FFD32B2B' // red
|
|
1180
|
+
})
|
|
1181
|
+
|
|
1182
|
+
// With hex color
|
|
1183
|
+
sock.sendMessage(jid, {
|
|
1184
|
+
text: 'Hello world!',
|
|
1185
|
+
status: true,
|
|
1186
|
+
backgroundColor: '#FF0057FF' // blue
|
|
1187
|
+
})
|
|
1188
|
+
|
|
1189
|
+
// With font style (0-5)
|
|
1190
|
+
sock.sendMessage(jid, {
|
|
1191
|
+
text: 'Hello world!',
|
|
1192
|
+
status: true,
|
|
1193
|
+
backgroundColor: '#FF1FA15A', // green
|
|
1194
|
+
font: 2 // norican
|
|
1195
|
+
})
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
**Available colors:** `red`, `blue`, `green`, `black`, `white`, `purple`, `orange`, `pink`, `yellow`, `teal`
|
|
1199
|
+
|
|
1200
|
+
**Available fonts:** `0=sans`, `1=serif`, `2=norican`, `3=bryndan`, `4=bebasneue`, `5=futura`
|
|
1201
|
+
|
|
1202
|
+
### Media Status
|
|
1203
|
+
|
|
1204
|
+
```javascript
|
|
1205
|
+
// Image status
|
|
1206
|
+
sock.sendMessage(jid, {
|
|
1207
|
+
image: { url: './image.jpg' },
|
|
1208
|
+
caption: 'My status!',
|
|
1209
|
+
status: true
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
// Video status
|
|
1213
|
+
sock.sendMessage(jid, {
|
|
1214
|
+
video: { url: './video.mp4' },
|
|
1215
|
+
caption: 'Watch this!',
|
|
1216
|
+
status: true
|
|
1217
|
+
})
|
|
1218
|
+
|
|
1219
|
+
// Audio status
|
|
1220
|
+
sock.sendMessage(jid, {
|
|
1221
|
+
audio: { url: './audio.mp3' },
|
|
1222
|
+
ptt: false,
|
|
1223
|
+
status: true
|
|
1224
|
+
})
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
### Status with Targeted Viewers
|
|
1228
|
+
|
|
1229
|
+
```javascript
|
|
1230
|
+
// Only specific contacts can see the status
|
|
1231
|
+
sock.sendMessage(jid, {
|
|
1232
|
+
text: 'Exclusive status!',
|
|
1233
|
+
status: true,
|
|
1234
|
+
statusJidList: [
|
|
1235
|
+
'628123456789@s.whatsapp.net',
|
|
1236
|
+
'628987654321@s.whatsapp.net'
|
|
1237
|
+
]
|
|
1238
|
+
})
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
### Status Mentions
|
|
1242
|
+
|
|
1243
|
+
```javascript
|
|
1244
|
+
// Mention users/groups in status (they get a notification)
|
|
1245
|
+
sock.sendMessage([jidA, jidB, jidC], {
|
|
1246
|
+
text: 'Hey check my status!'
|
|
1247
|
+
})
|
|
1248
|
+
```
|
|
1249
|
+
|
|
1250
|
+
---
|
|
1251
|
+
|
|
1252
|
+
## Favorites
|
|
1253
|
+
|
|
1254
|
+
Manage your WhatsApp Favorites list โ add, remove, and sync across devices.
|
|
1255
|
+
|
|
1256
|
+
### Add to Favorites
|
|
1257
|
+
|
|
1258
|
+
```javascript
|
|
1259
|
+
// Add a single JID
|
|
1260
|
+
await sock.addToFavorites(['628123456789@s.whatsapp.net'])
|
|
1261
|
+
|
|
1262
|
+
// Add multiple JIDs (replaces entire list โ merge handled by caller)
|
|
1263
|
+
await sock.addToFavorites([
|
|
1264
|
+
'628123456789@s.whatsapp.net',
|
|
1265
|
+
'628987654321@s.whatsapp.net',
|
|
1266
|
+
'1234@g.us'
|
|
1267
|
+
])
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
### Remove from Favorites
|
|
1271
|
+
|
|
1272
|
+
```javascript
|
|
1273
|
+
// Remove specific JIDs (pass remaining list after filter)
|
|
1274
|
+
await sock.removeFromFavorites([
|
|
1275
|
+
'628123456789@s.whatsapp.net' // only this one remains
|
|
1276
|
+
])
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
### Full Example with Local Persistence
|
|
1280
|
+
|
|
1281
|
+
```javascript
|
|
1282
|
+
const fs = require('fs')
|
|
1283
|
+
const path = require('path')
|
|
1284
|
+
|
|
1285
|
+
const FAV_FILE = path.join(__dirname, 'database', 'favorites.json')
|
|
1286
|
+
|
|
1287
|
+
const loadFavs = () => {
|
|
1288
|
+
try { return JSON.parse(fs.readFileSync(FAV_FILE, 'utf8')) }
|
|
1289
|
+
catch { return [] }
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
const saveFavs = (favs) => {
|
|
1293
|
+
fs.mkdirSync(path.dirname(FAV_FILE), { recursive: true })
|
|
1294
|
+
fs.writeFileSync(FAV_FILE, JSON.stringify(favs, null, 2))
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Add
|
|
1298
|
+
const existing = loadFavs()
|
|
1299
|
+
const target = '628123456789@s.whatsapp.net'
|
|
1300
|
+
if (!existing.includes(target)) {
|
|
1301
|
+
const merged = [...existing, target]
|
|
1302
|
+
await sock.addToFavorites(merged)
|
|
1303
|
+
saveFavs(merged)
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// Remove
|
|
1307
|
+
const toRemove = '628123456789@s.whatsapp.net'
|
|
1308
|
+
const remaining = existing.filter(jid => jid !== toRemove)
|
|
1309
|
+
await sock.addToFavorites(remaining)
|
|
1310
|
+
saveFavs(remaining)
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
> **Note:** WhatsApp favorites use a single app state record. Each `SET` replaces the entire list. Always pass the complete desired array.
|
|
1314
|
+
|
|
1315
|
+
---
|
|
1316
|
+
|
|
1193
1317
|
## Newsletter Management
|
|
1194
1318
|
|
|
1195
1319
|
```javascript
|
|
@@ -1541,6 +1665,91 @@ sock.updateDisableLinkPreviewsPrivacy(true)
|
|
|
1541
1665
|
|
|
1542
1666
|
---
|
|
1543
1667
|
|
|
1668
|
+
## Utility Methods
|
|
1669
|
+
|
|
1670
|
+
### LID / Phone Number Resolution
|
|
1671
|
+
|
|
1672
|
+
```javascript
|
|
1673
|
+
// Resolve LID โ PN cross-mappings
|
|
1674
|
+
const userId = await sock.findUserId('628123456789@s.whatsapp.net')
|
|
1675
|
+
console.log(userId)
|
|
1676
|
+
// { lid: '1234567890@lid', phoneNumber: '628123456789@s.whatsapp.net' }
|
|
1677
|
+
|
|
1678
|
+
const userId2 = await sock.findUserId('1234567890@lid')
|
|
1679
|
+
console.log(userId2)
|
|
1680
|
+
// { lid: '1234567890@lid', phoneNumber: '628123456789@s.whatsapp.net' }
|
|
1681
|
+
```
|
|
1682
|
+
|
|
1683
|
+
### Fetch User Status
|
|
1684
|
+
|
|
1685
|
+
```javascript
|
|
1686
|
+
// Fetch status metadata for one or more users
|
|
1687
|
+
const statusList = await sock.fetchStatus('628123456789@s.whatsapp.net', '628987654321@s.whatsapp.net')
|
|
1688
|
+
```
|
|
1689
|
+
|
|
1690
|
+
### Fetch Disappearing Duration
|
|
1691
|
+
|
|
1692
|
+
```javascript
|
|
1693
|
+
// Get disappearing message duration for contacts
|
|
1694
|
+
const durations = await sock.fetchDisappearingDuration('628123456789@s.whatsapp.net')
|
|
1695
|
+
```
|
|
1696
|
+
|
|
1697
|
+
### Bot List
|
|
1698
|
+
|
|
1699
|
+
```javascript
|
|
1700
|
+
// Fetch official bot list (v2)
|
|
1701
|
+
const bots = await sock.getBotListV2()
|
|
1702
|
+
// [{ jid: '...', personaId: '...' }]
|
|
1703
|
+
```
|
|
1704
|
+
|
|
1705
|
+
### Call Links
|
|
1706
|
+
|
|
1707
|
+
```javascript
|
|
1708
|
+
// Create voice/video call link
|
|
1709
|
+
const token = await sock.createCallLink('audio') // voice call
|
|
1710
|
+
const token2 = await sock.createCallLink('video') // video call
|
|
1711
|
+
const token3 = await sock.createCallLink('video', { // with scheduled event
|
|
1712
|
+
startTime: Date.now() + 3600000
|
|
1713
|
+
})
|
|
1714
|
+
```
|
|
1715
|
+
|
|
1716
|
+
### Server Properties
|
|
1717
|
+
|
|
1718
|
+
```javascript
|
|
1719
|
+
// Access server-assigned AB props
|
|
1720
|
+
console.log(sock.serverProps)
|
|
1721
|
+
// {
|
|
1722
|
+
// privacyTokenOn1to1: true, // tctoken on 1:1 messages
|
|
1723
|
+
// profilePicPrivacyToken: true, // tctoken on profile pic IQs
|
|
1724
|
+
// lidTrustedTokenIssueToLid: false // issue tctokens to LID
|
|
1725
|
+
// }
|
|
1726
|
+
```
|
|
1727
|
+
|
|
1728
|
+
### App State Sync
|
|
1729
|
+
|
|
1730
|
+
```javascript
|
|
1731
|
+
// Force resync specific collections
|
|
1732
|
+
await sock.resyncAppState(['regular_high', 'regular_low'], false)
|
|
1733
|
+
|
|
1734
|
+
// Apply custom app patch
|
|
1735
|
+
await sock.appPatch({
|
|
1736
|
+
syncAction: { ... },
|
|
1737
|
+
index: ['...'],
|
|
1738
|
+
type: 'regular_low',
|
|
1739
|
+
apiVersion: 5,
|
|
1740
|
+
operation: proto.SyncdMutation.SyncdOperation.SET
|
|
1741
|
+
})
|
|
1742
|
+
```
|
|
1743
|
+
|
|
1744
|
+
### Clean Dirty Bits
|
|
1745
|
+
|
|
1746
|
+
```javascript
|
|
1747
|
+
// Clear dirty bits for specific sync types
|
|
1748
|
+
await sock.cleanDirtyBits('account_sync', timestamp)
|
|
1749
|
+
```
|
|
1750
|
+
|
|
1751
|
+
---
|
|
1752
|
+
|
|
1544
1753
|
## Events Reference
|
|
1545
1754
|
|
|
1546
1755
|
```javascript
|
|
@@ -1654,6 +1863,10 @@ Full credit to the original maintainers and contributors:
|
|
|
1654
1863
|
- Rich message types (code blocks, tables, inline entities)
|
|
1655
1864
|
- Meta AI-style compositing and replay planning
|
|
1656
1865
|
- Welcome flow with FAQ auto-greeting
|
|
1866
|
+
- Status posting with text, media, colors, fonts, mentions
|
|
1867
|
+
- Favorites management with full list sync
|
|
1868
|
+
- LID/PN cross-resolution
|
|
1869
|
+
- Member labels for groups
|
|
1657
1870
|
- Newsletter media fixes and quiz support
|
|
1658
1871
|
- Image processing auto-detection
|
|
1659
1872
|
- Safe FFmpeg spawn-based execution
|
package/lib/Socket/chats.js
CHANGED
|
@@ -936,6 +936,26 @@ export const makeChatsSocket = (config) => {
|
|
|
936
936
|
quickReply: { timestamp, deleted: true }
|
|
937
937
|
}, '');
|
|
938
938
|
};
|
|
939
|
+
/**
|
|
940
|
+
* crysnovax@Favorites --- Set complete WhatsApp Favorites list.
|
|
941
|
+
* Replaces server-side list with the provided array (merging is handled by caller).
|
|
942
|
+
* @param jids โ complete array of JIDs to set as favorites
|
|
943
|
+
*/
|
|
944
|
+
const addToFavorites = (jids) => {
|
|
945
|
+
return chatModify({
|
|
946
|
+
favorites: { jids, add: true }
|
|
947
|
+
}, '');
|
|
948
|
+
};
|
|
949
|
+
/**
|
|
950
|
+
* crysnovax@Favorites --- Remove all favorites (clear list).
|
|
951
|
+
*/
|
|
952
|
+
const removeFromFavorites = (jids) => {
|
|
953
|
+
// For single removal, caller must pass remaining list to addToFavorites
|
|
954
|
+
// This sends the provided jids array (should be remaining items after filter)
|
|
955
|
+
return chatModify({
|
|
956
|
+
favorites: { jids, add: true }
|
|
957
|
+
}, '');
|
|
958
|
+
};
|
|
939
959
|
/**
|
|
940
960
|
* queries need to be fired on connection open
|
|
941
961
|
* help ensure parity with WA Web
|
|
@@ -1222,6 +1242,8 @@ export const makeChatsSocket = (config) => {
|
|
|
1222
1242
|
removeMessageLabel,
|
|
1223
1243
|
star,
|
|
1224
1244
|
addOrEditQuickReply,
|
|
1225
|
-
removeQuickReply
|
|
1245
|
+
removeQuickReply,
|
|
1246
|
+
addToFavorites,
|
|
1247
|
+
removeFromFavorites
|
|
1226
1248
|
};
|
|
1227
1249
|
};
|
|
@@ -5,6 +5,7 @@ import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY
|
|
|
5
5
|
import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
|
|
6
6
|
import { SyncState } from '../Types/State.js';
|
|
7
7
|
import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
|
|
8
|
+
import { generateProfilePictureHD } from '../Utils/messages-media.js';
|
|
8
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
9
10
|
import processMessage from '../Utils/process-message.js';
|
|
10
11
|
import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
|
|
@@ -207,7 +208,15 @@ export const makeChatsSocket = (config) => {
|
|
|
207
208
|
}
|
|
208
209
|
return userId;
|
|
209
210
|
};
|
|
210
|
-
/** update the profile picture for yourself or a group
|
|
211
|
+
/** update the profile picture for yourself or a group
|
|
212
|
+
*
|
|
213
|
+
* Standard (crop + resize to 720ร720):
|
|
214
|
+
* sock.updateProfilePicture(jid, content)
|
|
215
|
+
* sock.updateProfilePicture(jid, content, { width: 640, height: 640 })
|
|
216
|
+
*
|
|
217
|
+
* HD (full-size, no crop, no resize):
|
|
218
|
+
* sock.updateProfilePicture(jid, content, { hd: true })
|
|
219
|
+
*/
|
|
211
220
|
const updateProfilePicture = async (jid, content, dimensions) => {
|
|
212
221
|
let targetJid;
|
|
213
222
|
if (!jid) {
|
|
@@ -219,7 +228,12 @@ export const makeChatsSocket = (config) => {
|
|
|
219
228
|
else {
|
|
220
229
|
targetJid = undefined;
|
|
221
230
|
}
|
|
222
|
-
|
|
231
|
+
// crysnovax@HD-Profile --- Dual mode:
|
|
232
|
+
// hd:true โ generateProfilePictureHD (preserves aspect ratio, caps at 1920, manages file size)
|
|
233
|
+
// standard โ generateProfilePicture (720ร720 square crop, or custom dimensions)
|
|
234
|
+
const { img } = dimensions?.hd
|
|
235
|
+
? await generateProfilePictureHD(content)
|
|
236
|
+
: await generateProfilePicture(content, dimensions);
|
|
223
237
|
await query({
|
|
224
238
|
tag: 'iq',
|
|
225
239
|
attrs: {
|
|
@@ -3,7 +3,7 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { AssociationType } from '../Types/index.js';
|
|
8
8
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
9
9
|
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
@@ -1218,6 +1218,169 @@ export const makeMessagesSocket = (config) => {
|
|
|
1218
1218
|
: disappearingMessagesInChat;
|
|
1219
1219
|
await groupToggleEphemeral(jid, value);
|
|
1220
1220
|
}
|
|
1221
|
+
// crysnovax@Status --- status:true flag routes any message type to status@broadcast
|
|
1222
|
+
// Supports: text with backgroundColor + font, image, video, audio, sticker
|
|
1223
|
+
// Usage: sock.sendMessage(jid, { text: 'Hello', status: true, backgroundColor: '#FF0000', font: 2 })
|
|
1224
|
+
// sock.sendMessage(jid, { audio: buffer, status: true, ptt: false })
|
|
1225
|
+
else if ('status' in content && content.status === true) {
|
|
1226
|
+
const { status: _, backgroundColor, font, statusJidList: contentJidList, ...statusContent } = content;
|
|
1227
|
+
const fullMsg = await generateWAMessage('status@broadcast', statusContent, {
|
|
1228
|
+
logger,
|
|
1229
|
+
userJid,
|
|
1230
|
+
upload: waUploadToServer,
|
|
1231
|
+
mediaCache: config.mediaCache,
|
|
1232
|
+
options: config.options,
|
|
1233
|
+
...options,
|
|
1234
|
+
...(backgroundColor ? { backgroundColor } : {}),
|
|
1235
|
+
...(font !== undefined ? { font } : {}),
|
|
1236
|
+
messageId: generateMessageIDV2(userJid)
|
|
1237
|
+
});
|
|
1238
|
+
await relayMessage('status@broadcast', fullMsg.message, {
|
|
1239
|
+
messageId: fullMsg.key.id,
|
|
1240
|
+
statusJidList: contentJidList || options.statusJidList,
|
|
1241
|
+
additionalAttributes: options.additionalAttributes || {},
|
|
1242
|
+
additionalNodes: options.additionalNodes || []
|
|
1243
|
+
});
|
|
1244
|
+
if (config.emitOwnEvents) {
|
|
1245
|
+
process.nextTick(async () => {
|
|
1246
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
return fullMsg;
|
|
1250
|
+
}
|
|
1251
|
+
// crysnovax@RichPreview --- richPreview:true auto-builds a manually-constructed
|
|
1252
|
+
// extendedTextMessage with a large preview image, bypassing generateWAMessage's
|
|
1253
|
+
// getUrlInfo scraper (which fails on bot-blocked domains like chat.whatsapp.com)
|
|
1254
|
+
// and avoiding the undocumented ~7KB jpegThumbnail size ceiling that causes a
|
|
1255
|
+
// blank/black render on WA clients when exceeded.
|
|
1256
|
+
//
|
|
1257
|
+
// Usage:
|
|
1258
|
+
// sock.sendMessage(jid, {
|
|
1259
|
+
// text: 'https://chat.whatsapp.com/CODE',
|
|
1260
|
+
// richPreview: true,
|
|
1261
|
+
// previewTitle: 'Group Name',
|
|
1262
|
+
// previewDescription: '12 members ยท Tap to join',
|
|
1263
|
+
// previewImage: imageBufferOrUrl // Buffer, or a URL string to fetch
|
|
1264
|
+
// })
|
|
1265
|
+
else if ('richPreview' in content && content.richPreview === true) {
|
|
1266
|
+
const {
|
|
1267
|
+
richPreview: __rp,
|
|
1268
|
+
text: previewLink,
|
|
1269
|
+
previewTitle,
|
|
1270
|
+
previewDescription,
|
|
1271
|
+
previewImage,
|
|
1272
|
+
quoted,
|
|
1273
|
+
...restContent
|
|
1274
|
+
} = content;
|
|
1275
|
+
|
|
1276
|
+
if (!previewLink || typeof previewLink !== 'string') {
|
|
1277
|
+
throw new Boom('richPreview requires a `text` field containing the URL', { statusCode: 400 });
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Resolve previewImage into a raw Buffer, whether given as
|
|
1281
|
+
// a Buffer directly or a URL string to fetch
|
|
1282
|
+
let imageBuffer = null;
|
|
1283
|
+
if (previewImage) {
|
|
1284
|
+
if (Buffer.isBuffer(previewImage)) {
|
|
1285
|
+
imageBuffer = previewImage;
|
|
1286
|
+
}
|
|
1287
|
+
else if (typeof previewImage === 'string') {
|
|
1288
|
+
try {
|
|
1289
|
+
const res = await fetch(previewImage);
|
|
1290
|
+
imageBuffer = Buffer.from(await res.arrayBuffer());
|
|
1291
|
+
}
|
|
1292
|
+
catch (err) {
|
|
1293
|
+
logger?.warn({ err }, 'richPreview: failed to fetch previewImage URL');
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Small embedded jpegThumbnail โ kept under the ~7KB ceiling
|
|
1299
|
+
// that causes WA clients to render a blank/black preview if exceeded.
|
|
1300
|
+
// 296px @ quality 50 (fixed internally by extractImageThumb) sits
|
|
1301
|
+
// safely under that threshold while staying as sharp as reliably possible.
|
|
1302
|
+
let smallThumb = null;
|
|
1303
|
+
if (imageBuffer) {
|
|
1304
|
+
try {
|
|
1305
|
+
const { buffer } = await extractImageThumb(imageBuffer, 296);
|
|
1306
|
+
smallThumb = buffer;
|
|
1307
|
+
}
|
|
1308
|
+
catch (err) {
|
|
1309
|
+
logger?.warn({ err }, 'richPreview: failed to generate small thumbnail');
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// Upload the image through the real media pipeline to get a
|
|
1314
|
+
// proper highQualityThumbnail reference (directPath/mediaKey/etc)
|
|
1315
|
+
let hq = null;
|
|
1316
|
+
if (imageBuffer) {
|
|
1317
|
+
try {
|
|
1318
|
+
const prepared = await prepareWAMessageMedia({ image: imageBuffer }, { upload: waUploadToServer });
|
|
1319
|
+
hq = prepared.imageMessage;
|
|
1320
|
+
}
|
|
1321
|
+
catch (err) {
|
|
1322
|
+
logger?.warn({ err }, 'richPreview: failed to upload HQ thumbnail');
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
const previewMessage = {
|
|
1327
|
+
extendedTextMessage: {
|
|
1328
|
+
text: previewLink,
|
|
1329
|
+
matchedText: previewLink,
|
|
1330
|
+
canonicalUrl: previewLink,
|
|
1331
|
+
title: previewTitle || '',
|
|
1332
|
+
description: previewDescription || '',
|
|
1333
|
+
previewType: 5, // IMAGE
|
|
1334
|
+
jpegThumbnail: smallThumb || undefined,
|
|
1335
|
+
...(hq
|
|
1336
|
+
? {
|
|
1337
|
+
thumbnailDirectPath: hq.directPath,
|
|
1338
|
+
mediaKey: hq.mediaKey,
|
|
1339
|
+
mediaKeyTimestamp: hq.mediaKeyTimestamp,
|
|
1340
|
+
thumbnailWidth: hq.width,
|
|
1341
|
+
thumbnailHeight: hq.height,
|
|
1342
|
+
thumbnailSha256: hq.fileSha256,
|
|
1343
|
+
thumbnailEncSha256: hq.fileEncSha256
|
|
1344
|
+
}
|
|
1345
|
+
: {}),
|
|
1346
|
+
...restContent
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
const msgId = options.messageId || generateMessageIDV2(userJid);
|
|
1351
|
+
|
|
1352
|
+
if (quoted) {
|
|
1353
|
+
previewMessage.extendedTextMessage.contextInfo = {
|
|
1354
|
+
...(previewMessage.extendedTextMessage.contextInfo || {}),
|
|
1355
|
+
stanzaId: quoted.key.id,
|
|
1356
|
+
participant: jidNormalizedUser(quoted.key.fromMe ? userJid : (quoted.key.participant || quoted.key.remoteJid)),
|
|
1357
|
+
quotedMessage: quoted.message
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
await relayMessage(jid, previewMessage, {
|
|
1362
|
+
messageId: msgId,
|
|
1363
|
+
additionalAttributes: options.additionalAttributes || {},
|
|
1364
|
+
additionalNodes: options.additionalNodes || []
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
const fullMsg = {
|
|
1368
|
+
key: {
|
|
1369
|
+
remoteJid: jid,
|
|
1370
|
+
fromMe: true,
|
|
1371
|
+
id: msgId
|
|
1372
|
+
},
|
|
1373
|
+
message: previewMessage,
|
|
1374
|
+
messageTimestamp: unixTimestampSeconds()
|
|
1375
|
+
};
|
|
1376
|
+
|
|
1377
|
+
if (config.emitOwnEvents) {
|
|
1378
|
+
process.nextTick(async () => {
|
|
1379
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
return fullMsg;
|
|
1383
|
+
}
|
|
1221
1384
|
else {
|
|
1222
1385
|
const fullMsg = await generateWAMessage(jid, content, {
|
|
1223
1386
|
logger,
|