plogme 2.0.8 → 2.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/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  [![npm version](https://img.shields.io/npm/v/plogme?style=flat-square)](https://www.npmjs.com/package/plogme)
9
9
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-10b981?style=flat-square&logo=node.js)](https://nodejs.org/)
10
- [![Tests](https://img.shields.io/badge/tests-30%20passing-10b981?style=flat-square)](https://github.com/crysnovax/baileys)
10
+ [![Tests](https://img.shields.io/badge/tests-174%20passing-10b981?style=flat-square)](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. [Development](#development)
32
- 19. [License and support](#license-and-support)
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. Image primitives explicitly request full-width presentation and carry preview/full URL fallbacks.
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. Delete it manually when ready — no "edited" badge ever appears.
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
- // Delete the indicator cleanly
2348
- await sock.sendMessage(jid, { delete: placeholder.key })
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
- [auto-deletes]
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: indicator shows → auto-deletes → clean final message lands. Works with every rich content type.
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, then the final rich message lands clean.
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'