@vanzxy/baileys 1.6.7 → 1.6.8

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.
@@ -2977,6 +2977,14 @@ class AIRich extends BaseBuilder {
2977
2977
  addWidget(data = {}, { layout } = {}) {
2978
2978
  const items = Array.isArray(data) ? data : [data];
2979
2979
 
2980
+ // Vanz@Fix (bug 44) --- layout: 'Single' forces `widgets[0]` below (a "Single" layout's
2981
+ // view_model can only ever hold one `primitive`, never a `primitives` array — see
2982
+ // newLayout()). Previously an explicit { layout: 'Single' } combined with a multi-item
2983
+ // array silently dropped every item past the first with no error. Fail loud instead.
2984
+ if (layout === 'Single' && items.length > 1) {
2985
+ throw new TypeError(`addWidget(): layout "Single" can only hold one widget (got ${items.length}) — use "HScroll"/"ActionRow" (or omit layout) for multiple`);
2986
+ }
2987
+
2980
2988
  items.forEach((item, i) => {
2981
2989
  // header.title or top-level title required
2982
2990
  const hasTitle = item?.title || item?.header?.title;
@@ -2994,6 +3002,13 @@ class AIRich extends BaseBuilder {
2994
3002
  messageText: items.map((item) => item.header?.title ?? item.title).join(', '),
2995
3003
  });
2996
3004
 
3005
+ // Vanz@Fix (bug 45) --- auto tool_call_id used to be `idx` scoped per-item (ctas.map's own
3006
+ // index), resetting to 0 for every widget item. Two items (or two separate addWidget()
3007
+ // calls) that both omit tool_call_id/id ended up minting the identical auto id ("00"),
3008
+ // so a CTA tap could route to the wrong widget's tool call. Track the counter on the
3009
+ // instance instead so every auto-generated id is unique for this AIRich's lifetime.
3010
+ this._widgetCtaCounter ??= 0;
3011
+
2997
3012
  const widgets = items.map((item) => {
2998
3013
  const ctas = item.ctas ?? item.actions;
2999
3014
  // header accepts either a string title (legacy) or an object { title, subtitle }
@@ -3007,11 +3022,11 @@ class AIRich extends BaseBuilder {
3007
3022
  },
3008
3023
  body: {
3009
3024
  sections: item.sections ?? [],
3010
- ctas: ctas.map((cta, idx) => ({
3025
+ ctas: ctas.map((cta) => ({
3011
3026
  label: cta.label ?? '',
3012
3027
  state: cta.state ?? 'PENDING',
3013
3028
  kind: cta.kind ?? 'OTHER',
3014
- tool_call_id: cta.tool_call_id ?? cta.id ?? String(idx).padStart(2, '0'),
3029
+ tool_call_id: cta.tool_call_id ?? cta.id ?? String(this._widgetCtaCounter++).padStart(2, '0'),
3015
3030
  ...(cta.toast !== false && {
3016
3031
  toast: { label: typeof cta.toast === 'string' ? cta.toast : headerTitle, __typename: 'GenAI3PExtWidgetToast' },
3017
3032
  }),
@@ -80,12 +80,20 @@ export class MessageStore {
80
80
  stored.isDeleted = true;
81
81
  stored.deletedAt = now;
82
82
  stored.deletedBy = deletedBy;
83
+ // Vanz@Fix (bug 66): the old check (`deletedBy === stored.message.key.participant`)
84
+ // only works in groups, where `participant` identifies who sent/revoked a message.
85
+ // In a private chat `key.participant` is always undefined (it's a group-only field),
86
+ // while `deletedBy` there falls back to `remoteJid` — so the comparison could never
87
+ // match and isRevokedBySender was always false for every DM, even though
88
+ // delete-for-everyone in a DM can only be done by the original sender. Treat a
89
+ // missing `participant` (i.e. not a group message) as "revoked by sender" by definition.
90
+ const isGroupMessage = !!stored.message.key.participant;
83
91
  const info = {
84
92
  originalMessage: stored.message,
85
93
  key,
86
94
  deletedAt: now,
87
95
  deletedBy,
88
- isRevokedBySender: !deletedBy || deletedBy === stored.message.key.participant
96
+ isRevokedBySender: !deletedBy || !isGroupMessage || deletedBy === stored.message.key.participant
89
97
  };
90
98
  this.deletedMessages.set(this.getKey(key), info);
91
99
  return info;
@@ -71,7 +71,25 @@ export const encodeBigEndian = (e, t = 4) => {
71
71
  };
72
72
  export const toNumber = (t) => typeof t === 'object' && t ? ('toNumber' in t ? t.toNumber() : t.low) : t || 0;
73
73
  /** unix timestamp of a date in seconds */
74
- export const unixTimestampSeconds = (date = new Date()) => date.getTime() / 1000 | 0;
74
+ // Vanz@Fix (bug 69): unixTimestampSeconds(date) assumed `date` is always a real Date
75
+ // instance and called date.getTime() unconditionally. Any caller that passed a raw
76
+ // number (Date.now(), or an already-converted unix timestamp) or an ISO string instead
77
+ // of a Date crashed here with "date.getTime is not a function" — this is a coercion
78
+ // bug in THIS function, not a proto/BloksWidget/InteractiveMessage issue (traced and
79
+ // confirmed: normalizeMessageContent/getContentType never touch nested message content,
80
+ // and this function is called before any encode/serialize step even starts). Coerce the
81
+ // common input shapes instead of assuming Date, but keep throwing on genuinely invalid
82
+ // input (NaN) so silent bad-timestamp bugs don't get hidden.
83
+ export const unixTimestampSeconds = (date) => {
84
+ if (date == null) date = new Date(); // null AND undefined both mean "now" (default params only catch undefined)
85
+ const d = date instanceof Date
86
+ ? date
87
+ : new Date(typeof date === 'number' && date < 1e12 ? date * 1000 : date); // treat sub-1e12 numbers as already-seconds
88
+ if (Number.isNaN(d.getTime())) {
89
+ throw new TypeError(`unixTimestampSeconds: invalid timestamp input (${typeof date}): ${date}`);
90
+ }
91
+ return d.getTime() / 1000 | 0;
92
+ };
75
93
  export const debouncedTimeout = (intervalMs = 1000, task) => {
76
94
  let timeout;
77
95
  return {
@@ -145,7 +145,11 @@ export const groupLabel = async (jid, text, sock) => {
145
145
  type: 30,
146
146
  memberLabel: {
147
147
  label: text.slice(0, 30),
148
- labelTimestamp: Date.now()
148
+ // Vanz@Fix (bug 67): this used Date.now() (milliseconds) while the
149
+ // sibling groupSetMemberLabel() correctly uses unixTimestampSeconds()
150
+ // for the same proto field — WA's *Timestamp fields are unix-seconds,
151
+ // so this was sending a timestamp ~1000x too large.
152
+ labelTimestamp: unixTimestampSeconds() || Date.now()
149
153
  }
150
154
  }
151
155
  }, {
@@ -160,7 +160,9 @@ const FLOWS_MAP = {
160
160
  // routed anything real; kept as a harmless alias in case any external caller
161
161
  // is still constructing a raw button object with the old (wrong) name.
162
162
  flow: true,
163
- flow_action: true,
163
+ // Vanz@Fix (bug 68): removed duplicate `flow_action: true` key — already declared
164
+ // above (Vanzxy extended button types block); this was a leftover copy-paste dupe,
165
+ // harmless (same value) but confusing on re-read.
164
166
  // Vanz@Fix (single_select never renders alone) --- single_select must NEVER get
165
167
  // its own dedicated native_flow node here. WhatsApp only renders a single_select
166
168
  // button through the generic <native_flow v='9' name='mixed'> node — the same one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanzxy/baileys",
3
- "version": "1.6.7",
3
+ "version": "1.6.8",
4
4
  "description": "Enhanced Baileys fork by Vanzxy \u2014 based on @itsliaaa/baileys + @whiskeysockets/baileys with fixes for audio group status and clean media without newsletter button.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",