plogme 2.0.8 → 2.0.9
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 +565 -18
- package/WAProto/WAProto.proto +934 -3
- package/WAProto/index.d.ts +33887 -21445
- package/WAProto/index.js +114447 -78804
- package/lib/Defaults/index.js +1 -1
- package/lib/Socket/messages-send.js +99 -66
- package/lib/Types/Message.js +2 -1
- package/lib/Utils/bot-planning-replay.js +6 -9
- package/lib/Utils/chat-utils.js +8 -0
- package/lib/Utils/history.js +21 -1
- package/lib/Utils/messages.js +84 -11
- package/lib/Utils/meta-ai-msmsg.js +75 -2
- package/lib/Utils/meta-compositing.js +38 -9
- package/lib/Utils/rich-message-utils.js +89 -9
- package/lib/Utils/validate-connection.js +4 -2
- package/lib/index.d.ts +45 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
[](https://www.npmjs.com/package/plogme)
|
|
9
9
|
[](https://nodejs.org/)
|
|
10
|
-
[](https://github.com/crysnovax/baileys)
|
|
11
11
|
|
|
12
12
|
## Contents
|
|
13
13
|
|
|
@@ -28,8 +28,9 @@
|
|
|
28
28
|
15. [View-once utilities](#view-once-utilities)
|
|
29
29
|
16. [Connection handling](#connection-handling)
|
|
30
30
|
17. [Security and removed automatic behavior](#security-and-removed-automatic-behavior)
|
|
31
|
-
18. [
|
|
32
|
-
19. [
|
|
31
|
+
18. [Complete public API examples](#complete-public-api-examples)
|
|
32
|
+
19. [Development](#development)
|
|
33
|
+
20. [License and support](#license-and-support)
|
|
33
34
|
|
|
34
35
|
## Installation
|
|
35
36
|
|
|
@@ -196,6 +197,19 @@ await sock.sendMessage(jid, {
|
|
|
196
197
|
}
|
|
197
198
|
}
|
|
198
199
|
})
|
|
200
|
+
|
|
201
|
+
// Solid-color themes use ARGB values internally. Hex strings and numbers are accepted.
|
|
202
|
+
await sock.sendMessage(jid, {
|
|
203
|
+
chatTheme: {
|
|
204
|
+
solidColor: {
|
|
205
|
+
colorLight: '#FFFFFFFF',
|
|
206
|
+
colorDark: '#FF101010',
|
|
207
|
+
doodleColorLight: '#FFCCE8FF',
|
|
208
|
+
doodleColorDark: 0xFF202020,
|
|
209
|
+
isDoodleEnabled: true
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
})
|
|
199
213
|
```
|
|
200
214
|
|
|
201
215
|
### Editing and deleting
|
|
@@ -251,6 +265,57 @@ await sock.sendMessage(jid, {
|
|
|
251
265
|
}
|
|
252
266
|
})
|
|
253
267
|
|
|
268
|
+
// EventInviteMessage supports call links, cover handles, locations, timestamps, and status.
|
|
269
|
+
await sock.sendMessage(jid, {
|
|
270
|
+
eventInvite: {
|
|
271
|
+
eventId: 'release-2026',
|
|
272
|
+
title: 'Plogme release room',
|
|
273
|
+
text: 'Join the release discussion',
|
|
274
|
+
startTime: Math.floor(Date.now() / 1000) + 3600,
|
|
275
|
+
endTime: Math.floor(Date.now() / 1000) + 7200,
|
|
276
|
+
callLink: 'https://call.whatsapp.com/video/example',
|
|
277
|
+
coverImageHandle: 'cover-handle-from-whatsapp',
|
|
278
|
+
locationName: 'Lagos',
|
|
279
|
+
lastUpdatedTsUsec: Date.now() * 1000,
|
|
280
|
+
status: 'ACTIVE'
|
|
281
|
+
}
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
// Plogme already supports sending a live location through the existing
|
|
285
|
+
// `location` builder by setting `isLive: true`.
|
|
286
|
+
const liveLocationMessage = await sock.sendMessage(jid, {
|
|
287
|
+
location: {
|
|
288
|
+
degreesLatitude: 6.5244,
|
|
289
|
+
degreesLongitude: 3.3792,
|
|
290
|
+
name: 'Lagos',
|
|
291
|
+
isLive: true,
|
|
292
|
+
accuracyInMeters: 10,
|
|
293
|
+
speedInMps: 0
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
// These newer fields are different: they ask the recipient to share a
|
|
298
|
+
// location, or update/cancel a request for an existing live location.
|
|
299
|
+
await sock.sendMessage(jid, { requestLocation: true })
|
|
300
|
+
await sock.sendMessage(jid, {
|
|
301
|
+
requestLocationUpdate: {
|
|
302
|
+
key: liveLocationMessage.key,
|
|
303
|
+
cancel: false,
|
|
304
|
+
senderTimestampMs: Date.now()
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
await sock.sendMessage(jid, {
|
|
308
|
+
requestLocationUpdate: { key: liveLocationMessage.key, cancel: true }
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
// The latest proto also exposes these lower-level fields for forward-compatible relays.
|
|
312
|
+
await sock.relayMessage(jid, {
|
|
313
|
+
instantImageMessage: { caption: 'Instant image' }
|
|
314
|
+
}, {})
|
|
315
|
+
await sock.relayMessage(groupJid, {
|
|
316
|
+
botGroupParticipantMessage: {}
|
|
317
|
+
}, {})
|
|
318
|
+
|
|
254
319
|
await sock.sendMessage(jid, {
|
|
255
320
|
poll: {
|
|
256
321
|
name: 'Release preference',
|
|
@@ -263,6 +328,53 @@ await sock.sendMessage(jid, {
|
|
|
263
328
|
})
|
|
264
329
|
```
|
|
265
330
|
|
|
331
|
+
### Latest WAProto additions
|
|
332
|
+
|
|
333
|
+
The WAProto generation is updated to WhatsApp Web revision
|
|
334
|
+
`2.3000.1049983640`. The following new fields are available through the
|
|
335
|
+
generated `proto` namespace and are preserved during encode/decode:
|
|
336
|
+
|
|
337
|
+
| Surface | What it represents |
|
|
338
|
+
| --- | --- |
|
|
339
|
+
| `requestLocationMessage` | Ask a chat to share its current location. |
|
|
340
|
+
| `requestLocationUpdateMessage` | Request a live-location update or cancel an existing request. |
|
|
341
|
+
| `instantImageMessage` | Image content using the newer instant-image message slot. |
|
|
342
|
+
| `botGroupParticipantMessage` | Bot participant content for group-addressed protocol messages. |
|
|
343
|
+
| `favoriteStickers` | Favorite sticker metadata in history sync. |
|
|
344
|
+
| `omittedConversations` | Conversations deliberately omitted from a history-sync batch. |
|
|
345
|
+
| `CommunityNestingStateAction` | Community nesting state changes from app-state sync. |
|
|
346
|
+
| ARGB wallpaper fields | Light, dark, and doodle wallpaper colors as fixed ARGB values. |
|
|
347
|
+
| Event-invite fields | Call link, cover handle, location, update timestamp, and status. |
|
|
348
|
+
|
|
349
|
+
Favorite stickers and omitted conversations arrive through the normal history
|
|
350
|
+
event. `omittedConversationsProvided` tells consumers that the omission list
|
|
351
|
+
was explicitly supplied by WhatsApp, so an incomplete batch is not mistaken
|
|
352
|
+
for a complete history:
|
|
353
|
+
|
|
354
|
+
```javascript
|
|
355
|
+
sock.ev.on('messaging-history.set', ({ favoriteStickers, omittedConversations, omittedConversationsProvided }) => {
|
|
356
|
+
if (favoriteStickers?.length) {
|
|
357
|
+
console.log('favorite stickers:', favoriteStickers.length)
|
|
358
|
+
}
|
|
359
|
+
if (omittedConversationsProvided) {
|
|
360
|
+
console.log('history intentionally omitted:', omittedConversations)
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Community nesting changes arrive through `groups.update`. The update contains
|
|
366
|
+
the raw proto enum and a convenient boolean:
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
sock.ev.on('groups.update', updates => {
|
|
370
|
+
for (const update of updates) {
|
|
371
|
+
if (update.nestingState !== undefined) {
|
|
372
|
+
console.log('community nested:', update.nested, update.nestingState)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
})
|
|
376
|
+
```
|
|
377
|
+
|
|
266
378
|
### Forward and edit
|
|
267
379
|
|
|
268
380
|
```js
|
|
@@ -338,10 +450,10 @@ await sock.sendAlbumMessage(jid, [
|
|
|
338
450
|
image: {
|
|
339
451
|
sourceUrl: 'https://example.com/two-preview.jpg',
|
|
340
452
|
imageHighResUrl: 'https://example.com/two.jpg',
|
|
341
|
-
darkModePreviewUrl: 'https://example.com/two-dark-preview.jpg',
|
|
342
|
-
darkModeHighResUrl: 'https://example.com/two-dark.jpg',
|
|
343
453
|
width: 1200,
|
|
344
|
-
height: 800
|
|
454
|
+
height: 800,
|
|
455
|
+
fullWidth: 2400,
|
|
456
|
+
fullHeight: 1600
|
|
345
457
|
}
|
|
346
458
|
},
|
|
347
459
|
{
|
|
@@ -367,7 +479,7 @@ await sock.sendMessage(jid, {
|
|
|
367
479
|
})
|
|
368
480
|
```
|
|
369
481
|
|
|
370
|
-
`sendAlbumMessage()` accepts fetchable image and video URLs. Local `Buffer`/file inputs are not uploaded by this rich album API. The lower-level `prepareGridImageMessage()` helper remains available when a compact `GRID_IMAGE` layout is specifically required; `sendAlbumMessage()` itself uses a full-width `GenAIVStackLayoutViewModel` presentation for both images and videos.
|
|
482
|
+
`sendAlbumMessage()` accepts fetchable image and video URLs. Local `Buffer`/file inputs are not uploaded by this rich album API. The lower-level `prepareGridImageMessage()` helper remains available when a compact `GRID_IMAGE` layout is specifically required; `sendAlbumMessage()` itself uses a full-width `GenAIVStackLayoutViewModel` presentation for both images and videos. Vertical image album items intentionally send only `full_image`—without preview or dark-mode slots—so WhatsApp does not render a broken preview placeholder before opening the original. When available, `imageHighResUrl`, `highResUrl`, or `fullUrl` is used as the full asset; provide `fullWidth` and `fullHeight` to preserve the source dimensions. Preview and dark-mode URL fields are not used by this vertical album path.
|
|
371
483
|
|
|
372
484
|
### Video grids
|
|
373
485
|
|
|
@@ -534,6 +646,68 @@ await sock.sendMessage(jid, {
|
|
|
534
646
|
})
|
|
535
647
|
```
|
|
536
648
|
|
|
649
|
+
### Native carousel details
|
|
650
|
+
|
|
651
|
+
The native carousel composer accepts both `sendMessage` and the convenient
|
|
652
|
+
`sendCarousel` socket method. A top-level `text` is optional: cards-only
|
|
653
|
+
messages are valid. The default card type is horizontal scrolling
|
|
654
|
+
(`HSCROLL_CARDS`); use `carouselCardType: 2` or `'album'` only when the
|
|
655
|
+
receiving client supports the album-image card layout.
|
|
656
|
+
|
|
657
|
+
```js
|
|
658
|
+
await sock.sendCarousel(jid, [
|
|
659
|
+
{
|
|
660
|
+
title: 'Documentation',
|
|
661
|
+
subtitle: 'Read the guide',
|
|
662
|
+
body: { text: 'Open the latest API documentation.' },
|
|
663
|
+
image: { url: 'https://cdn.example.com/docs.jpg' },
|
|
664
|
+
buttons: [
|
|
665
|
+
{ text: 'Open docs', url: 'https://example.com/docs', useWebview: true }
|
|
666
|
+
],
|
|
667
|
+
footer: 'Plogme'
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
title: 'Release video',
|
|
671
|
+
body: 'See what changed in this release.',
|
|
672
|
+
video: { url: 'https://cdn.example.com/release.mp4' },
|
|
673
|
+
nativeFlow: [{ text: 'Watch', id: 'watch-release' }]
|
|
674
|
+
}
|
|
675
|
+
], {
|
|
676
|
+
carouselCardType: 'horizontal',
|
|
677
|
+
text: 'Choose an item',
|
|
678
|
+
footer: 'Swipe to continue'
|
|
679
|
+
})
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
The equivalent lower-level form is:
|
|
683
|
+
|
|
684
|
+
```js
|
|
685
|
+
await sock.sendMessage(jid, {
|
|
686
|
+
cards: [
|
|
687
|
+
{
|
|
688
|
+
title: 'First card',
|
|
689
|
+
body: { text: 'Cards may be sent without a top-level message.' },
|
|
690
|
+
image: { url: 'https://cdn.example.com/first.jpg' },
|
|
691
|
+
nativeFlow: [{ text: 'Select', id: 'first-card' }]
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
title: 'Second card',
|
|
695
|
+
caption: 'Use `caption` as a shorthand for body text.',
|
|
696
|
+
image: { url: 'https://cdn.example.com/second.jpg' }
|
|
697
|
+
}
|
|
698
|
+
],
|
|
699
|
+
carouselCardType: 1
|
|
700
|
+
})
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Carousel media must use the normal fetchable media inputs supported by
|
|
704
|
+
`prepareWAMessageMedia` (for example public URLs or uploaded media objects).
|
|
705
|
+
Each card can contain an image or video header, `title`, `subtitle`, `body`,
|
|
706
|
+
`caption`, `footer`, `thumbnail`, and native-flow buttons. A card that contains
|
|
707
|
+
both body text and media retains its media header; it is not converted into a
|
|
708
|
+
blank text-only card. Button IDs are event values and must be validated by the
|
|
709
|
+
receiving application.
|
|
710
|
+
|
|
537
711
|
### Hydrated templates
|
|
538
712
|
|
|
539
713
|
```js
|
|
@@ -1468,6 +1642,322 @@ Plogme does not automatically follow WhatsApp channels, fingerprint the host mac
|
|
|
1468
1642
|
|
|
1469
1643
|
The project license still applies. Removing runtime enforcement does not change the license terms.
|
|
1470
1644
|
|
|
1645
|
+
## Complete public API examples
|
|
1646
|
+
|
|
1647
|
+
The examples below provide a call shape for every public method in `lib/index.d.ts`. Replace the placeholder values with data from your application and review the method's TypeScript signature before using account, privacy, interop, or security operations. Methods that change account state, permissions, group membership, or credentials should only be called after your application has obtained the appropriate user authorization.
|
|
1648
|
+
|
|
1649
|
+
### Rich, status, and diagnostics
|
|
1650
|
+
|
|
1651
|
+
```js
|
|
1652
|
+
const jid = '1234567890@s.whatsapp.net'
|
|
1653
|
+
const groupJid = '120363000000000000@g.us'
|
|
1654
|
+
const userJid = '15551234567@s.whatsapp.net'
|
|
1655
|
+
|
|
1656
|
+
// relayMessage: send the raw forwarded GenAI label envelope.
|
|
1657
|
+
const labelPayload = {
|
|
1658
|
+
__typename: 'GenAIUnifiedResponse',
|
|
1659
|
+
response_id: 'test123',
|
|
1660
|
+
sections: [{
|
|
1661
|
+
__typename: 'GenAIUnifiedResponseSection',
|
|
1662
|
+
view_model: {
|
|
1663
|
+
__typename: 'GenAISingleLayoutViewModel',
|
|
1664
|
+
primitive: {
|
|
1665
|
+
__typename: 'GenAILabelPrimitive',
|
|
1666
|
+
text: 'Hello goys',
|
|
1667
|
+
variant: 'POSITIVE',
|
|
1668
|
+
background_color_override: '#FF0000FF',
|
|
1669
|
+
text_color_override: '#000000FF'
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}]
|
|
1673
|
+
}
|
|
1674
|
+
await sock.relayMessage(jid, {
|
|
1675
|
+
botForwardedMessage: {
|
|
1676
|
+
message: {
|
|
1677
|
+
richResponseMessage: {
|
|
1678
|
+
messageType: 1,
|
|
1679
|
+
unifiedResponse: {
|
|
1680
|
+
data: Buffer.from(JSON.stringify(labelPayload)).toString('base64')
|
|
1681
|
+
},
|
|
1682
|
+
contextInfo: { isForwarded: true, forwardOrigin: 4 }
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}, {})
|
|
1687
|
+
// sendStatusMentions
|
|
1688
|
+
await sock.sendStatusMentions({ text: 'Hello from my status' }, [userJid])
|
|
1689
|
+
// sendBotPlanning
|
|
1690
|
+
await sock.sendBotPlanning(jid, { text: 'Working through the plan', steps: ['Fetch data', 'Send result'] })
|
|
1691
|
+
// sendRichLabelMessage
|
|
1692
|
+
await sock.sendRichLabelMessage(jid, {
|
|
1693
|
+
text: 'Hello goys',
|
|
1694
|
+
responseId: 'test123',
|
|
1695
|
+
variant: 'POSITIVE',
|
|
1696
|
+
backgroundColor: '#FF0000FF',
|
|
1697
|
+
textColor: '#000000FF'
|
|
1698
|
+
})
|
|
1699
|
+
// sendRichGeneration
|
|
1700
|
+
await sock.sendRichGeneration(jid, {}, undefined, undefined)
|
|
1701
|
+
// getStatusPrivacy
|
|
1702
|
+
await sock.getStatusPrivacy()
|
|
1703
|
+
// setStatusPrivacy
|
|
1704
|
+
await sock.setStatusPrivacy('contacts', [userJid])
|
|
1705
|
+
// fetchBroadcastListQuota
|
|
1706
|
+
await sock.fetchBroadcastListQuota()
|
|
1707
|
+
// getChatBlockingStatus
|
|
1708
|
+
await sock.getChatBlockingStatus()
|
|
1709
|
+
// updateChatBlockingStatus
|
|
1710
|
+
await sock.updateChatBlockingStatus('block')
|
|
1711
|
+
// getUserDisclosures
|
|
1712
|
+
await sock.getUserDisclosures(0)
|
|
1713
|
+
// acceptTosNotice
|
|
1714
|
+
await sock.acceptTosNotice(0, {})
|
|
1715
|
+
// getOptOutList
|
|
1716
|
+
await sock.getOptOutList()
|
|
1717
|
+
// sendKeyIndexList
|
|
1718
|
+
await sock.sendKeyIndexList()
|
|
1719
|
+
```
|
|
1720
|
+
|
|
1721
|
+
### Account, privacy, and security
|
|
1722
|
+
|
|
1723
|
+
```js
|
|
1724
|
+
const jid = '1234567890@s.whatsapp.net'
|
|
1725
|
+
const groupJid = '120363000000000000@g.us'
|
|
1726
|
+
const userJid = '15551234567@s.whatsapp.net'
|
|
1727
|
+
|
|
1728
|
+
// signPrivateCredential
|
|
1729
|
+
await sock.signPrivateCredential(Buffer.from('payload'))
|
|
1730
|
+
// getPushConfig
|
|
1731
|
+
await sock.getPushConfig()
|
|
1732
|
+
// setPushConfig
|
|
1733
|
+
await sock.setPushConfig({})
|
|
1734
|
+
// toggleCallLinkWaitingRoom
|
|
1735
|
+
await sock.toggleCallLinkWaitingRoom('example', true, 0)
|
|
1736
|
+
// storePrivacyTokens
|
|
1737
|
+
await sock.storePrivacyTokens([userJid])
|
|
1738
|
+
// updateBioPrivacy
|
|
1739
|
+
await sock.updateBioPrivacy('example')
|
|
1740
|
+
// blockBot
|
|
1741
|
+
await sock.blockBot(jid)
|
|
1742
|
+
// unblockBot
|
|
1743
|
+
await sock.unblockBot(jid)
|
|
1744
|
+
// getBotProfile
|
|
1745
|
+
await sock.getBotProfile(jid)
|
|
1746
|
+
// fetchABProps
|
|
1747
|
+
await sock.fetchABProps('example', 'example', 'example', 'example')
|
|
1748
|
+
// removeCompanionDevice
|
|
1749
|
+
await sock.removeCompanionDevice(jid, 0)
|
|
1750
|
+
// updateKeyIndexList
|
|
1751
|
+
await sock.updateKeyIndexList(0, Buffer.from('payload'))
|
|
1752
|
+
// fetchMediaConn
|
|
1753
|
+
await sock.fetchMediaConn('example')
|
|
1754
|
+
// deleteBroadcastList
|
|
1755
|
+
await sock.deleteBroadcastList(0)
|
|
1756
|
+
// fetchQRCode
|
|
1757
|
+
await sock.fetchQRCode('example', 'example')
|
|
1758
|
+
// confirmDeviceLogout
|
|
1759
|
+
await sock.confirmDeviceLogout(0, true)
|
|
1760
|
+
// checkUsername
|
|
1761
|
+
await sock.checkUsername('example')
|
|
1762
|
+
// checkUsernameMulti
|
|
1763
|
+
await sock.checkUsernameMulti([userJid])
|
|
1764
|
+
// setUsername
|
|
1765
|
+
await sock.setUsername('example', undefined)
|
|
1766
|
+
// deleteUsername
|
|
1767
|
+
await sock.deleteUsername()
|
|
1768
|
+
// getMyUsername
|
|
1769
|
+
await sock.getMyUsername()
|
|
1770
|
+
// getUsernameRecommendations
|
|
1771
|
+
await sock.getUsernameRecommendations()
|
|
1772
|
+
// setUsernamePin
|
|
1773
|
+
await sock.setUsernamePin('example')
|
|
1774
|
+
// findUserByUsername
|
|
1775
|
+
await sock.findUserByUsername('example')
|
|
1776
|
+
// fetchContactUsernames
|
|
1777
|
+
await sock.fetchContactUsernames(jid)
|
|
1778
|
+
// getPrivacySettings
|
|
1779
|
+
await sock.getPrivacySettings()
|
|
1780
|
+
// setPrivacySetting
|
|
1781
|
+
await sock.setPrivacySetting(undefined, 'example')
|
|
1782
|
+
// updatePrivacyContactList
|
|
1783
|
+
await sock.updatePrivacyContactList(undefined, 'example', jid)
|
|
1784
|
+
// getPrivacyContactList
|
|
1785
|
+
await sock.getPrivacyContactList(undefined)
|
|
1786
|
+
// updateTextStatus
|
|
1787
|
+
await sock.updateTextStatus(undefined)
|
|
1788
|
+
// getTextStatusList
|
|
1789
|
+
await sock.getTextStatusList()
|
|
1790
|
+
// updateUserStatus
|
|
1791
|
+
await sock.updateUserStatus(undefined)
|
|
1792
|
+
// fetchUserPictureInfo
|
|
1793
|
+
await sock.fetchUserPictureInfo(jid)
|
|
1794
|
+
// setProfilePictureMex
|
|
1795
|
+
await sock.setProfilePictureMex(jid, Buffer.from('payload'))
|
|
1796
|
+
// hasPassword
|
|
1797
|
+
await sock.hasPassword()
|
|
1798
|
+
// setPassword
|
|
1799
|
+
await sock.setPassword('example')
|
|
1800
|
+
// checkPassword
|
|
1801
|
+
await sock.checkPassword('example')
|
|
1802
|
+
// deletePassword
|
|
1803
|
+
await sock.deletePassword()
|
|
1804
|
+
// passkeyExists
|
|
1805
|
+
await sock.passkeyExists()
|
|
1806
|
+
// getRegistrationUpsells
|
|
1807
|
+
await sock.getRegistrationUpsells()
|
|
1808
|
+
// contactsUpload
|
|
1809
|
+
await sock.contactsUpload([userJid])
|
|
1810
|
+
// submitAge
|
|
1811
|
+
await sock.submitAge(0)
|
|
1812
|
+
// managedAccountInitiateLinking
|
|
1813
|
+
await sock.managedAccountInitiateLinking()
|
|
1814
|
+
// managedAccountValidateLinking
|
|
1815
|
+
await sock.managedAccountValidateLinking('example')
|
|
1816
|
+
// managedAccountAcceptLinking
|
|
1817
|
+
await sock.managedAccountAcceptLinking('example')
|
|
1818
|
+
// managedAccountCompleteLinking
|
|
1819
|
+
await sock.managedAccountCompleteLinking('example')
|
|
1820
|
+
// managedAccountRevokeLinking
|
|
1821
|
+
await sock.managedAccountRevokeLinking()
|
|
1822
|
+
// managedAccountSyncActivities
|
|
1823
|
+
await sock.managedAccountSyncActivities()
|
|
1824
|
+
// managedAccountUpdatePin
|
|
1825
|
+
await sock.managedAccountUpdatePin('example')
|
|
1826
|
+
// setAccessToken
|
|
1827
|
+
await sock.setAccessToken('example')
|
|
1828
|
+
// setWamoAuth
|
|
1829
|
+
await sock.setWamoAuth('example')
|
|
1830
|
+
// acquireAccessToken
|
|
1831
|
+
await sock.acquireAccessToken()
|
|
1832
|
+
// executeWWWGraphQL
|
|
1833
|
+
await sock.executeWWWGraphQL('example', undefined)
|
|
1834
|
+
// executeFacebookGraphQL
|
|
1835
|
+
await sock.executeFacebookGraphQL('example', undefined)
|
|
1836
|
+
// executeWamoGraphQL
|
|
1837
|
+
await sock.executeWamoGraphQL('example', undefined)
|
|
1838
|
+
```
|
|
1839
|
+
|
|
1840
|
+
### Groups, AI groups, and calls
|
|
1841
|
+
|
|
1842
|
+
```js
|
|
1843
|
+
const jid = '1234567890@s.whatsapp.net'
|
|
1844
|
+
const groupJid = '120363000000000000@g.us'
|
|
1845
|
+
const userJid = '15551234567@s.whatsapp.net'
|
|
1846
|
+
|
|
1847
|
+
// groupCall
|
|
1848
|
+
await sock.groupCall(jid, [userJid], true)
|
|
1849
|
+
// cancelGroupCall
|
|
1850
|
+
await sock.cancelGroupCall(jid, 'example')
|
|
1851
|
+
// aiGroupMetadata
|
|
1852
|
+
await sock.aiGroupMetadata(jid)
|
|
1853
|
+
// aiGroupCreate
|
|
1854
|
+
await sock.aiGroupCreate('example', [userJid], undefined)
|
|
1855
|
+
// aiGroupAddBot
|
|
1856
|
+
await sock.aiGroupAddBot(jid, undefined)
|
|
1857
|
+
// aiGroupLeave
|
|
1858
|
+
await sock.aiGroupLeave('example')
|
|
1859
|
+
// aiGroupParticipantsUpdate
|
|
1860
|
+
await sock.aiGroupParticipantsUpdate(jid, [userJid], 'example')
|
|
1861
|
+
// aiGroupUpdateSubject
|
|
1862
|
+
await sock.aiGroupUpdateSubject(jid, 'example')
|
|
1863
|
+
// aiGroupInviteCode
|
|
1864
|
+
await sock.aiGroupInviteCode(jid)
|
|
1865
|
+
// aiGroupRevokeInvite
|
|
1866
|
+
await sock.aiGroupRevokeInvite(jid)
|
|
1867
|
+
// aiGroupAcceptInvite
|
|
1868
|
+
await sock.aiGroupAcceptInvite('example')
|
|
1869
|
+
// aiGroupSettingUpdate
|
|
1870
|
+
await sock.aiGroupSettingUpdate(jid, 'example')
|
|
1871
|
+
// aiGroupToggleEphemeral
|
|
1872
|
+
await sock.aiGroupToggleEphemeral(jid, 0)
|
|
1873
|
+
// groupAcknowledge
|
|
1874
|
+
await sock.groupAcknowledge(jid)
|
|
1875
|
+
// groupGetLinkedParticipants
|
|
1876
|
+
await sock.groupGetLinkedParticipants(jid)
|
|
1877
|
+
// groupJoinLinked
|
|
1878
|
+
await sock.groupJoinLinked(jid, jid, 'example')
|
|
1879
|
+
// groupCreateSubGroupSuggestion
|
|
1880
|
+
await sock.groupCreateSubGroupSuggestion(jid, {})
|
|
1881
|
+
// groupSubGroupSuggestionsAction
|
|
1882
|
+
await sock.groupSubGroupSuggestionsAction(jid, 'example', {})
|
|
1883
|
+
```
|
|
1884
|
+
|
|
1885
|
+
### Interop
|
|
1886
|
+
|
|
1887
|
+
```js
|
|
1888
|
+
const jid = '1234567890@s.whatsapp.net'
|
|
1889
|
+
const groupJid = '120363000000000000@g.us'
|
|
1890
|
+
const userJid = '15551234567@s.whatsapp.net'
|
|
1891
|
+
|
|
1892
|
+
// initInterop
|
|
1893
|
+
await sock.initInterop()
|
|
1894
|
+
// resetInteropSession
|
|
1895
|
+
await sock.resetInteropSession()
|
|
1896
|
+
// acceptInteropTOS
|
|
1897
|
+
await sock.acceptInteropTOS()
|
|
1898
|
+
// resolveInteropUser
|
|
1899
|
+
await sock.resolveInteropUser(jid)
|
|
1900
|
+
// resolveInteropUsers
|
|
1901
|
+
await sock.resolveInteropUsers(jid)
|
|
1902
|
+
// blockInteropUser
|
|
1903
|
+
await sock.blockInteropUser(jid)
|
|
1904
|
+
// unblockInteropUser
|
|
1905
|
+
await sock.unblockInteropUser(jid)
|
|
1906
|
+
// reportInteropSpam
|
|
1907
|
+
await sock.reportInteropSpam(jid)
|
|
1908
|
+
// trustInteropContact
|
|
1909
|
+
await sock.trustInteropContact(jid)
|
|
1910
|
+
// createInteropGroup
|
|
1911
|
+
await sock.createInteropGroup('example', [userJid])
|
|
1912
|
+
// leaveInteropGroup
|
|
1913
|
+
await sock.leaveInteropGroup(jid)
|
|
1914
|
+
// addParticipantsToInteropGroup
|
|
1915
|
+
await sock.addParticipantsToInteropGroup(jid, [userJid])
|
|
1916
|
+
// queryInteropGroupInfo
|
|
1917
|
+
await sock.queryInteropGroupInfo(jid)
|
|
1918
|
+
// queryInteropPrivacySettings
|
|
1919
|
+
await sock.queryInteropPrivacySettings()
|
|
1920
|
+
// updateInteropPrivacySetting
|
|
1921
|
+
await sock.updateInteropPrivacySetting('example', 'example')
|
|
1922
|
+
// updateInteropPrivacySettingWithContactList
|
|
1923
|
+
await sock.updateInteropPrivacySettingWithContactList('example', 'example', [userJid])
|
|
1924
|
+
// getInteropGroupAddPrivacy
|
|
1925
|
+
await sock.getInteropGroupAddPrivacy()
|
|
1926
|
+
```
|
|
1927
|
+
|
|
1928
|
+
### Generic helpers
|
|
1929
|
+
|
|
1930
|
+
```js
|
|
1931
|
+
const jid = '1234567890@s.whatsapp.net'
|
|
1932
|
+
const groupJid = '120363000000000000@g.us'
|
|
1933
|
+
const userJid = '15551234567@s.whatsapp.net'
|
|
1934
|
+
|
|
1935
|
+
// updateRichGeneration
|
|
1936
|
+
await sock.updateRichGeneration(jid, 'example', {}, undefined)
|
|
1937
|
+
// aiPrompt
|
|
1938
|
+
await sock.aiPrompt(jid, 'example', undefined)
|
|
1939
|
+
// getGroupProfilePictures
|
|
1940
|
+
await sock.getGroupProfilePictures(jid, 'example')
|
|
1941
|
+
// fetchIntegrators
|
|
1942
|
+
await sock.fetchIntegrators()
|
|
1943
|
+
// optInIntegrators
|
|
1944
|
+
await sock.optInIntegrators()
|
|
1945
|
+
// optOutIntegrators
|
|
1946
|
+
await sock.optOutIntegrators()
|
|
1947
|
+
// getReachabilitySettings
|
|
1948
|
+
await sock.getReachabilitySettings()
|
|
1949
|
+
// setReachabilitySettings
|
|
1950
|
+
await sock.setReachabilitySettings('example')
|
|
1951
|
+
// get
|
|
1952
|
+
await sock.get(undefined)
|
|
1953
|
+
// set
|
|
1954
|
+
await sock.set(undefined, 'example', 0)
|
|
1955
|
+
// delete
|
|
1956
|
+
await sock.delete(undefined)
|
|
1957
|
+
// keys
|
|
1958
|
+
await sock.keys(undefined)
|
|
1959
|
+
```
|
|
1960
|
+
|
|
1471
1961
|
## Development
|
|
1472
1962
|
|
|
1473
1963
|
```bash
|
|
@@ -2328,14 +2818,66 @@ await sock.cleanDirtyBits('account_sync', timestamp)
|
|
|
2328
2818
|
|
|
2329
2819
|
Meta AI-style thinking indicators and live reasoning feeds. Works on all WhatsApp clients — no "Update WhatsApp" messages.
|
|
2330
2820
|
|
|
2821
|
+
### Verified Meta AI prompts and streaming `MESSAGE_EDIT` replies
|
|
2822
|
+
|
|
2823
|
+
The Hatch-compatible Meta AI sender routes prompts to the bot endpoint and
|
|
2824
|
+
returns the outgoing message ID:
|
|
2825
|
+
|
|
2826
|
+
```javascript
|
|
2827
|
+
const messageId = await sock.sendMetaAI('Summarize this conversation', {
|
|
2828
|
+
// Defaults to 867051314767696@bot
|
|
2829
|
+
jid: '867051314767696@bot'
|
|
2830
|
+
})
|
|
2831
|
+
```
|
|
2832
|
+
|
|
2833
|
+
Meta AI responses can arrive as a sequence rather than one final message. The
|
|
2834
|
+
first message is often a placeholder or partial response. WhatsApp then sends
|
|
2835
|
+
`MESSAGE_EDIT` protocol messages whose `protocolMessage.editedMessage` contains
|
|
2836
|
+
the newest version of the bot response. Each edit replaces the previous text;
|
|
2837
|
+
it is not a separate conversation message.
|
|
2838
|
+
|
|
2839
|
+
Plogme's `extractMetaAiText()` checks the edited body first and also handles
|
|
2840
|
+
plain text, rich-response submessages, and base64 unified responses:
|
|
2841
|
+
|
|
2842
|
+
```javascript
|
|
2843
|
+
import { extractMetaAiText } from 'plogme'
|
|
2844
|
+
|
|
2845
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
2846
|
+
for (const message of messages) {
|
|
2847
|
+
const text = extractMetaAiText(message.message)
|
|
2848
|
+
if (text) console.log('latest Meta AI text:', text)
|
|
2849
|
+
}
|
|
2850
|
+
})
|
|
2851
|
+
```
|
|
2852
|
+
|
|
2853
|
+
An incoming edit has the conceptual shape below:
|
|
2854
|
+
|
|
2855
|
+
```javascript
|
|
2856
|
+
{
|
|
2857
|
+
protocolMessage: {
|
|
2858
|
+
type: 'MESSAGE_EDIT',
|
|
2859
|
+
key: { remoteJid: '867051314767696@bot', id: 'ORIGINAL_ID' },
|
|
2860
|
+
editedMessage: {
|
|
2861
|
+
extendedTextMessage: { text: 'latest streamed response' }
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
```
|
|
2866
|
+
|
|
2867
|
+
For unified responses, the raw payload remains available in
|
|
2868
|
+
`unifiedResponse.data`; the decoder adds `decodedData` and flattened `text` in
|
|
2869
|
+
place. This makes it possible to render partial edits immediately while still
|
|
2870
|
+
retaining the original wire representation.
|
|
2871
|
+
|
|
2331
2872
|
**Note:** These use plain text placeholders with typing indicators by default, avoiding unsupported-message bubbles. Final code blocks, tables, links, and rich responses are unchanged. Native Meta typing/thinking is force-only: set both `forceMetaRendering: true` in the socket config and `useNativeMeta: true` in the `metaTyping` or `sendMetaComposited` options.
|
|
2332
2873
|
|
|
2333
2874
|
### Meta Typing Indicator
|
|
2334
2875
|
|
|
2335
|
-
Show a live thinking indicator that you control.
|
|
2876
|
+
Show a live thinking indicator that you control. It is a real message, so you
|
|
2877
|
+
can edit it in place or delete it manually when finished.
|
|
2336
2878
|
|
|
2337
2879
|
```javascript
|
|
2338
|
-
import { metaTyping, buildSteps } from 'plogme'
|
|
2880
|
+
import { metaTyping, editMetaMessage, buildSteps } from 'plogme'
|
|
2339
2881
|
|
|
2340
2882
|
const placeholder = await metaTyping(sock, jid, {
|
|
2341
2883
|
description: 'Thinking…',
|
|
@@ -2344,11 +2886,9 @@ const placeholder = await metaTyping(sock, jid, {
|
|
|
2344
2886
|
|
|
2345
2887
|
// Do your work here…
|
|
2346
2888
|
|
|
2347
|
-
//
|
|
2348
|
-
await sock
|
|
2349
|
-
|
|
2350
|
-
// Send the real message
|
|
2351
|
-
await sock.sendMessage(jid, { text: 'Here is your answer!' })
|
|
2889
|
+
// Keep the same message key while streaming progress
|
|
2890
|
+
await editMetaMessage(sock, jid, placeholder.key, { text: 'Thinking… I found something.' })
|
|
2891
|
+
await editMetaMessage(sock, jid, placeholder.key, { text: 'Here is your answer!' })
|
|
2352
2892
|
```
|
|
2353
2893
|
|
|
2354
2894
|
What users see:
|
|
@@ -2360,14 +2900,15 @@ _Thinking…_
|
|
|
2360
2900
|
○ Reading your message…
|
|
2361
2901
|
○ Writing response…
|
|
2362
2902
|
|
|
2363
|
-
|
|
2903
|
+
_Thinking… I found something._
|
|
2364
2904
|
|
|
2365
|
-
Here is your answer!
|
|
2905
|
+
Here is your answer! // same message, updated through MESSAGE_EDIT
|
|
2366
2906
|
```
|
|
2367
2907
|
|
|
2368
2908
|
### Meta Compositing
|
|
2369
2909
|
|
|
2370
|
-
Full flow:
|
|
2910
|
+
Full flow: initial message → optional `MESSAGE_EDIT` stream frames → final
|
|
2911
|
+
`MESSAGE_EDIT` on the same message key. Works with every rich content type.
|
|
2371
2912
|
|
|
2372
2913
|
```javascript
|
|
2373
2914
|
import { sendMetaComposited, PlanningStepStatus } from 'plogme'
|
|
@@ -2379,6 +2920,11 @@ await sendMetaComposited(
|
|
|
2379
2920
|
{
|
|
2380
2921
|
thinkingMs: 3000,
|
|
2381
2922
|
description: 'Analyzing…',
|
|
2923
|
+
streamUpdates: [
|
|
2924
|
+
'Thinking…',
|
|
2925
|
+
'Thinking… I found the relevant code.'
|
|
2926
|
+
],
|
|
2927
|
+
streamUpdateDelayMs: 700,
|
|
2382
2928
|
steps: [
|
|
2383
2929
|
{ title: 'Reading context…', status: PlanningStepStatus.DONE },
|
|
2384
2930
|
{ title: 'Writing code…', status: PlanningStepStatus.IN_PROGRESS }
|
|
@@ -2416,7 +2962,8 @@ await sendMetaComposited(
|
|
|
2416
2962
|
|
|
2417
2963
|
### Replay Planning
|
|
2418
2964
|
|
|
2419
|
-
Live Meta AI-style reasoning feed — each step visibly completes in real time,
|
|
2965
|
+
Live Meta AI-style reasoning feed — each step visibly completes in real time,
|
|
2966
|
+
then the final rich message is written with `MESSAGE_EDIT` on the same key.
|
|
2420
2967
|
|
|
2421
2968
|
```javascript
|
|
2422
2969
|
import { replayPlanning, mixedSteps } from 'plogme'
|