plogme 2.0.4 → 2.0.6
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 +1526 -5
- package/lib/Socket/chats.js +3 -0
- package/lib/Socket/messages-send.js +178 -9
- package/lib/Utils/messages.js +10 -1
- package/lib/Utils/rich-message-utils.js +270 -33
- package/lib/index.d.ts +29 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Plogme
|
|
1
|
+
# Plogme ⚉
|
|
2
2
|
|
|
3
3
|
**Plogme** is a Node.js WhatsApp Web client built on the Baileys protocol implementation. It provides authentication, messaging, media uploads, groups, status updates, interactive messages, albums, rich responses, Meta AI-style envelopes, HTML screens, and selected WhatsApp Web protocol features.
|
|
4
4
|
|
|
@@ -234,6 +234,44 @@ await sock.updateProfileName('Cody AI')
|
|
|
234
234
|
await sock.updateProfileStatus('Building helpful WhatsApp tools')
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
+
### Events and polls
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
await sock.sendMessage(jid, {
|
|
241
|
+
event: {
|
|
242
|
+
name: 'Meet and Mingle',
|
|
243
|
+
description: 'A scheduled community event.',
|
|
244
|
+
call: 'audio',
|
|
245
|
+
startDate: new Date(Date.now() + 3600000),
|
|
246
|
+
endDate: new Date(Date.now() + 28800000),
|
|
247
|
+
isCancelled: false,
|
|
248
|
+
isScheduleCall: false,
|
|
249
|
+
extraGuestsAllowed: false,
|
|
250
|
+
location: { name: 'Lagos', degreesLatitude: 6.5244, degreesLongitude: 3.3792 }
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
await sock.sendMessage(jid, {
|
|
255
|
+
poll: {
|
|
256
|
+
name: 'Release preference',
|
|
257
|
+
values: ['Stable', 'Beta'],
|
|
258
|
+
selectableCount: 1,
|
|
259
|
+
endDate: new Date(Date.now() + 28800000),
|
|
260
|
+
hideVoter: false,
|
|
261
|
+
canAddOption: false
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Forward and edit
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
await sock.sendMessage(jid, { forward: message, force: true })
|
|
270
|
+
await sock.sendMessage(jid, { delete: message.key })
|
|
271
|
+
await sock.sendMessage(jid, { text: 'Updated text', edit: message.key })
|
|
272
|
+
await sock.sendMessage(jid, { caption: 'Updated caption', edit: message.key })
|
|
273
|
+
```
|
|
274
|
+
|
|
237
275
|
## Media and albums
|
|
238
276
|
|
|
239
277
|
### Images, video, audio, documents, and stickers
|
|
@@ -329,7 +367,7 @@ await sock.sendMessage(jid, {
|
|
|
329
367
|
})
|
|
330
368
|
```
|
|
331
369
|
|
|
332
|
-
`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
|
|
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.
|
|
333
371
|
|
|
334
372
|
### Video grids
|
|
335
373
|
|
|
@@ -384,6 +422,29 @@ await sock.sendMessage(jid, {
|
|
|
384
422
|
})
|
|
385
423
|
```
|
|
386
424
|
|
|
425
|
+
Buttons can also carry media and a native-flow selector:
|
|
426
|
+
|
|
427
|
+
```js
|
|
428
|
+
await sock.sendMessage(jid, {
|
|
429
|
+
image: { url: 'https://example.com/image.jpg' },
|
|
430
|
+
caption: 'Interactive buttons',
|
|
431
|
+
footer: 'CODY AI',
|
|
432
|
+
buttons: [
|
|
433
|
+
{ text: 'Rating', id: '#Rating' },
|
|
434
|
+
{
|
|
435
|
+
text: 'Select',
|
|
436
|
+
sections: [{
|
|
437
|
+
title: 'Available options',
|
|
438
|
+
rows: [
|
|
439
|
+
{ header: '', title: 'Secret Ingredient', description: '', id: '#SecretIngredient' },
|
|
440
|
+
{ header: '', title: 'Coupon', description: '', id: '#CouponCode' }
|
|
441
|
+
]
|
|
442
|
+
}]
|
|
443
|
+
}
|
|
444
|
+
]
|
|
445
|
+
})
|
|
446
|
+
```
|
|
447
|
+
|
|
387
448
|
### Native flow
|
|
388
449
|
|
|
389
450
|
```js
|
|
@@ -406,6 +467,89 @@ await sock.sendRichWebview(jid, {
|
|
|
406
467
|
})
|
|
407
468
|
```
|
|
408
469
|
|
|
470
|
+
The lower-level `sendMessage` form also supports native-flow options, offer metadata, calls, copy actions, and webviews:
|
|
471
|
+
|
|
472
|
+
```js
|
|
473
|
+
await sock.sendMessage(jid, {
|
|
474
|
+
image: { url: 'https://example.com/image.jpg' },
|
|
475
|
+
caption: 'Interactive options',
|
|
476
|
+
footer: 'CODY AI',
|
|
477
|
+
optionText: 'Select options',
|
|
478
|
+
optionTitle: 'Select options',
|
|
479
|
+
offerText: 'New coupon',
|
|
480
|
+
offerCode: 'SAVE20',
|
|
481
|
+
offerUrl: 'https://example.com/coupon',
|
|
482
|
+
offerExpiration: Date.now() + 3600000,
|
|
483
|
+
nativeFlow: [
|
|
484
|
+
{ text: 'Greeting', id: '#Greeting', icon: 'review' },
|
|
485
|
+
{ text: 'Call', call: '2348000000000' },
|
|
486
|
+
{ text: 'Copy', copy: 'CODY AI' },
|
|
487
|
+
{ text: 'Source', url: 'https://example.com', useWebview: true },
|
|
488
|
+
{
|
|
489
|
+
text: 'Select',
|
|
490
|
+
icon: 'default',
|
|
491
|
+
sections: [{
|
|
492
|
+
title: 'Available options',
|
|
493
|
+
rows: [{ header: '', title: 'Coupon', description: '', id: '#CouponCode' }]
|
|
494
|
+
}]
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
interactiveAsTemplate: false
|
|
498
|
+
})
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Carousel cards and an audio footer are supported by the same `sendMessage` shape:
|
|
502
|
+
|
|
503
|
+
```js
|
|
504
|
+
await sock.sendMessage(jid, {
|
|
505
|
+
text: 'Choose a service',
|
|
506
|
+
footer: 'CODY AI',
|
|
507
|
+
cards: [
|
|
508
|
+
{
|
|
509
|
+
image: { url: 'https://example.com/service-a.jpg' },
|
|
510
|
+
caption: 'Service A',
|
|
511
|
+
footer: 'CODY AI',
|
|
512
|
+
nativeFlow: [{ text: 'Open source', url: 'https://example.com/a', useWebview: true }]
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
image: { url: 'https://example.com/service-b.jpg' },
|
|
516
|
+
caption: 'Service B',
|
|
517
|
+
footer: 'CODY AI',
|
|
518
|
+
offerText: 'New coupon',
|
|
519
|
+
offerCode: 'SAVE20',
|
|
520
|
+
offerUrl: 'https://example.com/coupon',
|
|
521
|
+
offerExpiration: Date.now() + 3600000,
|
|
522
|
+
nativeFlow: [{ text: 'Open source', url: 'https://example.com/b' }]
|
|
523
|
+
}
|
|
524
|
+
]
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
await sock.sendMessage(jid, {
|
|
528
|
+
text: 'Music in footer',
|
|
529
|
+
audioFooter: { url: 'https://example.com/footer.mp3' },
|
|
530
|
+
nativeFlow: [
|
|
531
|
+
{ text: 'Next', id: '#Next', icon: 'review' },
|
|
532
|
+
{ text: 'Skip', id: '#Skip', icon: 'default' }
|
|
533
|
+
]
|
|
534
|
+
})
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Hydrated templates
|
|
538
|
+
|
|
539
|
+
```js
|
|
540
|
+
await sock.sendMessage(jid, {
|
|
541
|
+
title: 'CODY AI',
|
|
542
|
+
image: { url: 'https://example.com/image.jpg' },
|
|
543
|
+
caption: 'Choose an action',
|
|
544
|
+
footer: 'Plogme',
|
|
545
|
+
templateButtons: [
|
|
546
|
+
{ text: 'Open menu', id: '#Menu' },
|
|
547
|
+
{ text: 'Open source', url: 'https://example.com' },
|
|
548
|
+
{ text: 'Call support', call: '2348000000000' }
|
|
549
|
+
]
|
|
550
|
+
})
|
|
551
|
+
```
|
|
552
|
+
|
|
409
553
|
### Interactive table
|
|
410
554
|
|
|
411
555
|
```js
|
|
@@ -481,6 +625,103 @@ await sock.sendRichLink(jid, {
|
|
|
481
625
|
})
|
|
482
626
|
```
|
|
483
627
|
|
|
628
|
+
### Instagram profile card with AI summary
|
|
629
|
+
|
|
630
|
+
`sendInstagramProfile` builds the complete unified-response structure: a compact profile entity, divider, and clickable social-profile summary. The summary is encoded as an inline `GenAISocialEntityItem`, not as ordinary plain text.
|
|
631
|
+
|
|
632
|
+
```js
|
|
633
|
+
await sock.sendInstagramProfile(jid, {
|
|
634
|
+
username: 'crysnovax',
|
|
635
|
+
title: 'CODY AI',
|
|
636
|
+
subtitle: '⚉',
|
|
637
|
+
imageUrl: 'https://cdn.example/profile.png',
|
|
638
|
+
entityId: '123456',
|
|
639
|
+
entityUrl: 'https://www.instagram.com/crysnovax',
|
|
640
|
+
fullName: 'CRYSNOVAX',
|
|
641
|
+
isVerified: true,
|
|
642
|
+
resultText: 'See results'
|
|
643
|
+
})
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
The same complete card and clickable summary are available for other platforms:
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
await sock.sendFacebookProfile(jid, {
|
|
650
|
+
username: 'crysnovax',
|
|
651
|
+
title: 'CODY AI',
|
|
652
|
+
imageUrl: 'https://cdn.example/facebook.png',
|
|
653
|
+
fullName: 'CRYSNOVAX',
|
|
654
|
+
isVerified: true,
|
|
655
|
+
resultText: 'Open Facebook profile'
|
|
656
|
+
})
|
|
657
|
+
|
|
658
|
+
await sock.sendTikTokProfile(jid, {
|
|
659
|
+
username: 'crysnovax',
|
|
660
|
+
title: 'CODY AI',
|
|
661
|
+
imageUrl: 'https://cdn.example/tiktok.png',
|
|
662
|
+
fullName: 'CRYSNOVAX',
|
|
663
|
+
isVerified: true,
|
|
664
|
+
resultText: 'Open TikTok profile'
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
await sock.sendYouTubeProfile(jid, {
|
|
668
|
+
username: 'crysnovax',
|
|
669
|
+
title: 'CODY AI',
|
|
670
|
+
imageUrl: 'https://cdn.example/youtube.png',
|
|
671
|
+
fullName: 'CRYSNOVAX',
|
|
672
|
+
resultText: 'Open YouTube channel'
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
await sock.sendXProfile(jid, {
|
|
676
|
+
username: 'crysnovax',
|
|
677
|
+
title: 'CODY AI',
|
|
678
|
+
imageUrl: 'https://cdn.example/x.png',
|
|
679
|
+
fullName: 'CRYSNOVAX',
|
|
680
|
+
resultText: 'Open X profile'
|
|
681
|
+
})
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
For a platform not covered by a named helper, use `sendSocialProfile` and supply the platform, entity type, and URL explicitly:
|
|
685
|
+
|
|
686
|
+
```js
|
|
687
|
+
await sock.sendSocialProfile(jid, {
|
|
688
|
+
platform: 'linkedin',
|
|
689
|
+
entityType: 'LINKEDIN_PROFILE',
|
|
690
|
+
username: 'crysnovax',
|
|
691
|
+
entityUrl: 'https://www.linkedin.com/in/crysnovax',
|
|
692
|
+
title: 'CODY AI',
|
|
693
|
+
resultText: 'Open LinkedIn profile'
|
|
694
|
+
})
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Complete custom unified responses
|
|
698
|
+
|
|
699
|
+
For newer WhatsApp primitives that do not yet have a dedicated helper, use `sendUnifiedResponse`. It preserves the complete `sections`, `view_model`, `primitives`, and inline entity objects you provide.
|
|
700
|
+
|
|
701
|
+
```js
|
|
702
|
+
await sock.sendUnifiedResponse(jid, {
|
|
703
|
+
sections: [
|
|
704
|
+
{
|
|
705
|
+
view_model: {
|
|
706
|
+
primitives: [
|
|
707
|
+
{
|
|
708
|
+
__typename: 'GenAIQueryPlanPrimitive',
|
|
709
|
+
title: 'Query plan',
|
|
710
|
+
steps: [
|
|
711
|
+
{ title: 'Search', status: 'PLANNED' },
|
|
712
|
+
{ title: 'Summarize', status: 'PLANNED' }
|
|
713
|
+
]
|
|
714
|
+
}
|
|
715
|
+
],
|
|
716
|
+
__typename: 'GenAIActionRowLayoutViewModel'
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
]
|
|
720
|
+
})
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
This path is useful for protocol structures that are already present in `WAProto` but are not yet normalized by a named convenience builder. It sends the payload through normal WhatsApp message generation before relay.
|
|
724
|
+
|
|
484
725
|
### Rich tables, lists, code, and LaTeX
|
|
485
726
|
|
|
486
727
|
```js
|
|
@@ -624,6 +865,63 @@ await sock.sendPlogmeMessage(jid, {
|
|
|
624
865
|
|
|
625
866
|
The compatibility edit can be disabled for a specific send with `{ renderRichResponse: false }`. This sends the generated rich envelope once without the follow-up edit.
|
|
626
867
|
|
|
868
|
+
### Rich response arrays
|
|
869
|
+
|
|
870
|
+
For mixed rich content, `richResponse` accepts text, code, and table items in one generated response:
|
|
871
|
+
|
|
872
|
+
```js
|
|
873
|
+
await sock.sendMessage(jid, {
|
|
874
|
+
disclaimerText: 'CODY AI result',
|
|
875
|
+
richResponse: [
|
|
876
|
+
{ text: 'Build result' },
|
|
877
|
+
{ language: 'javascript', code: [{ highlightType: 0, codeContent: 'console.log("online")' }] },
|
|
878
|
+
{ text: 'Runtime comparison:' },
|
|
879
|
+
{
|
|
880
|
+
title: 'Runtime',
|
|
881
|
+
table: [
|
|
882
|
+
{ isHeading: true, items: ['', 'Node.js', 'Bun'] },
|
|
883
|
+
{ isHeading: false, items: ['State', 'Online', 'Online'] }
|
|
884
|
+
]
|
|
885
|
+
}
|
|
886
|
+
]
|
|
887
|
+
})
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### Rich URL previews and verified media
|
|
891
|
+
|
|
892
|
+
```js
|
|
893
|
+
await sock.sendMessage(jid, {
|
|
894
|
+
text: 'https://example.com/docs',
|
|
895
|
+
richPreview: true
|
|
896
|
+
})
|
|
897
|
+
|
|
898
|
+
await sock.sendMessage(jid, {
|
|
899
|
+
text: 'https://example.com/docs',
|
|
900
|
+
richPreview: true,
|
|
901
|
+
previewTitle: 'CODY AI documentation',
|
|
902
|
+
previewDescription: 'Open the verified documentation'
|
|
903
|
+
})
|
|
904
|
+
|
|
905
|
+
await sock.sendMessage(jid, {
|
|
906
|
+
image: { url: 'https://example.com/verified-image.jpg' },
|
|
907
|
+
caption: 'Verified image',
|
|
908
|
+
verifiedMe: true
|
|
909
|
+
})
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
`verifiedMe` applies to image and video messages. Rich previews require a `text` field containing the URL; preview rendering remains client-dependent.
|
|
913
|
+
|
|
914
|
+
### Secured Meta service label
|
|
915
|
+
|
|
916
|
+
To request the supported secured Meta service label on an outgoing message:
|
|
917
|
+
|
|
918
|
+
```js
|
|
919
|
+
await sock.sendMessage(jid, {
|
|
920
|
+
text: 'CODY AI secured response',
|
|
921
|
+
secureMetaServiceLabel: true
|
|
922
|
+
})
|
|
923
|
+
```
|
|
924
|
+
|
|
627
925
|
## Rich menus, reels, and grids
|
|
628
926
|
|
|
629
927
|
### Original Gen4 rich menu
|
|
@@ -633,13 +931,19 @@ Use `sock.richMenu` for the original Gen4-style menu. This is the primary rich-m
|
|
|
633
931
|
```js
|
|
634
932
|
await sock.richMenu(jid, {
|
|
635
933
|
header: {
|
|
636
|
-
title: 'Deployment tools'
|
|
934
|
+
title: 'Deployment tools',
|
|
935
|
+
image: {
|
|
936
|
+
url: 'https://example.com/cover.jpg',
|
|
937
|
+
mimeType: 'image/jpeg',
|
|
938
|
+
width: 1200,
|
|
939
|
+
height: 800
|
|
940
|
+
}
|
|
637
941
|
},
|
|
638
942
|
body: {
|
|
639
943
|
title: 'Choose an action',
|
|
640
944
|
buttons: [
|
|
641
|
-
{ id: 'deploy', text: 'Deploy' },
|
|
642
|
-
{ id: 'logs', text: 'View logs' }
|
|
945
|
+
{ id: 'deploy', text: 'Deploy', toast: 'Deploy selected' },
|
|
946
|
+
{ id: 'logs', text: 'View logs', toast: 'Logs selected' }
|
|
643
947
|
]
|
|
644
948
|
},
|
|
645
949
|
footer: {
|
|
@@ -649,6 +953,33 @@ await sock.richMenu(jid, {
|
|
|
649
953
|
})
|
|
650
954
|
```
|
|
651
955
|
|
|
956
|
+
### Universal A2UI message
|
|
957
|
+
|
|
958
|
+
`sendA2UIMessage` is the generic sender. It accepts arbitrary A2UI components, Bloks widget data, native-flow buttons, and optional media; it is not restricted to the command-table template. It also uses the immediate relay/edit compatibility path.
|
|
959
|
+
|
|
960
|
+
```js
|
|
961
|
+
await sock.sendA2UIMessage(jid, {
|
|
962
|
+
bloksWidget: {
|
|
963
|
+
type: 'im_a2ui',
|
|
964
|
+
data: {
|
|
965
|
+
version: 'v0.9',
|
|
966
|
+
createSurface: {
|
|
967
|
+
surfaceId: 'custom-card',
|
|
968
|
+
catalogId: 'https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json',
|
|
969
|
+
components: [
|
|
970
|
+
{ id: 'root', component: 'Column', children: ['title'] },
|
|
971
|
+
{ id: 'title', component: 'Text', text: 'My custom A2UI card', variant: 'h2' }
|
|
972
|
+
]
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
fallback: 'My custom A2UI card'
|
|
976
|
+
},
|
|
977
|
+
nativeFlowMessage: {
|
|
978
|
+
buttons: [{ name: 'quick_reply', buttonParamsJson: JSON.stringify({ id: 'open', display_text: 'Open' }) }]
|
|
979
|
+
}
|
|
980
|
+
})
|
|
981
|
+
```
|
|
982
|
+
|
|
652
983
|
### Large A2UI command card
|
|
653
984
|
|
|
654
985
|
Use `sendA2UICommandMenu` for the full-size card layout with an uploaded image header, a command/function table, URL buttons, and a native-flow command selector. This is an `interactiveMessage`/A2UI payload, not an AIRich `unifiedResponse`, so it is intentionally separate from `sendPlogmeMessage` and `richMenu`.
|
|
@@ -720,6 +1051,41 @@ await sock.richMenu(jid, {
|
|
|
720
1051
|
|
|
721
1052
|
Validate button IDs on the server. A button ID is an event value, not an authorization grant.
|
|
722
1053
|
|
|
1054
|
+
### Universal social/entity cards
|
|
1055
|
+
|
|
1056
|
+
The leaked profile-result format is exposed through a provider-neutral API. It supports Instagram and other providers without hard-coding the Instagram wire format. Every send uses the same immediate AIRich relay/edit path as the other rich messages.
|
|
1057
|
+
|
|
1058
|
+
```js
|
|
1059
|
+
await sock.sendSocialEntity(jid, {
|
|
1060
|
+
platform: 'YOUTUBE',
|
|
1061
|
+
username: 'crysnovax',
|
|
1062
|
+
title: 'CODY AI',
|
|
1063
|
+
imageUrl: 'https://example.com/avatar.png',
|
|
1064
|
+
entityUrl: 'https://www.youtube.com/@crysnovax',
|
|
1065
|
+
fullName: 'CRYSNOVAX',
|
|
1066
|
+
isVerified: true,
|
|
1067
|
+
resultText: 'See results'
|
|
1068
|
+
})
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
### Instagram profile card
|
|
1072
|
+
|
|
1073
|
+
Instagram is the primary dedicated convenience API. It emits the `IG_PROFILE` social entity metadata while sharing the universal implementation.
|
|
1074
|
+
|
|
1075
|
+
```js
|
|
1076
|
+
await sock.sendInstagramProfile(jid, {
|
|
1077
|
+
username: 'crysnovax',
|
|
1078
|
+
title: 'CODY AI',
|
|
1079
|
+
subtitle: '⚉',
|
|
1080
|
+
imageUrl: 'https://example.com/avatar.png',
|
|
1081
|
+
entityId: '123456',
|
|
1082
|
+
entityUrl: 'https://www.instagram.com/crysnovax',
|
|
1083
|
+
fullName: 'CRYSNOVAX',
|
|
1084
|
+
isVerified: true,
|
|
1085
|
+
resultText: 'See results'
|
|
1086
|
+
})
|
|
1087
|
+
```
|
|
1088
|
+
|
|
723
1089
|
### Reels and rich media
|
|
724
1090
|
|
|
725
1091
|
`sendReels` accepts an array of reel records. The main rich-media path is used for reels, sources, links, tables, and future rich payloads.
|
|
@@ -925,6 +1291,24 @@ await sock.sendBotToolResult(jid, {
|
|
|
925
1291
|
})
|
|
926
1292
|
```
|
|
927
1293
|
|
|
1294
|
+
### Planning metadata and tool results
|
|
1295
|
+
|
|
1296
|
+
`sendBotPlan` serializes the generated `BotProgressIndicatorMetadata` structure and advertises the `AGENTIC_PLANNING` and `QUERY_PLAN` capabilities defined in `WAProto`. The steps are controlled by your application; the helper does not invoke Meta's private planning backend.
|
|
1297
|
+
|
|
1298
|
+
```js
|
|
1299
|
+
await sock.sendBotPlan(jid, {
|
|
1300
|
+
title: 'Deployment plan',
|
|
1301
|
+
text: 'I will check, deploy, and verify the service.',
|
|
1302
|
+
steps: [
|
|
1303
|
+
{ title: 'Health check', description: 'Check the API and database', status: 'planned' },
|
|
1304
|
+
{ title: 'Deploy', description: 'Publish the verified build', status: 'executing' },
|
|
1305
|
+
{ title: 'Verify', description: 'Confirm the public endpoint', status: 'finished' }
|
|
1306
|
+
]
|
|
1307
|
+
})
|
|
1308
|
+
```
|
|
1309
|
+
|
|
1310
|
+
`sendBotToolResult` carries the resolved tool-call metadata and advertises `QUERY_PLAN` so a tool result can be associated with a planning flow. It does not execute the tool. Your application must validate the tool name, arguments, permissions, and result before calling it.
|
|
1311
|
+
|
|
928
1312
|
These methods do not provide Meta's private verification credentials and must not be used to impersonate a first-party Meta AI message.
|
|
929
1313
|
|
|
930
1314
|
## WhatsApp flows and web views
|
|
@@ -948,6 +1332,25 @@ Flow identifiers and tokens must belong to a valid business configuration.
|
|
|
948
1332
|
|
|
949
1333
|
## View-once utilities
|
|
950
1334
|
|
|
1335
|
+
Text view-once messages use the client-compatible inner `ExtendedTextMessage.viewOnce` flag:
|
|
1336
|
+
|
|
1337
|
+
```js
|
|
1338
|
+
await sock.sendMessage(jid, {
|
|
1339
|
+
text: 'viewOnceMessage',
|
|
1340
|
+
viewOnce: true
|
|
1341
|
+
})
|
|
1342
|
+
```
|
|
1343
|
+
|
|
1344
|
+
Media view-once messages continue to use WhatsApp's standard outer `viewOnceMessage` envelope:
|
|
1345
|
+
|
|
1346
|
+
```js
|
|
1347
|
+
await sock.sendMessage(jid, {
|
|
1348
|
+
image: { url: 'https://example.com/secret.jpg' },
|
|
1349
|
+
caption: 'Open once',
|
|
1350
|
+
viewOnce: true
|
|
1351
|
+
})
|
|
1352
|
+
```
|
|
1353
|
+
|
|
951
1354
|
```js
|
|
952
1355
|
const info = sock.getViewOnceInfo(message)
|
|
953
1356
|
console.log(info)
|
|
@@ -1013,3 +1416,1121 @@ For implementation questions, include the Node.js version, Plogme version, opera
|
|
|
1013
1416
|
[1]: https://github.com/crysnovax/baileys "Plogme source repository"
|
|
1014
1417
|
[2]: https://www.npmjs.com/package/plogme "Plogme on npm"
|
|
1015
1418
|
[3]: https://github.com/WhiskeySockets/Baileys "Baileys protocol implementation"
|
|
1419
|
+
|
|
1420
|
+
---
|
|
1421
|
+
|
|
1422
|
+
# Additional APIs from the Bailey2 compatibility surface
|
|
1423
|
+
|
|
1424
|
+
The following reference sections document supported APIs that are not repeated in the core CODY/Plogme guide above. They are retained from the `crysnovax/baileys2` compatibility documentation and exclude package-specific ban-checker functionality.
|
|
1425
|
+
|
|
1426
|
+
## Welcome Flow
|
|
1427
|
+
|
|
1428
|
+
Auto-greet new contacts with an interactive FAQ menu. Fires once per contact, never repeats.
|
|
1429
|
+
|
|
1430
|
+
### Basic Setup
|
|
1431
|
+
|
|
1432
|
+
```javascript
|
|
1433
|
+
import { createWelcomeFlow } from '@crysnovax/baileys'
|
|
1434
|
+
|
|
1435
|
+
const welcome = createWelcomeFlow(sock, {
|
|
1436
|
+
greeting: 'Welcome! How can I help you today?',
|
|
1437
|
+
footer: 'Powered by MyBot',
|
|
1438
|
+
buttonText: 'Choose an option',
|
|
1439
|
+
sectionTitle: 'How can we help?',
|
|
1440
|
+
faqs: [
|
|
1441
|
+
{ id: 'order', title: 'Track my order', description: 'Check order status' },
|
|
1442
|
+
{ id: 'billing', title: 'Billing & payments', description: 'Payment issues' },
|
|
1443
|
+
{ id: 'support', title: 'Technical support', description: 'Get help' },
|
|
1444
|
+
{ id: 'human', title: 'Talk to a human', description: 'Connect with staff' }
|
|
1445
|
+
]
|
|
1446
|
+
})
|
|
1447
|
+
|
|
1448
|
+
welcome.listen() // start
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
### With Callbacks
|
|
1452
|
+
|
|
1453
|
+
```javascript
|
|
1454
|
+
const welcome = createWelcomeFlow(sock, {
|
|
1455
|
+
greeting: 'Hi there! What brings you here today?',
|
|
1456
|
+
faqs: [
|
|
1457
|
+
{ id: 'pricing', title: 'Pricing', description: 'Plans and costs' },
|
|
1458
|
+
{ id: 'demo', title: 'Request demo', description: 'See it in action' },
|
|
1459
|
+
{ id: 'support', title: 'Support', description: 'Get help' }
|
|
1460
|
+
],
|
|
1461
|
+
|
|
1462
|
+
onGreet: async (jid, message) => {
|
|
1463
|
+
console.log(`Greeted new contact: ${jid}`)
|
|
1464
|
+
},
|
|
1465
|
+
|
|
1466
|
+
onFaqReply: async (jid, faqId, message) => {
|
|
1467
|
+
switch (faqId) {
|
|
1468
|
+
case 'pricing':
|
|
1469
|
+
await sock.sendMessage(jid, { text: 'Our plans start at $9/month…' })
|
|
1470
|
+
break
|
|
1471
|
+
case 'demo':
|
|
1472
|
+
await sock.sendMessage(jid, { text: 'Book a demo here: https://…' })
|
|
1473
|
+
break
|
|
1474
|
+
case 'support':
|
|
1475
|
+
await sock.sendMessage(jid, { text: 'Describe your issue and we will help!' })
|
|
1476
|
+
break
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
})
|
|
1480
|
+
|
|
1481
|
+
welcome.listen()
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
### Persist Across Restarts
|
|
1485
|
+
|
|
1486
|
+
```javascript
|
|
1487
|
+
const welcome = createWelcomeFlow(sock, {
|
|
1488
|
+
greeting: 'Welcome!',
|
|
1489
|
+
faqs: [...],
|
|
1490
|
+
persistPath: './data/greeted-contacts.json'
|
|
1491
|
+
})
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
### Control Methods
|
|
1495
|
+
|
|
1496
|
+
```javascript
|
|
1497
|
+
welcome.listen() // start listening
|
|
1498
|
+
welcome.stop() // stop listening
|
|
1499
|
+
welcome.reset(jid) // force re-greet one contact
|
|
1500
|
+
welcome.resetAll() // clear all seen contacts
|
|
1501
|
+
welcome.hasGreeted(jid) // check if greeted → boolean
|
|
1502
|
+
```
|
|
1503
|
+
|
|
1504
|
+
### Config Reference
|
|
1505
|
+
|
|
1506
|
+
| Option | Type | Default | Description |
|
|
1507
|
+
|--------|------|---------|-------------|
|
|
1508
|
+
| greeting | string | 'Welcome!…' | Body text of welcome message |
|
|
1509
|
+
| footer | string | 'Powered by @crysnovax/baileys' | Footer text |
|
|
1510
|
+
| buttonText | string | 'Choose an option' | List button label |
|
|
1511
|
+
| sectionTitle | string | 'How can we help?' | Section header |
|
|
1512
|
+
| faqs | Array | 4 defaults | { id, title, description } |
|
|
1513
|
+
| typingDelayMs | number | 1200 | Typing indicator duration |
|
|
1514
|
+
| persistPath | string\|null | null | JSON file to persist JIDs |
|
|
1515
|
+
| ignoreGroups | boolean | true | Skip group chats |
|
|
1516
|
+
| ignoreNewsletter | boolean | true | Skip newsletters |
|
|
1517
|
+
| ignoreBroadcast | boolean | true | Skip broadcasts |
|
|
1518
|
+
| onGreet | async fn | null | Called after greeting sent |
|
|
1519
|
+
| onFaqReply | async fn | null | Called on FAQ selection |
|
|
1520
|
+
|
|
1521
|
+
---
|
|
1522
|
+
|
|
1523
|
+
## Payment Messages
|
|
1524
|
+
|
|
1525
|
+
```javascript
|
|
1526
|
+
// Payment invite
|
|
1527
|
+
sock.sendMessage(jid, {
|
|
1528
|
+
paymentInviteServiceType: 3 // 1, 2, or 3
|
|
1529
|
+
})
|
|
1530
|
+
|
|
1531
|
+
// Invoice (not supported yet)
|
|
1532
|
+
sock.sendMessage(jid, {
|
|
1533
|
+
image: { url: './image.jpg' },
|
|
1534
|
+
invoiceNote: 'Invoice'
|
|
1535
|
+
})
|
|
1536
|
+
|
|
1537
|
+
// Order
|
|
1538
|
+
sock.sendMessage(jid, {
|
|
1539
|
+
orderText: 'Order',
|
|
1540
|
+
thumbnail: fs.readFileSync('./image.jpg')
|
|
1541
|
+
})
|
|
1542
|
+
|
|
1543
|
+
// Request payment
|
|
1544
|
+
sock.sendMessage(jid, {
|
|
1545
|
+
text: 'Request Payment',
|
|
1546
|
+
requestPaymentFrom: '0@s.whatsapp.net'
|
|
1547
|
+
})
|
|
1548
|
+
```
|
|
1549
|
+
|
|
1550
|
+
---
|
|
1551
|
+
|
|
1552
|
+
## Message Options
|
|
1553
|
+
|
|
1554
|
+
```javascript
|
|
1555
|
+
// AI icon (private chat only)
|
|
1556
|
+
sock.sendMessage(jid, {
|
|
1557
|
+
image: { url: './image.jpg' },
|
|
1558
|
+
caption: 'With AI icon!',
|
|
1559
|
+
ai: true
|
|
1560
|
+
})
|
|
1561
|
+
|
|
1562
|
+
// Ephemeral
|
|
1563
|
+
sock.sendMessage(jid, {
|
|
1564
|
+
image: { url: './image.jpg' },
|
|
1565
|
+
caption: 'Ephemeral',
|
|
1566
|
+
ephemeral: true
|
|
1567
|
+
})
|
|
1568
|
+
|
|
1569
|
+
// External ad reply
|
|
1570
|
+
sock.sendMessage(jid, {
|
|
1571
|
+
text: 'External Ad Reply',
|
|
1572
|
+
externalAdReply: {
|
|
1573
|
+
title: 'Did you know?',
|
|
1574
|
+
body: 'I dont know',
|
|
1575
|
+
thumbnail: fs.readFileSync('./image.jpg'),
|
|
1576
|
+
largeThumbnail: false,
|
|
1577
|
+
url: 'https://example.com'
|
|
1578
|
+
}
|
|
1579
|
+
})
|
|
1580
|
+
|
|
1581
|
+
// Group status (a valid group JID is required)
|
|
1582
|
+
const groupStatus = await sock.sendMessage(groupJid, {
|
|
1583
|
+
image: { url: './image.jpg' },
|
|
1584
|
+
caption: 'Group Status!',
|
|
1585
|
+
groupStatus: true
|
|
1586
|
+
})
|
|
1587
|
+
|
|
1588
|
+
// Text, video, audio, stickers, mentions, and rich previews use the same flag.
|
|
1589
|
+
await sock.sendMessage(groupJid, {
|
|
1590
|
+
text: 'Group update',
|
|
1591
|
+
mentions: ['628123456789@s.whatsapp.net'],
|
|
1592
|
+
groupStatus: true
|
|
1593
|
+
})
|
|
1594
|
+
|
|
1595
|
+
// Delete using the key returned by the original group-status send.
|
|
1596
|
+
// The group JID must match key.remoteJid when that field is present.
|
|
1597
|
+
await sock.deleteGroupStatus(groupJid, groupStatus.key)
|
|
1598
|
+
|
|
1599
|
+
// Report APIs submit the report first, then apply the requested safety action.
|
|
1600
|
+
// Contacts are blocked and groups are left only after WhatsApp accepts the report.
|
|
1601
|
+
await sock.reportContact('628123456789@s.whatsapp.net', [message.key])
|
|
1602
|
+
await sock.reportGroup(groupJid, [message.key])
|
|
1603
|
+
|
|
1604
|
+
// Lottie sticker
|
|
1605
|
+
sock.sendMessage(jid, {
|
|
1606
|
+
sticker: { url: './sticker.webp' },
|
|
1607
|
+
isLottie: true
|
|
1608
|
+
})
|
|
1609
|
+
|
|
1610
|
+
// likeThis — relay message exactly as-is, zero processing
|
|
1611
|
+
// Bypasses generateWAMessage entirely — no re-encoding, no normalization.
|
|
1612
|
+
// Useful for: forwarding with original quality, relaying captured messages verbatim,
|
|
1613
|
+
// re-sending albums/carousels without re-uploading, testing raw proto constructions.
|
|
1614
|
+
sock.sendMessage(jid, {
|
|
1615
|
+
likeThis: true,
|
|
1616
|
+
...capturedMessage.message // spread any received message directly
|
|
1617
|
+
})
|
|
1618
|
+
|
|
1619
|
+
// Or with a manually built proto
|
|
1620
|
+
sock.sendMessage(jid, {
|
|
1621
|
+
likeThis: true,
|
|
1622
|
+
imageMessage: { ...rawProtoFields }
|
|
1623
|
+
})
|
|
1624
|
+
|
|
1625
|
+
// Or forwarding with original quality intact
|
|
1626
|
+
sock.sendMessage(jid, {
|
|
1627
|
+
likeThis: true,
|
|
1628
|
+
extendedTextMessage: {
|
|
1629
|
+
text: 'Built manually',
|
|
1630
|
+
contextInfo: {
|
|
1631
|
+
externalAdReply: {
|
|
1632
|
+
title: '@crysnovax/baileys',
|
|
1633
|
+
thumbnail: fs.readFileSync('./image.jpg'),
|
|
1634
|
+
sourceApp: 'whatsapp',
|
|
1635
|
+
showAdAttribution: true,
|
|
1636
|
+
mediaType: 1
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
})
|
|
1641
|
+
|
|
1642
|
+
// Secure Meta service label: adds actual_actors, host_storage, and
|
|
1643
|
+
// privacy_mode_ts to the outbound business node. The control flag itself
|
|
1644
|
+
// is consumed locally and is not encoded into the WhatsApp message.
|
|
1645
|
+
sock.sendMessage(jid, {
|
|
1646
|
+
text: 'Just a label!',
|
|
1647
|
+
secureMetaServiceLabel: true
|
|
1648
|
+
})
|
|
1649
|
+
|
|
1650
|
+
// Spoiler (compatible context flag; no unsupported future-proof wrapper)
|
|
1651
|
+
sock.sendMessage(jid, {
|
|
1652
|
+
image: { url: './image.jpg' },
|
|
1653
|
+
caption: 'Spoiler',
|
|
1654
|
+
spoiler: true
|
|
1655
|
+
})
|
|
1656
|
+
|
|
1657
|
+
// View once
|
|
1658
|
+
sock.sendMessage(jid, {
|
|
1659
|
+
image: { url: './image.jpg' },
|
|
1660
|
+
caption: 'View Once',
|
|
1661
|
+
viewOnce: true
|
|
1662
|
+
})
|
|
1663
|
+
|
|
1664
|
+
// View once v2
|
|
1665
|
+
sock.sendMessage(jid, {
|
|
1666
|
+
image: { url: './image.jpg' },
|
|
1667
|
+
caption: 'View Once V2',
|
|
1668
|
+
viewOnceV2: true
|
|
1669
|
+
})
|
|
1670
|
+
|
|
1671
|
+
// View once v2 extension
|
|
1672
|
+
sock.sendMessage(jid, {
|
|
1673
|
+
image: { url: './image.jpg' },
|
|
1674
|
+
caption: 'View Once V2 Extension',
|
|
1675
|
+
viewOnceV2Extension: true
|
|
1676
|
+
})
|
|
1677
|
+
```
|
|
1678
|
+
|
|
1679
|
+
---
|
|
1680
|
+
|
|
1681
|
+
## Status & Stories
|
|
1682
|
+
|
|
1683
|
+
Statuses are sent to `status@broadcast` and require at least one viewer JID. Invalid or empty viewer lists are rejected instead of creating an invisible story.
|
|
1684
|
+
|
|
1685
|
+
```javascript
|
|
1686
|
+
const viewers = [
|
|
1687
|
+
'628123456789@s.whatsapp.net',
|
|
1688
|
+
'628987654321@s.whatsapp.net'
|
|
1689
|
+
]
|
|
1690
|
+
|
|
1691
|
+
// Standard API: styled text status. Fonts 0-9 are supported.
|
|
1692
|
+
await sock.sendMessage('status@broadcast', {
|
|
1693
|
+
text: 'Hello world!',
|
|
1694
|
+
backgroundColor: '#FF1FA15A',
|
|
1695
|
+
font: 0
|
|
1696
|
+
}, { statusJidList: viewers })
|
|
1697
|
+
|
|
1698
|
+
// Convenience API (equivalent to the standard form)
|
|
1699
|
+
await sock.sendMessage('status@broadcast', {
|
|
1700
|
+
status: true,
|
|
1701
|
+
text: 'Exclusive status!',
|
|
1702
|
+
statusJidList: viewers,
|
|
1703
|
+
backgroundColor: 'teal',
|
|
1704
|
+
font: 2
|
|
1705
|
+
})
|
|
1706
|
+
|
|
1707
|
+
// Image and video statuses support captions
|
|
1708
|
+
await sock.sendMessage('status@broadcast', {
|
|
1709
|
+
status: true,
|
|
1710
|
+
image: { url: './image.jpg' },
|
|
1711
|
+
caption: 'My status!',
|
|
1712
|
+
statusJidList: viewers
|
|
1713
|
+
})
|
|
1714
|
+
await sock.sendMessage('status@broadcast', {
|
|
1715
|
+
status: true,
|
|
1716
|
+
video: { url: './video.mp4' },
|
|
1717
|
+
caption: 'Watch this!',
|
|
1718
|
+
statusJidList: viewers
|
|
1719
|
+
})
|
|
1720
|
+
|
|
1721
|
+
// Audio or voice-note status, including waveform/background metadata
|
|
1722
|
+
await sock.sendMessage('status@broadcast', {
|
|
1723
|
+
status: true,
|
|
1724
|
+
audio: { url: './audio.ogg' },
|
|
1725
|
+
mimetype: 'audio/ogg; codecs=opus',
|
|
1726
|
+
ptt: true,
|
|
1727
|
+
waveform: new Uint8Array([0, 20, 45, 80, 45, 20, 0]),
|
|
1728
|
+
backgroundColor: '#FF0057FF',
|
|
1729
|
+
statusJidList: viewers
|
|
1730
|
+
})
|
|
1731
|
+
```
|
|
1732
|
+
|
|
1733
|
+
Named, hex, and ARGB colors are accepted. Viewer JIDs are normalized and deduplicated.
|
|
1734
|
+
|
|
1735
|
+
### Status Mentions
|
|
1736
|
+
|
|
1737
|
+
Passing an array as the destination posts a status and sends mention notifications to those contacts or groups. This is intentionally separate from `statusJidList`, which controls viewers without mentioning them.
|
|
1738
|
+
|
|
1739
|
+
```javascript
|
|
1740
|
+
await sock.sendMessage([jidA, groupJid], { text: 'Hey, check my status!' })
|
|
1741
|
+
```
|
|
1742
|
+
|
|
1743
|
+
---
|
|
1744
|
+
|
|
1745
|
+
## Favorites
|
|
1746
|
+
|
|
1747
|
+
Manage your WhatsApp Favorites list — add, remove, and sync across devices.
|
|
1748
|
+
|
|
1749
|
+
### Add to Favorites
|
|
1750
|
+
|
|
1751
|
+
```javascript
|
|
1752
|
+
// Add a single JID
|
|
1753
|
+
await sock.addToFavorites(['628123456789@s.whatsapp.net'])
|
|
1754
|
+
|
|
1755
|
+
// Add multiple JIDs (replaces entire list — merge handled by caller)
|
|
1756
|
+
await sock.addToFavorites([
|
|
1757
|
+
'628123456789@s.whatsapp.net',
|
|
1758
|
+
'628987654321@s.whatsapp.net',
|
|
1759
|
+
'1234@g.us'
|
|
1760
|
+
])
|
|
1761
|
+
```
|
|
1762
|
+
|
|
1763
|
+
### Remove from Favorites
|
|
1764
|
+
|
|
1765
|
+
```javascript
|
|
1766
|
+
// Remove specific JIDs (pass remaining list after filter)
|
|
1767
|
+
await sock.removeFromFavorites([
|
|
1768
|
+
'628123456789@s.whatsapp.net' // only this one remains
|
|
1769
|
+
])
|
|
1770
|
+
```
|
|
1771
|
+
|
|
1772
|
+
### Full Example with Local Persistence
|
|
1773
|
+
|
|
1774
|
+
```javascript
|
|
1775
|
+
import fs from 'fs'
|
|
1776
|
+
import path from 'path'
|
|
1777
|
+
|
|
1778
|
+
const FAV_FILE = path.join(process.cwd(), 'database', 'favorites.json')
|
|
1779
|
+
|
|
1780
|
+
const loadFavs = () => {
|
|
1781
|
+
try { return JSON.parse(fs.readFileSync(FAV_FILE, 'utf8')) }
|
|
1782
|
+
catch { return [] }
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
const saveFavs = (favs) => {
|
|
1786
|
+
fs.mkdirSync(path.dirname(FAV_FILE), { recursive: true })
|
|
1787
|
+
fs.writeFileSync(FAV_FILE, JSON.stringify(favs, null, 2))
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// Add
|
|
1791
|
+
const existing = loadFavs()
|
|
1792
|
+
const target = '628123456789@s.whatsapp.net'
|
|
1793
|
+
if (!existing.includes(target)) {
|
|
1794
|
+
const merged = [...existing, target]
|
|
1795
|
+
await sock.addToFavorites(merged)
|
|
1796
|
+
saveFavs(merged)
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
// Remove
|
|
1800
|
+
const toRemove = '628123456789@s.whatsapp.net'
|
|
1801
|
+
const remaining = existing.filter(jid => jid !== toRemove)
|
|
1802
|
+
await sock.addToFavorites(remaining)
|
|
1803
|
+
saveFavs(remaining)
|
|
1804
|
+
```
|
|
1805
|
+
|
|
1806
|
+
**Note:** WhatsApp favorites use a single app state record. Each SET replaces the entire list. Always pass the complete desired array.
|
|
1807
|
+
|
|
1808
|
+
---
|
|
1809
|
+
|
|
1810
|
+
## Newsletter Management
|
|
1811
|
+
|
|
1812
|
+
```javascript
|
|
1813
|
+
// Create
|
|
1814
|
+
sock.newsletterCreate('@crysnovax/baileys', 'Fresh updates weekly')
|
|
1815
|
+
|
|
1816
|
+
// Metadata
|
|
1817
|
+
const metadata = await sock.newsletterMetadata('1231111111111@newsletter')
|
|
1818
|
+
|
|
1819
|
+
// Subscribers count
|
|
1820
|
+
const subscribers = await sock.newsletterSubscribers('1231111111111@newsletter')
|
|
1821
|
+
|
|
1822
|
+
// Follow / Unfollow
|
|
1823
|
+
sock.newsletterFollow('1231111111111@newsletter')
|
|
1824
|
+
sock.newsletterUnfollow('1231111111111@newsletter')
|
|
1825
|
+
|
|
1826
|
+
// Mute / Unmute
|
|
1827
|
+
sock.newsletterMute('1231111111111@newsletter')
|
|
1828
|
+
sock.newsletterUnmute('1231111111111@newsletter')
|
|
1829
|
+
|
|
1830
|
+
// Admin management
|
|
1831
|
+
sock.newsletterDemote('1231111111111@newsletter', '6281111111111@s.whatsapp.net')
|
|
1832
|
+
sock.newsletterChangeOwner('1231111111111@newsletter', '6281111111111@s.whatsapp.net')
|
|
1833
|
+
|
|
1834
|
+
// Update
|
|
1835
|
+
sock.newsletterUpdate('1231111111111@newsletter', { name: '@crysnovax/baileys' })
|
|
1836
|
+
sock.newsletterUpdateName('1231111111111@newsletter', '@crysnovax/baileys')
|
|
1837
|
+
sock.newsletterUpdateDescription('1231111111111@newsletter', 'Fresh updates weekly')
|
|
1838
|
+
sock.newsletterUpdatePicture('1231111111111@newsletter', { url: 'path/to/image.jpg' })
|
|
1839
|
+
sock.newsletterRemovePicture('1231111111111@newsletter')
|
|
1840
|
+
|
|
1841
|
+
// React to message
|
|
1842
|
+
sock.newsletterReactMessage('1231111111111@newsletter', '100', '💛')
|
|
1843
|
+
|
|
1844
|
+
// Admin count
|
|
1845
|
+
const count = await sock.newsletterAdminCount('1231111111111@newsletter')
|
|
1846
|
+
|
|
1847
|
+
// Get all subscribed
|
|
1848
|
+
const newsletters = await sock.newsletterSubscribed()
|
|
1849
|
+
|
|
1850
|
+
// Fetch messages
|
|
1851
|
+
const messages = sock.newsletterFetchMessages('jid', '1231111111111@newsletter', 50, 0, 0)
|
|
1852
|
+
|
|
1853
|
+
// Delete
|
|
1854
|
+
sock.newsletterDelete('1231111111111@newsletter')
|
|
1855
|
+
```
|
|
1856
|
+
|
|
1857
|
+
---
|
|
1858
|
+
|
|
1859
|
+
## Group Management
|
|
1860
|
+
|
|
1861
|
+
```javascript
|
|
1862
|
+
// Create
|
|
1863
|
+
const group = await sock.groupCreate('@crysnovax/baileys', ['628123456789@s.whatsapp.net'])
|
|
1864
|
+
|
|
1865
|
+
// Metadata
|
|
1866
|
+
const metadata = await sock.groupMetadata(jid)
|
|
1867
|
+
|
|
1868
|
+
// Invite
|
|
1869
|
+
const inviteCode = await sock.groupInviteCode(jid)
|
|
1870
|
+
sock.groupRevokeInvite(jid)
|
|
1871
|
+
sock.groupAcceptInvite(inviteCode)
|
|
1872
|
+
|
|
1873
|
+
// Leave
|
|
1874
|
+
sock.groupLeave(jid)
|
|
1875
|
+
|
|
1876
|
+
// Participants
|
|
1877
|
+
sock.groupParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'add')
|
|
1878
|
+
sock.groupParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'remove')
|
|
1879
|
+
sock.groupParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'promote')
|
|
1880
|
+
sock.groupParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'demote')
|
|
1881
|
+
|
|
1882
|
+
// Join requests
|
|
1883
|
+
sock.groupRequestParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'approve')
|
|
1884
|
+
|
|
1885
|
+
// Info updates
|
|
1886
|
+
sock.groupUpdateSubject(jid, '@crysnovax/baileys')
|
|
1887
|
+
sock.groupUpdateDescription(jid, 'Updated description')
|
|
1888
|
+
sock.updateProfilePicture(jid, { url: 'path/to/image.jpg' })
|
|
1889
|
+
sock.removeProfilePicture(jid)
|
|
1890
|
+
|
|
1891
|
+
// Settings
|
|
1892
|
+
sock.groupSettingUpdate(jid, 'announcement') // admin only chat
|
|
1893
|
+
sock.groupSettingUpdate(jid, 'not_announcement') // open chat
|
|
1894
|
+
sock.groupSettingUpdate(jid, 'locked') // admin only edit info
|
|
1895
|
+
sock.groupSettingUpdate(jid, 'unlocked') // all edit info
|
|
1896
|
+
|
|
1897
|
+
// Add mode
|
|
1898
|
+
sock.groupMemberAddMode(jid, 'admin_add')
|
|
1899
|
+
sock.groupMemberAddMode(jid, 'all_member_add')
|
|
1900
|
+
|
|
1901
|
+
// Ephemeral
|
|
1902
|
+
sock.groupToggleEphemeral(jid, 86400) // enable
|
|
1903
|
+
sock.groupToggleEphemeral(jid, 0) // disable
|
|
1904
|
+
|
|
1905
|
+
// Approval mode
|
|
1906
|
+
sock.groupJoinApprovalMode(jid, 'on')
|
|
1907
|
+
sock.groupJoinApprovalMode(jid, 'off')
|
|
1908
|
+
|
|
1909
|
+
// Fetch all
|
|
1910
|
+
const groups = await sock.groupFetchAllParticipating()
|
|
1911
|
+
|
|
1912
|
+
// Pending requests
|
|
1913
|
+
const requests = await sock.groupRequestParticipantsList(jid)
|
|
1914
|
+
|
|
1915
|
+
// Invite info
|
|
1916
|
+
const group = await sock.groupGetInviteInfo('ABC123456789')
|
|
1917
|
+
|
|
1918
|
+
// Member label
|
|
1919
|
+
sock.updateMemberLabel(jid, '@crysnovax/baileys')
|
|
1920
|
+
```
|
|
1921
|
+
|
|
1922
|
+
---
|
|
1923
|
+
|
|
1924
|
+
## Community Management
|
|
1925
|
+
|
|
1926
|
+
```javascript
|
|
1927
|
+
// Create
|
|
1928
|
+
const community = await sock.communityCreate('@crysnovax/baileys', 'Fresh updates weekly')
|
|
1929
|
+
|
|
1930
|
+
// Create subgroup
|
|
1931
|
+
const group = await sock.communityCreateGroup(
|
|
1932
|
+
'Announcements',
|
|
1933
|
+
['628123456789@s.whatsapp.net'],
|
|
1934
|
+
communityJid
|
|
1935
|
+
)
|
|
1936
|
+
|
|
1937
|
+
// Link / Unlink
|
|
1938
|
+
sock.communityLinkGroup(groupJid, communityJid)
|
|
1939
|
+
sock.communityUnlinkGroup(groupJid, communityJid)
|
|
1940
|
+
|
|
1941
|
+
// Metadata
|
|
1942
|
+
const metadata = await sock.communityMetadata(jid)
|
|
1943
|
+
|
|
1944
|
+
// Invite
|
|
1945
|
+
const inviteCode = await sock.communityInviteCode(jid)
|
|
1946
|
+
sock.communityRevokeInvite(jid)
|
|
1947
|
+
sock.communityAcceptInvite(inviteCode)
|
|
1948
|
+
|
|
1949
|
+
// Leave
|
|
1950
|
+
sock.communityLeave(jid)
|
|
1951
|
+
|
|
1952
|
+
// Join requests
|
|
1953
|
+
sock.communityRequestParticipantsUpdate(jid, ['628123456789@s.whatsapp.net'], 'approve')
|
|
1954
|
+
|
|
1955
|
+
// Updates
|
|
1956
|
+
sock.communityUpdateSubject(jid, '@crysnovax/baileys')
|
|
1957
|
+
sock.communityUpdateDescription(jid, 'Updated description')
|
|
1958
|
+
|
|
1959
|
+
// Settings
|
|
1960
|
+
sock.communitySettingUpdate(jid, 'announcement')
|
|
1961
|
+
sock.communitySettingUpdate(jid, 'not_announcement')
|
|
1962
|
+
sock.communitySettingUpdate(jid, 'locked')
|
|
1963
|
+
sock.communitySettingUpdate(jid, 'unlocked')
|
|
1964
|
+
|
|
1965
|
+
// Add mode
|
|
1966
|
+
sock.communityMemberAddMode(jid, 'admin_add')
|
|
1967
|
+
sock.communityMemberAddMode(jid, 'all_member_add')
|
|
1968
|
+
|
|
1969
|
+
// Ephemeral
|
|
1970
|
+
sock.communityToggleEphemeral(jid, 86400)
|
|
1971
|
+
sock.communityToggleEphemeral(jid, 0)
|
|
1972
|
+
|
|
1973
|
+
// Approval mode
|
|
1974
|
+
sock.communityJoinApprovalMode(jid, 'on')
|
|
1975
|
+
sock.communityJoinApprovalMode(jid, 'off')
|
|
1976
|
+
|
|
1977
|
+
// Fetch all
|
|
1978
|
+
const communities = await sock.communityFetchAllParticipating()
|
|
1979
|
+
|
|
1980
|
+
// Linked groups
|
|
1981
|
+
const linked = await sock.communityFetchLinkedGroups(jid)
|
|
1982
|
+
|
|
1983
|
+
// Pending requests
|
|
1984
|
+
const requests = await sock.communityRequestParticipantsList(jid)
|
|
1985
|
+
|
|
1986
|
+
// Invite info
|
|
1987
|
+
const community = await sock.communityGetInviteInfo('ABC123456789')
|
|
1988
|
+
```
|
|
1989
|
+
|
|
1990
|
+
---
|
|
1991
|
+
|
|
1992
|
+
## Profile & Business
|
|
1993
|
+
|
|
1994
|
+
```javascript
|
|
1995
|
+
// Profile picture
|
|
1996
|
+
const url = await sock.profilePictureUrl(jid, 'image')
|
|
1997
|
+
|
|
1998
|
+
// Standard — auto crop + resize to 720×720
|
|
1999
|
+
sock.updateProfilePicture(jid, buffer)
|
|
2000
|
+
sock.updateProfilePicture(jid, { url })
|
|
2001
|
+
|
|
2002
|
+
// Standard with custom dimensions
|
|
2003
|
+
sock.updateProfilePicture(jid, { url }, { width: 640, height: 640 })
|
|
2004
|
+
|
|
2005
|
+
// HD — preserves original aspect ratio, no crop, no padding
|
|
2006
|
+
// Images under 720px pass through unchanged.
|
|
2007
|
+
// Larger images are scaled down proportionally to fit within 720px.
|
|
2008
|
+
sock.updateProfilePicture(jid, buffer, { hd: true })
|
|
2009
|
+
sock.updateProfilePicture(jid, { url }, { hd: true })
|
|
2010
|
+
|
|
2011
|
+
sock.removeProfilePicture(jid)
|
|
2012
|
+
|
|
2013
|
+
// Profile info (name and personal About/bio)
|
|
2014
|
+
await sock.updateProfileName('My Name')
|
|
2015
|
+
await sock.updateProfileStatus('Available')
|
|
2016
|
+
// Business descriptions are separate: updateBusinessProfile({ description })
|
|
2017
|
+
|
|
2018
|
+
// Presence
|
|
2019
|
+
sock.sendPresenceUpdate('available', jid)
|
|
2020
|
+
sock.presenceSubscribe(jid)
|
|
2021
|
+
|
|
2022
|
+
// Read receipts
|
|
2023
|
+
sock.readMessages([message.key])
|
|
2024
|
+
sock.sendReceipt(jid, participant, [messageId], 'read')
|
|
2025
|
+
|
|
2026
|
+
// Block / Unblock
|
|
2027
|
+
sock.updateBlockStatus(jid, 'block')
|
|
2028
|
+
sock.updateBlockStatus(jid, 'unblock')
|
|
2029
|
+
|
|
2030
|
+
// Blocklist
|
|
2031
|
+
const blocked = await sock.fetchBlocklist()
|
|
2032
|
+
|
|
2033
|
+
// Chat modify
|
|
2034
|
+
sock.chatModify({
|
|
2035
|
+
archive: true,
|
|
2036
|
+
lastMessageOrig: message,
|
|
2037
|
+
lastMessage: message
|
|
2038
|
+
}, jid)
|
|
2039
|
+
|
|
2040
|
+
// Star
|
|
2041
|
+
sock.star(jid, [{ id: messageId, fromMe: true }], true)
|
|
2042
|
+
|
|
2043
|
+
// Contact
|
|
2044
|
+
sock.addOrEditContact(jid, { displayName: 'Name' })
|
|
2045
|
+
sock.removeContact(jid)
|
|
2046
|
+
|
|
2047
|
+
// Labels
|
|
2048
|
+
sock.addChatLabel(jid, labelId)
|
|
2049
|
+
sock.removeChatLabel(jid, labelId)
|
|
2050
|
+
sock.addMessageLabel(jid, messageId, labelId)
|
|
2051
|
+
|
|
2052
|
+
// App state sync
|
|
2053
|
+
sock.resyncAppState(['regular', 'critical_block'], true)
|
|
2054
|
+
|
|
2055
|
+
// Business profile
|
|
2056
|
+
const profile = await sock.getBusinessProfile(jid)
|
|
2057
|
+
|
|
2058
|
+
// Product create
|
|
2059
|
+
const product = await sock.productCreate({
|
|
2060
|
+
name: 'Product',
|
|
2061
|
+
description: 'Description',
|
|
2062
|
+
price: 100000,
|
|
2063
|
+
currency: 'IDR',
|
|
2064
|
+
originCountryCode: 'ID',
|
|
2065
|
+
images: [buffer, { url: './image.jpg' }]
|
|
2066
|
+
})
|
|
2067
|
+
|
|
2068
|
+
// Product update
|
|
2069
|
+
await sock.productUpdate(productId, {
|
|
2070
|
+
name: 'Product',
|
|
2071
|
+
description: 'Updated',
|
|
2072
|
+
price: 75000,
|
|
2073
|
+
currency: 'IDR',
|
|
2074
|
+
images: [{ url: './image.jpg' }]
|
|
2075
|
+
})
|
|
2076
|
+
|
|
2077
|
+
// Product delete
|
|
2078
|
+
sock.productDelete([productId])
|
|
2079
|
+
|
|
2080
|
+
// Catalog
|
|
2081
|
+
const { products, nextPageCursor } = await sock.getCatalog({
|
|
2082
|
+
jid: '628123456789@s.whatsapp.net',
|
|
2083
|
+
limit: 10
|
|
2084
|
+
})
|
|
2085
|
+
|
|
2086
|
+
// Collections
|
|
2087
|
+
const collections = await sock.getCollections('628123456789@s.whatsapp.net', 10)
|
|
2088
|
+
|
|
2089
|
+
// Order details
|
|
2090
|
+
const order = await sock.getOrderDetails(orderId, tokenBase64)
|
|
2091
|
+
|
|
2092
|
+
// Business profile update
|
|
2093
|
+
await sock.updateBusinessProfile({
|
|
2094
|
+
address: 'Jakarta, Indonesia',
|
|
2095
|
+
description: 'Official Store',
|
|
2096
|
+
websites: ['https://example.com'],
|
|
2097
|
+
email: 'email@example.com',
|
|
2098
|
+
hours: {
|
|
2099
|
+
timezone: 'Asia/Jakarta',
|
|
2100
|
+
days: [{ day: 'mon', mode: 'open_24h' }]
|
|
2101
|
+
}
|
|
2102
|
+
})
|
|
2103
|
+
|
|
2104
|
+
// Use empty strings or an empty websites array to clear profile fields.
|
|
2105
|
+
await sock.updateBusinessProfile({ description: '', websites: [] })
|
|
2106
|
+
|
|
2107
|
+
// Cover photo: updateCoverPhoto returns the uploaded cover ID and always
|
|
2108
|
+
// removes its local temporary upload file, including after failures.
|
|
2109
|
+
const coverId = await sock.updateCoverPhoto({ url: './image.jpg' })
|
|
2110
|
+
await sock.removeCoverPhoto(coverId)
|
|
2111
|
+
|
|
2112
|
+
// Quick replies
|
|
2113
|
+
sock.addOrEditQuickReply({
|
|
2114
|
+
shortcut: 'hello',
|
|
2115
|
+
message: 'Hello from business account'
|
|
2116
|
+
})
|
|
2117
|
+
sock.removeQuickReply(timestamp)
|
|
2118
|
+
```
|
|
2119
|
+
|
|
2120
|
+
---
|
|
2121
|
+
|
|
2122
|
+
## Privacy & Security
|
|
2123
|
+
|
|
2124
|
+
```javascript
|
|
2125
|
+
// Last seen
|
|
2126
|
+
sock.updateLastSeenPrivacy('all')
|
|
2127
|
+
sock.updateLastSeenPrivacy('contacts')
|
|
2128
|
+
sock.updateLastSeenPrivacy('contact_blacklist')
|
|
2129
|
+
sock.updateLastSeenPrivacy('nobody')
|
|
2130
|
+
|
|
2131
|
+
// Online
|
|
2132
|
+
sock.updateOnlinePrivacy('all')
|
|
2133
|
+
sock.updateOnlinePrivacy('match_last_seen')
|
|
2134
|
+
|
|
2135
|
+
// Profile picture
|
|
2136
|
+
sock.updateProfilePicturePrivacy('contacts')
|
|
2137
|
+
|
|
2138
|
+
// Status
|
|
2139
|
+
sock.updateStatusPrivacy('contacts')
|
|
2140
|
+
|
|
2141
|
+
// Read receipts
|
|
2142
|
+
sock.updateReadReceiptsPrivacy('all')
|
|
2143
|
+
sock.updateReadReceiptsPrivacy('none')
|
|
2144
|
+
|
|
2145
|
+
// Groups add
|
|
2146
|
+
sock.updateGroupsAddPrivacy('all')
|
|
2147
|
+
sock.updateGroupsAddPrivacy('contacts')
|
|
2148
|
+
|
|
2149
|
+
// Messages
|
|
2150
|
+
sock.updateMessagesPrivacy('all')
|
|
2151
|
+
sock.updateMessagesPrivacy('contacts')
|
|
2152
|
+
sock.updateMessagesPrivacy('nobody')
|
|
2153
|
+
|
|
2154
|
+
// Call
|
|
2155
|
+
sock.updateCallPrivacy('everyone')
|
|
2156
|
+
|
|
2157
|
+
// Default disappearing mode
|
|
2158
|
+
sock.updateDefaultDisappearingMode(86400)
|
|
2159
|
+
|
|
2160
|
+
// Link previews
|
|
2161
|
+
sock.updateDisableLinkPreviewsPrivacy(true)
|
|
2162
|
+
```
|
|
2163
|
+
|
|
2164
|
+
---
|
|
2165
|
+
|
|
2166
|
+
## Utility Methods
|
|
2167
|
+
|
|
2168
|
+
### LID / Phone Number Resolution
|
|
2169
|
+
|
|
2170
|
+
```javascript
|
|
2171
|
+
// Resolve LID ↔ PN cross-mappings
|
|
2172
|
+
const userId = await sock.findUserId('628123456789@s.whatsapp.net')
|
|
2173
|
+
console.log(userId)
|
|
2174
|
+
// { lid: '1234567890@lid', phoneNumber: '628123456789@s.whatsapp.net' }
|
|
2175
|
+
|
|
2176
|
+
const userId2 = await sock.findUserId('1234567890@lid')
|
|
2177
|
+
console.log(userId2)
|
|
2178
|
+
// { lid: '1234567890@lid', phoneNumber: '628123456789@s.whatsapp.net' }
|
|
2179
|
+
```
|
|
2180
|
+
|
|
2181
|
+
LID-to-phone resolution uses mappings learned from trusted WhatsApp envelopes, history, or PN-to-LID USync. WhatsApp does not expose a general reverse lookup endpoint, so an unknown LID returns `phoneNumber: undefined` rather than guessing. Primary devices resolve to canonical `number@s.whatsapp.net` JIDs; linked-device suffixes and hosted domains are preserved.
|
|
2182
|
+
|
|
2183
|
+
### Fetch User Status
|
|
2184
|
+
|
|
2185
|
+
```javascript
|
|
2186
|
+
// Fetch status metadata for one or more users
|
|
2187
|
+
const statusList = await sock.fetchStatus('628123456789@s.whatsapp.net', '628987654321@s.whatsapp.net')
|
|
2188
|
+
```
|
|
2189
|
+
|
|
2190
|
+
### Fetch Disappearing Duration
|
|
2191
|
+
|
|
2192
|
+
```javascript
|
|
2193
|
+
// Get disappearing message duration for contacts
|
|
2194
|
+
const durations = await sock.fetchDisappearingDuration('628123456789@s.whatsapp.net')
|
|
2195
|
+
```
|
|
2196
|
+
|
|
2197
|
+
### Bot List
|
|
2198
|
+
|
|
2199
|
+
```javascript
|
|
2200
|
+
// Fetch official bot list (v2)
|
|
2201
|
+
const bots = await sock.getBotListV2()
|
|
2202
|
+
// [{ jid: '...', personaId: '...' }]
|
|
2203
|
+
```
|
|
2204
|
+
|
|
2205
|
+
### Call Links
|
|
2206
|
+
|
|
2207
|
+
```javascript
|
|
2208
|
+
// Create voice/video call link
|
|
2209
|
+
const token = await sock.createCallLink('audio') // voice call
|
|
2210
|
+
const token2 = await sock.createCallLink('video') // video call
|
|
2211
|
+
const token3 = await sock.createCallLink('video', { // with scheduled event
|
|
2212
|
+
startTime: Date.now() + 3600000
|
|
2213
|
+
})
|
|
2214
|
+
```
|
|
2215
|
+
|
|
2216
|
+
### Server Properties
|
|
2217
|
+
|
|
2218
|
+
```javascript
|
|
2219
|
+
// Access server-assigned AB props
|
|
2220
|
+
console.log(sock.serverProps)
|
|
2221
|
+
// {
|
|
2222
|
+
// privacyTokenOn1to1: true, // tctoken on 1:1 messages
|
|
2223
|
+
// profilePicPrivacyToken: true, // tctoken on profile pic IQs
|
|
2224
|
+
// lidTrustedTokenIssueToLid: false // issue tctokens to LID
|
|
2225
|
+
// }
|
|
2226
|
+
```
|
|
2227
|
+
|
|
2228
|
+
### App State Sync
|
|
2229
|
+
|
|
2230
|
+
```javascript
|
|
2231
|
+
// Force resync specific collections
|
|
2232
|
+
await sock.resyncAppState(['regular_high', 'regular_low'], false)
|
|
2233
|
+
|
|
2234
|
+
// Apply custom app patch
|
|
2235
|
+
await sock.appPatch({
|
|
2236
|
+
syncAction: { ... },
|
|
2237
|
+
index: ['...'],
|
|
2238
|
+
type: 'regular_low',
|
|
2239
|
+
apiVersion: 5,
|
|
2240
|
+
operation: proto.SyncdMutation.SyncdOperation.SET
|
|
2241
|
+
})
|
|
2242
|
+
```
|
|
2243
|
+
|
|
2244
|
+
### Clean Dirty Bits
|
|
2245
|
+
|
|
2246
|
+
```javascript
|
|
2247
|
+
// Clear dirty bits for specific sync types
|
|
2248
|
+
await sock.cleanDirtyBits('account_sync', timestamp)
|
|
2249
|
+
```
|
|
2250
|
+
|
|
2251
|
+
---
|
|
2252
|
+
|
|
2253
|
+
## Meta AI Features
|
|
2254
|
+
|
|
2255
|
+
Meta AI-style thinking indicators and live reasoning feeds. Works on all WhatsApp clients — no "Update WhatsApp" messages.
|
|
2256
|
+
|
|
2257
|
+
**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.
|
|
2258
|
+
|
|
2259
|
+
### Meta Typing Indicator
|
|
2260
|
+
|
|
2261
|
+
Show a live thinking indicator that you control. Delete it manually when ready — no "edited" badge ever appears.
|
|
2262
|
+
|
|
2263
|
+
```javascript
|
|
2264
|
+
import { metaTyping, buildSteps } from '@crysnovax/baileys'
|
|
2265
|
+
|
|
2266
|
+
const placeholder = await metaTyping(sock, jid, {
|
|
2267
|
+
description: 'Thinking…',
|
|
2268
|
+
steps: buildSteps(['Reading your message…', 'Writing response…'])
|
|
2269
|
+
})
|
|
2270
|
+
|
|
2271
|
+
// Do your work here…
|
|
2272
|
+
|
|
2273
|
+
// Delete the indicator cleanly
|
|
2274
|
+
await sock.sendMessage(jid, { delete: placeholder.key })
|
|
2275
|
+
|
|
2276
|
+
// Send the real message
|
|
2277
|
+
await sock.sendMessage(jid, { text: 'Here is your answer!' })
|
|
2278
|
+
```
|
|
2279
|
+
|
|
2280
|
+
What users see:
|
|
2281
|
+
|
|
2282
|
+
```
|
|
2283
|
+
[typing… indicator]
|
|
2284
|
+
|
|
2285
|
+
_Thinking…_
|
|
2286
|
+
○ Reading your message…
|
|
2287
|
+
○ Writing response…
|
|
2288
|
+
|
|
2289
|
+
[auto-deletes]
|
|
2290
|
+
|
|
2291
|
+
Here is your answer!
|
|
2292
|
+
```
|
|
2293
|
+
|
|
2294
|
+
### Meta Compositing
|
|
2295
|
+
|
|
2296
|
+
Full flow: indicator shows → auto-deletes → clean final message lands. Works with every rich content type.
|
|
2297
|
+
|
|
2298
|
+
```javascript
|
|
2299
|
+
import { sendMetaComposited, PlanningStepStatus } from '@crysnovax/baileys'
|
|
2300
|
+
|
|
2301
|
+
// With code block
|
|
2302
|
+
await sendMetaComposited(
|
|
2303
|
+
sock, jid,
|
|
2304
|
+
{ code: 'const x = 1 + 1', language: 'javascript' },
|
|
2305
|
+
{
|
|
2306
|
+
thinkingMs: 3000,
|
|
2307
|
+
description: 'Analyzing…',
|
|
2308
|
+
steps: [
|
|
2309
|
+
{ title: 'Reading context…', status: PlanningStepStatus.DONE },
|
|
2310
|
+
{ title: 'Writing code…', status: PlanningStepStatus.IN_PROGRESS }
|
|
2311
|
+
]
|
|
2312
|
+
}
|
|
2313
|
+
)
|
|
2314
|
+
|
|
2315
|
+
// With table
|
|
2316
|
+
await sendMetaComposited(
|
|
2317
|
+
sock, jid,
|
|
2318
|
+
{
|
|
2319
|
+
title: 'Comparison',
|
|
2320
|
+
table: [
|
|
2321
|
+
['Feature', 'Baileys', 'Crysnovax'],
|
|
2322
|
+
['Rich Messages', '❌', '✅'],
|
|
2323
|
+
['Meta Compositing', '❌', '✅']
|
|
2324
|
+
]
|
|
2325
|
+
},
|
|
2326
|
+
{ thinkingMs: 2500, description: 'Building table…' }
|
|
2327
|
+
)
|
|
2328
|
+
|
|
2329
|
+
// With rich response array
|
|
2330
|
+
await sendMetaComposited(
|
|
2331
|
+
sock, jid,
|
|
2332
|
+
{
|
|
2333
|
+
richResponse: [
|
|
2334
|
+
{ text: 'Here is your result:' },
|
|
2335
|
+
{ code: 'console.log("hello")', language: 'javascript' },
|
|
2336
|
+
{ text: 'Run it with `node index.js`' }
|
|
2337
|
+
]
|
|
2338
|
+
},
|
|
2339
|
+
{ thinkingMs: 2000 }
|
|
2340
|
+
)
|
|
2341
|
+
```
|
|
2342
|
+
|
|
2343
|
+
### Replay Planning
|
|
2344
|
+
|
|
2345
|
+
Live Meta AI-style reasoning feed — each step visibly completes in real time, then the final rich message lands clean.
|
|
2346
|
+
|
|
2347
|
+
```javascript
|
|
2348
|
+
import { replayPlanning, mixedSteps } from '@crysnovax/baileys'
|
|
2349
|
+
|
|
2350
|
+
await replayPlanning(
|
|
2351
|
+
sock, jid,
|
|
2352
|
+
|
|
2353
|
+
// Steps — status managed automatically
|
|
2354
|
+
mixedSteps([
|
|
2355
|
+
{ title: 'Understanding your question…', type: 'reasoning' },
|
|
2356
|
+
{ title: 'Searching for data…', type: 'search' },
|
|
2357
|
+
{ title: 'Writing the answer…' }
|
|
2358
|
+
]),
|
|
2359
|
+
|
|
2360
|
+
// Final rich message
|
|
2361
|
+
{ code: 'const answer = 42', language: 'javascript' },
|
|
2362
|
+
|
|
2363
|
+
// Options
|
|
2364
|
+
{
|
|
2365
|
+
description: 'Thinking…',
|
|
2366
|
+
stepDelayMs: 900,
|
|
2367
|
+
finalPauseMs: 600
|
|
2368
|
+
}
|
|
2369
|
+
)
|
|
2370
|
+
```
|
|
2371
|
+
|
|
2372
|
+
What users see:
|
|
2373
|
+
|
|
2374
|
+
```
|
|
2375
|
+
_Thinking…_
|
|
2376
|
+
○ Understanding your question…
|
|
2377
|
+
○ Searching for data…
|
|
2378
|
+
○ Writing the answer…
|
|
2379
|
+
|
|
2380
|
+
[step 1 completes]
|
|
2381
|
+
_Thinking…_
|
|
2382
|
+
✓ Understanding your question…
|
|
2383
|
+
○ Searching for data…
|
|
2384
|
+
○ Writing the answer…
|
|
2385
|
+
|
|
2386
|
+
[step 2 completes]
|
|
2387
|
+
_Thinking…_
|
|
2388
|
+
✓ Understanding your question…
|
|
2389
|
+
✓ Searching for data…
|
|
2390
|
+
○ Writing the answer…
|
|
2391
|
+
|
|
2392
|
+
[all done, deletes, then:]
|
|
2393
|
+
|
|
2394
|
+
const answer = 42
|
|
2395
|
+
```
|
|
2396
|
+
|
|
2397
|
+
Step type helpers:
|
|
2398
|
+
|
|
2399
|
+
```javascript
|
|
2400
|
+
import {
|
|
2401
|
+
buildReasoningSteps, // isReasoning: true
|
|
2402
|
+
buildSearchSteps, // isEnhancedSearch: true
|
|
2403
|
+
mixedSteps, // mix any combination
|
|
2404
|
+
buildSteps // plain steps
|
|
2405
|
+
} from '@crysnovax/baileys'
|
|
2406
|
+
|
|
2407
|
+
// All reasoning
|
|
2408
|
+
buildReasoningSteps(['Analyzing the problem…', 'Checking edge cases…'])
|
|
2409
|
+
|
|
2410
|
+
// All search
|
|
2411
|
+
buildSearchSteps(['Searching the web…', 'Reading top results…'])
|
|
2412
|
+
|
|
2413
|
+
// Mixed — most realistic Meta AI look
|
|
2414
|
+
mixedSteps([
|
|
2415
|
+
{ title: 'Reading your message…', type: 'reasoning' },
|
|
2416
|
+
{ title: 'Searching sources…', type: 'search' },
|
|
2417
|
+
{ title: 'Composing response…' }
|
|
2418
|
+
])
|
|
2419
|
+
```
|
|
2420
|
+
|
|
2421
|
+
Replay planning only (no final message):
|
|
2422
|
+
|
|
2423
|
+
```javascript
|
|
2424
|
+
import { replayPlanningOnly, buildSearchSteps } from '@crysnovax/baileys'
|
|
2425
|
+
|
|
2426
|
+
await replayPlanningOnly(
|
|
2427
|
+
sock, jid,
|
|
2428
|
+
buildSearchSteps(['Looking up prices…', 'Comparing results…']),
|
|
2429
|
+
{ stepDelayMs: 1200 }
|
|
2430
|
+
)
|
|
2431
|
+
|
|
2432
|
+
// Send whatever you want after — no badge, no trace
|
|
2433
|
+
await sock.sendMessage(jid, { text: 'Here are the results!' })
|
|
2434
|
+
```
|
|
2435
|
+
|
|
2436
|
+
Options reference:
|
|
2437
|
+
|
|
2438
|
+
| Option | Type | Default | Description |
|
|
2439
|
+
|--------|------|---------|-------------|
|
|
2440
|
+
| description | string | 'Thinking…' | Top label on the indicator bubble |
|
|
2441
|
+
| placeholderText | string | '' | Body text while steps run |
|
|
2442
|
+
| stepDelayMs | number | 900 | Ms between each step completing |
|
|
2443
|
+
| finalPauseMs | number | 600 | Ms to hold after all steps done |
|
|
2444
|
+
| abortOnDisconnect | boolean | true | Stops cleanly if socket closes |
|
|
2445
|
+
| sendOptions | object | {} | Extra options for final sendMessage |
|
|
2446
|
+
|
|
2447
|
+
---
|
|
2448
|
+
|
|
2449
|
+
## Events Reference
|
|
2450
|
+
|
|
2451
|
+
```javascript
|
|
2452
|
+
sock.ev.on('connection.update', (update) => {})
|
|
2453
|
+
sock.ev.on('creds.update', (update) => {})
|
|
2454
|
+
sock.ev.on('messaging-history.set', (update) => {})
|
|
2455
|
+
sock.ev.on('messaging-history.status', (update) => {})
|
|
2456
|
+
sock.ev.on('chats.upsert', (update) => {})
|
|
2457
|
+
sock.ev.on('chats.update', (update) => {})
|
|
2458
|
+
sock.ev.on('chats.delete', (update) => {})
|
|
2459
|
+
sock.ev.on('chats.lock', (update) => {})
|
|
2460
|
+
sock.ev.on('lid-mapping.update', (update) => {})
|
|
2461
|
+
sock.ev.on('presence.update', (update) => {})
|
|
2462
|
+
sock.ev.on('contacts.upsert', (update) => {})
|
|
2463
|
+
sock.ev.on('contacts.update', (update) => {})
|
|
2464
|
+
sock.ev.on('messages.delete', (update) => {})
|
|
2465
|
+
sock.ev.on('messages.update', (update) => {})
|
|
2466
|
+
sock.ev.on('messages.media-update', (update) => {})
|
|
2467
|
+
sock.ev.on('messages.upsert', (update) => {})
|
|
2468
|
+
sock.ev.on('messages.reaction', (update) => {})
|
|
2469
|
+
sock.ev.on('message-receipt.update', (update) => {})
|
|
2470
|
+
sock.ev.on('groups.upsert', (update) => {})
|
|
2471
|
+
sock.ev.on('groups.update', (update) => {})
|
|
2472
|
+
sock.ev.on('group-participants.update', (update) => {})
|
|
2473
|
+
sock.ev.on('group.join-request', (update) => {})
|
|
2474
|
+
sock.ev.on('group.member-tag.update', (update) => {})
|
|
2475
|
+
sock.ev.on('blocklist.set', (update) => {})
|
|
2476
|
+
sock.ev.on('blocklist.update', (update) => {})
|
|
2477
|
+
sock.ev.on('call', (update) => {})
|
|
2478
|
+
sock.ev.on('labels.edit', (update) => {})
|
|
2479
|
+
sock.ev.on('labels.association', (update) => {})
|
|
2480
|
+
sock.ev.on('newsletter.reaction', (update) => {})
|
|
2481
|
+
sock.ev.on('newsletter.view', (update) => {})
|
|
2482
|
+
sock.ev.on('newsletter-participants.update', (update) => {})
|
|
2483
|
+
sock.ev.on('newsletter-settings.update', (update) => {})
|
|
2484
|
+
sock.ev.on('settings.update', (update) => {})
|
|
2485
|
+
```
|
|
2486
|
+
|
|
2487
|
+
---
|
|
2488
|
+
|
|
2489
|
+
## Image Processing
|
|
2490
|
+
|
|
2491
|
+
Auto-detects available libraries: sharp, @napi-rs/image, or jimp.
|
|
2492
|
+
|
|
2493
|
+
```javascript
|
|
2494
|
+
import { getImageProcessingLibrary } from '@crysnovax/baileys'
|
|
2495
|
+
import { readFile } from 'fs/promises'
|
|
2496
|
+
|
|
2497
|
+
const lib = await getImageProcessingLibrary()
|
|
2498
|
+
const bufferOrFilePath = './image.jpg'
|
|
2499
|
+
const width = 512
|
|
2500
|
+
let output
|
|
2501
|
+
|
|
2502
|
+
// Sharp
|
|
2503
|
+
if (lib.sharp?.default) {
|
|
2504
|
+
const img = lib.sharp.default(bufferOrFilePath)
|
|
2505
|
+
output = await img.resize(width).jpeg({ quality: 80 }).toBuffer()
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
// NAPI-RS Image
|
|
2509
|
+
else if (lib.image?.Transformer) {
|
|
2510
|
+
const inputBuffer = Buffer.isBuffer(bufferOrFilePath)
|
|
2511
|
+
? bufferOrFilePath
|
|
2512
|
+
: await readFile(bufferOrFilePath)
|
|
2513
|
+
const img = new lib.image.Transformer(inputBuffer)
|
|
2514
|
+
output = await img.resize(width, undefined, 0).jpeg(50)
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// Jimp
|
|
2518
|
+
else if (lib.jimp?.Jimp) {
|
|
2519
|
+
const img = await lib.jimp.Jimp.read(bufferOrFilePath)
|
|
2520
|
+
output = await img
|
|
2521
|
+
.resize({ w: width, mode: lib.jimp.ResizeStrategy.BILINEAR })
|
|
2522
|
+
.getBuffer('image/jpeg', { quality: 50 })
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
else {
|
|
2526
|
+
throw new Error('No image processing library available')
|
|
2527
|
+
}
|
|
2528
|
+
```
|
|
2529
|
+
|
|
2530
|
+
---
|
|
2531
|
+
|
|
2532
|
+
## Credits and attribution
|
|
2533
|
+
|
|
2534
|
+
Plogme/CODY is a downstream fork and enhancement of the Baileys protocol implementation by [WhiskeySockets/Baileys](https://github.com/WhiskeySockets/Baileys). The underlying WhatsApp Web protocol work, structure, and many foundational APIs come from WhiskeySockets. Additional changes in this fork include CODY/Plogme rich-message composition, immediate AIRich rendering relay, A2UI and Gen4 menu helpers, albums, video grids, and related documentation.
|
|
2535
|
+
|
|
2536
|
+
This README also incorporates compatible API examples from [crysnovax/baileys2](https://github.com/crysnovax/baileys2). Custom package-specific ban-checker APIs are intentionally not documented here.
|