fixo-baileys 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/WAProto/WAProto.proto +1 -0
- package/WAProto/index.d.ts +2 -0
- package/WAProto/index.js +23 -0
- package/lib/Socket/messages-send.js +21 -1
- package/lib/Utils/messages.js +2 -1
- package/package.json +3 -2
- package/tools/capture-channel-status.js +29 -0
package/README.md
CHANGED
|
@@ -962,6 +962,33 @@ Errors: a non-channel JID throws `400`; posting from an account that is not owne
|
|
|
962
962
|
|
|
963
963
|
> 🎨 A **text** status always carries a background colour — if you don't pass `backgroundColor`, `#FFC107` is used.
|
|
964
964
|
|
|
965
|
+
### ⚠️ `mode: 'status'` (default) vs `mode: 'post'`
|
|
966
|
+
|
|
967
|
+
| `options.mode` | What is sent | Where it shows up |
|
|
968
|
+
|:---|:---|:---|
|
|
969
|
+
| `'status'` *(default, **experimental**)* | the message wrapped in `proto.Message.newsletterAdminProfileStatusMessage` (field 126) and published to the channel JID | meant to be a real **Channel Status** (Updates tab, 24 h) |
|
|
970
|
+
| `'post'` | plain channel message (the old behaviour) | channel chat only — a normal post |
|
|
971
|
+
|
|
972
|
+
> The `'status'` wrapper is based on WhatsApp's own protobuf definition, but the exact stanza WhatsApp uses has **not been verified against a real capture yet**.
|
|
973
|
+
> If it still lands as a normal post, capture the real stanza (below) and open an issue / send the log.
|
|
974
|
+
> Add `rawLog: true` to the 3rd argument to log the final payload: `sock.sendChannelStatus(jid, 'Hi', { rawLog: true })`.
|
|
975
|
+
|
|
976
|
+
```js
|
|
977
|
+
await sock.sendChannelStatus(channelJid, { image: { url: './pic.jpg' }, caption: 'Hi' }) // status (experimental)
|
|
978
|
+
await sock.sendChannelStatus(channelJid, { image: { url: './pic.jpg' }, caption: 'Hi' }, { mode: 'post' }) // old plain post
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
### 🔍 Capturing the real Channel Status stanza
|
|
982
|
+
|
|
983
|
+
```js
|
|
984
|
+
import makeWASocket from 'fixo-baileys'
|
|
985
|
+
import { attachCapture } from 'fixo-baileys/tools/capture-channel-status.js'
|
|
986
|
+
|
|
987
|
+
const sock = makeWASocket({ /* ... */ })
|
|
988
|
+
attachCapture(sock) // writes every received stanza to ./capture.log
|
|
989
|
+
```
|
|
990
|
+
Then post a real Channel Status (one text, one photo) **from your phone** and send `capture.log`.
|
|
991
|
+
|
|
965
992
|
**How it works (for contributors)**
|
|
966
993
|
- `lib/Socket/messages-send.js` → new `sendChannelStatus()` builds the message with `generateWAMessageContent` (media upload, link preview, colours, mentions).
|
|
967
994
|
- `lib/Socket/newsletter-channel.js` → all channel node builders / parsers / error mapping (see the [Channel API](#-channel-api-newsletter-methods) below).
|
package/WAProto/WAProto.proto
CHANGED
|
@@ -2150,6 +2150,7 @@ message Message {
|
|
|
2150
2150
|
optional FutureProofMessage questionMessage = 101;
|
|
2151
2151
|
optional MessageHistoryNotice messageHistoryNotice = 102;
|
|
2152
2152
|
optional FutureProofMessage groupStatusMessageV2 = 103;
|
|
2153
|
+
optional FutureProofMessage newsletterAdminProfileStatusMessage = 126;
|
|
2153
2154
|
optional FutureProofMessage botForwardedMessage = 104;
|
|
2154
2155
|
optional StatusQuestionAnswerMessage statusQuestionAnswerMessage = 105;
|
|
2155
2156
|
optional FutureProofMessage questionReplyMessage = 106;
|
package/WAProto/index.d.ts
CHANGED
|
@@ -5269,6 +5269,7 @@ export namespace proto {
|
|
|
5269
5269
|
questionMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5270
5270
|
messageHistoryNotice?: (proto.Message.IMessageHistoryNotice|null);
|
|
5271
5271
|
groupStatusMessageV2?: (proto.Message.IFutureProofMessage|null);
|
|
5272
|
+
newsletterAdminProfileStatusMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5272
5273
|
botForwardedMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5273
5274
|
statusQuestionAnswerMessage?: (proto.Message.IStatusQuestionAnswerMessage|null);
|
|
5274
5275
|
questionReplyMessage?: (proto.Message.IFutureProofMessage|null);
|
|
@@ -5368,6 +5369,7 @@ export namespace proto {
|
|
|
5368
5369
|
public questionMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5369
5370
|
public messageHistoryNotice?: (proto.Message.IMessageHistoryNotice|null);
|
|
5370
5371
|
public groupStatusMessageV2?: (proto.Message.IFutureProofMessage|null);
|
|
5372
|
+
public newsletterAdminProfileStatusMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5371
5373
|
public botForwardedMessage?: (proto.Message.IFutureProofMessage|null);
|
|
5372
5374
|
public statusQuestionAnswerMessage?: (proto.Message.IStatusQuestionAnswerMessage|null);
|
|
5373
5375
|
public questionReplyMessage?: (proto.Message.IFutureProofMessage|null);
|
package/WAProto/index.js
CHANGED
|
@@ -35552,6 +35552,7 @@ export const proto = $root.proto = (() => {
|
|
|
35552
35552
|
Message.prototype.questionMessage = null;
|
|
35553
35553
|
Message.prototype.messageHistoryNotice = null;
|
|
35554
35554
|
Message.prototype.groupStatusMessageV2 = null;
|
|
35555
|
+
Message.prototype.newsletterAdminProfileStatusMessage = null;
|
|
35555
35556
|
Message.prototype.botForwardedMessage = null;
|
|
35556
35557
|
Message.prototype.statusQuestionAnswerMessage = null;
|
|
35557
35558
|
Message.prototype.questionReplyMessage = null;
|
|
@@ -36080,6 +36081,12 @@ export const proto = $root.proto = (() => {
|
|
|
36080
36081
|
set: $util.oneOfSetter($oneOfFields)
|
|
36081
36082
|
});
|
|
36082
36083
|
|
|
36084
|
+
// Virtual OneOf for proto3 optional field
|
|
36085
|
+
Object.defineProperty(Message.prototype, "_newsletterAdminProfileStatusMessage", {
|
|
36086
|
+
get: $util.oneOfGetter($oneOfFields = ["newsletterAdminProfileStatusMessage"]),
|
|
36087
|
+
set: $util.oneOfSetter($oneOfFields)
|
|
36088
|
+
});
|
|
36089
|
+
|
|
36083
36090
|
// Virtual OneOf for proto3 optional field
|
|
36084
36091
|
Object.defineProperty(Message.prototype, "_botForwardedMessage", {
|
|
36085
36092
|
get: $util.oneOfGetter($oneOfFields = ["botForwardedMessage"]),
|
|
@@ -36313,6 +36320,8 @@ export const proto = $root.proto = (() => {
|
|
|
36313
36320
|
$root.proto.Message.MessageHistoryNotice.encode(m.messageHistoryNotice, w.uint32(818).fork()).ldelim();
|
|
36314
36321
|
if (m.groupStatusMessageV2 != null && Object.hasOwnProperty.call(m, "groupStatusMessageV2"))
|
|
36315
36322
|
$root.proto.Message.FutureProofMessage.encode(m.groupStatusMessageV2, w.uint32(826).fork()).ldelim();
|
|
36323
|
+
if (m.newsletterAdminProfileStatusMessage != null && Object.hasOwnProperty.call(m, "newsletterAdminProfileStatusMessage"))
|
|
36324
|
+
$root.proto.Message.FutureProofMessage.encode(m.newsletterAdminProfileStatusMessage, w.uint32(1010).fork()).ldelim();
|
|
36316
36325
|
if (m.botForwardedMessage != null && Object.hasOwnProperty.call(m, "botForwardedMessage"))
|
|
36317
36326
|
$root.proto.Message.FutureProofMessage.encode(m.botForwardedMessage, w.uint32(834).fork()).ldelim();
|
|
36318
36327
|
if (m.statusQuestionAnswerMessage != null && Object.hasOwnProperty.call(m, "statusQuestionAnswerMessage"))
|
|
@@ -36687,6 +36696,10 @@ export const proto = $root.proto = (() => {
|
|
|
36687
36696
|
m.groupStatusMessageV2 = $root.proto.Message.FutureProofMessage.decode(r, r.uint32());
|
|
36688
36697
|
break;
|
|
36689
36698
|
}
|
|
36699
|
+
case 126: {
|
|
36700
|
+
m.newsletterAdminProfileStatusMessage = $root.proto.Message.FutureProofMessage.decode(r, r.uint32());
|
|
36701
|
+
break;
|
|
36702
|
+
}
|
|
36690
36703
|
case 104: {
|
|
36691
36704
|
m.botForwardedMessage = $root.proto.Message.FutureProofMessage.decode(r, r.uint32());
|
|
36692
36705
|
break;
|
|
@@ -37163,6 +37176,11 @@ export const proto = $root.proto = (() => {
|
|
|
37163
37176
|
throw TypeError(".proto.Message.groupStatusMessageV2: object expected");
|
|
37164
37177
|
m.groupStatusMessageV2 = $root.proto.Message.FutureProofMessage.fromObject(d.groupStatusMessageV2);
|
|
37165
37178
|
}
|
|
37179
|
+
if (d.newsletterAdminProfileStatusMessage != null) {
|
|
37180
|
+
if (typeof d.newsletterAdminProfileStatusMessage !== "object")
|
|
37181
|
+
throw TypeError(".proto.Message.newsletterAdminProfileStatusMessage: object expected");
|
|
37182
|
+
m.newsletterAdminProfileStatusMessage = $root.proto.Message.FutureProofMessage.fromObject(d.newsletterAdminProfileStatusMessage);
|
|
37183
|
+
}
|
|
37166
37184
|
if (d.botForwardedMessage != null) {
|
|
37167
37185
|
if (typeof d.botForwardedMessage !== "object")
|
|
37168
37186
|
throw TypeError(".proto.Message.botForwardedMessage: object expected");
|
|
@@ -37645,6 +37663,11 @@ export const proto = $root.proto = (() => {
|
|
|
37645
37663
|
if (o.oneofs)
|
|
37646
37664
|
d._groupStatusMessageV2 = "groupStatusMessageV2";
|
|
37647
37665
|
}
|
|
37666
|
+
if (m.newsletterAdminProfileStatusMessage != null && m.hasOwnProperty("newsletterAdminProfileStatusMessage")) {
|
|
37667
|
+
d.newsletterAdminProfileStatusMessage = $root.proto.Message.FutureProofMessage.toObject(m.newsletterAdminProfileStatusMessage, o);
|
|
37668
|
+
if (o.oneofs)
|
|
37669
|
+
d._newsletterAdminProfileStatusMessage = "newsletterAdminProfileStatusMessage";
|
|
37670
|
+
}
|
|
37648
37671
|
if (m.botForwardedMessage != null && m.hasOwnProperty("botForwardedMessage")) {
|
|
37649
37672
|
d.botForwardedMessage = $root.proto.Message.FutureProofMessage.toObject(m.botForwardedMessage, o);
|
|
37650
37673
|
if (o.oneofs)
|
|
@@ -1268,6 +1268,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
1268
1268
|
// ── Channel Status (post to a WhatsApp Channel like a user posts a status) ──
|
|
1269
1269
|
// sock.sendChannelStatus(channelJid, 'text' | { text, backgroundColor, font, textColor }
|
|
1270
1270
|
// | { image|video|audio|document|sticker, caption, ... }, options)
|
|
1271
|
+
//
|
|
1272
|
+
// options.mode:
|
|
1273
|
+
// 'status' (default, EXPERIMENTAL) -> the message is wrapped in
|
|
1274
|
+
// proto.Message.newsletterAdminProfileStatusMessage (field 126), which is the
|
|
1275
|
+
// wrapper WhatsApp uses for a channel admin's *status* (Updates tab, 24h).
|
|
1276
|
+
// The exact wire format is not verified against a real capture yet.
|
|
1277
|
+
// 'post' -> old behaviour: plain channel post (shows up inside the channel chat only).
|
|
1278
|
+
// options.rawLog = true -> logs the final proto + stanza attrs (logger.info) for debugging.
|
|
1271
1279
|
sendChannelStatus: async (jid, content, options = {}) => {
|
|
1272
1280
|
if (!isJidNewsletter(jid)) {
|
|
1273
1281
|
throw new Boom('sendChannelStatus needs a channel JID (xxxx@newsletter)', { statusCode: 400 });
|
|
@@ -1334,8 +1342,20 @@ export const makeMessagesSocket = (config) => {
|
|
|
1334
1342
|
else if (inner.documentMessage) [type, mediatype] = ['media', 'document'];
|
|
1335
1343
|
else if (inner.stickerMessage) [type, mediatype] = ['media', 'sticker'];
|
|
1336
1344
|
|
|
1345
|
+
const mode = options.mode === 'post' ? 'post' : 'status';
|
|
1346
|
+
const toSend =
|
|
1347
|
+
mode === 'status'
|
|
1348
|
+
? proto.Message.create({
|
|
1349
|
+
newsletterAdminProfileStatusMessage: proto.Message.FutureProofMessage.create({ message })
|
|
1350
|
+
})
|
|
1351
|
+
: message;
|
|
1352
|
+
|
|
1353
|
+
if (options.rawLog) {
|
|
1354
|
+
logger.info({ jid, mode, type, mediatype, proto: toSend.toJSON?.() }, 'sendChannelStatus payload');
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1337
1357
|
try {
|
|
1338
|
-
return await sock.newsletterPublish(jid,
|
|
1358
|
+
return await sock.newsletterPublish(jid, toSend, {
|
|
1339
1359
|
messageId: options.messageId,
|
|
1340
1360
|
additionalAttributes: options.additionalAttributes,
|
|
1341
1361
|
type,
|
package/lib/Utils/messages.js
CHANGED
|
@@ -816,7 +816,8 @@ export const normalizeMessageContent = (content) => {
|
|
|
816
816
|
message?.editedMessage ||
|
|
817
817
|
message?.associatedChildMessage ||
|
|
818
818
|
message?.groupStatusMessage ||
|
|
819
|
-
message?.groupStatusMessageV2
|
|
819
|
+
message?.groupStatusMessageV2 ||
|
|
820
|
+
message?.newsletterAdminProfileStatusMessage);
|
|
820
821
|
}
|
|
821
822
|
};
|
|
822
823
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fixo-baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.9",
|
|
5
5
|
"description": "A WebSockets library for interacting with WhatsApp Web",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"lib/**/*",
|
|
18
18
|
"WAProto/**/*",
|
|
19
19
|
"engine-requirements.js",
|
|
20
|
-
"assets/**/*"
|
|
20
|
+
"assets/**/*",
|
|
21
|
+
"tools/**/*"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"build": "tsc && tsc-esm-fix",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// capture-channel-status.js
|
|
2
|
+
// Logs every raw stanza the bot receives/sends into capture.log so the real
|
|
3
|
+
// "Channel Status" wire format can be inspected.
|
|
4
|
+
//
|
|
5
|
+
// Usage: in your bot, right after you create the socket:
|
|
6
|
+
//
|
|
7
|
+
// import { attachCapture } from 'fixo-baileys/tools/capture-channel-status.js'
|
|
8
|
+
// const sock = makeWASocket({ ... })
|
|
9
|
+
// attachCapture(sock)
|
|
10
|
+
//
|
|
11
|
+
// Then post a real Channel Status from the phone (one text, one photo)
|
|
12
|
+
// and send capture.log back (remove phone numbers if you like).
|
|
13
|
+
import fs from 'fs'
|
|
14
|
+
import { binaryNodeToString } from '../lib/WABinary/index.js'
|
|
15
|
+
|
|
16
|
+
export const attachCapture = (sock, file = 'capture.log') => {
|
|
17
|
+
const out = fs.createWriteStream(file, { flags: 'a' })
|
|
18
|
+
sock.ws.on('frame', (frame) => {
|
|
19
|
+
if (frame instanceof Uint8Array) return
|
|
20
|
+
// skip noisy keep-alive / presence traffic
|
|
21
|
+
if (['presence', 'chatstate', 'receipt', 'ack'].includes(frame.tag)) return
|
|
22
|
+
try {
|
|
23
|
+
out.write(`\n[${new Date().toISOString()}] RECV\n${binaryNodeToString(frame)}\n`)
|
|
24
|
+
} catch (e) {
|
|
25
|
+
out.write(`\n[${new Date().toISOString()}] RECV (unprintable) ${e.message}\n`)
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
console.log(`capture started -> ${file}`)
|
|
29
|
+
}
|