Spaces:
Runtime error
Runtime error
| diff --git a/index.d.ts b/index.d.ts | |
| index 8127770492b..b155be8391d 100644 | |
| --- a/index.d.ts | |
| +++ b/index.d.ts | |
| declare namespace WAWebJS { | |
| ): Promise<Message>; | |
| /** Send a reaction to a specific messageId */ | |
| - sendReaction( | |
| - messageId: string, | |
| - reaction: string, | |
| - ): Promise<void>; | |
| + sendReaction(messageId: string, reaction: string): Promise<void>; | |
| /** Sends a channel admin invitation to a user, allowing them to become an admin of the channel */ | |
| sendChannelAdminInvite( | |
| diff --git a/src/Client.js b/src/Client.js | |
| index a122a8f336b..62de5395407 100644 | |
| --- a/src/Client.js | |
| +++ b/src/Client.js | |
| class Client extends EventEmitter { | |
| const parentMsgKey = reaction.reactionParentKey; | |
| const timestamp = reaction.reactionTimestamp / 1000; | |
| const sender = reaction.author ?? reaction.from; | |
| - const senderUserJid = sender._serialized; | |
| + const senderUserJid = | |
| + sender._serialized || sender.$1; | |
| return { | |
| ...reaction, | |
| class Client extends EventEmitter { | |
| const parentMsgKey = vote.pollUpdateParentKey; | |
| const timestamp = vote.t / 1000; | |
| const sender = vote.author ?? vote.from; | |
| - const senderUserJid = sender._serialized; | |
| + const senderUserJid = | |
| + sender._serialized || sender.$1; | |
| let parentMessage = Msg.get( | |
| - parentMsgKey._serialized, | |
| + parentMsgKey._serialized || parentMsgKey.$1, | |
| ); | |
| if (!parentMessage) { | |
| const fetched = await Msg.getMessagesById([ | |
| - parentMsgKey._serialized, | |
| + parentMsgKey._serialized || parentMsgKey.$1, | |
| ]); | |
| parentMessage = fetched?.messages?.[0] || null; | |
| } | |
| class Client extends EventEmitter { | |
| .joinGroupViaInvite(inviteCode); | |
| }, inviteCode); | |
| - return res.gid._serialized; | |
| + return res.gid._serialized || res.gid.$1; | |
| } | |
| /** | |
| class Client extends EventEmitter { | |
| (participant.wid = window | |
| .require('WAWebApiContact') | |
| .getPhoneNumber(participant.wid)); | |
| - const participantId = participant.wid._serialized; | |
| + const participantId = | |
| + participant.wid._serialized || participant.wid.$1; | |
| const statusCode = participant.error || 200; | |
| if (autoSendInviteV4 && statusCode === 403) { | |
| class Client extends EventEmitter { | |
| (await window | |
| .require('WAWebCollections') | |
| .Chat.find(participant.wid)), | |
| - createGroupResult.wid._serialized, | |
| + createGroupResult.wid._serialized || | |
| + createGroupResult.wid.$1, | |
| createGroupResult.subject, | |
| participant.invite_code, | |
| participant.invite_code_exp, | |
| class Client extends EventEmitter { | |
| let chatIds = window | |
| .require('WAWebCollections') | |
| .Blocklist.getModelsArray() | |
| - .map((a) => a.id._serialized); | |
| + .map((a) => a.id._serialized || a.id.$1); | |
| return Promise.all( | |
| chatIds.map((id) => window.WWebJS.getContact(id)), | |
| ); | |
| class Client extends EventEmitter { | |
| ); | |
| const chats = window | |
| .require('WAWebCollections') | |
| - .Chat.filter((e) => chatIds.includes(e.id._serialized)); | |
| + .Chat.filter((e) => | |
| + chatIds.includes(e.id._serialized || e.id.$1), | |
| + ); | |
| let actions = labels.map((label) => ({ | |
| id: label.id, | |
| class Client extends EventEmitter { | |
| await window.WWebJS.enforceLidAndPnRetrieval(userId); | |
| return { | |
| - lid: lid?._serialized, | |
| - pn: phone?._serialized, | |
| + lid: lid?._serialized || lid?.$1, | |
| + pn: phone?._serialized || phone?.$1, | |
| }; | |
| }), | |
| ); | |
| class Client extends EventEmitter { | |
| if (!serialized) return null; | |
| - serialized.chatId = window | |
| - .require('WAWebJidToWid') | |
| - .userJidToUserWid(serialized.chatJid)._serialized; | |
| + serialized.chatId = (() => { | |
| + const _w = window | |
| + .require('WAWebJidToWid') | |
| + .userJidToUserWid(serialized.chatJid); | |
| + return _w._serialized || _w.$1; | |
| + })(); | |
| delete serialized.chatJid; | |
| return serialized; | |
| diff --git a/src/structures/Base.js b/src/structures/Base.js | |
| index ed1d83c09e6..a22afdf817a 100644 | |
| --- a/src/structures/Base.js | |
| +++ b/src/structures/Base.js | |
| class Base { | |
| _patch(data) { | |
| return data; | |
| } | |
| + | |
| + /** | |
| + * Normalizes a WhatsApp ID object so that `_serialized` is always defined. | |
| + * WhatsApp Web changed `_serialized` to `$1` in July 2026. This ensures | |
| + * backward compatibility so all downstream code can continue using `_serialized`. | |
| + * @param {object} id | |
| + * @returns {object} | |
| + */ | |
| + static _normalizeId(id) { | |
| + if (id && id._serialized == null && id.$1 != null) { | |
| + return Object.assign({}, id, { _serialized: id.$1 }); | |
| + } | |
| + return id; | |
| + } | |
| } | |
| module.exports = Base; | |
| diff --git a/src/structures/Broadcast.js b/src/structures/Broadcast.js | |
| index ce03dfaf5fc..f0bbb8ed330 100644 | |
| --- a/src/structures/Broadcast.js | |
| +++ b/src/structures/Broadcast.js | |
| class Broadcast extends Base { | |
| * ID that represents the chat | |
| * @type {object} | |
| */ | |
| - this.id = data.id; | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * Unix timestamp of last status | |
| diff --git a/src/structures/Channel.js b/src/structures/Channel.js | |
| index cd3e08786fe..25181de6b86 100644 | |
| --- a/src/structures/Channel.js | |
| +++ b/src/structures/Channel.js | |
| class Channel extends Base { | |
| * ID that represents the channel | |
| * @type {ChannelId} | |
| */ | |
| - this.id = data.id; | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * Title of the channel | |
| diff --git a/src/structures/Chat.js b/src/structures/Chat.js | |
| index 40211bf04d4..79624e34430 100644 | |
| --- a/src/structures/Chat.js | |
| +++ b/src/structures/Chat.js | |
| class Chat extends Base { | |
| * ID that represents the chat | |
| * @type {object} | |
| */ | |
| - this.id = data.id; | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * Title of the chat | |
| diff --git a/src/structures/ClientInfo.js b/src/structures/ClientInfo.js | |
| index 8e273c16a8d..de3dece19d9 100644 | |
| --- a/src/structures/ClientInfo.js | |
| +++ b/src/structures/ClientInfo.js | |
| class ClientInfo extends Base { | |
| * Current user ID | |
| * @type {object} | |
| */ | |
| - this.wid = data.wid; | |
| + this.wid = Base._normalizeId(data.wid); | |
| /** | |
| * @type {object} | |
| diff --git a/src/structures/Contact.js b/src/structures/Contact.js | |
| index 339fa5c9e51..b56c967aa94 100644 | |
| --- a/src/structures/Contact.js | |
| +++ b/src/structures/Contact.js | |
| class Contact extends Base { | |
| * ID that represents the contact | |
| * @type {ContactId} | |
| */ | |
| - this.id = data.id; | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * Contact's phone number | |
| class Contact extends Base { | |
| contact = await window | |
| .require('WAWebCollections') | |
| - .Contact.find(lid._serialized); | |
| + .Contact.find(lid._serialized || lid.$1); | |
| } | |
| await window | |
| .require('WAWebBlockContactAction') | |
| diff --git a/src/structures/GroupChat.js b/src/structures/GroupChat.js | |
| index 3cecc82845b..b9049d472cc 100644 | |
| --- a/src/structures/GroupChat.js | |
| +++ b/src/structures/GroupChat.js | |
| class GroupChat extends Chat { | |
| }; | |
| for (let pWid of participantWids) { | |
| - const pId = pWid._serialized; | |
| + const pId = pWid._serialized || pWid.$1; | |
| pWid = | |
| pWid.server === 'lid' | |
| ? window | |
| class GroupChat extends Chat { | |
| isInviteV4Sent: false, | |
| }; | |
| - if (groupParticipants.some((p) => p._serialized === pId)) { | |
| + if ( | |
| + groupParticipants.some( | |
| + (p) => (p._serialized || p.$1) === pId, | |
| + ) | |
| + ) { | |
| participantData[pId].code = 409; | |
| participantData[pId].message = errorCodes[409]; | |
| continue; | |
| class GroupChat extends Chat { | |
| .require('WAWebChatSendMessages') | |
| .sendGroupInviteMessage( | |
| userChat, | |
| - group.id._serialized, | |
| + group.id._serialized || group.id.$1, | |
| groupName, | |
| rpcResult.inviteV4Code, | |
| rpcResult.inviteV4CodeExp, | |
| class GroupChat extends Chat { | |
| return ( | |
| chat.groupMetadata.participants.get( | |
| - lid?._serialized, | |
| + lid?._serialized || lid?.$1, | |
| ) || | |
| chat.groupMetadata.participants.get( | |
| - phone?._serialized, | |
| + phone?._serialized || phone?.$1, | |
| ) | |
| ); | |
| }), | |
| class GroupChat extends Chat { | |
| return ( | |
| chat.groupMetadata.participants.get( | |
| - lid?._serialized, | |
| + lid?._serialized || lid?.$1, | |
| ) || | |
| chat.groupMetadata.participants.get( | |
| - phone?._serialized, | |
| + phone?._serialized || phone?.$1, | |
| ) | |
| ); | |
| }), | |
| class GroupChat extends Chat { | |
| return ( | |
| chat.groupMetadata.participants.get( | |
| - lid?._serialized, | |
| + lid?._serialized || lid?.$1, | |
| ) || | |
| chat.groupMetadata.participants.get( | |
| - phone?._serialized, | |
| + phone?._serialized || phone?.$1, | |
| ) | |
| ); | |
| }), | |
| diff --git a/src/structures/GroupNotification.js b/src/structures/GroupNotification.js | |
| index a723639f4ef..61d597851aa 100644 | |
| --- a/src/structures/GroupNotification.js | |
| +++ b/src/structures/GroupNotification.js | |
| class GroupNotification extends Base { | |
| * ID that represents the groupNotification | |
| * @type {object} | |
| */ | |
| - this.id = data.id; | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * Extra content | |
| class GroupNotification extends Base { | |
| */ | |
| this.chatId = | |
| typeof data.id.remote === 'object' | |
| - ? data.id.remote._serialized | |
| + ? data.id.remote._serialized || data.id.remote.$1 | |
| : data.id.remote; | |
| /** | |
| class GroupNotification extends Base { | |
| */ | |
| this.author = | |
| typeof data.author === 'object' | |
| - ? data.author._serialized | |
| + ? data.author._serialized || data.author.$1 | |
| : data.author; | |
| /** | |
| diff --git a/src/structures/Message.js b/src/structures/Message.js | |
| index 51e9062dbc0..ed7991352d7 100644 | |
| --- a/src/structures/Message.js | |
| +++ b/src/structures/Message.js | |
| class Message extends Base { | |
| * ID that represents the message | |
| * @type {object} | |
| */ | |
| - this.id = data.id; | |
| + // Normalize id: WhatsApp Web changed _serialized to $1 in 2026-07 update. | |
| + // Keep _serialized always populated for backward compatibility. | |
| + this.id = Base._normalizeId(data.id); | |
| /** | |
| * ACK status for the message | |
| class Message extends Base { | |
| */ | |
| this.from = | |
| typeof data.from === 'object' && data.from !== null | |
| - ? data.from._serialized | |
| + ? data.from._serialized || data.from.$1 | |
| : data.from; | |
| /** | |
| class Message extends Base { | |
| */ | |
| this.to = | |
| typeof data.to === 'object' && data.to !== null | |
| - ? data.to._serialized | |
| + ? data.to._serialized || data.to.$1 | |
| : data.to; | |
| /** | |
| class Message extends Base { | |
| */ | |
| this.author = | |
| typeof data.author === 'object' && data.author !== null | |
| - ? data.author._serialized | |
| + ? data.author._serialized || data.author.$1 | |
| : data.author; | |
| /** | |
| class Message extends Base { | |
| groupName: data.inviteGrpName, | |
| fromId: | |
| typeof data.from === 'object' && | |
| - '_serialized' in data.from | |
| - ? data.from._serialized | |
| + (data.from._serialized || data.from.$1) | |
| + ? data.from._serialized || data.from.$1 | |
| : data.from, | |
| toId: | |
| typeof data.to === 'object' && | |
| - '_serialized' in data.to | |
| - ? data.to._serialized | |
| + (data.to._serialized || data.to.$1) | |
| + ? data.to._serialized || data.to.$1 | |
| : data.to, | |
| } | |
| : undefined; | |
| diff --git a/src/util/Injected/Utils.js b/src/util/Injected/Utils.js | |
| index dfa30a579de..b7e23bc7fe7 100644 | |
| --- a/src/util/Injected/Utils.js | |
| +++ b/src/util/Injected/Utils.js | |
| exports.LoadUtils = () => { | |
| return window | |
| .require('WAWebCollections') | |
| - .Msg.get(newMsgKey._serialized); | |
| + .Msg.get(newMsgKey._serialized || newMsgKey.$1); | |
| }; | |
| window.WWebJS.editMessage = async (msg, content, options = {}) => { | |
| exports.LoadUtils = () => { | |
| await window | |
| .require('WAWebSendMessageEditAction') | |
| .sendMessageEdit(msg, content, internalOptions); | |
| - return window.require('WAWebCollections').Msg.get(msg.id._serialized); | |
| + return window | |
| + .require('WAWebCollections') | |
| + .Msg.get(msg.id._serialized || msg.id.$1); | |
| }; | |
| window.WWebJS.toStickerData = async (mediaInfo) => { | |
| exports.LoadUtils = () => { | |
| if (typeof msg.id.remote === 'object') { | |
| msg.id = Object.assign({}, msg.id, { | |
| - remote: msg.id.remote._serialized, | |
| + remote: msg.id.remote._serialized || msg.id.remote.$1, | |
| }); | |
| } | |
| + // WhatsApp Web changed _serialized to $1 in message IDs (2026-07 update). | |
| + // Normalize here so all downstream Node.js code can keep using _serialized. | |
| + if (msg.id && msg.id._serialized == null && msg.id.$1 != null) { | |
| + msg.id = Object.assign({}, msg.id, { _serialized: msg.id.$1 }); | |
| + } | |
| + | |
| delete msg.pendingAckUpdate; | |
| return msg; | |
| exports.LoadUtils = () => { | |
| model.isGroup = true; | |
| const chatWid = window | |
| .require('WAWebWidFactory') | |
| - .createWid(chat.id._serialized); | |
| + .createWid(chat.id._serialized || chat.id.$1); | |
| const groupMetadata = | |
| window.require('WAWebCollections').GroupMetadata || | |
| window.require('WAWebCollections').WAWebGroupMetadataCollection; | |
| exports.LoadUtils = () => { | |
| model.lastMessage = null; | |
| if (model.msgs && model.msgs.length) { | |
| - const lastMessage = chat.lastReceivedKey | |
| + const _lastReceivedKeyId = chat.lastReceivedKey | |
| + ? chat.lastReceivedKey._serialized || chat.lastReceivedKey.$1 | |
| + : null; | |
| + const lastMessage = _lastReceivedKeyId | |
| ? window | |
| .require('WAWebCollections') | |
| - .Msg.get(chat.lastReceivedKey._serialized) || | |
| + .Msg.get(_lastReceivedKeyId) || | |
| ( | |
| await window | |
| .require('WAWebCollections') | |
| - .Msg.getMessagesById([ | |
| - chat.lastReceivedKey._serialized, | |
| - ]) | |
| + .Msg.getMessagesById([_lastReceivedKeyId]) | |
| )?.messages?.[0] | |
| : null; | |
| lastMessage && | |
| exports.LoadUtils = () => { | |
| }; | |
| window.WWebJS.rejectCall = async (peerJid, id) => { | |
| - let userId = window | |
| + const _meUser = window | |
| .require('WAWebUserPrefsMeUser') | |
| - .getMaybeMePnUser()._serialized; | |
| + .getMaybeMePnUser(); | |
| + let userId = _meUser._serialized || _meUser.$1; | |
| const stanza = window.require('WAWap').wap( | |
| 'call', | |
| exports.LoadUtils = () => { | |
| .membershipRequestsActionRejectParticipantMixins | |
| ?.value.error; | |
| return { | |
| - requesterId: window | |
| - .require('WAWebWidFactory') | |
| - .createWid(p.jid)._serialized, | |
| + requesterId: (() => { | |
| + const _w = window | |
| + .require('WAWebWidFactory') | |
| + .createWid(p.jid); | |
| + return _w._serialized || _w.$1; | |
| + })(), | |
| ...(error | |
| ? { | |
| error: +error, | |
| exports.LoadUtils = () => { | |
| } | |
| } else { | |
| result.push({ | |
| - requesterId: window | |
| - .require('WAWebJidToWid') | |
| - .userJidToUserWid( | |
| - participant.participantArgs[0].participantJid, | |
| - )._serialized, | |
| + requesterId: (() => { | |
| + const _w = window | |
| + .require('WAWebJidToWid') | |
| + .userJidToUserWid( | |
| + participant.participantArgs[0] | |
| + .participantJid, | |
| + ); | |
| + return _w._serialized || _w.$1; | |
| + })(), | |
| message: 'ServerStatusCodeError', | |
| }); | |
| } | |