@fer2809fl/baileys 7.0.2 → 7.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/README.md +409 -32
  2. package/lib/Defaults/index.js +2 -1
  3. package/lib/Modded/message_builder.js +2356 -0
  4. package/lib/Signal/libsignal.js +19 -0
  5. package/lib/Socket/business.d.ts +213 -532
  6. package/lib/Socket/business.js +359 -401
  7. package/lib/Socket/chats.d.ts +30 -2
  8. package/lib/Socket/chats.js +295 -40
  9. package/lib/Socket/groups.d.ts +16 -0
  10. package/lib/Socket/groups.js +101 -18
  11. package/lib/Socket/index.d.ts +17 -0
  12. package/lib/Socket/messages-recv.js +18 -1
  13. package/lib/Socket/messages-send.d.ts +18 -0
  14. package/lib/Socket/messages-send.js +50 -2
  15. package/lib/Socket/newsletter.js +3 -3
  16. package/lib/Socket/socket.js +50 -6
  17. package/lib/Types/Newsletter.d.ts +13 -4
  18. package/lib/Types/Newsletter.js +12 -2
  19. package/lib/Utils/anti-ban.d.ts +41 -0
  20. package/lib/Utils/anti-ban.js +182 -0
  21. package/lib/Utils/banner.d.ts +8 -0
  22. package/lib/Utils/banner.js +76 -0
  23. package/lib/Utils/bot-utils.d.ts +57 -0
  24. package/lib/Utils/bot-utils.js +241 -0
  25. package/lib/Utils/chat-utils.d.ts +34 -4
  26. package/lib/Utils/chat-utils.js +80 -20
  27. package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
  28. package/lib/Utils/companion-reg-client-utils.js +35 -0
  29. package/lib/Utils/enhanced-cache.d.ts +40 -0
  30. package/lib/Utils/enhanced-cache.js +242 -0
  31. package/lib/Utils/enhanced-logger.d.ts +41 -0
  32. package/lib/Utils/enhanced-logger.js +185 -0
  33. package/lib/Utils/event-buffer.js +49 -1
  34. package/lib/Utils/index.d.ts +14 -0
  35. package/lib/Utils/index.js +14 -0
  36. package/lib/Utils/lid-utils.d.ts +139 -0
  37. package/lib/Utils/lid-utils.js +503 -0
  38. package/lib/Utils/message-queue.d.ts +47 -0
  39. package/lib/Utils/message-queue.js +226 -0
  40. package/lib/Utils/message-retry-manager.js +40 -0
  41. package/lib/Utils/rich-message-utils.d.ts +21 -0
  42. package/lib/Utils/rich-message-utils.js +229 -0
  43. package/lib/Utils/rich-messages.d.ts +52 -0
  44. package/lib/Utils/rich-messages.js +185 -0
  45. package/lib/Utils/scheduled-messages.d.ts +122 -0
  46. package/lib/Utils/scheduled-messages.js +289 -0
  47. package/lib/Utils/smart-reconnect.d.ts +48 -0
  48. package/lib/Utils/smart-reconnect.js +207 -0
  49. package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
  50. package/lib/Utils/use-sqlite-auth-state.js +95 -0
  51. package/lib/VoIP/audio-feeder.d.ts +15 -0
  52. package/lib/VoIP/audio-feeder.js +132 -0
  53. package/lib/VoIP/index.js +277 -0
  54. package/lib/VoIP/relay-transport.d.ts +43 -0
  55. package/lib/VoIP/relay-transport.js +559 -0
  56. package/lib/VoIP/signaling.js +594 -0
  57. package/lib/VoIP/types.d.ts +69 -0
  58. package/lib/VoIP/types.js +17 -0
  59. package/lib/VoIP/wasm-engine.d.ts +103 -0
  60. package/lib/VoIP/wasm-engine.js +1214 -0
  61. package/lib/VoIP/worker-bootstrap.js +1042 -0
  62. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  63. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  64. package/lib/WAUSync/Protocols/index.js +1 -0
  65. package/lib/WAUSync/USyncQuery.js +5 -1
  66. package/lib/assets/wasm/loader.js +5 -0
  67. package/lib/assets/wasm/whatsapp.wasm +0 -0
  68. package/lib/assets/wasm/worker-modules.js +273 -0
  69. package/lib/index.d.ts +41 -0
  70. package/lib/index.js +3 -0
  71. package/package.json +15 -7
  72. package/lib/Defaults/index.d.ts.map +0 -1
  73. package/lib/Defaults/index.js.map +0 -1
  74. package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
  75. package/lib/Signal/Group/ciphertext-message.js.map +0 -1
  76. package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
  77. package/lib/Signal/Group/group-session-builder.js.map +0 -1
  78. package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
  79. package/lib/Signal/Group/group_cipher.js.map +0 -1
  80. package/lib/Signal/Group/index.d.ts.map +0 -1
  81. package/lib/Signal/Group/index.js.map +0 -1
  82. package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
  83. package/lib/Signal/Group/keyhelper.js.map +0 -1
  84. package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
  85. package/lib/Signal/Group/sender-chain-key.js.map +0 -1
  86. package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
  87. package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
  88. package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
  89. package/lib/Signal/Group/sender-key-message.js.map +0 -1
  90. package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
  91. package/lib/Signal/Group/sender-key-name.js.map +0 -1
  92. package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
  93. package/lib/Signal/Group/sender-key-record.js.map +0 -1
  94. package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
  95. package/lib/Signal/Group/sender-key-state.js.map +0 -1
  96. package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
  97. package/lib/Signal/Group/sender-message-key.js.map +0 -1
  98. package/lib/Signal/libsignal.d.ts.map +0 -1
  99. package/lib/Signal/libsignal.js.map +0 -1
  100. package/lib/Signal/lid-mapping.d.ts.map +0 -1
  101. package/lib/Signal/lid-mapping.js.map +0 -1
  102. package/lib/Socket/Client/index.d.ts.map +0 -1
  103. package/lib/Socket/Client/index.js.map +0 -1
  104. package/lib/Socket/Client/types.d.ts.map +0 -1
  105. package/lib/Socket/Client/types.js.map +0 -1
  106. package/lib/Socket/Client/websocket.d.ts.map +0 -1
  107. package/lib/Socket/Client/websocket.js.map +0 -1
  108. package/lib/Socket/business.d.ts.map +0 -1
  109. package/lib/Socket/business.js.map +0 -1
  110. package/lib/Socket/chats.d.ts.map +0 -1
  111. package/lib/Socket/chats.js.map +0 -1
  112. package/lib/Socket/communities.d.ts.map +0 -1
  113. package/lib/Socket/communities.js.map +0 -1
  114. package/lib/Socket/dugong.d.ts.map +0 -1
  115. package/lib/Socket/dugong.js.map +0 -1
  116. package/lib/Socket/groups.d.ts.map +0 -1
  117. package/lib/Socket/groups.js.map +0 -1
  118. package/lib/Socket/index.d.ts.map +0 -1
  119. package/lib/Socket/index.js.map +0 -1
  120. package/lib/Socket/messages-recv.d.ts.map +0 -1
  121. package/lib/Socket/messages-recv.js.map +0 -1
  122. package/lib/Socket/messages-send.d.ts.map +0 -1
  123. package/lib/Socket/messages-send.js.map +0 -1
  124. package/lib/Socket/mex.d.ts.map +0 -1
  125. package/lib/Socket/mex.js.map +0 -1
  126. package/lib/Socket/newsletter.d.ts.map +0 -1
  127. package/lib/Socket/newsletter.js.map +0 -1
  128. package/lib/Socket/socket.d.ts.map +0 -1
  129. package/lib/Socket/socket.js.map +0 -1
  130. package/lib/Types/Auth.d.ts.map +0 -1
  131. package/lib/Types/Auth.js.map +0 -1
  132. package/lib/Types/Bussines.d.ts.map +0 -1
  133. package/lib/Types/Bussines.js.map +0 -1
  134. package/lib/Types/Call.d.ts.map +0 -1
  135. package/lib/Types/Call.js.map +0 -1
  136. package/lib/Types/Chat.d.ts.map +0 -1
  137. package/lib/Types/Chat.js.map +0 -1
  138. package/lib/Types/Contact.d.ts.map +0 -1
  139. package/lib/Types/Contact.js.map +0 -1
  140. package/lib/Types/Events.d.ts.map +0 -1
  141. package/lib/Types/Events.js.map +0 -1
  142. package/lib/Types/GroupMetadata.d.ts.map +0 -1
  143. package/lib/Types/GroupMetadata.js.map +0 -1
  144. package/lib/Types/Label.d.ts.map +0 -1
  145. package/lib/Types/Label.js.map +0 -1
  146. package/lib/Types/LabelAssociation.d.ts.map +0 -1
  147. package/lib/Types/LabelAssociation.js.map +0 -1
  148. package/lib/Types/Message.d.ts.map +0 -1
  149. package/lib/Types/Message.js.map +0 -1
  150. package/lib/Types/Newsletter.d.ts.map +0 -1
  151. package/lib/Types/Newsletter.js.map +0 -1
  152. package/lib/Types/Product.d.ts.map +0 -1
  153. package/lib/Types/Product.js.map +0 -1
  154. package/lib/Types/Signal.d.ts.map +0 -1
  155. package/lib/Types/Signal.js.map +0 -1
  156. package/lib/Types/Socket.d.ts.map +0 -1
  157. package/lib/Types/Socket.js.map +0 -1
  158. package/lib/Types/State.d.ts.map +0 -1
  159. package/lib/Types/State.js.map +0 -1
  160. package/lib/Types/USync.d.ts.map +0 -1
  161. package/lib/Types/USync.js.map +0 -1
  162. package/lib/Types/index.d.ts.map +0 -1
  163. package/lib/Types/index.js.map +0 -1
  164. package/lib/Utils/auth-utils.d.ts.map +0 -1
  165. package/lib/Utils/auth-utils.js.map +0 -1
  166. package/lib/Utils/browser-utils.d.ts.map +0 -1
  167. package/lib/Utils/browser-utils.js.map +0 -1
  168. package/lib/Utils/business.d.ts.map +0 -1
  169. package/lib/Utils/business.js.map +0 -1
  170. package/lib/Utils/chat-utils.d.ts.map +0 -1
  171. package/lib/Utils/chat-utils.js.map +0 -1
  172. package/lib/Utils/crypto.d.ts.map +0 -1
  173. package/lib/Utils/crypto.js.map +0 -1
  174. package/lib/Utils/decode-wa-message.d.ts.map +0 -1
  175. package/lib/Utils/decode-wa-message.js.map +0 -1
  176. package/lib/Utils/event-buffer.d.ts.map +0 -1
  177. package/lib/Utils/event-buffer.js.map +0 -1
  178. package/lib/Utils/generics.d.ts.map +0 -1
  179. package/lib/Utils/generics.js.map +0 -1
  180. package/lib/Utils/history.d.ts.map +0 -1
  181. package/lib/Utils/history.js.map +0 -1
  182. package/lib/Utils/identity-change-handler.d.ts.map +0 -1
  183. package/lib/Utils/identity-change-handler.js.map +0 -1
  184. package/lib/Utils/index.d.ts.map +0 -1
  185. package/lib/Utils/index.js.map +0 -1
  186. package/lib/Utils/link-preview.d.ts.map +0 -1
  187. package/lib/Utils/link-preview.js.map +0 -1
  188. package/lib/Utils/logger.d.ts.map +0 -1
  189. package/lib/Utils/logger.js.map +0 -1
  190. package/lib/Utils/lt-hash.d.ts.map +0 -1
  191. package/lib/Utils/lt-hash.js.map +0 -1
  192. package/lib/Utils/make-mutex.d.ts.map +0 -1
  193. package/lib/Utils/make-mutex.js.map +0 -1
  194. package/lib/Utils/message-retry-manager.d.ts.map +0 -1
  195. package/lib/Utils/message-retry-manager.js.map +0 -1
  196. package/lib/Utils/messages-media.d.ts.map +0 -1
  197. package/lib/Utils/messages-media.js.map +0 -1
  198. package/lib/Utils/messages.d.ts.map +0 -1
  199. package/lib/Utils/messages.js.map +0 -1
  200. package/lib/Utils/noise-handler.d.ts.map +0 -1
  201. package/lib/Utils/noise-handler.js.map +0 -1
  202. package/lib/Utils/offline-node-processor.d.ts.map +0 -1
  203. package/lib/Utils/offline-node-processor.js.map +0 -1
  204. package/lib/Utils/pre-key-manager.d.ts.map +0 -1
  205. package/lib/Utils/pre-key-manager.js.map +0 -1
  206. package/lib/Utils/process-message.d.ts.map +0 -1
  207. package/lib/Utils/process-message.js.map +0 -1
  208. package/lib/Utils/reporting-utils.d.ts.map +0 -1
  209. package/lib/Utils/reporting-utils.js.map +0 -1
  210. package/lib/Utils/rich-messages.d.ts.map +0 -1
  211. package/lib/Utils/rich-messages.js.map +0 -1
  212. package/lib/Utils/signal.d.ts.map +0 -1
  213. package/lib/Utils/signal.js.map +0 -1
  214. package/lib/Utils/stanza-ack.d.ts.map +0 -1
  215. package/lib/Utils/stanza-ack.js.map +0 -1
  216. package/lib/Utils/sync-action-utils.d.ts.map +0 -1
  217. package/lib/Utils/sync-action-utils.js.map +0 -1
  218. package/lib/Utils/tc-token-utils.d.ts.map +0 -1
  219. package/lib/Utils/tc-token-utils.js.map +0 -1
  220. package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
  221. package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
  222. package/lib/Utils/validate-connection.d.ts.map +0 -1
  223. package/lib/Utils/validate-connection.js.map +0 -1
  224. package/lib/WABinary/constants.d.ts.map +0 -1
  225. package/lib/WABinary/constants.js.map +0 -1
  226. package/lib/WABinary/decode.d.ts.map +0 -1
  227. package/lib/WABinary/decode.js.map +0 -1
  228. package/lib/WABinary/encode.d.ts.map +0 -1
  229. package/lib/WABinary/encode.js.map +0 -1
  230. package/lib/WABinary/generic-utils.d.ts.map +0 -1
  231. package/lib/WABinary/generic-utils.js.map +0 -1
  232. package/lib/WABinary/index.d.ts.map +0 -1
  233. package/lib/WABinary/index.js.map +0 -1
  234. package/lib/WABinary/jid-utils.d.ts.map +0 -1
  235. package/lib/WABinary/jid-utils.js.map +0 -1
  236. package/lib/WABinary/types.d.ts.map +0 -1
  237. package/lib/WABinary/types.js.map +0 -1
  238. package/lib/WAM/BinaryInfo.d.ts.map +0 -1
  239. package/lib/WAM/BinaryInfo.js.map +0 -1
  240. package/lib/WAM/constants.d.ts.map +0 -1
  241. package/lib/WAM/constants.js.map +0 -1
  242. package/lib/WAM/encode.d.ts.map +0 -1
  243. package/lib/WAM/encode.js.map +0 -1
  244. package/lib/WAM/index.d.ts.map +0 -1
  245. package/lib/WAM/index.js.map +0 -1
  246. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
  247. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
  248. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
  249. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
  250. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
  251. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
  252. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
  253. package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
  254. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
  255. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
  256. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
  257. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
  258. package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
  259. package/lib/WAUSync/Protocols/index.js.map +0 -1
  260. package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
  261. package/lib/WAUSync/USyncQuery.js.map +0 -1
  262. package/lib/WAUSync/USyncUser.d.ts.map +0 -1
  263. package/lib/WAUSync/USyncUser.js.map +0 -1
  264. package/lib/WAUSync/index.d.ts.map +0 -1
  265. package/lib/WAUSync/index.js.map +0 -1
  266. package/lib/index.d.ts.map +0 -1
  267. package/lib/index.js.map +0 -1
