@vanzxy/baileys 1.2.5 → 1.2.7

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.
@@ -269,7 +269,7 @@ const prepareProductMessage = async (message, options) => {
269
269
  */
270
270
  // Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
271
271
  const prepareStickerPackMessage = async (message, options) => {
272
- const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: itsliaaa', description = '🏷️ itsliaaa/baileys' } = message;
272
+ const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: vanzxy', description = '🏷️ vanzxy/baileys' } = message;
273
273
  if (stickers.length > 60) {
274
274
  throw new Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
275
275
  }
@@ -469,7 +469,7 @@ const prepareNativeFlowButtons = (message) => {
469
469
  Object.assign(messageParamsJson, {
470
470
  limited_time_offer: {
471
471
  text: message.offerText || LIBRARY_NAME,
472
- url: message.offerUrl || DONATE_URL, // Lia@Note 02-02-26 --- Apologies if this feels cheeky, just a fallback
472
+ url: message.offerUrl || DONATE_URL || undefined, // Vanz@Fix (bug 10): DONATE_URL now empty don't inject fallback link
473
473
  copy_code: message.offerCode,
474
474
  expiration_time: message.offerExpiration
475
475
  }
@@ -795,7 +795,16 @@ export const generateForwardMessageContent = (message, forceForward) => {
795
795
  content = normalizeMessageContent(content);
796
796
  content = proto.Message.decode(proto.Message.encode(content).finish());
797
797
  let key = Object.keys(content)[0];
798
- let score = content?.[key]?.contextInfo?.forwardingScore || 0;
798
+ // Vanz@Fix (bug 27): viewOnce/ephemeral messages wrap content in an outer key.
799
+ // Must unwrap first before reading forwardingScore, otherwise score stays 0.
800
+ let innerContent = content?.[key];
801
+ if (key === 'viewOnceMessage' || key === 'ephemeralMessage') {
802
+ const innerKey = innerContent?.message ? Object.keys(innerContent.message)[0] : null;
803
+ if (innerKey) {
804
+ innerContent = innerContent.message[innerKey];
805
+ }
806
+ }
807
+ let score = innerContent?.contextInfo?.forwardingScore || 0;
799
808
  score += message.key.fromMe && !forceForward ? 0 : 1;
800
809
  if (key === 'conversation') {
801
810
  content.extendedTextMessage = { text: content[key] };
@@ -944,7 +953,7 @@ export const generateWAMessageContent = async (message, options) => {
944
953
  else if (hasNonNullishProperty(message, 'groupInvite')) {
945
954
  m.groupInviteMessage = {};
946
955
  m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
947
- m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
956
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration ?? 0; // Vanz@Fix: default 0 (no expiry) instead of undefined
948
957
  m.groupInviteMessage.caption = message.groupInvite.text;
949
958
  m.groupInviteMessage.groupJid = message.groupInvite.jid;
950
959
  m.groupInviteMessage.groupName = message.groupInvite.subject;
@@ -956,7 +965,24 @@ export const generateWAMessageContent = async (message, options) => {
956
965
  const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
957
966
  if (resp.ok) {
958
967
  const buf = Buffer.from(await resp.arrayBuffer());
959
- m.groupInviteMessage.jpegThumbnail = buf;
968
+ // Vanz@Fix: upload thumbnail to WA server so thumbnailDirectPath/mediaKey are set properly
969
+ if (options.upload) {
970
+ try {
971
+ const uploaded = await prepareWAMessageMedia({ image: buf }, { upload: options.upload });
972
+ if (uploaded.imageMessage) {
973
+ m.groupInviteMessage.jpegThumbnail = buf;
974
+ m.groupInviteMessage.thumbnailDirectPath = uploaded.imageMessage.directPath;
975
+ m.groupInviteMessage.thumbnailSha256 = uploaded.imageMessage.fileSha256;
976
+ m.groupInviteMessage.thumbnailEncSha256 = uploaded.imageMessage.fileEncSha256;
977
+ m.groupInviteMessage.mediaKey = uploaded.imageMessage.mediaKey;
978
+ }
979
+ } catch {
980
+ // fallback: at least attach raw jpeg
981
+ m.groupInviteMessage.jpegThumbnail = buf;
982
+ }
983
+ } else {
984
+ m.groupInviteMessage.jpegThumbnail = buf;
985
+ }
960
986
  }
961
987
  }
962
988
  }
@@ -1425,6 +1451,11 @@ export const generateWAMessageContent = async (message, options) => {
1425
1451
  else if (hasOptionalProperty(card, 'footer')) {
1426
1452
  carouselCard.footer = { text: card.footer };
1427
1453
  }
1454
+ // Vanz@Fix (bug 20): add per-card contextInfo support
1455
+ // Allows each carousel card to have its own reply context, forward info, etc.
1456
+ if (hasNonNullishProperty(card, 'contextInfo')) {
1457
+ carouselCard.contextInfo = card.contextInfo;
1458
+ }
1428
1459
  return carouselCard;
1429
1460
  })),
1430
1461
  carouselCardType: CarouselCardType.UNKNOWN,
@@ -1498,7 +1529,7 @@ export const generateWAMessageContent = async (message, options) => {
1498
1529
  throw new Boom('Thumbnail must in buffer type', { statusCode: 400 });
1499
1530
  }
1500
1531
  if (!content.url || typeof content.url !== 'string') {
1501
- content.url = DONATE_URL; // Lia@Note 02-02-26 --- Apologies if this feels cheeky, just a fallback
1532
+ content.url = DONATE_URL || ''; // Vanz@Fix (bug 10): DONATE_URL now empty use empty string as safe fallback
1502
1533
  }
1503
1534
  const externalAdReply = {
1504
1535
  ...content,
@@ -691,56 +691,65 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
691
691
  const method = message.messageStubParameters?.[2];
692
692
  emitGroupRequestJoin(participant, action, method);
693
693
  break;
694
+ // Vanz@Fix (bug 44): handle previously unhandled stub types
695
+ case WAMessageStubType.GROUP_CHANGE_ICON:
696
+ emitGroupUpdate({ icon: message.messageStubParameters?.[0] });
697
+ break;
698
+ case WAMessageStubType.GROUP_CHANGE_NO_FREQUENTLY_FORWARDED:
699
+ emitGroupUpdate({ noFrequentlyForwarded: message.messageStubParameters?.[0] === 'on' });
700
+ break;
701
+ case WAMessageStubType.GROUP_V4_ADD_INVITE_SENT:
702
+ // notification that a v4 invite was sent — no group metadata change, but emit for plugin awareness
703
+ ev.emit('groups.update', [{ id: jid, v4AddInviteSent: true }]);
704
+ break;
705
+ case WAMessageStubType.GROUP_CHANGE_RECENT_HISTORY_SHARING:
706
+ emitGroupUpdate({ recentHistorySharing: message.messageStubParameters?.[0] === 'on' });
707
+ break;
708
+ // Vanz@Fix (bug 45): handle GROUP_CREATE — bot entered a new group via link
709
+ case WAMessageStubType.GROUP_CREATE:
710
+ ev.emit('groups.upsert', [{ id: jid, subject: message.messageStubParameters?.[0] || '' }]);
711
+ break;
694
712
  }
695
- } /* else if(content?.pollUpdateMessage) {
696
- const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
697
- // we need to fetch the poll creation message to get the poll enc key
698
- // TODO: make standalone, remove getMessage reference
699
- // TODO: Remove entirely
700
- const pollMsg = await getMessage(creationMsgKey)
701
- if(pollMsg) {
702
- const meIdNormalised = jidNormalizedUser(meId)
703
- const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
704
- const voterJid = getKeyAuthor(message.key, meIdNormalised)
705
- const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
706
-
707
- try {
708
- const voteMsg = decryptPollVote(
709
- content.pollUpdateMessage.vote!,
710
- {
713
+ // Vanz@Fix (bug 47): poll update handler was entirely commented out.
714
+ // Re-enabled: decrypts poll votes and emits messages.update with pollUpdates.
715
+ } else if (content?.pollUpdateMessage) {
716
+ const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey;
717
+ const pollMsg = await getMessage(creationMsgKey);
718
+ if (pollMsg) {
719
+ const meIdNormalised = jidNormalizedUser(meId);
720
+ const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised);
721
+ const voterJid = getKeyAuthor(message.key, meIdNormalised);
722
+ const pollEncKey = pollMsg.messageContextInfo?.messageSecret;
723
+ if (pollEncKey) {
724
+ try {
725
+ const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
711
726
  pollEncKey,
712
727
  pollCreatorJid,
713
- pollMsgId: creationMsgKey.id!,
728
+ pollMsgId: creationMsgKey.id,
714
729
  voterJid,
715
- }
716
- )
717
- ev.emit('messages.update', [
718
- {
730
+ });
731
+ ev.emit('messages.update', [{
719
732
  key: creationMsgKey,
720
733
  update: {
721
- pollUpdates: [
722
- {
723
- pollUpdateMessageKey: message.key,
724
- vote: voteMsg,
725
- senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
726
- }
727
- ]
734
+ pollUpdates: [{
735
+ pollUpdateMessageKey: message.key,
736
+ vote: voteMsg,
737
+ senderTimestampMs: typeof content.pollUpdateMessage.senderTimestampMs === 'object'
738
+ ? content.pollUpdateMessage.senderTimestampMs.toNumber()
739
+ : Number(content.pollUpdateMessage.senderTimestampMs),
740
+ }]
728
741
  }
729
- }
730
- ])
731
- } catch(err) {
732
- logger?.warn(
733
- { err, creationMsgKey },
734
- 'failed to decrypt poll vote'
735
- )
742
+ }]);
743
+ } catch (err) {
744
+ logger?.warn({ err, creationMsgKey }, 'failed to decrypt poll vote');
745
+ }
746
+ } else {
747
+ logger?.warn({ creationMsgKey }, 'poll message has no messageSecret — cannot decrypt vote');
736
748
  }
737
749
  } else {
738
- logger?.warn(
739
- { creationMsgKey },
740
- 'poll creation message not found, cannot decrypt update'
741
- )
750
+ logger?.warn({ creationMsgKey }, 'poll creation message not found, cannot decrypt update');
742
751
  }
743
- } */
752
+ }
744
753
  if (Object.keys(chat).length > 1) {
745
754
  ev.emit('chats.update', [chat]);
746
755
  }
@@ -62,11 +62,46 @@ export const toUnified = (submessages, uuid) => ({
62
62
  }
63
63
  };
64
64
  case RichSubMessageType.CONTENT_ITEMS:
65
- return {};
65
+ // Vanz@Fix (bug 40): was returning {} — now renders content items carousel
66
+ const contentItemsMeta = submessage.contentItemsMetadata;
67
+ return {
68
+ view_model: {
69
+ primitive: {
70
+ items: contentItemsMeta?.itemsMetadata || [],
71
+ content_type: contentItemsMeta?.contentType ?? 1,
72
+ __typename: 'GenAIContentItemsUXPrimitive'
73
+ },
74
+ __typename: 'GenAISingleLayoutViewModel'
75
+ }
76
+ };
66
77
  case RichSubMessageType.INLINE_IMAGE:
67
- return {};
78
+ // Vanz@Fix (bug 40): was returning {} — now renders inline image
79
+ const imgMeta = submessage.imageMetadata;
80
+ return {
81
+ view_model: {
82
+ primitive: {
83
+ image_url: imgMeta?.imageUrl || '',
84
+ image_text: imgMeta?.imageText || '',
85
+ alignment: imgMeta?.alignment || 'center',
86
+ tap_link_url: imgMeta?.tapLinkUrl || '',
87
+ __typename: 'GenAIInlineImageUXPrimitive'
88
+ },
89
+ __typename: 'GenAISingleLayoutViewModel'
90
+ }
91
+ };
68
92
  case RichSubMessageType.LATEX:
69
- return {};
93
+ // Vanz@Fix (bug 40): was returning {} — now renders LaTeX expressions
94
+ const latexMeta = submessage.latexMetadata;
95
+ return {
96
+ view_model: {
97
+ primitive: {
98
+ text: latexMeta?.text || '',
99
+ expressions: latexMeta?.expressions || [],
100
+ __typename: 'GenAILatexUXPrimitive'
101
+ },
102
+ __typename: 'GenAISingleLayoutViewModel'
103
+ }
104
+ };
70
105
  case RichSubMessageType.TABLE:
71
106
  const tableMetadata = submessage.tableMetadata;
72
107
  return {
@@ -44,6 +44,28 @@ export async function useSqliteAuthState(opts) {
44
44
  db.pragma('journal_mode = WAL');
45
45
  db.pragma('synchronous = NORMAL');
46
46
  db.exec(CREATE_SCHEMA_SQL);
47
+ // Vanz@Fix (bug 8): periodic WAL checkpoint + cleanup old signal keys to prevent DB bloat.
48
+ // Runs every 30 minutes. WAL checkpoint reclaims WAL file space; key cleanup removes stale session entries.
49
+ const _walCleanupInterval = setInterval(() => {
50
+ try {
51
+ db.pragma('wal_checkpoint(PASSIVE)');
52
+ // Remove signal keys older than 30 days (pre-keys, session keys that have expired)
53
+ // Only removes types that are safe to prune (not creds or app-state-sync-key)
54
+ const pruneTypes = ['pre-key', 'session'];
55
+ for (const type of pruneTypes) {
56
+ try {
57
+ // Keep last 500 per type to avoid breaking active sessions
58
+ db.prepare(`
59
+ DELETE FROM signal_keys WHERE type = ? AND id NOT IN (
60
+ SELECT id FROM signal_keys WHERE type = ? ORDER BY rowid DESC LIMIT 500
61
+ )
62
+ `).run(type, type);
63
+ } catch { /* ignore per-type errors */ }
64
+ }
65
+ } catch { /* ignore checkpoint errors — non-fatal */ }
66
+ }, 30 * 60 * 1000);
67
+ // Allow Node process to exit even if interval is still running
68
+ if (_walCleanupInterval.unref) _walCleanupInterval.unref();
47
69
  const stmts = {
48
70
  credsSelect: db.prepare('SELECT value FROM creds WHERE key = ?'),
49
71
  credsUpsert: db.prepare('INSERT INTO creds (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value'),
@@ -57,8 +57,8 @@ export const generateLoginNode = (userJid, config) => {
57
57
  pull: true,
58
58
  username: +user,
59
59
  device: device,
60
- // TODO: investigate (hard set as false atm)
61
- lidDbMigrated: false
60
+ // Vanz@Fix (bug 49): was hardcoded false now reads from config.lidDbMigrated (default false until investigated)
61
+ lidDbMigrated: config.lidDbMigrated ?? false
62
62
  };
63
63
  return proto.ClientPayload.fromObject(payload);
64
64
  };
@@ -124,12 +124,31 @@ export function binaryNodeToString(node, i = 0) {
124
124
  * @returns {object} A node with shape { tag, attrs, [content] } to inject into additionalNodes.
125
125
  */
126
126
  const FLOWS_MAP = {
127
+ // Original flow types
127
128
  mpm: true,
128
129
  cta_catalog: true,
129
130
  send_location: true,
130
131
  call_permission_request: true,
131
132
  wa_payment_transaction_details: true,
132
- automated_greeting_message_view_catalog: true
133
+ automated_greeting_message_view_catalog: true,
134
+ // Vanzxy extended button types
135
+ card_message: true,
136
+ order_status: true,
137
+ track_order: true,
138
+ reorder: true,
139
+ cancel_order: true,
140
+ clear_chat: true,
141
+ navigateToScreen: true,
142
+ payment_status: true,
143
+ payment_method: true,
144
+ flow_action: true,
145
+ voice_call: true,
146
+ video_call_button: true,
147
+ otp_button: true,
148
+ authentication_button: true,
149
+ cta_reminder: true,
150
+ cta_cancel_reminder: true,
151
+ single_select: true,
133
152
  };
134
153
  const DECISION_SOURCE_CONTENT = [
135
154
  {
@@ -168,10 +187,20 @@ export const getBizBinaryNode = (message) => {
168
187
  host_storage: '2',
169
188
  privacy_mode_ts: `${Date.now() / 1_000 | 0}`
170
189
  };
171
- if (firstButtonName === 'review_and_pay' || firstButtonName === 'payment_info') {
172
- bizAttributes.native_flow_name = firstButtonName === 'review_and_pay' ?
173
- 'order_details' :
174
- firstButtonName;
190
+ const ORDER_RESPONSE_ALIAS = {
191
+ review_and_pay: 'order_details',
192
+ review_order: 'order_status',
193
+ payment_info: 'payment_info',
194
+ payment_status: 'payment_status',
195
+ payment_method: 'payment_method',
196
+ order_details: 'order_details',
197
+ order_status: 'order_status',
198
+ track_order: 'track_order',
199
+ reorder: 'reorder',
200
+ cancel_order: 'cancel_order',
201
+ };
202
+ if (firstButtonName && ORDER_RESPONSE_ALIAS[firstButtonName]) {
203
+ bizAttributes.native_flow_name = ORDER_RESPONSE_ALIAS[firstButtonName];
175
204
  return {
176
205
  tag: 'biz',
177
206
  attrs: bizAttributes,
@@ -11,10 +11,19 @@ export class USyncDeviceProtocol {
11
11
  }
12
12
  };
13
13
  }
14
- getUserElement( /* user: USyncUser */) {
15
- //TODO: Implement device phashing, ts and expectedTs
16
- //TODO: if all are not present, return null <- current behavior
17
- //TODO: otherwise return a node w tag 'devices' w those as attrs
14
+ getUserElement(user) {
15
+ // Vanz@Fix (bug 51): Implement device phashing for sync
16
+ // Include phash (participant hash) if devices exist to enable proper sync
17
+ if (user?.devices?.deviceList && user.devices.deviceList.length > 0) {
18
+ return {
19
+ tag: 'devices',
20
+ attrs: {
21
+ phash: user.devices.phash || '',
22
+ ts: user.devices.keyIndex?.timestamp?.toString() || '',
23
+ expectedTs: user.devices.keyIndex?.expectedTimestamp?.toString() || ''
24
+ }
25
+ };
26
+ }
18
27
  return null;
19
28
  }
20
29
  parser(node) {
@@ -3,4 +3,6 @@ export * from './USyncContactProtocol.js';
3
3
  export * from './USyncStatusProtocol.js';
4
4
  export * from './USyncDisappearingModeProtocol.js';
5
5
  export * from './USyncUsernameProtocol.js';
6
+ export * from './UsyncBotProfileProtocol.js'; // Vanz@Fix: was missing
7
+ export * from './UsyncLIDProtocol.js'; // Vanz@Fix: was missing
6
8
  //# sourceMappingURL=index.js.map
@@ -62,8 +62,32 @@ export class USyncQuery {
62
62
  return acc;
63
63
  }, []);
64
64
  }
65
- //TODO: implement side list
66
- //const sideListNode = getBinaryNodeChild(usyncNode, 'side_list')
65
+ // Vanz@Fix (bug 52): implement sideList for side band sync
66
+ // sideList contains additional sync data that should be processed separately
67
+ const sideListNode = usyncNode ? getBinaryNodeChild(usyncNode, 'side_list') : undefined;
68
+ if (sideListNode?.content && Array.isArray(sideListNode.content)) {
69
+ queryResult.sideList = sideListNode.content.reduce((acc, node) => {
70
+ const id = node?.attrs.jid;
71
+ if (id) {
72
+ const data = Array.isArray(node?.content)
73
+ ? Object.fromEntries(node.content
74
+ .map(content => {
75
+ const protocol = content.tag;
76
+ const parser = protocolMap[protocol];
77
+ if (parser) {
78
+ return [protocol, parser(content)];
79
+ }
80
+ else {
81
+ return [protocol, null];
82
+ }
83
+ })
84
+ .filter(([, b]) => b !== null))
85
+ : {};
86
+ acc.push({ ...data, id });
87
+ }
88
+ return acc;
89
+ }, []);
90
+ }
67
91
  return queryResult;
68
92
  }
69
93
  withDeviceProtocol() {
package/lib/index.js CHANGED
@@ -7,6 +7,7 @@ export * from './Defaults/index.js';
7
7
  export * from './WABinary/index.js';
8
8
  export * from './WAM/index.js';
9
9
  export * from './WAUSync/index.js';
10
+ export { Dugong } from './Socket/dugong.js';
10
11
  export { makeWASocket };
11
12
  export default makeWASocket;
12
- //# sourceMappingURL=index.js.map
13
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanzxy/baileys",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "Enhanced Baileys fork by Vanzxy — based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -39,7 +39,6 @@
39
39
  "@adiwajshing/keyed-db": "^0.2.4",
40
40
  "@cacheable/node-cache": "^1.4.0",
41
41
  "@hapi/boom": "^9.1.3",
42
- "@vanzxy/baileys": "^1.1.2",
43
42
  "async-mutex": "^0.5.0",
44
43
  "fflate": "^0.8.2",
45
44
  "libsignal": "^6.0.0",