Compare commits

...

13 Commits

Author SHA1 Message Date
Renato Alcara e152aee740 Fix/pn lid session reuse (#294)
* fix: unify PN and LID session reuse for 1:1 sends

* fix: limit PN/LID reuse changes to session cache
2026-03-16 23:22:05 -03:00
Renato Alcara ff9b84c561 fix: unify PN and LID session reuse for 1:1 sends (#293)
fix: unify PN and LID session reuse for 1:1 sends (#293)
2026-03-16 22:59:28 -03:00
Renato Alcara 50c13398c4 fix: harden carousel live rendering path (#292)
* fix: harden carousel live rendering path

* fix: flatten carousel thumbnail fallback
2026-03-16 22:09:14 -03:00
Renato Alcara d991d0212d fix: add biz node injection and quality_control for carousel WhatsApp Web rendering (#291)
- Add interactive message detection helpers (getButtonType, isCarouselMessage, etc.)
- Inject biz node with interactive/native_flow for non-carousel interactive messages
- Inject biz + quality_control with decision_id for carousel messages
- Skip bot node for native_flow/carousel/catalog (breaks Web rendering)
- Force device-identity inclusion for carousel messages
- Append deferred biz/bot/quality_control nodes after device-identity and tctoken
- Store tctoken under both LID and PN for reliable lookup
2026-03-16 21:25:29 -03:00
Renato Alcara 7c095c84a5 chore: update WhatsApp Web version to v2.3000.1035223526 (#289)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-16 06:20:34 -03:00
github-actions[bot] a25e6740fd chore: update proto/version to v2.3000.1035216863 (#288)
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
2026-03-16 00:58:19 -03:00
Renato Alcara 986ac588a9 chore: update WhatsApp Web version to v2.3000.1035203283 (#287)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-15 06:08:25 -03:00
github-actions[bot] 64c73faab2 chore: update proto/version to v2.3000.1035198198 (#286)
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
2026-03-15 00:56:35 -03:00
Renato Alcara b5464bec73 chore: update WhatsApp Web version to v2.3000.1035176028 (#285)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-14 06:07:31 -03:00
github-actions[bot] 9f8f74fc7a chore: update proto/version to v2.3000.1035169204 (#284)
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
2026-03-14 00:44:33 -03:00
Renato Alcara aaf3bd83eb chore: update WhatsApp Web version to v2.3000.1035102652 (#283)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-13 06:11:31 -03:00
github-actions[bot] 8fe71b03d5 chore: update proto/version to v2.3000.1035083696 (#282)
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
2026-03-13 00:45:20 -03:00
Renato Alcara c2c156d707 chore(deps): update music-metadata from 11.12.0 to 11.12.3 (#281)
Includes security fix for CWE-85 (infinite loop in ASF parsing),
Ogg/Vorbis duration fix, and restored TypeScript declaration files.
2026-03-12 23:52:05 -03:00
9 changed files with 809 additions and 37 deletions
+26 -1
View File
@@ -1,7 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package proto; package proto;
/// WhatsApp Version: 2.3000.1034989030 /// WhatsApp Version: 2.3000.1035216863
message ADVDeviceIdentity { message ADVDeviceIdentity {
optional uint32 rawId = 1; optional uint32 rawId = 1;
@@ -415,6 +415,8 @@ 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;
} }
} }
@@ -1082,6 +1084,7 @@ 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 {
@@ -1462,6 +1465,7 @@ 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;
@@ -1616,6 +1620,8 @@ 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;
@@ -1914,6 +1920,8 @@ 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 {
@@ -1922,6 +1930,9 @@ 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 {
@@ -1929,6 +1940,7 @@ 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;
} }
} }
@@ -3166,6 +3178,11 @@ 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;
@@ -3587,6 +3604,7 @@ 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;
} }
} }
@@ -4148,6 +4166,7 @@ enum MutationProps {
BUSINESS_BROADCAST_INSIGHTS_ACTION = 82; BUSINESS_BROADCAST_INSIGHTS_ACTION = 82;
CUSTOMER_DATA_ACTION = 83; CUSTOMER_DATA_ACTION = 83;
SUBSCRIPTIONS_SYNC_V2_ACTION = 84; 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;
@@ -4616,6 +4635,7 @@ message StatusAttribution {
APPLE_MUSIC = 8; APPLE_MUSIC = 8;
SHARECHAT = 9; SHARECHAT = 9;
GOOGLE_PHOTOS = 10; GOOGLE_PHOTOS = 10;
SOUNDCLOUD = 11;
} }
} }
@@ -4785,6 +4805,7 @@ message SyncActionValue {
optional BusinessBroadcastInsightsAction businessBroadcastInsightsAction = 82; optional BusinessBroadcastInsightsAction businessBroadcastInsightsAction = 82;
optional CustomerDataAction customerDataAction = 83; optional CustomerDataAction customerDataAction = 83;
optional SubscriptionsSyncV2Action subscriptionsSyncV2Action = 84; 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;
@@ -5334,6 +5355,10 @@ 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;
} }
+53 -3
View File
@@ -1090,7 +1090,9 @@ 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
} }
} }
@@ -2801,6 +2803,7 @@ 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 {
@@ -2809,6 +2812,7 @@ 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;
@@ -3586,6 +3590,7 @@ 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 {
@@ -3617,6 +3622,7 @@ 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;
@@ -3881,6 +3887,8 @@ 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 {
@@ -3940,6 +3948,8 @@ 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;
@@ -4720,6 +4730,8 @@ 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 {
@@ -4727,6 +4739,8 @@ 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;
@@ -4742,6 +4756,9 @@ 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 {
@@ -4751,6 +4768,9 @@ 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;
@@ -4765,6 +4785,7 @@ 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 {
@@ -4773,6 +4794,7 @@ 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;
@@ -8054,6 +8076,7 @@ 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 {
@@ -8062,6 +8085,7 @@ 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;
@@ -8073,6 +8097,11 @@ 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,
@@ -9238,7 +9267,8 @@ 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
} }
} }
@@ -10533,6 +10563,7 @@ export namespace proto {
BUSINESS_BROADCAST_INSIGHTS_ACTION = 82, BUSINESS_BROADCAST_INSIGHTS_ACTION = 82,
CUSTOMER_DATA_ACTION = 83, CUSTOMER_DATA_ACTION = 83,
SUBSCRIPTIONS_SYNC_V2_ACTION = 84, 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
@@ -11816,7 +11847,8 @@ 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
} }
} }
@@ -12128,6 +12160,7 @@ export namespace proto {
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); subscriptionsSyncV2Action?: (proto.SyncActionValue.ISubscriptionsSyncV2Action|null);
threadPinAction?: (proto.SyncActionValue.IThreadPinAction|null);
} }
class SyncActionValue implements ISyncActionValue { class SyncActionValue implements ISyncActionValue {
@@ -12207,6 +12240,7 @@ export namespace proto {
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 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;
@@ -13850,6 +13884,22 @@ 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);
} }
+395
View File
@@ -6889,6 +6889,14 @@ export const proto = $root.proto = (() => {
case 58: case 58:
m.capabilities[i] = 58; m.capabilities[i] = 58;
break; break;
case "AI_TAB_FORCE_CLIPPY":
case 59:
m.capabilities[i] = 59;
break;
case "UNIFIED_RESPONSE_EMBEDDED_SCREENS":
case 60:
m.capabilities[i] = 60;
break;
} }
} }
} }
@@ -6983,6 +6991,8 @@ export const proto = $root.proto = (() => {
values[valuesById[56] = "RICH_RESPONSE_INLINE_LINKS_ENABLED"] = 56; values[valuesById[56] = "RICH_RESPONSE_INLINE_LINKS_ENABLED"] = 56;
values[valuesById[57] = "RICH_RESPONSE_UR_IMAGINE_VIDEO"] = 57; values[valuesById[57] = "RICH_RESPONSE_UR_IMAGINE_VIDEO"] = 57;
values[valuesById[58] = "JSON_PATCH_STREAMING"] = 58; values[valuesById[58] = "JSON_PATCH_STREAMING"] = 58;
values[valuesById[59] = "AI_TAB_FORCE_CLIPPY"] = 59;
values[valuesById[60] = "UNIFIED_RESPONSE_EMBEDDED_SCREENS"] = 60;
return values; return values;
})(); })();
@@ -18028,6 +18038,7 @@ export const proto = $root.proto = (() => {
ClientPairingProps.prototype.isSyncdPureLidSession = null; ClientPairingProps.prototype.isSyncdPureLidSession = null;
ClientPairingProps.prototype.isSyncdSnapshotRecoveryEnabled = null; ClientPairingProps.prototype.isSyncdSnapshotRecoveryEnabled = null;
ClientPairingProps.prototype.isHsThumbnailSyncEnabled = null; ClientPairingProps.prototype.isHsThumbnailSyncEnabled = null;
ClientPairingProps.prototype.subscriptionSyncPayload = null;
let $oneOfFields; let $oneOfFields;
@@ -18055,6 +18066,12 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientPairingProps.prototype, "_subscriptionSyncPayload", {
get: $util.oneOfGetter($oneOfFields = ["subscriptionSyncPayload"]),
set: $util.oneOfSetter($oneOfFields)
});
ClientPairingProps.create = function create(properties) { ClientPairingProps.create = function create(properties) {
return new ClientPairingProps(properties); return new ClientPairingProps(properties);
}; };
@@ -18070,6 +18087,8 @@ export const proto = $root.proto = (() => {
w.uint32(24).bool(m.isSyncdSnapshotRecoveryEnabled); w.uint32(24).bool(m.isSyncdSnapshotRecoveryEnabled);
if (m.isHsThumbnailSyncEnabled != null && Object.hasOwnProperty.call(m, "isHsThumbnailSyncEnabled")) if (m.isHsThumbnailSyncEnabled != null && Object.hasOwnProperty.call(m, "isHsThumbnailSyncEnabled"))
w.uint32(32).bool(m.isHsThumbnailSyncEnabled); w.uint32(32).bool(m.isHsThumbnailSyncEnabled);
if (m.subscriptionSyncPayload != null && Object.hasOwnProperty.call(m, "subscriptionSyncPayload"))
w.uint32(42).bytes(m.subscriptionSyncPayload);
return w; return w;
}; };
@@ -18098,6 +18117,10 @@ export const proto = $root.proto = (() => {
m.isHsThumbnailSyncEnabled = r.bool(); m.isHsThumbnailSyncEnabled = r.bool();
break; break;
} }
case 5: {
m.subscriptionSyncPayload = r.bytes();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -18122,6 +18145,12 @@ export const proto = $root.proto = (() => {
if (d.isHsThumbnailSyncEnabled != null) { if (d.isHsThumbnailSyncEnabled != null) {
m.isHsThumbnailSyncEnabled = Boolean(d.isHsThumbnailSyncEnabled); m.isHsThumbnailSyncEnabled = Boolean(d.isHsThumbnailSyncEnabled);
} }
if (d.subscriptionSyncPayload != null) {
if (typeof d.subscriptionSyncPayload === "string")
$util.base64.decode(d.subscriptionSyncPayload, m.subscriptionSyncPayload = $util.newBuffer($util.base64.length(d.subscriptionSyncPayload)), 0);
else if (d.subscriptionSyncPayload.length >= 0)
m.subscriptionSyncPayload = d.subscriptionSyncPayload;
}
return m; return m;
}; };
@@ -18149,6 +18178,11 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._isHsThumbnailSyncEnabled = "isHsThumbnailSyncEnabled"; d._isHsThumbnailSyncEnabled = "isHsThumbnailSyncEnabled";
} }
if (m.subscriptionSyncPayload != null && m.hasOwnProperty("subscriptionSyncPayload")) {
d.subscriptionSyncPayload = o.bytes === String ? $util.base64.encode(m.subscriptionSyncPayload, 0, m.subscriptionSyncPayload.length) : o.bytes === Array ? Array.prototype.slice.call(m.subscriptionSyncPayload) : m.subscriptionSyncPayload;
if (o.oneofs)
d._subscriptionSyncPayload = "subscriptionSyncPayload";
}
return d; return d;
}; };
@@ -23966,6 +24000,7 @@ export const proto = $root.proto = (() => {
ExternalAdReplyInfo.prototype.adType = null; ExternalAdReplyInfo.prototype.adType = null;
ExternalAdReplyInfo.prototype.wtwaWebsiteUrl = null; ExternalAdReplyInfo.prototype.wtwaWebsiteUrl = null;
ExternalAdReplyInfo.prototype.adPreviewUrl = null; ExternalAdReplyInfo.prototype.adPreviewUrl = null;
ExternalAdReplyInfo.prototype.containsCtwaFlowsAutoReply = null;
let $oneOfFields; let $oneOfFields;
@@ -24131,6 +24166,12 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(ExternalAdReplyInfo.prototype, "_containsCtwaFlowsAutoReply", {
get: $util.oneOfGetter($oneOfFields = ["containsCtwaFlowsAutoReply"]),
set: $util.oneOfSetter($oneOfFields)
});
ExternalAdReplyInfo.create = function create(properties) { ExternalAdReplyInfo.create = function create(properties) {
return new ExternalAdReplyInfo(properties); return new ExternalAdReplyInfo(properties);
}; };
@@ -24192,6 +24233,8 @@ export const proto = $root.proto = (() => {
w.uint32(210).string(m.wtwaWebsiteUrl); w.uint32(210).string(m.wtwaWebsiteUrl);
if (m.adPreviewUrl != null && Object.hasOwnProperty.call(m, "adPreviewUrl")) if (m.adPreviewUrl != null && Object.hasOwnProperty.call(m, "adPreviewUrl"))
w.uint32(218).string(m.adPreviewUrl); w.uint32(218).string(m.adPreviewUrl);
if (m.containsCtwaFlowsAutoReply != null && Object.hasOwnProperty.call(m, "containsCtwaFlowsAutoReply"))
w.uint32(224).bool(m.containsCtwaFlowsAutoReply);
return w; return w;
}; };
@@ -24312,6 +24355,10 @@ export const proto = $root.proto = (() => {
m.adPreviewUrl = r.string(); m.adPreviewUrl = r.string();
break; break;
} }
case 28: {
m.containsCtwaFlowsAutoReply = r.bool();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -24438,6 +24485,9 @@ export const proto = $root.proto = (() => {
if (d.adPreviewUrl != null) { if (d.adPreviewUrl != null) {
m.adPreviewUrl = String(d.adPreviewUrl); m.adPreviewUrl = String(d.adPreviewUrl);
} }
if (d.containsCtwaFlowsAutoReply != null) {
m.containsCtwaFlowsAutoReply = Boolean(d.containsCtwaFlowsAutoReply);
}
return m; return m;
}; };
@@ -24580,6 +24630,11 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._adPreviewUrl = "adPreviewUrl"; d._adPreviewUrl = "adPreviewUrl";
} }
if (m.containsCtwaFlowsAutoReply != null && m.hasOwnProperty("containsCtwaFlowsAutoReply")) {
d.containsCtwaFlowsAutoReply = m.containsCtwaFlowsAutoReply;
if (o.oneofs)
d._containsCtwaFlowsAutoReply = "containsCtwaFlowsAutoReply";
}
return d; return d;
}; };
@@ -25605,6 +25660,8 @@ export const proto = $root.proto = (() => {
Conversation.prototype.limitSharingInitiatedByMe = null; Conversation.prototype.limitSharingInitiatedByMe = null;
Conversation.prototype.maibaAiThreadEnabled = null; Conversation.prototype.maibaAiThreadEnabled = null;
Conversation.prototype.isMarketingMessageThread = null; Conversation.prototype.isMarketingMessageThread = null;
Conversation.prototype.isSenderNewAccount = null;
Conversation.prototype.afterReadDuration = null;
let $oneOfFields; let $oneOfFields;
@@ -25926,6 +25983,18 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(Conversation.prototype, "_isSenderNewAccount", {
get: $util.oneOfGetter($oneOfFields = ["isSenderNewAccount"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(Conversation.prototype, "_afterReadDuration", {
get: $util.oneOfGetter($oneOfFields = ["afterReadDuration"]),
set: $util.oneOfSetter($oneOfFields)
});
Conversation.create = function create(properties) { Conversation.create = function create(properties) {
return new Conversation(properties); return new Conversation(properties);
}; };
@@ -26047,6 +26116,10 @@ export const proto = $root.proto = (() => {
w.uint32(432).bool(m.maibaAiThreadEnabled); w.uint32(432).bool(m.maibaAiThreadEnabled);
if (m.isMarketingMessageThread != null && Object.hasOwnProperty.call(m, "isMarketingMessageThread")) if (m.isMarketingMessageThread != null && Object.hasOwnProperty.call(m, "isMarketingMessageThread"))
w.uint32(440).bool(m.isMarketingMessageThread); w.uint32(440).bool(m.isMarketingMessageThread);
if (m.isSenderNewAccount != null && Object.hasOwnProperty.call(m, "isSenderNewAccount"))
w.uint32(448).bool(m.isSenderNewAccount);
if (m.afterReadDuration != null && Object.hasOwnProperty.call(m, "afterReadDuration"))
w.uint32(456).uint32(m.afterReadDuration);
return w; return w;
}; };
@@ -26283,6 +26356,14 @@ export const proto = $root.proto = (() => {
m.isMarketingMessageThread = r.bool(); m.isMarketingMessageThread = r.bool();
break; break;
} }
case 56: {
m.isSenderNewAccount = r.bool();
break;
}
case 57: {
m.afterReadDuration = r.uint32();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -26620,6 +26701,12 @@ export const proto = $root.proto = (() => {
if (d.isMarketingMessageThread != null) { if (d.isMarketingMessageThread != null) {
m.isMarketingMessageThread = Boolean(d.isMarketingMessageThread); m.isMarketingMessageThread = Boolean(d.isMarketingMessageThread);
} }
if (d.isSenderNewAccount != null) {
m.isSenderNewAccount = Boolean(d.isSenderNewAccount);
}
if (d.afterReadDuration != null) {
m.afterReadDuration = d.afterReadDuration >>> 0;
}
return m; return m;
}; };
@@ -26932,6 +27019,16 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._isMarketingMessageThread = "isMarketingMessageThread"; d._isMarketingMessageThread = "isMarketingMessageThread";
} }
if (m.isSenderNewAccount != null && m.hasOwnProperty("isSenderNewAccount")) {
d.isSenderNewAccount = m.isSenderNewAccount;
if (o.oneofs)
d._isSenderNewAccount = "isSenderNewAccount";
}
if (m.afterReadDuration != null && m.hasOwnProperty("afterReadDuration")) {
d.afterReadDuration = m.afterReadDuration;
if (o.oneofs)
d._afterReadDuration = "afterReadDuration";
}
return d; return d;
}; };
@@ -32299,6 +32396,8 @@ export const proto = $root.proto = (() => {
ClientFinish.prototype["static"] = null; ClientFinish.prototype["static"] = null;
ClientFinish.prototype.payload = null; ClientFinish.prototype.payload = null;
ClientFinish.prototype.extendedCiphertext = null; ClientFinish.prototype.extendedCiphertext = null;
ClientFinish.prototype.paddedBytes = null;
ClientFinish.prototype.simulateXxkemFs = null;
let $oneOfFields; let $oneOfFields;
@@ -32320,6 +32419,18 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientFinish.prototype, "_paddedBytes", {
get: $util.oneOfGetter($oneOfFields = ["paddedBytes"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientFinish.prototype, "_simulateXxkemFs", {
get: $util.oneOfGetter($oneOfFields = ["simulateXxkemFs"]),
set: $util.oneOfSetter($oneOfFields)
});
ClientFinish.create = function create(properties) { ClientFinish.create = function create(properties) {
return new ClientFinish(properties); return new ClientFinish(properties);
}; };
@@ -32333,6 +32444,10 @@ export const proto = $root.proto = (() => {
w.uint32(18).bytes(m.payload); w.uint32(18).bytes(m.payload);
if (m.extendedCiphertext != null && Object.hasOwnProperty.call(m, "extendedCiphertext")) if (m.extendedCiphertext != null && Object.hasOwnProperty.call(m, "extendedCiphertext"))
w.uint32(26).bytes(m.extendedCiphertext); w.uint32(26).bytes(m.extendedCiphertext);
if (m.paddedBytes != null && Object.hasOwnProperty.call(m, "paddedBytes"))
w.uint32(34).bytes(m.paddedBytes);
if (m.simulateXxkemFs != null && Object.hasOwnProperty.call(m, "simulateXxkemFs"))
w.uint32(40).bool(m.simulateXxkemFs);
return w; return w;
}; };
@@ -32357,6 +32472,14 @@ export const proto = $root.proto = (() => {
m.extendedCiphertext = r.bytes(); m.extendedCiphertext = r.bytes();
break; break;
} }
case 4: {
m.paddedBytes = r.bytes();
break;
}
case 5: {
m.simulateXxkemFs = r.bool();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -32387,6 +32510,15 @@ export const proto = $root.proto = (() => {
else if (d.extendedCiphertext.length >= 0) else if (d.extendedCiphertext.length >= 0)
m.extendedCiphertext = d.extendedCiphertext; m.extendedCiphertext = d.extendedCiphertext;
} }
if (d.paddedBytes != null) {
if (typeof d.paddedBytes === "string")
$util.base64.decode(d.paddedBytes, m.paddedBytes = $util.newBuffer($util.base64.length(d.paddedBytes)), 0);
else if (d.paddedBytes.length >= 0)
m.paddedBytes = d.paddedBytes;
}
if (d.simulateXxkemFs != null) {
m.simulateXxkemFs = Boolean(d.simulateXxkemFs);
}
return m; return m;
}; };
@@ -32409,6 +32541,16 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._extendedCiphertext = "extendedCiphertext"; d._extendedCiphertext = "extendedCiphertext";
} }
if (m.paddedBytes != null && m.hasOwnProperty("paddedBytes")) {
d.paddedBytes = o.bytes === String ? $util.base64.encode(m.paddedBytes, 0, m.paddedBytes.length) : o.bytes === Array ? Array.prototype.slice.call(m.paddedBytes) : m.paddedBytes;
if (o.oneofs)
d._paddedBytes = "paddedBytes";
}
if (m.simulateXxkemFs != null && m.hasOwnProperty("simulateXxkemFs")) {
d.simulateXxkemFs = m.simulateXxkemFs;
if (o.oneofs)
d._simulateXxkemFs = "simulateXxkemFs";
}
return d; return d;
}; };
@@ -32440,6 +32582,9 @@ export const proto = $root.proto = (() => {
ClientHello.prototype.payload = null; ClientHello.prototype.payload = null;
ClientHello.prototype.useExtended = null; ClientHello.prototype.useExtended = null;
ClientHello.prototype.extendedCiphertext = null; ClientHello.prototype.extendedCiphertext = null;
ClientHello.prototype.paddedBytes = null;
ClientHello.prototype.sendServerHelloPaddedBytes = null;
ClientHello.prototype.simulateXxkemFs = null;
let $oneOfFields; let $oneOfFields;
@@ -32473,6 +32618,24 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientHello.prototype, "_paddedBytes", {
get: $util.oneOfGetter($oneOfFields = ["paddedBytes"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientHello.prototype, "_sendServerHelloPaddedBytes", {
get: $util.oneOfGetter($oneOfFields = ["sendServerHelloPaddedBytes"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(ClientHello.prototype, "_simulateXxkemFs", {
get: $util.oneOfGetter($oneOfFields = ["simulateXxkemFs"]),
set: $util.oneOfSetter($oneOfFields)
});
ClientHello.create = function create(properties) { ClientHello.create = function create(properties) {
return new ClientHello(properties); return new ClientHello(properties);
}; };
@@ -32490,6 +32653,12 @@ export const proto = $root.proto = (() => {
w.uint32(32).bool(m.useExtended); w.uint32(32).bool(m.useExtended);
if (m.extendedCiphertext != null && Object.hasOwnProperty.call(m, "extendedCiphertext")) if (m.extendedCiphertext != null && Object.hasOwnProperty.call(m, "extendedCiphertext"))
w.uint32(42).bytes(m.extendedCiphertext); w.uint32(42).bytes(m.extendedCiphertext);
if (m.paddedBytes != null && Object.hasOwnProperty.call(m, "paddedBytes"))
w.uint32(50).bytes(m.paddedBytes);
if (m.sendServerHelloPaddedBytes != null && Object.hasOwnProperty.call(m, "sendServerHelloPaddedBytes"))
w.uint32(56).bool(m.sendServerHelloPaddedBytes);
if (m.simulateXxkemFs != null && Object.hasOwnProperty.call(m, "simulateXxkemFs"))
w.uint32(64).bool(m.simulateXxkemFs);
return w; return w;
}; };
@@ -32522,6 +32691,18 @@ export const proto = $root.proto = (() => {
m.extendedCiphertext = r.bytes(); m.extendedCiphertext = r.bytes();
break; break;
} }
case 6: {
m.paddedBytes = r.bytes();
break;
}
case 7: {
m.sendServerHelloPaddedBytes = r.bool();
break;
}
case 8: {
m.simulateXxkemFs = r.bool();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -32561,6 +32742,18 @@ export const proto = $root.proto = (() => {
else if (d.extendedCiphertext.length >= 0) else if (d.extendedCiphertext.length >= 0)
m.extendedCiphertext = d.extendedCiphertext; m.extendedCiphertext = d.extendedCiphertext;
} }
if (d.paddedBytes != null) {
if (typeof d.paddedBytes === "string")
$util.base64.decode(d.paddedBytes, m.paddedBytes = $util.newBuffer($util.base64.length(d.paddedBytes)), 0);
else if (d.paddedBytes.length >= 0)
m.paddedBytes = d.paddedBytes;
}
if (d.sendServerHelloPaddedBytes != null) {
m.sendServerHelloPaddedBytes = Boolean(d.sendServerHelloPaddedBytes);
}
if (d.simulateXxkemFs != null) {
m.simulateXxkemFs = Boolean(d.simulateXxkemFs);
}
return m; return m;
}; };
@@ -32593,6 +32786,21 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._extendedCiphertext = "extendedCiphertext"; d._extendedCiphertext = "extendedCiphertext";
} }
if (m.paddedBytes != null && m.hasOwnProperty("paddedBytes")) {
d.paddedBytes = o.bytes === String ? $util.base64.encode(m.paddedBytes, 0, m.paddedBytes.length) : o.bytes === Array ? Array.prototype.slice.call(m.paddedBytes) : m.paddedBytes;
if (o.oneofs)
d._paddedBytes = "paddedBytes";
}
if (m.sendServerHelloPaddedBytes != null && m.hasOwnProperty("sendServerHelloPaddedBytes")) {
d.sendServerHelloPaddedBytes = m.sendServerHelloPaddedBytes;
if (o.oneofs)
d._sendServerHelloPaddedBytes = "sendServerHelloPaddedBytes";
}
if (m.simulateXxkemFs != null && m.hasOwnProperty("simulateXxkemFs")) {
d.simulateXxkemFs = m.simulateXxkemFs;
if (o.oneofs)
d._simulateXxkemFs = "simulateXxkemFs";
}
return d; return d;
}; };
@@ -32623,6 +32831,7 @@ export const proto = $root.proto = (() => {
ServerHello.prototype["static"] = null; ServerHello.prototype["static"] = null;
ServerHello.prototype.payload = null; ServerHello.prototype.payload = null;
ServerHello.prototype.extendedStatic = null; ServerHello.prototype.extendedStatic = null;
ServerHello.prototype.paddingBytes = null;
let $oneOfFields; let $oneOfFields;
@@ -32650,6 +32859,12 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(ServerHello.prototype, "_paddingBytes", {
get: $util.oneOfGetter($oneOfFields = ["paddingBytes"]),
set: $util.oneOfSetter($oneOfFields)
});
ServerHello.create = function create(properties) { ServerHello.create = function create(properties) {
return new ServerHello(properties); return new ServerHello(properties);
}; };
@@ -32665,6 +32880,8 @@ export const proto = $root.proto = (() => {
w.uint32(26).bytes(m.payload); w.uint32(26).bytes(m.payload);
if (m.extendedStatic != null && Object.hasOwnProperty.call(m, "extendedStatic")) if (m.extendedStatic != null && Object.hasOwnProperty.call(m, "extendedStatic"))
w.uint32(34).bytes(m.extendedStatic); w.uint32(34).bytes(m.extendedStatic);
if (m.paddingBytes != null && Object.hasOwnProperty.call(m, "paddingBytes"))
w.uint32(42).bytes(m.paddingBytes);
return w; return w;
}; };
@@ -32693,6 +32910,10 @@ export const proto = $root.proto = (() => {
m.extendedStatic = r.bytes(); m.extendedStatic = r.bytes();
break; break;
} }
case 5: {
m.paddingBytes = r.bytes();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -32729,6 +32950,12 @@ export const proto = $root.proto = (() => {
else if (d.extendedStatic.length >= 0) else if (d.extendedStatic.length >= 0)
m.extendedStatic = d.extendedStatic; m.extendedStatic = d.extendedStatic;
} }
if (d.paddingBytes != null) {
if (typeof d.paddingBytes === "string")
$util.base64.decode(d.paddingBytes, m.paddingBytes = $util.newBuffer($util.base64.length(d.paddingBytes)), 0);
else if (d.paddingBytes.length >= 0)
m.paddingBytes = d.paddingBytes;
}
return m; return m;
}; };
@@ -32756,6 +32983,11 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._extendedStatic = "extendedStatic"; d._extendedStatic = "extendedStatic";
} }
if (m.paddingBytes != null && m.hasOwnProperty("paddingBytes")) {
d.paddingBytes = o.bytes === String ? $util.base64.encode(m.paddingBytes, 0, m.paddingBytes.length) : o.bytes === Array ? Array.prototype.slice.call(m.paddingBytes) : m.paddingBytes;
if (o.oneofs)
d._paddingBytes = "paddingBytes";
}
return d; return d;
}; };
@@ -56527,6 +56759,7 @@ export const proto = $root.proto = (() => {
PaymentInviteMessage.prototype.expiryTimestamp = null; PaymentInviteMessage.prototype.expiryTimestamp = null;
PaymentInviteMessage.prototype.incentiveEligible = null; PaymentInviteMessage.prototype.incentiveEligible = null;
PaymentInviteMessage.prototype.referralId = null; PaymentInviteMessage.prototype.referralId = null;
PaymentInviteMessage.prototype.inviteType = null;
let $oneOfFields; let $oneOfFields;
@@ -56554,6 +56787,12 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(PaymentInviteMessage.prototype, "_inviteType", {
get: $util.oneOfGetter($oneOfFields = ["inviteType"]),
set: $util.oneOfSetter($oneOfFields)
});
PaymentInviteMessage.create = function create(properties) { PaymentInviteMessage.create = function create(properties) {
return new PaymentInviteMessage(properties); return new PaymentInviteMessage(properties);
}; };
@@ -56569,6 +56808,8 @@ export const proto = $root.proto = (() => {
w.uint32(24).bool(m.incentiveEligible); w.uint32(24).bool(m.incentiveEligible);
if (m.referralId != null && Object.hasOwnProperty.call(m, "referralId")) if (m.referralId != null && Object.hasOwnProperty.call(m, "referralId"))
w.uint32(34).string(m.referralId); w.uint32(34).string(m.referralId);
if (m.inviteType != null && Object.hasOwnProperty.call(m, "inviteType"))
w.uint32(40).int32(m.inviteType);
return w; return w;
}; };
@@ -56597,6 +56838,10 @@ export const proto = $root.proto = (() => {
m.referralId = r.string(); m.referralId = r.string();
break; break;
} }
case 5: {
m.inviteType = r.int32();
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -56649,6 +56894,22 @@ export const proto = $root.proto = (() => {
if (d.referralId != null) { if (d.referralId != null) {
m.referralId = String(d.referralId); m.referralId = String(d.referralId);
} }
switch (d.inviteType) {
default:
if (typeof d.inviteType === "number") {
m.inviteType = d.inviteType;
break;
}
break;
case "DEFAULT":
case 0:
m.inviteType = 0;
break;
case "MAPPER":
case 1:
m.inviteType = 1;
break;
}
return m; return m;
}; };
@@ -56679,6 +56940,11 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._referralId = "referralId"; d._referralId = "referralId";
} }
if (m.inviteType != null && m.hasOwnProperty("inviteType")) {
d.inviteType = o.enums === String ? $root.proto.Message.PaymentInviteMessage.InviteType[m.inviteType] === undefined ? m.inviteType : $root.proto.Message.PaymentInviteMessage.InviteType[m.inviteType] : m.inviteType;
if (o.oneofs)
d._inviteType = "inviteType";
}
return d; return d;
}; };
@@ -56693,6 +56959,13 @@ export const proto = $root.proto = (() => {
return typeUrlPrefix + "/proto.Message.PaymentInviteMessage"; return typeUrlPrefix + "/proto.Message.PaymentInviteMessage";
}; };
PaymentInviteMessage.InviteType = (function() {
const valuesById = {}, values = Object.create(valuesById);
values[valuesById[0] = "DEFAULT"] = 0;
values[valuesById[1] = "MAPPER"] = 1;
return values;
})();
PaymentInviteMessage.ServiceType = (function() { PaymentInviteMessage.ServiceType = (function() {
const valuesById = {}, values = Object.create(valuesById); const valuesById = {}, values = Object.create(valuesById);
values[valuesById[0] = "UNKNOWN"] = 0; values[valuesById[0] = "UNKNOWN"] = 0;
@@ -64465,6 +64738,10 @@ export const proto = $root.proto = (() => {
case 32: case 32:
m.type = 32; m.type = 32;
break; break;
case "BOT_UNLINK_MESSAGE":
case 33:
m.type = 33;
break;
} }
if (d.ephemeralExpiration != null) { if (d.ephemeralExpiration != null) {
m.ephemeralExpiration = d.ephemeralExpiration >>> 0; m.ephemeralExpiration = d.ephemeralExpiration >>> 0;
@@ -64778,6 +65055,7 @@ export const proto = $root.proto = (() => {
values[valuesById[30] = "GROUP_MEMBER_LABEL_CHANGE"] = 30; values[valuesById[30] = "GROUP_MEMBER_LABEL_CHANGE"] = 30;
values[valuesById[31] = "AI_MEDIA_COLLECTION_MESSAGE"] = 31; values[valuesById[31] = "AI_MEDIA_COLLECTION_MESSAGE"] = 31;
values[valuesById[32] = "MESSAGE_UNSCHEDULE"] = 32; values[valuesById[32] = "MESSAGE_UNSCHEDULE"] = 32;
values[valuesById[33] = "BOT_UNLINK_MESSAGE"] = 33;
return values; return values;
})(); })();
@@ -73887,6 +74165,7 @@ export const proto = $root.proto = (() => {
values[valuesById[82] = "BUSINESS_BROADCAST_INSIGHTS_ACTION"] = 82; values[valuesById[82] = "BUSINESS_BROADCAST_INSIGHTS_ACTION"] = 82;
values[valuesById[83] = "CUSTOMER_DATA_ACTION"] = 83; values[valuesById[83] = "CUSTOMER_DATA_ACTION"] = 83;
values[valuesById[84] = "SUBSCRIPTIONS_SYNC_V2_ACTION"] = 84; values[valuesById[84] = "SUBSCRIPTIONS_SYNC_V2_ACTION"] = 84;
values[valuesById[85] = "THREAD_PIN_ACTION"] = 85;
values[valuesById[10001] = "SHARE_OWN_PN"] = 10001; values[valuesById[10001] = "SHARE_OWN_PN"] = 10001;
values[valuesById[10002] = "BUSINESS_BROADCAST_ACTION"] = 10002; values[valuesById[10002] = "BUSINESS_BROADCAST_ACTION"] = 10002;
values[valuesById[10003] = "AI_THREAD_DELETE_ACTION"] = 10003; values[valuesById[10003] = "AI_THREAD_DELETE_ACTION"] = 10003;
@@ -82502,6 +82781,10 @@ export const proto = $root.proto = (() => {
case 10: case 10:
m.source = 10; m.source = 10;
break; break;
case "SOUNDCLOUD":
case 11:
m.source = 11;
break;
} }
if (d.duration != null) { if (d.duration != null) {
m.duration = d.duration | 0; m.duration = d.duration | 0;
@@ -82563,6 +82846,7 @@ export const proto = $root.proto = (() => {
values[valuesById[8] = "APPLE_MUSIC"] = 8; values[valuesById[8] = "APPLE_MUSIC"] = 8;
values[valuesById[9] = "SHARECHAT"] = 9; values[valuesById[9] = "SHARECHAT"] = 9;
values[valuesById[10] = "GOOGLE_PHOTOS"] = 10; values[valuesById[10] = "GOOGLE_PHOTOS"] = 10;
values[valuesById[11] = "SOUNDCLOUD"] = 11;
return values; return values;
})(); })();
@@ -84136,6 +84420,7 @@ export const proto = $root.proto = (() => {
SyncActionValue.prototype.businessBroadcastInsightsAction = null; SyncActionValue.prototype.businessBroadcastInsightsAction = null;
SyncActionValue.prototype.customerDataAction = null; SyncActionValue.prototype.customerDataAction = null;
SyncActionValue.prototype.subscriptionsSyncV2Action = null; SyncActionValue.prototype.subscriptionsSyncV2Action = null;
SyncActionValue.prototype.threadPinAction = null;
let $oneOfFields; let $oneOfFields;
@@ -84589,6 +84874,12 @@ export const proto = $root.proto = (() => {
set: $util.oneOfSetter($oneOfFields) set: $util.oneOfSetter($oneOfFields)
}); });
// Virtual OneOf for proto3 optional field
Object.defineProperty(SyncActionValue.prototype, "_threadPinAction", {
get: $util.oneOfGetter($oneOfFields = ["threadPinAction"]),
set: $util.oneOfSetter($oneOfFields)
});
SyncActionValue.create = function create(properties) { SyncActionValue.create = function create(properties) {
return new SyncActionValue(properties); return new SyncActionValue(properties);
}; };
@@ -84746,6 +85037,8 @@ export const proto = $root.proto = (() => {
$root.proto.SyncActionValue.CustomerDataAction.encode(m.customerDataAction, w.uint32(666).fork()).ldelim(); $root.proto.SyncActionValue.CustomerDataAction.encode(m.customerDataAction, w.uint32(666).fork()).ldelim();
if (m.subscriptionsSyncV2Action != null && Object.hasOwnProperty.call(m, "subscriptionsSyncV2Action")) if (m.subscriptionsSyncV2Action != null && Object.hasOwnProperty.call(m, "subscriptionsSyncV2Action"))
$root.proto.SyncActionValue.SubscriptionsSyncV2Action.encode(m.subscriptionsSyncV2Action, w.uint32(674).fork()).ldelim(); $root.proto.SyncActionValue.SubscriptionsSyncV2Action.encode(m.subscriptionsSyncV2Action, w.uint32(674).fork()).ldelim();
if (m.threadPinAction != null && Object.hasOwnProperty.call(m, "threadPinAction"))
$root.proto.SyncActionValue.ThreadPinAction.encode(m.threadPinAction, w.uint32(682).fork()).ldelim();
return w; return w;
}; };
@@ -85058,6 +85351,10 @@ export const proto = $root.proto = (() => {
m.subscriptionsSyncV2Action = $root.proto.SyncActionValue.SubscriptionsSyncV2Action.decode(r, r.uint32()); m.subscriptionsSyncV2Action = $root.proto.SyncActionValue.SubscriptionsSyncV2Action.decode(r, r.uint32());
break; break;
} }
case 85: {
m.threadPinAction = $root.proto.SyncActionValue.ThreadPinAction.decode(r, r.uint32());
break;
}
default: default:
r.skipType(t & 7); r.skipType(t & 7);
break; break;
@@ -85450,6 +85747,11 @@ export const proto = $root.proto = (() => {
throw TypeError(".proto.SyncActionValue.subscriptionsSyncV2Action: object expected"); throw TypeError(".proto.SyncActionValue.subscriptionsSyncV2Action: object expected");
m.subscriptionsSyncV2Action = $root.proto.SyncActionValue.SubscriptionsSyncV2Action.fromObject(d.subscriptionsSyncV2Action); m.subscriptionsSyncV2Action = $root.proto.SyncActionValue.SubscriptionsSyncV2Action.fromObject(d.subscriptionsSyncV2Action);
} }
if (d.threadPinAction != null) {
if (typeof d.threadPinAction !== "object")
throw TypeError(".proto.SyncActionValue.threadPinAction: object expected");
m.threadPinAction = $root.proto.SyncActionValue.ThreadPinAction.fromObject(d.threadPinAction);
}
return m; return m;
}; };
@@ -85835,6 +86137,11 @@ export const proto = $root.proto = (() => {
if (o.oneofs) if (o.oneofs)
d._subscriptionsSyncV2Action = "subscriptionsSyncV2Action"; d._subscriptionsSyncV2Action = "subscriptionsSyncV2Action";
} }
if (m.threadPinAction != null && m.hasOwnProperty("threadPinAction")) {
d.threadPinAction = $root.proto.SyncActionValue.ThreadPinAction.toObject(m.threadPinAction, o);
if (o.oneofs)
d._threadPinAction = "threadPinAction";
}
return d; return d;
}; };
@@ -96080,6 +96387,94 @@ export const proto = $root.proto = (() => {
return SyncActionMessageRange; return SyncActionMessageRange;
})(); })();
SyncActionValue.ThreadPinAction = (function() {
function ThreadPinAction(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
ThreadPinAction.prototype.pinned = null;
let $oneOfFields;
// Virtual OneOf for proto3 optional field
Object.defineProperty(ThreadPinAction.prototype, "_pinned", {
get: $util.oneOfGetter($oneOfFields = ["pinned"]),
set: $util.oneOfSetter($oneOfFields)
});
ThreadPinAction.create = function create(properties) {
return new ThreadPinAction(properties);
};
ThreadPinAction.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.pinned != null && Object.hasOwnProperty.call(m, "pinned"))
w.uint32(8).bool(m.pinned);
return w;
};
ThreadPinAction.decode = function decode(r, l, e) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.proto.SyncActionValue.ThreadPinAction();
while (r.pos < c) {
var t = r.uint32();
if (t === e)
break;
switch (t >>> 3) {
case 1: {
m.pinned = r.bool();
break;
}
default:
r.skipType(t & 7);
break;
}
}
return m;
};
ThreadPinAction.fromObject = function fromObject(d) {
if (d instanceof $root.proto.SyncActionValue.ThreadPinAction)
return d;
var m = new $root.proto.SyncActionValue.ThreadPinAction();
if (d.pinned != null) {
m.pinned = Boolean(d.pinned);
}
return m;
};
ThreadPinAction.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (m.pinned != null && m.hasOwnProperty("pinned")) {
d.pinned = m.pinned;
if (o.oneofs)
d._pinned = "pinned";
}
return d;
};
ThreadPinAction.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
ThreadPinAction.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/proto.SyncActionValue.ThreadPinAction";
};
return ThreadPinAction;
})();
SyncActionValue.TimeFormatAction = (function() { SyncActionValue.TimeFormatAction = (function() {
function TimeFormatAction(p) { function TimeFormatAction(p) {
+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.0", "music-metadata": "^11.12.3",
"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,1035018135]} {"version":[2,3000,1035223526]}
+249 -7
View File
@@ -1,3 +1,4 @@
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'
@@ -45,6 +46,7 @@ import {
getBinaryNodeChildren, getBinaryNodeChildren,
isHostedLidUser, isHostedLidUser,
isHostedPnUser, isHostedPnUser,
isJidBot,
isJidGroup, isJidGroup,
isLidUser, isLidUser,
isPnUser, isPnUser,
@@ -66,7 +68,8 @@ 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 {
@@ -414,6 +417,39 @@ export const makeMessagesSocket = (config: SocketConfig) => {
) )
} }
const resolveSessionJid = async (jid: string) => {
if (isLidUser(jid) || isHostedLidUser(jid)) {
return jid
}
if (isPnUser(jid) || isHostedPnUser(jid)) {
return await signalRepository.lidMapping.getLIDForPN(jid) || jid
}
return jid
}
const canonicalizeSessionRecipients = async (recipientJids: string[]) => {
const uniqueRecipients = [...new Set(recipientJids)]
const canonicalRecipients: string[] = []
for (const jid of uniqueRecipients) {
const canonicalJid = await resolveSessionJid(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 },
'[SESSION] Canonicalized recipient addressing for session reuse'
)
}
return canonicalRecipients
}
const assertSessions = async (jids: string[], force?: boolean) => { const assertSessions = async (jids: string[], force?: boolean) => {
let didFetchNewSession = false let didFetchNewSession = false
const uniqueJids = [...new Set(jids)] // Deduplicate JIDs const uniqueJids = [...new Set(jids)] // Deduplicate JIDs
@@ -423,22 +459,32 @@ export const makeMessagesSocket = (config: SocketConfig) => {
// Check peerSessionsCache and validate sessions using libsignal loadSession // Check peerSessionsCache and validate sessions using libsignal loadSession
for (const jid of uniqueJids) { for (const jid of uniqueJids) {
const signalId = signalRepository.jidToSignalProtocolAddress(jid) const canonicalJid = await resolveSessionJid(jid)
const cachedSession = peerSessionsCache.get(signalId) const signalIds = [
signalRepository.jidToSignalProtocolAddress(jid),
signalRepository.jidToSignalProtocolAddress(canonicalJid)
]
const cachedSession = signalIds
.map(signalId => peerSessionsCache.get(signalId))
.find(session => session !== undefined)
if (cachedSession !== undefined) { if (cachedSession !== undefined) {
if (cachedSession && !force) { if (cachedSession && !force) {
continue // Session exists in cache continue // Session exists in cache
} }
} else { } else {
const sessionValidation = await signalRepository.validateSession(jid) const sessionValidation = await signalRepository.validateSession(canonicalJid)
const hasSession = sessionValidation.exists const hasSession = sessionValidation.exists
peerSessionsCache.set(signalId, hasSession) for (const signalId of signalIds) {
peerSessionsCache.set(signalId, hasSession)
}
if (hasSession && !force) { if (hasSession && !force) {
continue continue
} }
} }
jidsRequiringFetch.push(jid) jidsRequiringFetch.push(canonicalJid)
} }
if (jidsRequiringFetch.length) { if (jidsRequiringFetch.length) {
@@ -600,6 +646,85 @@ 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 relayMessage = async ( const relayMessage = async (
jid: string, jid: string,
message: proto.IMessage, message: proto.IMessage,
@@ -886,7 +1011,13 @@ export const makeMessagesSocket = (config: SocketConfig) => {
allRecipients.push(jid) allRecipients.push(jid)
} }
await assertSessions(allRecipients) await assertSessions(allRecipients)
const effectiveMeRecipients = await canonicalizeSessionRecipients(meRecipients)
const effectiveOtherRecipients = await canonicalizeSessionRecipients(otherRecipients)
const effectiveAllRecipients = [...effectiveMeRecipients, ...effectiveOtherRecipients]
await assertSessions(effectiveAllRecipients)
const [ const [
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
@@ -962,6 +1093,110 @@ 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
@@ -979,7 +1214,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
stanza.attrs.to = destinationJid stanza.attrs.to = destinationJid
} }
if (shouldIncludeDeviceIdentity) { // Force device-identity for carousel (ensures Web can decrypt)
if (shouldIncludeDeviceIdentity || isCarousel) {
;(stanza.content as BinaryNode[]).push({ ;(stanza.content as BinaryNode[]).push({
tag: 'device-identity', tag: 'device-identity',
attrs: {}, attrs: {},
@@ -1030,6 +1266,12 @@ 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)
+48 -1
View File
@@ -41,10 +41,12 @@ 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'
@@ -473,6 +475,48 @@ 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
@@ -648,7 +692,10 @@ 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)
// Validate image fields needed for WhatsApp rendering if (imageMessage) {
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 },
+18 -12
View File
@@ -154,18 +154,24 @@ export async function storeTcTokensFromIqResult({
continue continue
} }
await keys.set({ const tokenEntry = {
tctoken: { ...existingEntry,
[storageJid]: { token: Buffer.from(tokenNode.content),
...existingEntry, timestamp: tokenNode.attrs.t,
token: Buffer.from(tokenNode.content), // Resets real_issue_timestamp to null when storing a new token
timestamp: tokenNode.attrs.t, realIssueTimestamp: null
// 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 // 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)
} }
} }
+18 -11
View File
@@ -388,6 +388,13 @@ __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"
@@ -3105,7 +3112,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.0" music-metadata: "npm:^11.12.3"
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"
@@ -4556,15 +4563,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"file-type@npm:^21.3.0": "file-type@npm:^21.3.1":
version: 21.3.0 version: 21.3.1
resolution: "file-type@npm:21.3.0" resolution: "file-type@npm:21.3.1"
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/1b1fa909e6063044a6da1d2ea348ee4d747ed9286382d3f0d4d6532c11fb2ea9f2e7e67b2bc7d745d1bc937e05dee1aa8cb912c64250933bcb393a3744f4e284 checksum: 10c0/66a8eda781c803c6fc372464abba88cee564cfe30f029716f06909da1564bc51d0a4e8d34654b881dc751cdb0513338b3c0747e06a608cee0dd5c5499b018d47
languageName: node languageName: node
linkType: hard linkType: hard
@@ -6504,21 +6511,21 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"music-metadata@npm:^11.12.0": "music-metadata@npm:^11.12.3":
version: 11.12.0 version: 11.12.3
resolution: "music-metadata@npm:11.12.0" resolution: "music-metadata@npm:11.12.3"
dependencies: dependencies:
"@borewit/text-codec": "npm:^0.2.1" "@borewit/text-codec": "npm:^0.2.2"
"@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.0" file-type: "npm:^21.3.1"
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/014a120b8941ab80452171def0ec3cba013041ba4b94f8061ad493a037d3423e6d316131a13fb0433404685ebd3c8e3ae2255c1bafaeb20673fcd73af2df0148 checksum: 10c0/57df905f51ec792e5b4c994645eab64d47d5608b9de11151f54b26fbd5f563598ec04d8aed7f244ef1479030d78ddab8af1ee84dfcee40a93b3241941b50999d
languageName: node languageName: node
linkType: hard linkType: hard