@@ -1,11 +1,20 @@
1
1
  import { Boom } from '@hapi/boom';
2
2
  import { proto } from '../../WAProto/index.js';
3
- import type { BotListInfo, ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types/index.js';
3
+ import type { BotListInfo, CacheStore, ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAMessage, WAPatchCreate, WAPresence, WAPrivacyCallValue, WAPrivacyGroupAddValue, WAPrivacyMessagesValue, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types/index.js';
4
4
  import type { QuickReplyAction } from '../Types/Bussines.js';
5
5
  import type { LabelActionBody } from '../Types/Label.js';
6
6
  import { type BinaryNode } from '../WABinary/index.js';
7
7
  import { USyncQuery } from '../WAUSync/index.js';
8
+ export declare const buildProfilePictureQueryContent: (type: "preview" | "image", tcTokenContent?: BinaryNode[]) => BinaryNode[];
8
9
  export declare const makeChatsSocket: (config: SocketConfig) => {
10
+ serverProps: {
11
+ /** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
12
+ privacyTokenOn1to1: boolean;
13
+ /** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
14
+ profilePicPrivacyToken: boolean;
15
+ /** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
16
+ lidTrustedTokenIssueToLid: boolean;
17
+ };
9
18
  createCallLink: (type: "audio" | "video", event?: {
10
19
  startTime: number;
11
20
  }, timeoutMs?: number) => Promise<string | undefined>;
@@ -57,6 +66,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
57
66
  cleanDirtyBits: (type: "account_sync" | "groups", fromTimestamp?: number | string) => Promise<void>;
58
67
  addOrEditContact: (jid: string, contact: proto.SyncActionValue.IContactAction) => Promise<void>;
59
68
  removeContact: (jid: string) => Promise<void>;
69
+ placeholderResendCache: CacheStore;
60
70
  addLabel: (jid: string, labels: LabelActionBody) => Promise<void>;
61
71
  addChatLabel: (jid: string, labelId: string) => Promise<void>;
62
72
  removeChatLabel: (jid: string, labelId: string) => Promise<void>;
@@ -66,6 +76,20 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
66
76
  id: string;
67
77
  fromMe?: boolean;
68
78
  }[], star: boolean) => Promise<void>;
79
+ /** Fija o desfija un chat en la parte superior de la lista de chats. */
80
+ pinChat: (jid: string, pin?: boolean) => Promise<void>;
81
+ /** Archiva o desarchiva un chat. */
82
+ archiveChat: (jid: string, archive?: boolean, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
83
+ /** Silencia un chat hasta `muteEndTimestamp` (ms). Pasa `undefined` para quitar el silencio. */
84
+ muteChat: (jid: string, muteEndTimestamp?: number) => Promise<void>;
85
+ /** Marca un chat como leído (o no leído con `read: false`). */
86
+ markChatRead: (jid: string, read?: boolean, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
87
+ /** Atajo para marcar un chat como no leído. */
88
+ markChatUnread: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
89
+ /** Vacía el historial de un chat sin eliminar el chat. */
90
+ clearChat: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
91
+ /** Elimina un chat completo de la lista de chats. */
92
+ deleteChat: (jid: string, lastMessages?: import("../Types/index.js").LastMessageList) => Promise<void>;
69
93
  addOrEditQuickReply: (quickReply: QuickReplyAction) => Promise<void>;
70
94
  removeQuickReply: (timestamp: string) => Promise<void>;
71
95
  type: "md";
@@ -76,6 +100,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
76
100
  createBufferedFunction<A extends any[], T>(work: (...args: A) => Promise<T>): (...args: A) => Promise<T>;
77
101
  flush(): boolean;
78
102
  isBuffering(): boolean;
103
+ destroy(): void;
79
104
  };
80
105
  authState: {
81
106
  creds: import("../Types/index.js").AuthenticationCreds;
@@ -91,8 +116,9 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
91
116
  sendNode: (frame: BinaryNode) => Promise<void>;
92
117
  logout: (msg?: string) => Promise<void>;
93
118
  end: (error: Error | undefined) => Promise<void>;
119
+ registerSocketEndHandler: (handler: (error: Error | undefined) => void | Promise<void>) => void;
94
120
  onUnexpectedError: (err: Error | Boom, msg: string) => void;
95
- uploadPreKeys: (count?: number, retryCount?: number) => Promise<void>;
121
+ uploadPreKeys: (count?: number) => Promise<void>;
96
122
  uploadPreKeysToServerIfRequired: () => Promise<void>;
97
123
  digestKeyBundle: () => Promise<void>;
98
124
  rotateSignedPreKey: () => Promise<void>;
@@ -107,5 +133,7 @@ export declare const makeChatsSocket: (config: SocketConfig) => {
107
133
  jid: string;
108
134
  exists: boolean;
109
135
  }[] | undefined>;
136
+ fetchAccountReachoutTimelock: () => Promise<import("../Types/index.js").ReachoutTimelockState>;
137
+ fetchNewChatMessageCap: () => Promise<import("../Types/index.js").NewChatMessageCapInfo>;
110
138
  };
111
139
  //# sourceMappingURL=chats.d.ts.map
@@ -1,22 +1,38 @@
1
1
  import NodeCache from '@cacheable/node-cache';
2
2
  import { Boom } from '@hapi/boom';
3
3
  import { proto } from '../../WAProto/index.js';
4
- import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
4
+ import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
5
5
  import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
6
6
  import { SyncState } from '../Types/State.js';
7
- import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, extractSyncdPatches, generateProfilePicture, getHistoryMsg, newLTHashState, processSyncAction } from '../Utils/index.js';
7
+ import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
8
8
  import { makeMutex } from '../Utils/make-mutex.js';
9
9
  import processMessage from '../Utils/process-message.js';
10
10
  import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
11
- import { getBinaryNodeChild, getBinaryNodeChildren, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
11
+ import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
12
12
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
13
13
  import { makeSocket } from './socket.js';
14
- const MAX_SYNC_ATTEMPTS = 2;
14
+ export const buildProfilePictureQueryContent = (type, tcTokenContent) => {
15
+ const picture = { tag: 'picture', attrs: { type, query: 'url' } };
16
+ if (tcTokenContent?.length) {
17
+ picture.content = tcTokenContent;
18
+ }
19
+ return [picture];
20
+ };
15
21
  export const makeChatsSocket = (config) => {
16
22
  const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
17
23
  const sock = makeSocket(config);
18
- const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
24
+ const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession, registerSocketEndHandler } = sock;
25
+ const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
19
26
  let privacySettings;
27
+ /** Server-assigned AB props for protocol behavior. */
28
+ const serverProps = {
29
+ /** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
30
+ privacyTokenOn1to1: true,
31
+ /** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
32
+ profilePicPrivacyToken: true,
33
+ /** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
34
+ lidTrustedTokenIssueToLid: false
35
+ };
20
36
  let syncState = SyncState.Connecting;
21
37
  /** this mutex ensures that messages are processed in order */
22
38
  const messageMutex = makeMutex();
@@ -28,14 +44,20 @@ export const makeChatsSocket = (config) => {
28
44
  const notificationMutex = makeMutex();
29
45
  // Timeout for AwaitingInitialSync state
30
46
  let awaitingSyncTimeout;
47
+ // In-memory history sync completion tracking (resets on reconnection)
48
+ const historySyncStatus = {
49
+ initialBootstrapComplete: false,
50
+ recentSyncComplete: false
51
+ };
52
+ let historySyncPausedTimeout;
53
+ // Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
54
+ // When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
55
+ const blockedCollections = new Set();
31
56
  const placeholderResendCache = config.placeholderResendCache ||
32
57
  new NodeCache({
33
58
  stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
34
59
  useClones: false
35
60
  });
36
- if (!config.placeholderResendCache) {
37
- config.placeholderResendCache = placeholderResendCache;
38
- }
39
61
  /** helper function to fetch the given app state sync key */
40
62
  const getAppStateSyncKey = async (keyId) => {
41
63
  const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
@@ -258,6 +280,42 @@ export const makeChatsSocket = (config) => {
258
280
  return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
259
281
  };
260
282
  const updateBlockStatus = async (jid, action) => {
283
+ const normalizedJid = jidNormalizedUser(jid);
284
+ let lid;
285
+ let pn_jid;
286
+ if (isLidUser(normalizedJid) || isHostedLidUser(normalizedJid)) {
287
+ lid = normalizedJid;
288
+ if (action === 'block') {
289
+ const pn = await signalRepository.lidMapping.getPNForLID(normalizedJid);
290
+ if (!pn) {
291
+ throw new Boom(`Unable to resolve PN JID for LID: ${jid}`, { statusCode: 400 });
292
+ }
293
+ pn_jid = jidNormalizedUser(pn);
294
+ }
295
+ }
296
+ else if (isPnUser(normalizedJid) || isHostedPnUser(normalizedJid)) {
297
+ const mapped = await signalRepository.lidMapping.getLIDForPN(normalizedJid);
298
+ if (!mapped) {
299
+ throw new Boom(`Unable to resolve LID for PN JID: ${jid}`, { statusCode: 400 });
300
+ }
301
+ lid = mapped;
302
+ if (action === 'block') {
303
+ pn_jid = jidNormalizedUser(normalizedJid);
304
+ }
305
+ }
306
+ else {
307
+ throw new Boom(`Invalid jid: ${jid}`, { statusCode: 400 });
308
+ }
309
+ const itemAttrs = {
310
+ action,
311
+ jid: lid
312
+ };
313
+ if (action === 'block') {
314
+ if (!pn_jid) {
315
+ throw new Boom(`pn_jid required for block: ${jid}`, { statusCode: 400 });
316
+ }
317
+ itemAttrs.pn_jid = pn_jid;
318
+ }
261
319
  await query({
262
320
  tag: 'iq',
263
321
  attrs: {
@@ -268,10 +326,7 @@ export const makeChatsSocket = (config) => {
268
326
  content: [
269
327
  {
270
328
  tag: 'item',
271
- attrs: {
272
- action,
273
- jid
274
- }
329
+ attrs: itemAttrs
275
330
  }
276
331
  ]
277
332
  });
@@ -370,6 +425,9 @@ export const makeChatsSocket = (config) => {
370
425
  const collectionsToHandle = new Set(collections);
371
426
  // in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
372
427
  const attemptsMap = {};
428
+ // collections that failed and need a full snapshot on retry
429
+ // mirrors WA Web's ErrorFatal -> force snapshot behavior
430
+ const forceSnapshotCollections = new Set();
373
431
  // keep executing till all collections are done
374
432
  // sometimes a single patch request will not return all the patches (God knows why)
375
433
  // so we fetch till they're all done (this is determined by the "has_more_patches" flag)
@@ -380,6 +438,7 @@ export const makeChatsSocket = (config) => {
380
438
  const result = await authState.keys.get('app-state-sync-version', [name]);
381
439
  let state = result[name];
382
440
  if (state) {
441
+ state = ensureLTHashStateVersion(state);
383
442
  if (typeof initialVersionMap[name] === 'undefined') {
384
443
  initialVersionMap[name] = state.version;
385
444
  }
@@ -388,14 +447,18 @@ export const makeChatsSocket = (config) => {
388
447
  state = newLTHashState();
389
448
  }
390
449
  states[name] = state;
391
- logger.info(`resyncing ${name} from v${state.version}`);
450
+ const shouldForceSnapshot = forceSnapshotCollections.has(name);
451
+ if (shouldForceSnapshot) {
452
+ forceSnapshotCollections.delete(name);
453
+ }
454
+ logger.info(`resyncing ${name} from v${state.version}${shouldForceSnapshot ? ' (forcing snapshot)' : ''}`);
392
455
  nodes.push({
393
456
  tag: 'collection',
394
457
  attrs: {
395
458
  name,
396
459
  version: state.version.toString(),
397
- // return snapshot if being synced from scratch
398
- return_snapshot: (!state.version).toString()
460
+ // return snapshot if syncing from scratch or forcing after a failed attempt
461
+ return_snapshot: (shouldForceSnapshot || !state.version).toString()
399
462
  }
400
463
  });
401
464
  }
@@ -421,7 +484,7 @@ export const makeChatsSocket = (config) => {
421
484
  const { patches, hasMorePatches, snapshot } = decoded[name];
422
485
  try {
423
486
  if (snapshot) {
424
- const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
487
+ const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot, logger);
425
488
  states[name] = newState;
426
489
  Object.assign(globalMutationMap, mutationMap);
427
490
  logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
@@ -444,19 +507,37 @@ export const makeChatsSocket = (config) => {
444
507
  }
445
508
  }
446
509
  catch (error) {
447
- // if retry attempts overshoot
448
- // or key not found
449
- const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
450
- error.output?.statusCode === 404 ||
451
- error.name === 'TypeError';
452
- logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
453
- await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
454
- // increment number of retries
455
510
  attemptsMap[name] = (attemptsMap[name] || 0) + 1;
456
- if (isIrrecoverableError) {
457
- // stop retrying
511
+ const logData = {
512
+ name,
513
+ attempt: attemptsMap[name],
514
+ version: states[name].version,
515
+ statusCode: error.output?.statusCode,
516
+ errorType: error.name,
517
+ error: error.stack
518
+ };
519
+ if (isMissingKeyError(error) && attemptsMap[name] >= MAX_SYNC_ATTEMPTS) {
520
+ // WA Web treats missing keys as "Blocked" — park the collection
521
+ // until the key arrives via APP_STATE_SYNC_KEY_SHARE.
522
+ logger.warn(logData, `${name} blocked on missing key from v${states[name].version}, parking after ${attemptsMap[name]} attempts`);
523
+ blockedCollections.add(name);
458
524
  collectionsToHandle.delete(name);
459
525
  }
526
+ else if (isMissingKeyError(error)) {
527
+ // Retry with a snapshot which may use a different key.
528
+ logger.info(logData, `${name} blocked on missing key from v${states[name].version}, retrying with snapshot`);
529
+ forceSnapshotCollections.add(name);
530
+ }
531
+ else if (isAppStateSyncIrrecoverable(error, attemptsMap[name])) {
532
+ logger.warn(logData, `failed to sync ${name} from v${states[name].version}, giving up`);
533
+ collectionsToHandle.delete(name);
534
+ }
535
+ else {
536
+ logger.info(logData, `failed to sync ${name} from v${states[name].version}, forcing snapshot retry`);
537
+ // force a full snapshot on retry to recover from
538
+ // corrupted local state (e.g. LTHash MAC mismatch)
539
+ forceSnapshotCollections.add(name);
540
+ }
460
541
  }
461
542
  }
462
543
  }
@@ -466,14 +547,68 @@ export const makeChatsSocket = (config) => {
466
547
  onMutation(globalMutationMap[key]);
467
548
  }
468
549
  });
550
+ /**
551
+ * Fija o desfija un chat en la parte superior de la lista de chats.
552
+ */
553
+ const pinChat = (jid, pin = true) => {
554
+ return chatModify({ pin }, jid);
555
+ };
556
+ /**
557
+ * Archiva o desarchiva un chat. Si se pasan `lastMessages`, se usan para
558
+ * calcular el rango de mensajes que WhatsApp debe archivar/desarchivar.
559
+ */
560
+ const archiveChat = (jid, archive = true, lastMessages) => {
561
+ return chatModify({ archive, lastMessages }, jid);
562
+ };
563
+ /**
564
+ * Silencia un chat. `muteEndTimestamp` es el timestamp (ms) hasta el que
565
+ * estará silenciado; pasa `undefined`/`null` (o llama con `false`) para
566
+ * quitar el silencio.
567
+ */
568
+ const muteChat = (jid, muteEndTimestamp) => {
569
+ return chatModify({ mute: muteEndTimestamp || undefined }, jid);
570
+ };
571
+ /**
572
+ * Marca un chat como leído o no leído.
573
+ */
574
+ const markChatRead = (jid, read = true, lastMessages) => {
575
+ return chatModify({ markRead: read, lastMessages }, jid);
576
+ };
577
+ /** Atajo para marcar un chat como no leído. */
578
+ const markChatUnread = (jid, lastMessages) => markChatRead(jid, false, lastMessages);
579
+ /**
580
+ * Vacía el historial de un chat (sin eliminar el chat en sí).
581
+ */
582
+ const clearChat = (jid, lastMessages) => {
583
+ return chatModify({ clear: true, lastMessages }, jid);
584
+ };
585
+ /**
586
+ * Elimina un chat completo de la lista de chats.
587
+ */
588
+ const deleteChat = (jid, lastMessages) => {
589
+ return chatModify({ delete: true, lastMessages }, jid);
590
+ };
469
591
  /**
470
592
  * fetch the profile picture of a user/group
471
593
  * type = "preview" for a low res picture
472
594
  * type = "image for the high res picture"
473
595
  */
474
596
  const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
475
- const baseContent = [{ tag: 'picture', attrs: { type, query: 'url' } }];
476
- const tcTokenContent = await buildTcTokenFromJid({ authState, jid, baseContent });
597
+ // WA Web only includes tctoken for user JIDs (not groups/newsletters)
598
+ // and never for own profile pic (Chat model for self has no tcToken).
599
+ // Including tctoken for own JID causes the server to never respond.
600
+ const normalizedJid = jidNormalizedUser(jid);
601
+ const isUserJid = isPnUser(normalizedJid) || isLidUser(normalizedJid);
602
+ const me = authState.creds.me;
603
+ const isSelf = me && (normalizedJid === jidNormalizedUser(me.id) || (me.lid && normalizedJid === jidNormalizedUser(me.lid)));
604
+ let tcTokenContent;
605
+ if (serverProps.profilePicPrivacyToken && isUserJid && !isSelf) {
606
+ tcTokenContent = await buildTcTokenFromJid({
607
+ authState,
608
+ jid: normalizedJid,
609
+ getLIDForPN
610
+ });
611
+ }
477
612
  jid = jidNormalizedUser(jid);
478
613
  const result = await query({
479
614
  tag: 'iq',
@@ -483,7 +618,7 @@ export const makeChatsSocket = (config) => {
483
618
  type: 'get',
484
619
  xmlns: 'w:profile:picture'
485
620
  },
486
- content: tcTokenContent
621
+ content: buildProfilePictureQueryContent(type, tcTokenContent)
487
622
  }, timeoutMs);
488
623
  const child = getBinaryNodeChild(result, 'picture');
489
624
  return child?.attrs?.url;
@@ -549,7 +684,12 @@ export const makeChatsSocket = (config) => {
549
684
  * @param tcToken token for subscription, use if present
550
685
  */
551
686
  const presenceSubscribe = async (toJid) => {
552
- const tcTokenContent = await buildTcTokenFromJid({ authState, jid: toJid });
687
+ // Only include tctoken for user JIDs groups/newsletters don't use tctokens
688
+ const normalizedToJid = jidNormalizedUser(toJid);
689
+ const isUserJid = isPnUser(normalizedToJid) || isLidUser(normalizedToJid);
690
+ const tcTokenContent = isUserJid
691
+ ? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
692
+ : undefined;
553
693
  return sendNode({
554
694
  tag: 'presence',
555
695
  attrs: {
@@ -570,7 +710,8 @@ export const makeChatsSocket = (config) => {
570
710
  if (tag === 'presence') {
571
711
  presence = {
572
712
  lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
573
- lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
713
+ lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined,
714
+ groupOnlineCount: attrs.count ? +attrs.count : undefined
574
715
  };
575
716
  }
576
717
  else if (Array.isArray(content)) {
@@ -604,7 +745,7 @@ export const makeChatsSocket = (config) => {
604
745
  logger.debug({ patch: patchCreate }, 'applying app patch');
605
746
  await resyncAppState([name], false);
606
747
  const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
607
- initial = currentSyncVersion || newLTHashState();
748
+ initial = currentSyncVersion ? ensureLTHashStateVersion(currentSyncVersion) : newLTHashState();
608
749
  encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
609
750
  const { patch, state } = encodeResult;
610
751
  const node = {
@@ -650,22 +791,21 @@ export const makeChatsSocket = (config) => {
650
791
  }
651
792
  }
652
793
  };
653
- /** sending non-abt props may fix QR scan fail if server expects */
794
+ /** fetch AB props */
654
795
  const fetchProps = async () => {
655
- //TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
656
796
  const resultNode = await query({
657
797
  tag: 'iq',
658
798
  attrs: {
659
799
  to: S_WHATSAPP_NET,
660
- xmlns: 'w',
800
+ xmlns: 'abt',
661
801
  type: 'get'
662
802
  },
663
803
  content: [
664
804
  {
665
805
  tag: 'props',
666
806
  attrs: {
667
- protocol: '2',
668
- hash: authState?.creds?.lastPropHash || ''
807
+ protocol: '1',
808
+ ...(authState?.creds?.lastPropHash ? { hash: authState.creds.lastPropHash } : {})
669
809
  }
670
810
  }
671
811
  ]
@@ -680,7 +820,20 @@ export const makeChatsSocket = (config) => {
680
820
  }
681
821
  props = reduceBinaryNodeToDictionary(propsNode, 'prop');
682
822
  }
683
- logger.debug('fetched props');
823
+ // Extract protocol-relevant AB props (only the ones we need)
824
+ const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages'];
825
+ if (privacyTokenProp !== undefined) {
826
+ serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1';
827
+ }
828
+ const profilePicProp = props['9666'] ?? props['profile_scraping_privacy_token_in_photo_iq'];
829
+ if (profilePicProp !== undefined) {
830
+ serverProps.profilePicPrivacyToken = profilePicProp === 'true' || profilePicProp === '1';
831
+ }
832
+ const lidIssueProp = props['14303'] ?? props['lid_trusted_token_issue_to_lid'];
833
+ if (lidIssueProp !== undefined) {
834
+ serverProps.lidTrustedTokenIssueToLid = lidIssueProp === 'true' || lidIssueProp === '1';
835
+ }
836
+ logger.debug({ serverProps }, 'fetched props');
684
837
  return props;
685
838
  };
686
839
  /**
@@ -820,6 +973,47 @@ export const makeChatsSocket = (config) => {
820
973
  ? shouldSyncHistoryMessage(historyMsg) &&
821
974
  PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
822
975
  : false;
976
+ if (historyMsg && shouldProcessHistoryMsg) {
977
+ const syncType = historyMsg.syncType;
978
+ // INITIAL_BOOTSTRAP — fire immediately, no progress check (same as WA Web K function)
979
+ if (syncType === proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
980
+ !historySyncStatus.initialBootstrapComplete) {
981
+ historySyncStatus.initialBootstrapComplete = true;
982
+ ev.emit('messaging-history.status', {
983
+ syncType,
984
+ status: 'complete',
985
+ explicit: true
986
+ });
987
+ }
988
+ // RECENT with progress === 100 — explicit completion
989
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT &&
990
+ historyMsg.progress === 100 &&
991
+ !historySyncStatus.recentSyncComplete) {
992
+ historySyncStatus.recentSyncComplete = true;
993
+ clearTimeout(historySyncPausedTimeout);
994
+ historySyncPausedTimeout = undefined;
995
+ ev.emit('messaging-history.status', {
996
+ syncType,
997
+ status: 'complete',
998
+ explicit: true
999
+ });
1000
+ }
1001
+ // Reset 120s paused timeout on any RECENT chunk (like WA Web's handleChunkProgress)
1002
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
1003
+ clearTimeout(historySyncPausedTimeout);
1004
+ historySyncPausedTimeout = setTimeout(() => {
1005
+ if (!historySyncStatus.recentSyncComplete) {
1006
+ historySyncStatus.recentSyncComplete = true;
1007
+ ev.emit('messaging-history.status', {
1008
+ syncType: proto.HistorySync.HistorySyncType.RECENT,
1009
+ status: 'paused',
1010
+ explicit: false
1011
+ });
1012
+ }
1013
+ historySyncPausedTimeout = undefined;
1014
+ }, HISTORY_SYNC_PAUSED_TIMEOUT_MS);
1015
+ }
1016
+ }
823
1017
  // State machine: decide on sync and flush
824
1018
  if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
825
1019
  if (awaitingSyncTimeout) {
@@ -839,6 +1033,8 @@ export const makeChatsSocket = (config) => {
839
1033
  }
840
1034
  const doAppStateSync = async () => {
841
1035
  if (syncState === SyncState.Syncing) {
1036
+ // All collections will be synced, so clear any blocked ones
1037
+ blockedCollections.clear();
842
1038
  logger.info('Doing app state sync');
843
1039
  await resyncAppState(ALL_WA_PATCH_NAMES, true);
844
1040
  // Sync is complete, go online and flush everything
@@ -898,6 +1094,11 @@ export const makeChatsSocket = (config) => {
898
1094
  }
899
1095
  });
900
1096
  ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
1097
+ if (connection === 'close') {
1098
+ blockedCollections.clear();
1099
+ clearTimeout(historySyncPausedTimeout);
1100
+ historySyncPausedTimeout = undefined;
1101
+ }
901
1102
  if (connection === 'open') {
902
1103
  if (fireInitQueries) {
903
1104
  executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
@@ -907,6 +1108,10 @@ export const makeChatsSocket = (config) => {
907
1108
  if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
908
1109
  return;
909
1110
  }
1111
+ historySyncStatus.initialBootstrapComplete = false;
1112
+ historySyncStatus.recentSyncComplete = false;
1113
+ clearTimeout(historySyncPausedTimeout);
1114
+ historySyncPausedTimeout = undefined;
910
1115
  syncState = SyncState.AwaitingInitialSync;
911
1116
  logger.info('Connection is now AwaitingInitialSync, buffering events');
912
1117
  ev.buffer();
@@ -919,19 +1124,49 @@ export const makeChatsSocket = (config) => {
919
1124
  setTimeout(() => ev.flush(), 0);
920
1125
  return;
921
1126
  }
922
- logger.info('History sync is enabled, awaiting notification with a 20s timeout.');
1127
+ // On reconnection (accountSyncCounter > 0), the server does not push
1128
+ // history sync notifications — the device already has its data.
1129
+ // Skip the 20s wait and go online immediately.
1130
+ if (authState.creds.accountSyncCounter > 0) {
1131
+ logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.');
1132
+ syncState = SyncState.Online;
1133
+ setTimeout(() => ev.flush(), 0);
1134
+ return;
1135
+ }
1136
+ logger.info('First connection, awaiting history sync notification with a 20s timeout.');
923
1137
  if (awaitingSyncTimeout) {
924
1138
  clearTimeout(awaitingSyncTimeout);
925
1139
  }
926
1140
  awaitingSyncTimeout = setTimeout(() => {
927
1141
  if (syncState === SyncState.AwaitingInitialSync) {
928
- // TODO: investigate
929
1142
  logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
930
1143
  syncState = SyncState.Online;
931
1144
  ev.flush();
1145
+ // Increment so subsequent reconnections skip the 20s wait.
1146
+ // Late-arriving history is still processed via processMessage
1147
+ // regardless of the state machine phase.
1148
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
1149
+ ev.emit('creds.update', { accountSyncCounter });
932
1150
  }
933
1151
  }, 20000);
934
1152
  });
1153
+ // When an app state sync key arrives (myAppStateKeyId is set) and there are
1154
+ // collections blocked on a missing key, trigger a re-sync for just those collections.
1155
+ // This mirrors WA Web's Blocked → retry-on-key-arrival behavior.
1156
+ ev.on('creds.update', ({ myAppStateKeyId }) => {
1157
+ if (!myAppStateKeyId || blockedCollections.size === 0) {
1158
+ return;
1159
+ }
1160
+ // If we're in the middle of a full sync, doAppStateSync handles all collections
1161
+ if (syncState === SyncState.Syncing) {
1162
+ blockedCollections.clear();
1163
+ return;
1164
+ }
1165
+ const collections = [...blockedCollections];
1166
+ blockedCollections.clear();
1167
+ logger.info({ collections }, 'app state sync key arrived, re-syncing blocked collections');
1168
+ resyncAppState(collections, false).catch(error => onUnexpectedError(error, 'blocked collections resync'));
1169
+ });
935
1170
  ev.on('lid-mapping.update', async ({ lid, pn }) => {
936
1171
  try {
937
1172
  await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
@@ -940,8 +1175,20 @@ export const makeChatsSocket = (config) => {
940
1175
  logger.warn({ lid, pn, error }, 'Failed to store LID-PN mapping');
941
1176
  }
942
1177
  });
1178
+ registerSocketEndHandler(() => {
1179
+ if (awaitingSyncTimeout) {
1180
+ clearTimeout(awaitingSyncTimeout);
1181
+ awaitingSyncTimeout = undefined;
1182
+ }
1183
+ if (!config.placeholderResendCache && placeholderResendCache.close) {
1184
+ placeholderResendCache.close();
1185
+ }
1186
+ syncState = SyncState.Connecting;
1187
+ privacySettings = undefined;
1188
+ });
943
1189
  return {
944
1190
  ...sock,
1191
+ serverProps,
945
1192
  createCallLink,
946
1193
  getBotListV2,
947
1194
  messageMutex,
@@ -978,12 +1225,20 @@ export const makeChatsSocket = (config) => {
978
1225
  cleanDirtyBits,
979
1226
  addOrEditContact,
980
1227
  removeContact,
1228
+ placeholderResendCache,
981
1229
  addLabel,
982
1230
  addChatLabel,
983
1231
  removeChatLabel,
984
1232
  addMessageLabel,
985
1233
  removeMessageLabel,
986
1234
  star,
1235
+ pinChat,
1236
+ archiveChat,
1237
+ muteChat,
1238
+ markChatRead,
1239
+ markChatUnread,
1240
+ clearChat,
1241
+ deleteChat,
987
1242
  addOrEditQuickReply,
988
1243
  removeQuickReply
989
1244
  };
@@ -3,6 +3,22 @@ import type { GroupMetadata, ParticipantAction, SocketConfig, WAMessageKey } fro
3
3
  import { type BinaryNode } from '../WABinary/index.js';
4
4
  export declare const makeGroupsSocket: (config: SocketConfig) => {
5
5
  groupMetadata: (jid: string) => Promise<GroupMetadata>;
6
+ /** groupMetadata con cache de 30s, invalidado automáticamente ante cambios reales de participantes. */
7
+ groupMetadataCached: (jid: string) => Promise<GroupMetadata>;
8
+ /**
9
+ * Resuelve un jid/@lid a su jid de número de teléfono real usando primero los participantes
10
+ * del grupo y, si no hay coincidencia, el mapeo LID↔PN nativo de Baileys (signalRepository).
11
+ * @param jidOrChatId el chatId del grupo, o directamente el array de participantes ya obtenido
12
+ * @param targetJid el jid/lid a resolver
13
+ */
14
+ resolveParticipantJid: (jidOrChatId: string | GroupMetadata["participants"], targetJid: string) => Promise<string>;
15
+ /** true si el participante (jid o @lid) es admin/superadmin del grupo. */
16
+ isGroupAdmin: (jid: string, participantJid: string) => Promise<boolean>;
17
+ /** Lista de admins del grupo ya resueltos a jid de número de teléfono. */
18
+ getGroupAdmins: (jid: string) => Promise<{
19
+ jid: string;
20
+ admin: "admin" | "superadmin" | null;
21
+ }[]>;
6
22
  groupCreate: (subject: string, participants: string[]) => Promise<GroupMetadata>;
7
23
  groupLeave: (id: string) => Promise<void>;
8
24
  groupUpdateSubject: (jid: string, subject: string) => Promise<void>;