Compare commits

..

2 Commits

Author SHA1 Message Date
Renato Alcara 6060293793 fix: jimp detection for thumbnail generation
Fix typeof check: Jimp constructor is 'function' not 'object' in
jimp v1.6+. Without this fix, jpegThumbnail is never generated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:41:54 -03:00
Renato Alcara afce764ce9 Revert "fix: carousel renders on WhatsApp Web without F5"
This reverts commit f2c14f9ad6.
2026-03-07 00:41:38 -03:00
9 changed files with 59 additions and 2118 deletions
+2 -75
View File
@@ -1,7 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package proto; package proto;
/// WhatsApp Version: 2.3000.1035216863 /// WhatsApp Version: 2.3000.1034621774
message ADVDeviceIdentity { message ADVDeviceIdentity {
optional uint32 rawId = 1; optional uint32 rawId = 1;
@@ -345,14 +345,6 @@ message BotAgeCollectionMetadata {
} }
} }
message BotAgentDeepLinkMetadata {
optional string token = 1;
}
message BotAgentMetadata {
optional BotAgentDeepLinkMetadata deepLinkMetadata = 1;
}
message BotCapabilityMetadata { message BotCapabilityMetadata {
repeated BotCapabilityType capabilities = 1; repeated BotCapabilityType capabilities = 1;
enum BotCapabilityType { enum BotCapabilityType {
@@ -415,8 +407,6 @@ message BotCapabilityMetadata {
RICH_RESPONSE_INLINE_LINKS_ENABLED = 56; RICH_RESPONSE_INLINE_LINKS_ENABLED = 56;
RICH_RESPONSE_UR_IMAGINE_VIDEO = 57; RICH_RESPONSE_UR_IMAGINE_VIDEO = 57;
JSON_PATCH_STREAMING = 58; JSON_PATCH_STREAMING = 58;
AI_TAB_FORCE_CLIPPY = 59;
UNIFIED_RESPONSE_EMBEDDED_SCREENS = 60;
} }
} }
@@ -1084,7 +1074,6 @@ message ClientPairingProps {
optional bool isSyncdPureLidSession = 2; optional bool isSyncdPureLidSession = 2;
optional bool isSyncdSnapshotRecoveryEnabled = 3; optional bool isSyncdSnapshotRecoveryEnabled = 3;
optional bool isHsThumbnailSyncEnabled = 4; optional bool isHsThumbnailSyncEnabled = 4;
optional bytes subscriptionSyncPayload = 5;
} }
message ClientPayload { message ClientPayload {
@@ -1465,7 +1454,6 @@ message ContextInfo {
optional AdType adType = 25; optional AdType adType = 25;
optional string wtwaWebsiteUrl = 26; optional string wtwaWebsiteUrl = 26;
optional string adPreviewUrl = 27; optional string adPreviewUrl = 27;
optional bool containsCtwaFlowsAutoReply = 28;
enum AdType { enum AdType {
CTWA = 0; CTWA = 0;
CAWC = 1; CAWC = 1;
@@ -1620,8 +1608,6 @@ message Conversation {
optional bool limitSharingInitiatedByMe = 53; optional bool limitSharingInitiatedByMe = 53;
optional bool maibaAiThreadEnabled = 54; optional bool maibaAiThreadEnabled = 54;
optional bool isMarketingMessageThread = 55; optional bool isMarketingMessageThread = 55;
optional bool isSenderNewAccount = 56;
optional uint32 afterReadDuration = 57;
enum EndOfHistoryTransferType { enum EndOfHistoryTransferType {
COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY = 0; COMPLETE_BUT_MORE_MESSAGES_REMAIN_ON_PRIMARY = 0;
COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY = 1; COMPLETE_AND_NO_MORE_MESSAGE_REMAIN_ON_PRIMARY = 1;
@@ -1649,8 +1635,6 @@ message DeviceCapabilities {
message BusinessBroadcast { message BusinessBroadcast {
optional bool importListEnabled = 1; optional bool importListEnabled = 1;
optional bool companionSupportEnabled = 2; optional bool companionSupportEnabled = 2;
optional bool campaignSyncEnabled = 3;
optional bool insightsSyncEnabled = 4;
} }
enum ChatLockSupportLevel { enum ChatLockSupportLevel {
@@ -1920,8 +1904,6 @@ message HandshakeMessage {
optional bytes static = 1; optional bytes static = 1;
optional bytes payload = 2; optional bytes payload = 2;
optional bytes extendedCiphertext = 3; optional bytes extendedCiphertext = 3;
optional bytes paddedBytes = 4;
optional bool simulateXxkemFs = 5;
} }
message ClientHello { message ClientHello {
@@ -1930,9 +1912,6 @@ message HandshakeMessage {
optional bytes payload = 3; optional bytes payload = 3;
optional bool useExtended = 4; optional bool useExtended = 4;
optional bytes extendedCiphertext = 5; optional bytes extendedCiphertext = 5;
optional bytes paddedBytes = 6;
optional bool sendServerHelloPaddedBytes = 7;
optional bool simulateXxkemFs = 8;
} }
message ServerHello { message ServerHello {
@@ -1940,7 +1919,6 @@ message HandshakeMessage {
optional bytes static = 2; optional bytes static = 2;
optional bytes payload = 3; optional bytes payload = 3;
optional bytes extendedStatic = 4; optional bytes extendedStatic = 4;
optional bytes paddingBytes = 5;
} }
} }
@@ -2297,7 +2275,6 @@ message Message {
optional PollCreationMessage pollCreationMessageV6 = 119; optional PollCreationMessage pollCreationMessageV6 = 119;
optional ConditionalRevealMessage conditionalRevealMessage = 120; optional ConditionalRevealMessage conditionalRevealMessage = 120;
optional PollAddOptionMessage pollAddOptionMessage = 121; optional PollAddOptionMessage pollAddOptionMessage = 121;
optional EventInviteMessage eventInviteMessage = 122;
message AlbumMessage { message AlbumMessage {
optional uint32 expectedImageCount = 2; optional uint32 expectedImageCount = 2;
optional uint32 expectedVideoCount = 3; optional uint32 expectedVideoCount = 3;
@@ -2578,16 +2555,6 @@ message Message {
optional bytes encIv = 3; optional bytes encIv = 3;
} }
message EventInviteMessage {
optional ContextInfo contextInfo = 1;
optional string eventId = 2;
optional string eventTitle = 3;
optional bytes jpegThumbnail = 4;
optional int64 startTime = 5;
optional string caption = 6;
optional bool isCanceled = 7;
}
message EventMessage { message EventMessage {
optional ContextInfo contextInfo = 1; optional ContextInfo contextInfo = 1;
optional bool isCanceled = 2; optional bool isCanceled = 2;
@@ -3114,10 +3081,9 @@ message Message {
message MessageHistoryMetadata { message MessageHistoryMetadata {
repeated string historyReceivers = 1; repeated string historyReceivers = 1;
optional int64 oldestMessageTimestampInWindow = 2; optional int64 oldestMessageTimestamp = 2;
optional int64 messageCount = 3; optional int64 messageCount = 3;
repeated string nonHistoryReceivers = 4; repeated string nonHistoryReceivers = 4;
optional int64 oldestMessageTimestampInBundle = 5;
} }
message MessageHistoryNotice { message MessageHistoryNotice {
@@ -3178,11 +3144,6 @@ message Message {
optional int64 expiryTimestamp = 2; optional int64 expiryTimestamp = 2;
optional bool incentiveEligible = 3; optional bool incentiveEligible = 3;
optional string referralId = 4; optional string referralId = 4;
optional InviteType inviteType = 5;
enum InviteType {
DEFAULT = 0;
MAPPER = 1;
}
enum ServiceType { enum ServiceType {
UNKNOWN = 0; UNKNOWN = 0;
FBPAY = 1; FBPAY = 1;
@@ -3604,7 +3565,6 @@ message Message {
GROUP_MEMBER_LABEL_CHANGE = 30; GROUP_MEMBER_LABEL_CHANGE = 30;
AI_MEDIA_COLLECTION_MESSAGE = 31; AI_MEDIA_COLLECTION_MESSAGE = 31;
MESSAGE_UNSCHEDULE = 32; MESSAGE_UNSCHEDULE = 32;
BOT_UNLINK_MESSAGE = 33;
} }
} }
@@ -3637,7 +3597,6 @@ message Message {
message RequestWelcomeMessageMetadata { message RequestWelcomeMessageMetadata {
optional LocalChatState localChatState = 1; optional LocalChatState localChatState = 1;
optional WelcomeTrigger welcomeTrigger = 2; optional WelcomeTrigger welcomeTrigger = 2;
optional BotAgentMetadata botAgentMetadata = 3;
enum LocalChatState { enum LocalChatState {
EMPTY = 0; EMPTY = 0;
NON_EMPTY = 1; NON_EMPTY = 1;
@@ -4165,8 +4124,6 @@ enum MutationProps {
BUSINESS_BROADCAST_CAMPAIGN_ACTION = 81; BUSINESS_BROADCAST_CAMPAIGN_ACTION = 81;
BUSINESS_BROADCAST_INSIGHTS_ACTION = 82; BUSINESS_BROADCAST_INSIGHTS_ACTION = 82;
CUSTOMER_DATA_ACTION = 83; CUSTOMER_DATA_ACTION = 83;
SUBSCRIPTIONS_SYNC_V2_ACTION = 84;
THREAD_PIN_ACTION = 85;
SHARE_OWN_PN = 10001; SHARE_OWN_PN = 10001;
BUSINESS_BROADCAST_ACTION = 10002; BUSINESS_BROADCAST_ACTION = 10002;
AI_THREAD_DELETE_ACTION = 10003; AI_THREAD_DELETE_ACTION = 10003;
@@ -4635,7 +4592,6 @@ message StatusAttribution {
APPLE_MUSIC = 8; APPLE_MUSIC = 8;
SHARECHAT = 9; SHARECHAT = 9;
GOOGLE_PHOTOS = 10; GOOGLE_PHOTOS = 10;
SOUNDCLOUD = 11;
} }
} }
@@ -4804,8 +4760,6 @@ message SyncActionValue {
optional BusinessBroadcastCampaignAction businessBroadcastCampaignAction = 81; optional BusinessBroadcastCampaignAction businessBroadcastCampaignAction = 81;
optional BusinessBroadcastInsightsAction businessBroadcastInsightsAction = 82; optional BusinessBroadcastInsightsAction businessBroadcastInsightsAction = 82;
optional CustomerDataAction customerDataAction = 83; optional CustomerDataAction customerDataAction = 83;
optional SubscriptionsSyncV2Action subscriptionsSyncV2Action = 84;
optional ThreadPinAction threadPinAction = 85;
message AgentAction { message AgentAction {
optional string name = 1; optional string name = 1;
optional int32 deviceID = 2; optional int32 deviceID = 2;
@@ -5321,29 +5275,6 @@ message SyncActionValue {
optional int64 expirationDate = 3; optional int64 expirationDate = 3;
} }
message SubscriptionsSyncV2Action {
repeated SubscriptionInfo subscriptions = 1;
repeated PaidFeature paidFeature = 2;
message PaidFeature {
optional string name = 1;
optional bool enabled = 2;
optional int32 limit = 3;
optional int64 expirationTime = 4;
}
message SubscriptionInfo {
optional string id = 1;
optional int32 tier = 2;
optional string status = 3;
optional int64 startTime = 4;
optional int64 endTime = 5;
optional bool isPlatformChanged = 6;
optional string source = 7;
optional int64 creationTime = 8;
}
}
message SyncActionMessage { message SyncActionMessage {
optional MessageKey key = 1; optional MessageKey key = 1;
optional int64 timestamp = 2; optional int64 timestamp = 2;
@@ -5355,10 +5286,6 @@ message SyncActionValue {
repeated SyncActionValue.SyncActionMessage messages = 3; repeated SyncActionValue.SyncActionMessage messages = 3;
} }
message ThreadPinAction {
optional bool pinned = 1;
}
message TimeFormatAction { message TimeFormatAction {
optional bool isTwentyFourHourFormatEnabled = 1; optional bool isTwentyFourHourFormatEnabled = 1;
} }
+5 -201
View File
@@ -981,38 +981,6 @@ export namespace proto {
} }
} }
interface IBotAgentDeepLinkMetadata {
token?: (string|null);
}
class BotAgentDeepLinkMetadata implements IBotAgentDeepLinkMetadata {
constructor(p?: proto.IBotAgentDeepLinkMetadata);
public token?: (string|null);
public static create(properties?: proto.IBotAgentDeepLinkMetadata): proto.BotAgentDeepLinkMetadata;
public static encode(m: proto.IBotAgentDeepLinkMetadata, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.BotAgentDeepLinkMetadata;
public static fromObject(d: { [k: string]: any }): proto.BotAgentDeepLinkMetadata;
public static toObject(m: proto.BotAgentDeepLinkMetadata, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
interface IBotAgentMetadata {
deepLinkMetadata?: (proto.IBotAgentDeepLinkMetadata|null);
}
class BotAgentMetadata implements IBotAgentMetadata {
constructor(p?: proto.IBotAgentMetadata);
public deepLinkMetadata?: (proto.IBotAgentDeepLinkMetadata|null);
public static create(properties?: proto.IBotAgentMetadata): proto.BotAgentMetadata;
public static encode(m: proto.IBotAgentMetadata, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.BotAgentMetadata;
public static fromObject(d: { [k: string]: any }): proto.BotAgentMetadata;
public static toObject(m: proto.BotAgentMetadata, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
interface IBotCapabilityMetadata { interface IBotCapabilityMetadata {
capabilities?: (proto.BotCapabilityMetadata.BotCapabilityType[]|null); capabilities?: (proto.BotCapabilityMetadata.BotCapabilityType[]|null);
} }
@@ -1090,9 +1058,7 @@ export namespace proto {
RICH_RESPONSE_UR_BLOKS_ENABLED = 55, RICH_RESPONSE_UR_BLOKS_ENABLED = 55,
RICH_RESPONSE_INLINE_LINKS_ENABLED = 56, RICH_RESPONSE_INLINE_LINKS_ENABLED = 56,
RICH_RESPONSE_UR_IMAGINE_VIDEO = 57, RICH_RESPONSE_UR_IMAGINE_VIDEO = 57,
JSON_PATCH_STREAMING = 58, JSON_PATCH_STREAMING = 58
AI_TAB_FORCE_CLIPPY = 59,
UNIFIED_RESPONSE_EMBEDDED_SCREENS = 60
} }
} }
@@ -2803,7 +2769,6 @@ export namespace proto {
isSyncdPureLidSession?: (boolean|null); isSyncdPureLidSession?: (boolean|null);
isSyncdSnapshotRecoveryEnabled?: (boolean|null); isSyncdSnapshotRecoveryEnabled?: (boolean|null);
isHsThumbnailSyncEnabled?: (boolean|null); isHsThumbnailSyncEnabled?: (boolean|null);
subscriptionSyncPayload?: (Uint8Array|null);
} }
class ClientPairingProps implements IClientPairingProps { class ClientPairingProps implements IClientPairingProps {
@@ -2812,7 +2777,6 @@ export namespace proto {
public isSyncdPureLidSession?: (boolean|null); public isSyncdPureLidSession?: (boolean|null);
public isSyncdSnapshotRecoveryEnabled?: (boolean|null); public isSyncdSnapshotRecoveryEnabled?: (boolean|null);
public isHsThumbnailSyncEnabled?: (boolean|null); public isHsThumbnailSyncEnabled?: (boolean|null);
public subscriptionSyncPayload?: (Uint8Array|null);
public static create(properties?: proto.IClientPairingProps): proto.ClientPairingProps; public static create(properties?: proto.IClientPairingProps): proto.ClientPairingProps;
public static encode(m: proto.IClientPairingProps, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.IClientPairingProps, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.ClientPairingProps; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.ClientPairingProps;
@@ -3590,7 +3554,6 @@ export namespace proto {
adType?: (proto.ContextInfo.ExternalAdReplyInfo.AdType|null); adType?: (proto.ContextInfo.ExternalAdReplyInfo.AdType|null);
wtwaWebsiteUrl?: (string|null); wtwaWebsiteUrl?: (string|null);
adPreviewUrl?: (string|null); adPreviewUrl?: (string|null);
containsCtwaFlowsAutoReply?: (boolean|null);
} }
class ExternalAdReplyInfo implements IExternalAdReplyInfo { class ExternalAdReplyInfo implements IExternalAdReplyInfo {
@@ -3622,7 +3585,6 @@ export namespace proto {
public adType?: (proto.ContextInfo.ExternalAdReplyInfo.AdType|null); public adType?: (proto.ContextInfo.ExternalAdReplyInfo.AdType|null);
public wtwaWebsiteUrl?: (string|null); public wtwaWebsiteUrl?: (string|null);
public adPreviewUrl?: (string|null); public adPreviewUrl?: (string|null);
public containsCtwaFlowsAutoReply?: (boolean|null);
public static create(properties?: proto.ContextInfo.IExternalAdReplyInfo): proto.ContextInfo.ExternalAdReplyInfo; public static create(properties?: proto.ContextInfo.IExternalAdReplyInfo): proto.ContextInfo.ExternalAdReplyInfo;
public static encode(m: proto.ContextInfo.IExternalAdReplyInfo, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.ContextInfo.IExternalAdReplyInfo, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.ContextInfo.ExternalAdReplyInfo; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.ContextInfo.ExternalAdReplyInfo;
@@ -3887,8 +3849,6 @@ export namespace proto {
limitSharingInitiatedByMe?: (boolean|null); limitSharingInitiatedByMe?: (boolean|null);
maibaAiThreadEnabled?: (boolean|null); maibaAiThreadEnabled?: (boolean|null);
isMarketingMessageThread?: (boolean|null); isMarketingMessageThread?: (boolean|null);
isSenderNewAccount?: (boolean|null);
afterReadDuration?: (number|null);
} }
class Conversation implements IConversation { class Conversation implements IConversation {
@@ -3948,8 +3908,6 @@ export namespace proto {
public limitSharingInitiatedByMe?: (boolean|null); public limitSharingInitiatedByMe?: (boolean|null);
public maibaAiThreadEnabled?: (boolean|null); public maibaAiThreadEnabled?: (boolean|null);
public isMarketingMessageThread?: (boolean|null); public isMarketingMessageThread?: (boolean|null);
public isSenderNewAccount?: (boolean|null);
public afterReadDuration?: (number|null);
public static create(properties?: proto.IConversation): proto.Conversation; public static create(properties?: proto.IConversation): proto.Conversation;
public static encode(m: proto.IConversation, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.IConversation, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Conversation; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Conversation;
@@ -4025,16 +3983,12 @@ export namespace proto {
interface IBusinessBroadcast { interface IBusinessBroadcast {
importListEnabled?: (boolean|null); importListEnabled?: (boolean|null);
companionSupportEnabled?: (boolean|null); companionSupportEnabled?: (boolean|null);
campaignSyncEnabled?: (boolean|null);
insightsSyncEnabled?: (boolean|null);
} }
class BusinessBroadcast implements IBusinessBroadcast { class BusinessBroadcast implements IBusinessBroadcast {
constructor(p?: proto.DeviceCapabilities.IBusinessBroadcast); constructor(p?: proto.DeviceCapabilities.IBusinessBroadcast);
public importListEnabled?: (boolean|null); public importListEnabled?: (boolean|null);
public companionSupportEnabled?: (boolean|null); public companionSupportEnabled?: (boolean|null);
public campaignSyncEnabled?: (boolean|null);
public insightsSyncEnabled?: (boolean|null);
public static create(properties?: proto.DeviceCapabilities.IBusinessBroadcast): proto.DeviceCapabilities.BusinessBroadcast; public static create(properties?: proto.DeviceCapabilities.IBusinessBroadcast): proto.DeviceCapabilities.BusinessBroadcast;
public static encode(m: proto.DeviceCapabilities.IBusinessBroadcast, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.DeviceCapabilities.IBusinessBroadcast, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.DeviceCapabilities.BusinessBroadcast; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.DeviceCapabilities.BusinessBroadcast;
@@ -4730,8 +4684,6 @@ export namespace proto {
"static"?: (Uint8Array|null); "static"?: (Uint8Array|null);
payload?: (Uint8Array|null); payload?: (Uint8Array|null);
extendedCiphertext?: (Uint8Array|null); extendedCiphertext?: (Uint8Array|null);
paddedBytes?: (Uint8Array|null);
simulateXxkemFs?: (boolean|null);
} }
class ClientFinish implements IClientFinish { class ClientFinish implements IClientFinish {
@@ -4739,8 +4691,6 @@ export namespace proto {
public static?: (Uint8Array|null); public static?: (Uint8Array|null);
public payload?: (Uint8Array|null); public payload?: (Uint8Array|null);
public extendedCiphertext?: (Uint8Array|null); public extendedCiphertext?: (Uint8Array|null);
public paddedBytes?: (Uint8Array|null);
public simulateXxkemFs?: (boolean|null);
public static create(properties?: proto.HandshakeMessage.IClientFinish): proto.HandshakeMessage.ClientFinish; public static create(properties?: proto.HandshakeMessage.IClientFinish): proto.HandshakeMessage.ClientFinish;
public static encode(m: proto.HandshakeMessage.IClientFinish, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.HandshakeMessage.IClientFinish, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ClientFinish; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ClientFinish;
@@ -4756,9 +4706,6 @@ export namespace proto {
payload?: (Uint8Array|null); payload?: (Uint8Array|null);
useExtended?: (boolean|null); useExtended?: (boolean|null);
extendedCiphertext?: (Uint8Array|null); extendedCiphertext?: (Uint8Array|null);
paddedBytes?: (Uint8Array|null);
sendServerHelloPaddedBytes?: (boolean|null);
simulateXxkemFs?: (boolean|null);
} }
class ClientHello implements IClientHello { class ClientHello implements IClientHello {
@@ -4768,9 +4715,6 @@ export namespace proto {
public payload?: (Uint8Array|null); public payload?: (Uint8Array|null);
public useExtended?: (boolean|null); public useExtended?: (boolean|null);
public extendedCiphertext?: (Uint8Array|null); public extendedCiphertext?: (Uint8Array|null);
public paddedBytes?: (Uint8Array|null);
public sendServerHelloPaddedBytes?: (boolean|null);
public simulateXxkemFs?: (boolean|null);
public static create(properties?: proto.HandshakeMessage.IClientHello): proto.HandshakeMessage.ClientHello; public static create(properties?: proto.HandshakeMessage.IClientHello): proto.HandshakeMessage.ClientHello;
public static encode(m: proto.HandshakeMessage.IClientHello, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.HandshakeMessage.IClientHello, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ClientHello; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ClientHello;
@@ -4785,7 +4729,6 @@ export namespace proto {
"static"?: (Uint8Array|null); "static"?: (Uint8Array|null);
payload?: (Uint8Array|null); payload?: (Uint8Array|null);
extendedStatic?: (Uint8Array|null); extendedStatic?: (Uint8Array|null);
paddingBytes?: (Uint8Array|null);
} }
class ServerHello implements IServerHello { class ServerHello implements IServerHello {
@@ -4794,7 +4737,6 @@ export namespace proto {
public static?: (Uint8Array|null); public static?: (Uint8Array|null);
public payload?: (Uint8Array|null); public payload?: (Uint8Array|null);
public extendedStatic?: (Uint8Array|null); public extendedStatic?: (Uint8Array|null);
public paddingBytes?: (Uint8Array|null);
public static create(properties?: proto.HandshakeMessage.IServerHello): proto.HandshakeMessage.ServerHello; public static create(properties?: proto.HandshakeMessage.IServerHello): proto.HandshakeMessage.ServerHello;
public static encode(m: proto.HandshakeMessage.IServerHello, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.HandshakeMessage.IServerHello, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ServerHello; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.HandshakeMessage.ServerHello;
@@ -5604,7 +5546,6 @@ export namespace proto {
pollCreationMessageV6?: (proto.Message.IPollCreationMessage|null); pollCreationMessageV6?: (proto.Message.IPollCreationMessage|null);
conditionalRevealMessage?: (proto.Message.IConditionalRevealMessage|null); conditionalRevealMessage?: (proto.Message.IConditionalRevealMessage|null);
pollAddOptionMessage?: (proto.Message.IPollAddOptionMessage|null); pollAddOptionMessage?: (proto.Message.IPollAddOptionMessage|null);
eventInviteMessage?: (proto.Message.IEventInviteMessage|null);
} }
class Message implements IMessage { class Message implements IMessage {
@@ -5710,7 +5651,6 @@ export namespace proto {
public pollCreationMessageV6?: (proto.Message.IPollCreationMessage|null); public pollCreationMessageV6?: (proto.Message.IPollCreationMessage|null);
public conditionalRevealMessage?: (proto.Message.IConditionalRevealMessage|null); public conditionalRevealMessage?: (proto.Message.IConditionalRevealMessage|null);
public pollAddOptionMessage?: (proto.Message.IPollAddOptionMessage|null); public pollAddOptionMessage?: (proto.Message.IPollAddOptionMessage|null);
public eventInviteMessage?: (proto.Message.IEventInviteMessage|null);
public static create(properties?: proto.IMessage): proto.Message; public static create(properties?: proto.IMessage): proto.Message;
public static encode(m: proto.IMessage, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.IMessage, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message;
@@ -6514,34 +6454,6 @@ export namespace proto {
public static getTypeUrl(typeUrlPrefix?: string): string; public static getTypeUrl(typeUrlPrefix?: string): string;
} }
interface IEventInviteMessage {
contextInfo?: (proto.IContextInfo|null);
eventId?: (string|null);
eventTitle?: (string|null);
jpegThumbnail?: (Uint8Array|null);
startTime?: (number|Long|null);
caption?: (string|null);
isCanceled?: (boolean|null);
}
class EventInviteMessage implements IEventInviteMessage {
constructor(p?: proto.Message.IEventInviteMessage);
public contextInfo?: (proto.IContextInfo|null);
public eventId?: (string|null);
public eventTitle?: (string|null);
public jpegThumbnail?: (Uint8Array|null);
public startTime?: (number|Long|null);
public caption?: (string|null);
public isCanceled?: (boolean|null);
public static create(properties?: proto.Message.IEventInviteMessage): proto.Message.EventInviteMessage;
public static encode(m: proto.Message.IEventInviteMessage, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.EventInviteMessage;
public static fromObject(d: { [k: string]: any }): proto.Message.EventInviteMessage;
public static toObject(m: proto.Message.EventInviteMessage, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
interface IEventMessage { interface IEventMessage {
contextInfo?: (proto.IContextInfo|null); contextInfo?: (proto.IContextInfo|null);
isCanceled?: (boolean|null); isCanceled?: (boolean|null);
@@ -7906,19 +7818,17 @@ export namespace proto {
interface IMessageHistoryMetadata { interface IMessageHistoryMetadata {
historyReceivers?: (string[]|null); historyReceivers?: (string[]|null);
oldestMessageTimestampInWindow?: (number|Long|null); oldestMessageTimestamp?: (number|Long|null);
messageCount?: (number|Long|null); messageCount?: (number|Long|null);
nonHistoryReceivers?: (string[]|null); nonHistoryReceivers?: (string[]|null);
oldestMessageTimestampInBundle?: (number|Long|null);
} }
class MessageHistoryMetadata implements IMessageHistoryMetadata { class MessageHistoryMetadata implements IMessageHistoryMetadata {
constructor(p?: proto.Message.IMessageHistoryMetadata); constructor(p?: proto.Message.IMessageHistoryMetadata);
public historyReceivers: string[]; public historyReceivers: string[];
public oldestMessageTimestampInWindow?: (number|Long|null); public oldestMessageTimestamp?: (number|Long|null);
public messageCount?: (number|Long|null); public messageCount?: (number|Long|null);
public nonHistoryReceivers: string[]; public nonHistoryReceivers: string[];
public oldestMessageTimestampInBundle?: (number|Long|null);
public static create(properties?: proto.Message.IMessageHistoryMetadata): proto.Message.MessageHistoryMetadata; public static create(properties?: proto.Message.IMessageHistoryMetadata): proto.Message.MessageHistoryMetadata;
public static encode(m: proto.Message.IMessageHistoryMetadata, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.Message.IMessageHistoryMetadata, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.MessageHistoryMetadata; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.MessageHistoryMetadata;
@@ -8076,7 +7986,6 @@ export namespace proto {
expiryTimestamp?: (number|Long|null); expiryTimestamp?: (number|Long|null);
incentiveEligible?: (boolean|null); incentiveEligible?: (boolean|null);
referralId?: (string|null); referralId?: (string|null);
inviteType?: (proto.Message.PaymentInviteMessage.InviteType|null);
} }
class PaymentInviteMessage implements IPaymentInviteMessage { class PaymentInviteMessage implements IPaymentInviteMessage {
@@ -8085,7 +7994,6 @@ export namespace proto {
public expiryTimestamp?: (number|Long|null); public expiryTimestamp?: (number|Long|null);
public incentiveEligible?: (boolean|null); public incentiveEligible?: (boolean|null);
public referralId?: (string|null); public referralId?: (string|null);
public inviteType?: (proto.Message.PaymentInviteMessage.InviteType|null);
public static create(properties?: proto.Message.IPaymentInviteMessage): proto.Message.PaymentInviteMessage; public static create(properties?: proto.Message.IPaymentInviteMessage): proto.Message.PaymentInviteMessage;
public static encode(m: proto.Message.IPaymentInviteMessage, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.Message.IPaymentInviteMessage, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.PaymentInviteMessage; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.PaymentInviteMessage;
@@ -8097,11 +8005,6 @@ export namespace proto {
namespace PaymentInviteMessage { namespace PaymentInviteMessage {
enum InviteType {
DEFAULT = 0,
MAPPER = 1
}
enum ServiceType { enum ServiceType {
UNKNOWN = 0, UNKNOWN = 0,
FBPAY = 1, FBPAY = 1,
@@ -9267,8 +9170,7 @@ export namespace proto {
AI_QUERY_FANOUT = 29, AI_QUERY_FANOUT = 29,
GROUP_MEMBER_LABEL_CHANGE = 30, GROUP_MEMBER_LABEL_CHANGE = 30,
AI_MEDIA_COLLECTION_MESSAGE = 31, AI_MEDIA_COLLECTION_MESSAGE = 31,
MESSAGE_UNSCHEDULE = 32, MESSAGE_UNSCHEDULE = 32
BOT_UNLINK_MESSAGE = 33
} }
} }
@@ -9359,14 +9261,12 @@ export namespace proto {
interface IRequestWelcomeMessageMetadata { interface IRequestWelcomeMessageMetadata {
localChatState?: (proto.Message.RequestWelcomeMessageMetadata.LocalChatState|null); localChatState?: (proto.Message.RequestWelcomeMessageMetadata.LocalChatState|null);
welcomeTrigger?: (proto.Message.RequestWelcomeMessageMetadata.WelcomeTrigger|null); welcomeTrigger?: (proto.Message.RequestWelcomeMessageMetadata.WelcomeTrigger|null);
botAgentMetadata?: (proto.IBotAgentMetadata|null);
} }
class RequestWelcomeMessageMetadata implements IRequestWelcomeMessageMetadata { class RequestWelcomeMessageMetadata implements IRequestWelcomeMessageMetadata {
constructor(p?: proto.Message.IRequestWelcomeMessageMetadata); constructor(p?: proto.Message.IRequestWelcomeMessageMetadata);
public localChatState?: (proto.Message.RequestWelcomeMessageMetadata.LocalChatState|null); public localChatState?: (proto.Message.RequestWelcomeMessageMetadata.LocalChatState|null);
public welcomeTrigger?: (proto.Message.RequestWelcomeMessageMetadata.WelcomeTrigger|null); public welcomeTrigger?: (proto.Message.RequestWelcomeMessageMetadata.WelcomeTrigger|null);
public botAgentMetadata?: (proto.IBotAgentMetadata|null);
public static create(properties?: proto.Message.IRequestWelcomeMessageMetadata): proto.Message.RequestWelcomeMessageMetadata; public static create(properties?: proto.Message.IRequestWelcomeMessageMetadata): proto.Message.RequestWelcomeMessageMetadata;
public static encode(m: proto.Message.IRequestWelcomeMessageMetadata, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.Message.IRequestWelcomeMessageMetadata, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.RequestWelcomeMessageMetadata; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.Message.RequestWelcomeMessageMetadata;
@@ -10562,8 +10462,6 @@ export namespace proto {
BUSINESS_BROADCAST_CAMPAIGN_ACTION = 81, BUSINESS_BROADCAST_CAMPAIGN_ACTION = 81,
BUSINESS_BROADCAST_INSIGHTS_ACTION = 82, BUSINESS_BROADCAST_INSIGHTS_ACTION = 82,
CUSTOMER_DATA_ACTION = 83, CUSTOMER_DATA_ACTION = 83,
SUBSCRIPTIONS_SYNC_V2_ACTION = 84,
THREAD_PIN_ACTION = 85,
SHARE_OWN_PN = 10001, SHARE_OWN_PN = 10001,
BUSINESS_BROADCAST_ACTION = 10002, BUSINESS_BROADCAST_ACTION = 10002,
AI_THREAD_DELETE_ACTION = 10003 AI_THREAD_DELETE_ACTION = 10003
@@ -11847,8 +11745,7 @@ export namespace proto {
THREADS = 7, THREADS = 7,
APPLE_MUSIC = 8, APPLE_MUSIC = 8,
SHARECHAT = 9, SHARECHAT = 9,
GOOGLE_PHOTOS = 10, GOOGLE_PHOTOS = 10
SOUNDCLOUD = 11
} }
} }
@@ -12159,8 +12056,6 @@ export namespace proto {
businessBroadcastCampaignAction?: (proto.SyncActionValue.IBusinessBroadcastCampaignAction|null); businessBroadcastCampaignAction?: (proto.SyncActionValue.IBusinessBroadcastCampaignAction|null);
businessBroadcastInsightsAction?: (proto.SyncActionValue.IBusinessBroadcastInsightsAction|null); businessBroadcastInsightsAction?: (proto.SyncActionValue.IBusinessBroadcastInsightsAction|null);
customerDataAction?: (proto.SyncActionValue.ICustomerDataAction|null); customerDataAction?: (proto.SyncActionValue.ICustomerDataAction|null);
subscriptionsSyncV2Action?: (proto.SyncActionValue.ISubscriptionsSyncV2Action|null);
threadPinAction?: (proto.SyncActionValue.IThreadPinAction|null);
} }
class SyncActionValue implements ISyncActionValue { class SyncActionValue implements ISyncActionValue {
@@ -12239,8 +12134,6 @@ export namespace proto {
public businessBroadcastCampaignAction?: (proto.SyncActionValue.IBusinessBroadcastCampaignAction|null); public businessBroadcastCampaignAction?: (proto.SyncActionValue.IBusinessBroadcastCampaignAction|null);
public businessBroadcastInsightsAction?: (proto.SyncActionValue.IBusinessBroadcastInsightsAction|null); public businessBroadcastInsightsAction?: (proto.SyncActionValue.IBusinessBroadcastInsightsAction|null);
public customerDataAction?: (proto.SyncActionValue.ICustomerDataAction|null); public customerDataAction?: (proto.SyncActionValue.ICustomerDataAction|null);
public subscriptionsSyncV2Action?: (proto.SyncActionValue.ISubscriptionsSyncV2Action|null);
public threadPinAction?: (proto.SyncActionValue.IThreadPinAction|null);
public static create(properties?: proto.ISyncActionValue): proto.SyncActionValue; public static create(properties?: proto.ISyncActionValue): proto.SyncActionValue;
public static encode(m: proto.ISyncActionValue, w?: $protobuf.Writer): $protobuf.Writer; public static encode(m: proto.ISyncActionValue, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue; public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue;
@@ -13773,79 +13666,6 @@ export namespace proto {
public static getTypeUrl(typeUrlPrefix?: string): string; public static getTypeUrl(typeUrlPrefix?: string): string;
} }
interface ISubscriptionsSyncV2Action {
subscriptions?: (proto.SyncActionValue.SubscriptionsSyncV2Action.ISubscriptionInfo[]|null);
paidFeature?: (proto.SyncActionValue.SubscriptionsSyncV2Action.IPaidFeature[]|null);
}
class SubscriptionsSyncV2Action implements ISubscriptionsSyncV2Action {
constructor(p?: proto.SyncActionValue.ISubscriptionsSyncV2Action);
public subscriptions: proto.SyncActionValue.SubscriptionsSyncV2Action.ISubscriptionInfo[];
public paidFeature: proto.SyncActionValue.SubscriptionsSyncV2Action.IPaidFeature[];
public static create(properties?: proto.SyncActionValue.ISubscriptionsSyncV2Action): proto.SyncActionValue.SubscriptionsSyncV2Action;
public static encode(m: proto.SyncActionValue.ISubscriptionsSyncV2Action, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue.SubscriptionsSyncV2Action;
public static fromObject(d: { [k: string]: any }): proto.SyncActionValue.SubscriptionsSyncV2Action;
public static toObject(m: proto.SyncActionValue.SubscriptionsSyncV2Action, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
namespace SubscriptionsSyncV2Action {
interface IPaidFeature {
name?: (string|null);
enabled?: (boolean|null);
limit?: (number|null);
expirationTime?: (number|Long|null);
}
class PaidFeature implements IPaidFeature {
constructor(p?: proto.SyncActionValue.SubscriptionsSyncV2Action.IPaidFeature);
public name?: (string|null);
public enabled?: (boolean|null);
public limit?: (number|null);
public expirationTime?: (number|Long|null);
public static create(properties?: proto.SyncActionValue.SubscriptionsSyncV2Action.IPaidFeature): proto.SyncActionValue.SubscriptionsSyncV2Action.PaidFeature;
public static encode(m: proto.SyncActionValue.SubscriptionsSyncV2Action.IPaidFeature, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue.SubscriptionsSyncV2Action.PaidFeature;
public static fromObject(d: { [k: string]: any }): proto.SyncActionValue.SubscriptionsSyncV2Action.PaidFeature;
public static toObject(m: proto.SyncActionValue.SubscriptionsSyncV2Action.PaidFeature, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
interface ISubscriptionInfo {
id?: (string|null);
tier?: (number|null);
status?: (string|null);
startTime?: (number|Long|null);
endTime?: (number|Long|null);
isPlatformChanged?: (boolean|null);
source?: (string|null);
creationTime?: (number|Long|null);
}
class SubscriptionInfo implements ISubscriptionInfo {
constructor(p?: proto.SyncActionValue.SubscriptionsSyncV2Action.ISubscriptionInfo);
public id?: (string|null);
public tier?: (number|null);
public status?: (string|null);
public startTime?: (number|Long|null);
public endTime?: (number|Long|null);
public isPlatformChanged?: (boolean|null);
public source?: (string|null);
public creationTime?: (number|Long|null);
public static create(properties?: proto.SyncActionValue.SubscriptionsSyncV2Action.ISubscriptionInfo): proto.SyncActionValue.SubscriptionsSyncV2Action.SubscriptionInfo;
public static encode(m: proto.SyncActionValue.SubscriptionsSyncV2Action.ISubscriptionInfo, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue.SubscriptionsSyncV2Action.SubscriptionInfo;
public static fromObject(d: { [k: string]: any }): proto.SyncActionValue.SubscriptionsSyncV2Action.SubscriptionInfo;
public static toObject(m: proto.SyncActionValue.SubscriptionsSyncV2Action.SubscriptionInfo, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
}
interface ISyncActionMessage { interface ISyncActionMessage {
key?: (proto.IMessageKey|null); key?: (proto.IMessageKey|null);
timestamp?: (number|Long|null); timestamp?: (number|Long|null);
@@ -13884,22 +13704,6 @@ export namespace proto {
public static getTypeUrl(typeUrlPrefix?: string): string; public static getTypeUrl(typeUrlPrefix?: string): string;
} }
interface IThreadPinAction {
pinned?: (boolean|null);
}
class ThreadPinAction implements IThreadPinAction {
constructor(p?: proto.SyncActionValue.IThreadPinAction);
public pinned?: (boolean|null);
public static create(properties?: proto.SyncActionValue.IThreadPinAction): proto.SyncActionValue.ThreadPinAction;
public static encode(m: proto.SyncActionValue.IThreadPinAction, w?: $protobuf.Writer): $protobuf.Writer;
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): proto.SyncActionValue.ThreadPinAction;
public static fromObject(d: { [k: string]: any }): proto.SyncActionValue.ThreadPinAction;
public static toObject(m: proto.SyncActionValue.ThreadPinAction, o?: $protobuf.IConversionOptions): { [k: string]: any };
public toJSON(): { [k: string]: any };
public static getTypeUrl(typeUrlPrefix?: string): string;
}
interface ITimeFormatAction { interface ITimeFormatAction {
isTwentyFourHourFormatEnabled?: (boolean|null); isTwentyFourHourFormatEnabled?: (boolean|null);
} }
+19 -1515
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -47,7 +47,7 @@
"fflate": "^0.8.2", "fflate": "^0.8.2",
"libsignal": "github:whiskeysockets/libsignal-node", "libsignal": "github:whiskeysockets/libsignal-node",
"lru-cache": "^11.2.6", "lru-cache": "^11.2.6",
"music-metadata": "^11.12.3", "music-metadata": "^11.12.0",
"p-queue": "^9.0.0", "p-queue": "^9.0.0",
"pino": "^10.3.1", "pino": "^10.3.1",
"prom-client": "^15.1.3", "prom-client": "^15.1.3",
+1 -1
View File
@@ -1 +1 @@
{"version":[2,3000,1035223526]} {"version":[2,3000,1034641024]}
+7 -241
View File
@@ -1,4 +1,3 @@
import { randomBytes } from 'crypto'
import NodeCache from '@cacheable/node-cache' import NodeCache from '@cacheable/node-cache'
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import { proto } from '../../WAProto/index.js' import { proto } from '../../WAProto/index.js'
@@ -46,7 +45,6 @@ import {
getBinaryNodeChildren, getBinaryNodeChildren,
isHostedLidUser, isHostedLidUser,
isHostedPnUser, isHostedPnUser,
isJidBot,
isJidGroup, isJidGroup,
isLidUser, isLidUser,
isPnUser, isPnUser,
@@ -68,8 +66,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
patchMessageBeforeSending, patchMessageBeforeSending,
cachedGroupMetadata, cachedGroupMetadata,
enableRecentMessageCache, enableRecentMessageCache,
maxMsgRetryCount, maxMsgRetryCount
enableInteractiveMessages
} = config } = config
const sock = makeNewsletterSocket(config) const sock = makeNewsletterSocket(config)
const { const {
@@ -603,112 +600,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
return { nodes, shouldIncludeDeviceIdentity } return { nodes, shouldIncludeDeviceIdentity }
} }
/** Detect interactive/button message type for biz node injection */
const getButtonType = (message: proto.IMessage): string | undefined => {
if (message.buttonsMessage) return 'buttons'
if (message.templateMessage) return 'template'
if (message.listMessage) return 'list'
if (message.buttonsResponseMessage) return 'buttons_response'
if (message.listResponseMessage) return 'list_response'
if (message.templateButtonReplyMessage) return 'template_reply'
if (message.interactiveMessage) {
if (message.interactiveMessage.nativeFlowMessage) return 'native_flow'
if (message.interactiveMessage.carouselMessage?.cards?.length) {
const hasNativeFlow = message.interactiveMessage.carouselMessage.cards.some(
(card: proto.Message.IInteractiveMessage) => card?.nativeFlowMessage?.buttons?.length
)
if (hasNativeFlow) return 'native_flow'
}
return 'interactive'
}
const innerMessage = message.viewOnceMessage?.message || message.viewOnceMessageV2?.message
if (innerMessage) {
if (innerMessage.buttonsMessage) return 'buttons'
if (innerMessage.templateMessage) return 'template'
if (innerMessage.listMessage) return 'list'
if (innerMessage.buttonsResponseMessage) return 'buttons_response'
if (innerMessage.listResponseMessage) return 'list_response'
if (innerMessage.templateButtonReplyMessage) return 'template_reply'
if (innerMessage.interactiveMessage) {
if (innerMessage.interactiveMessage.nativeFlowMessage) return 'native_flow'
if (innerMessage.interactiveMessage.carouselMessage?.cards?.length) {
const hasNativeFlow = innerMessage.interactiveMessage.carouselMessage.cards.some(
(card: any) => card?.nativeFlowMessage?.buttons?.length
)
if (hasNativeFlow) return 'native_flow'
}
return 'interactive'
}
}
return undefined
}
/** Check if message is a carousel (media or product carousel) */
const isCarouselMessage = (message: proto.IMessage): boolean => {
const interactiveMsg =
message.interactiveMessage ||
message.viewOnceMessage?.message?.interactiveMessage ||
message.viewOnceMessageV2?.message?.interactiveMessage
return !!(interactiveMsg?.carouselMessage?.cards?.length)
}
/** Check if message is a catalog/product message */
const isCatalogMessage = (message: proto.IMessage): boolean => {
const interactiveMsg =
message.interactiveMessage ||
message.viewOnceMessage?.message?.interactiveMessage ||
message.viewOnceMessageV2?.message?.interactiveMessage
const nativeFlow = interactiveMsg?.nativeFlowMessage
if (nativeFlow?.buttons?.length) {
return nativeFlow.buttons.some(
(btn: any) => btn?.name === 'catalog_message' || btn?.name === 'single_product' || btn?.name === 'product_list'
)
}
return false
}
/** Check if nativeFlowMessage is a list (single_select button) */
const isListNativeFlow = (message: proto.IMessage): boolean => {
const interactiveMsg =
message.interactiveMessage ||
message.viewOnceMessage?.message?.interactiveMessage ||
message.viewOnceMessageV2?.message?.interactiveMessage
const nativeFlow = interactiveMsg?.nativeFlowMessage
if (nativeFlow?.buttons?.length) {
return nativeFlow.buttons.some((btn: any) => btn?.name === 'single_select' || btn?.name === 'multi_select')
}
return false
}
const canonicalizeCarouselRecipients = async (recipientJids: string[]) => {
const uniqueRecipients = [...new Set(recipientJids)]
const pnRecipients = uniqueRecipients.filter(jid => isPnUser(jid) || isHostedPnUser(jid))
const lidMappings = pnRecipients.length > 0
? await signalRepository.lidMapping.getLIDsForPNs(pnRecipients)
: []
const lidByPn = new Map((lidMappings || []).map(({ pn, lid }) => [pn, lid]))
const canonicalRecipients: string[] = []
for (const jid of uniqueRecipients) {
const canonicalJid = lidByPn.get(jid) || jid
if (!canonicalRecipients.includes(canonicalJid)) {
canonicalRecipients.push(canonicalJid)
}
}
if (canonicalRecipients.length !== uniqueRecipients.length || canonicalRecipients.some((jid, index) => jid !== uniqueRecipients[index])) {
logger.debug(
{ before: uniqueRecipients, after: canonicalRecipients },
'[CAROUSEL] Canonicalized recipient addressing for session reuse'
)
}
return canonicalRecipients
}
const relayMessage = async ( const relayMessage = async (
jid: string, jid: string,
message: proto.IMessage, message: proto.IMessage,
@@ -995,30 +886,21 @@ export const makeMessagesSocket = (config: SocketConfig) => {
allRecipients.push(jid) allRecipients.push(jid)
} }
const isCarouselFanout = isCarouselMessage(message) await assertSessions(allRecipients)
const effectiveMeRecipients = isCarouselFanout
? await canonicalizeCarouselRecipients(meRecipients)
: meRecipients
const effectiveOtherRecipients = isCarouselFanout
? await canonicalizeCarouselRecipients(otherRecipients)
: otherRecipients
const effectiveAllRecipients = [...effectiveMeRecipients, ...effectiveOtherRecipients]
await assertSessions(effectiveAllRecipients)
const [ const [
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
{ nodes: otherNodes, shouldIncludeDeviceIdentity: s2 } { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }
] = await Promise.all([ ] = await Promise.all([
// For own devices: use DSM if available (1:1 chats only) // For own devices: use DSM if available (1:1 chats only)
createParticipantNodes(effectiveMeRecipients, meMsg || message, extraAttrs), createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
createParticipantNodes(effectiveOtherRecipients, message, extraAttrs, meMsg) createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
]) ])
participants.push(...meNodes) participants.push(...meNodes)
participants.push(...otherNodes) participants.push(...otherNodes)
if (effectiveMeRecipients.length > 0 || effectiveOtherRecipients.length > 0) { if (meRecipients.length > 0 || otherRecipients.length > 0) {
extraAttrs['phash'] = generateParticipantHashV2([...effectiveMeRecipients, ...effectiveOtherRecipients]) extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients])
} }
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2 shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
@@ -1080,110 +962,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
content: binaryNodeContent content: binaryNodeContent
} }
// Detect interactive message type for biz node injection
const buttonType = getButtonType(message)
const isCatalog = isCatalogMessage(message)
const isCarousel = isCarouselMessage(message)
// Collect biz/bot nodes to append AFTER device-identity and tctoken
// Stanza order: participants → device-identity → tctoken → biz
// Carousel messages must NOT have biz node (breaks WhatsApp Web rendering)
const deferredNodes: BinaryNode[] = []
if (buttonType && enableInteractiveMessages && !isCarousel) {
const interactiveMsg =
message.interactiveMessage ||
message.viewOnceMessage?.message?.interactiveMessage ||
message.viewOnceMessageV2?.message?.interactiveMessage
let nativeFlowButtons = interactiveMsg?.nativeFlowMessage?.buttons || []
if (nativeFlowButtons.length === 0 && interactiveMsg?.carouselMessage?.cards?.length) {
nativeFlowButtons = interactiveMsg.carouselMessage.cards.flatMap(
(card: proto.Message.IInteractiveMessage) => card?.nativeFlowMessage?.buttons || []
)
}
const isListDetected = isListNativeFlow(message)
logger.info(
{ msgId, buttonType, to: destinationJid, isListDetected, isCatalog },
'[Interactive] Preparing biz node'
)
try {
const allButtonNames = nativeFlowButtons.map((b: any) => b?.name).filter(Boolean)
const isNativeFlowButtons = buttonType === 'native_flow'
if (buttonType === 'list') {
deferredNodes.push({
tag: 'biz',
attrs: {},
content: [
{ tag: 'list', attrs: { type: 'product_list', v: '2' } }
]
})
} else {
const SPECIAL_FLOW_NAMES: Record<string, string> = {
review_and_pay: 'payment_info',
payment_info: 'payment_info',
mpm: 'mpm',
review_order: 'order_details'
}
const firstButtonName = allButtonNames[0] || ''
const nativeFlowName = SPECIAL_FLOW_NAMES[firstButtonName] || 'mixed'
deferredNodes.push({
tag: 'biz',
attrs: {},
content: [
{
tag: 'interactive',
attrs: { type: 'native_flow', v: '1' },
content: [
{ tag: 'native_flow', attrs: { v: '9', name: nativeFlowName } }
]
}
]
})
}
// Bot node — skip for native_flow, carousel, catalog
const isPrivateUserChat =
(isPnUser(destinationJid) || isLidUser(destinationJid) || destinationJid?.endsWith('@c.us')) &&
!isJidBot(destinationJid)
if (isPrivateUserChat && !isCatalog && buttonType !== 'list' && !isNativeFlowButtons) {
deferredNodes.push({ tag: 'bot', attrs: { biz_bot: '1' } })
}
} catch (error) {
logger.error({ error, msgId, buttonType }, '[BIZ NODE] Failed to inject biz node')
}
} else if (isCarousel && enableInteractiveMessages) {
// Carousel: inject quality_control with decision_id (required by WhatsApp Web)
const decisionId = randomBytes(20).toString('hex')
deferredNodes.push({
tag: 'biz',
attrs: {},
content: [
{
tag: 'interactive',
attrs: { type: 'native_flow', v: '1' },
content: [
{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }
]
}
]
})
deferredNodes.push({
tag: 'quality_control',
attrs: { decision_id: decisionId },
content: [
{ tag: 'decision_source', attrs: { value: 'df' } }
]
})
logger.info({ msgId, to: destinationJid, decisionId }, '[CAROUSEL] Injected biz + quality_control')
}
// if the participant to send to is explicitly specified (generally retry recp) // if the participant to send to is explicitly specified (generally retry recp)
// ensure the message is only sent to that person // ensure the message is only sent to that person
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
@@ -1201,8 +979,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
stanza.attrs.to = destinationJid stanza.attrs.to = destinationJid
} }
// Force device-identity for carousel (ensures Web can decrypt) if (shouldIncludeDeviceIdentity) {
if (shouldIncludeDeviceIdentity || isCarousel) {
;(stanza.content as BinaryNode[]).push({ ;(stanza.content as BinaryNode[]).push({
tag: 'device-identity', tag: 'device-identity',
attrs: {}, attrs: {},
@@ -1253,12 +1030,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
;(stanza.content as BinaryNode[]).push(...additionalNodes) ;(stanza.content as BinaryNode[]).push(...additionalNodes)
} }
// Append deferred biz/bot/quality_control nodes LAST
// Stanza order: participants → device-identity → tctoken → biz → quality_control
if (deferredNodes.length > 0) {
;(stanza.content as BinaryNode[]).push(...deferredNodes)
}
logger.debug({ msgId }, `sending message to ${participants.length} devices`) logger.debug({ msgId }, `sending message to ${participants.length} devices`)
await sendNode(stanza) await sendNode(stanza)
@@ -1297,11 +1068,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
return 'media' return 'media'
} }
// Carousel with images → media type for Web real-time rendering
if (normalizedMessage.interactiveMessage?.carouselMessage) {
return 'media'
}
return 'text' return 'text'
} }
+1 -48
View File
@@ -41,12 +41,10 @@ import type { ILogger } from './logger'
import { import {
downloadContentFromMessage, downloadContentFromMessage,
encryptedStream, encryptedStream,
extractImageThumb,
generateThumbnail, generateThumbnail,
getAudioDuration, getAudioDuration,
getAudioWaveform, getAudioWaveform,
getRawMediaUploadData, getRawMediaUploadData,
getStream,
type MediaDownloadOptions type MediaDownloadOptions
} from './messages-media' } from './messages-media'
import { shouldIncludeReportingToken } from './reporting-utils' import { shouldIncludeReportingToken } from './reporting-utils'
@@ -475,48 +473,6 @@ export const formatNativeFlowButton = (button: NativeButton): NativeFlowButton =
} }
} }
const recoverCarouselImageMetadata = async (
card: CarouselMessageOptions['cards'][number],
imageMessage: proto.Message.IImageMessage,
mediaOptions: MessageContentGenerationOptions
) => {
if (imageMessage.jpegThumbnail && imageMessage.height && imageMessage.width) {
return
}
try {
const { stream } = await getStream(card.image!, mediaOptions.options)
const thumb = await extractImageThumb(stream)
if (!imageMessage.jpegThumbnail) {
imageMessage.jpegThumbnail = thumb.buffer
}
if (!imageMessage.width && thumb.original.width) {
imageMessage.width = thumb.original.width
}
if (!imageMessage.height && thumb.original.height) {
imageMessage.height = thumb.original.height
}
mediaOptions.logger?.info(
{
cardTitle: card.title,
hasJpegThumbnail: !!imageMessage.jpegThumbnail,
width: imageMessage.width,
height: imageMessage.height
},
'[CAROUSEL] Recovered image thumbnail/dimensions from source media'
)
} catch (error) {
mediaOptions.logger?.warn(
{ cardTitle: card.title, error },
'[CAROUSEL] Failed to recover image thumbnail/dimensions from source media'
)
}
}
/** /**
* Generates a button message using Native Flow format wrapped in viewOnceMessage * Generates a button message using Native Flow format wrapped in viewOnceMessage
* This is the modern approach for button messages that works on iOS and Android * This is the modern approach for button messages that works on iOS and Android
@@ -692,10 +648,7 @@ export const generateCarouselMessage = async (
if (hasMedia && mediaOptions) { if (hasMedia && mediaOptions) {
if (card.image) { if (card.image) {
const { imageMessage } = await prepareWAMessageMedia({ image: card.image }, mediaOptions) const { imageMessage } = await prepareWAMessageMedia({ image: card.image }, mediaOptions)
if (imageMessage) { // Validate image fields needed for WhatsApp rendering
await recoverCarouselImageMetadata(card, imageMessage, mediaOptions)
}
if (imageMessage && !imageMessage.jpegThumbnail) { if (imageMessage && !imageMessage.jpegThumbnail) {
mediaOptions.logger?.warn( mediaOptions.logger?.warn(
{ cardTitle: card.title }, { cardTitle: card.title },
+6 -12
View File
@@ -154,24 +154,18 @@ export async function storeTcTokensFromIqResult({
continue continue
} }
const tokenEntry = { await keys.set({
tctoken: {
[storageJid]: {
...existingEntry, ...existingEntry,
token: Buffer.from(tokenNode.content), token: Buffer.from(tokenNode.content),
timestamp: tokenNode.attrs.t, timestamp: tokenNode.attrs.t,
// Resets real_issue_timestamp to null when storing a new token // WABA Android: resets real_issue_timestamp to null when storing a new token
// (UPDATE wa_trusted_contacts_send SET real_issue_timestamp=null)
realIssueTimestamp: null realIssueTimestamp: null
} }
// Store under resolved storageJid AND under fallbackJid (PN) for reliable lookup
const normalizedFallback = jidNormalizedUser(fallbackJid)
const keysToStore: Record<string, typeof tokenEntry | null> = {
[storageJid]: tokenEntry
} }
if (normalizedFallback !== storageJid) { })
keysToStore[normalizedFallback] = tokenEntry
}
await keys.set({ tctoken: keysToStore })
onNewJidStored?.(storageJid) onNewJidStored?.(storageJid)
} }
} }
+11 -18
View File
@@ -388,13 +388,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@borewit/text-codec@npm:^0.2.2":
version: 0.2.2
resolution: "@borewit/text-codec@npm:0.2.2"
checksum: 10c0/2d3fb132bc6a132914a8fbf8e9ff2fa1ead210ecc395b28bb7355bd7719548a5e351ffe39f21c3bee8048f6cabd99eabd404bb5cc809cad9cba25abed19d271f
languageName: node
linkType: hard
"@cacheable/node-cache@npm:^2.0.1": "@cacheable/node-cache@npm:^2.0.1":
version: 2.0.1 version: 2.0.1
resolution: "@cacheable/node-cache@npm:2.0.1" resolution: "@cacheable/node-cache@npm:2.0.1"
@@ -3112,7 +3105,7 @@ __metadata:
libsignal: "github:whiskeysockets/libsignal-node" libsignal: "github:whiskeysockets/libsignal-node"
link-preview-js: "npm:^4.0.0" link-preview-js: "npm:^4.0.0"
lru-cache: "npm:^11.2.6" lru-cache: "npm:^11.2.6"
music-metadata: "npm:^11.12.3" music-metadata: "npm:^11.12.0"
open: "npm:^11.0.0" open: "npm:^11.0.0"
p-queue: "npm:^9.0.0" p-queue: "npm:^9.0.0"
pino: "npm:^10.3.1" pino: "npm:^10.3.1"
@@ -4563,15 +4556,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"file-type@npm:^21.3.1": "file-type@npm:^21.3.0":
version: 21.3.1 version: 21.3.0
resolution: "file-type@npm:21.3.1" resolution: "file-type@npm:21.3.0"
dependencies: dependencies:
"@tokenizer/inflate": "npm:^0.4.1" "@tokenizer/inflate": "npm:^0.4.1"
strtok3: "npm:^10.3.4" strtok3: "npm:^10.3.4"
token-types: "npm:^6.1.1" token-types: "npm:^6.1.1"
uint8array-extras: "npm:^1.4.0" uint8array-extras: "npm:^1.4.0"
checksum: 10c0/66a8eda781c803c6fc372464abba88cee564cfe30f029716f06909da1564bc51d0a4e8d34654b881dc751cdb0513338b3c0747e06a608cee0dd5c5499b018d47 checksum: 10c0/1b1fa909e6063044a6da1d2ea348ee4d747ed9286382d3f0d4d6532c11fb2ea9f2e7e67b2bc7d745d1bc937e05dee1aa8cb912c64250933bcb393a3744f4e284
languageName: node languageName: node
linkType: hard linkType: hard
@@ -6511,21 +6504,21 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"music-metadata@npm:^11.12.3": "music-metadata@npm:^11.12.0":
version: 11.12.3 version: 11.12.0
resolution: "music-metadata@npm:11.12.3" resolution: "music-metadata@npm:11.12.0"
dependencies: dependencies:
"@borewit/text-codec": "npm:^0.2.2" "@borewit/text-codec": "npm:^0.2.1"
"@tokenizer/token": "npm:^0.3.0" "@tokenizer/token": "npm:^0.3.0"
content-type: "npm:^1.0.5" content-type: "npm:^1.0.5"
debug: "npm:^4.4.3" debug: "npm:^4.4.3"
file-type: "npm:^21.3.1" file-type: "npm:^21.3.0"
media-typer: "npm:^1.1.0" media-typer: "npm:^1.1.0"
strtok3: "npm:^10.3.4" strtok3: "npm:^10.3.4"
token-types: "npm:^6.1.2" token-types: "npm:^6.1.2"
uint8array-extras: "npm:^1.5.0" uint8array-extras: "npm:^1.5.0"
win-guid: "npm:^0.2.1" win-guid: "npm:^0.2.1"
checksum: 10c0/57df905f51ec792e5b4c994645eab64d47d5608b9de11151f54b26fbd5f563598ec04d8aed7f244ef1479030d78ddab8af1ee84dfcee40a93b3241941b50999d checksum: 10c0/014a120b8941ab80452171def0ec3cba013041ba4b94f8061ad493a037d3423e6d316131a13fb0433404685ebd3c8e3ae2255c1bafaeb20673fcd73af2df0148
languageName: node languageName: node
linkType: hard linkType: hard