@alannxd/baileys 6.0.6 → 6.0.9

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 (220) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +341 -286
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.d.ts +79257 -0
  7. package/WAProto/index.js +205861 -60565
  8. package/engine-requirements.js +1 -1
  9. package/lib/Defaults/index.js +119 -136
  10. package/lib/Signal/Group/ciphertext-message.js +2 -5
  11. package/lib/Signal/Group/group-session-builder.js +7 -41
  12. package/lib/Signal/Group/group_cipher.js +37 -51
  13. package/lib/Signal/Group/index.js +12 -57
  14. package/lib/Signal/Group/keyhelper.js +7 -44
  15. package/lib/Signal/Group/sender-chain-key.js +7 -15
  16. package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
  17. package/lib/Signal/Group/sender-key-message.js +9 -12
  18. package/lib/Signal/Group/sender-key-name.js +2 -5
  19. package/lib/Signal/Group/sender-key-record.js +9 -21
  20. package/lib/Signal/Group/sender-key-state.js +27 -42
  21. package/lib/Signal/Group/sender-message-key.js +4 -7
  22. package/lib/Signal/libsignal.js +347 -90
  23. package/lib/Signal/lid-mapping.js +277 -0
  24. package/lib/Socket/Client/index.js +3 -19
  25. package/lib/Socket/Client/types.js +11 -0
  26. package/lib/Socket/Client/websocket.js +54 -0
  27. package/lib/Socket/business.js +162 -43
  28. package/lib/Socket/chats.js +627 -427
  29. package/lib/Socket/communities.js +90 -80
  30. package/lib/Socket/groups.js +154 -161
  31. package/lib/Socket/index.js +11 -10
  32. package/lib/Socket/luxu.js +315 -469
  33. package/lib/Socket/messages-recv.js +1421 -615
  34. package/lib/Socket/messages-send.js +1150 -799
  35. package/lib/Socket/mex.js +42 -0
  36. package/lib/Socket/newsletter.js +152 -204
  37. package/lib/Socket/socket.js +544 -313
  38. package/lib/Store/index.js +10 -10
  39. package/lib/Store/keyed-db.js +108 -0
  40. package/lib/Store/make-cache-manager-store.js +43 -41
  41. package/lib/Store/make-in-memory-store.js +112 -341
  42. package/lib/Store/make-ordered-dictionary.js +14 -20
  43. package/lib/Store/object-repository.js +11 -6
  44. package/lib/Types/Auth.js +2 -2
  45. package/lib/Types/Bussines.js +2 -0
  46. package/lib/Types/Call.js +2 -2
  47. package/lib/Types/Chat.js +8 -4
  48. package/lib/Types/Contact.js +2 -2
  49. package/lib/Types/Events.js +2 -2
  50. package/lib/Types/GroupMetadata.js +2 -2
  51. package/lib/Types/Label.js +3 -5
  52. package/lib/Types/LabelAssociation.js +3 -5
  53. package/lib/Types/Message.js +11 -9
  54. package/lib/Types/Mex.js +37 -0
  55. package/lib/Types/Product.js +2 -2
  56. package/lib/Types/Signal.js +2 -2
  57. package/lib/Types/Socket.js +3 -2
  58. package/lib/Types/State.js +56 -2
  59. package/lib/Types/USync.js +2 -2
  60. package/lib/Types/index.js +15 -31
  61. package/lib/Utils/auth-utils.js +239 -143
  62. package/lib/Utils/browser-utils.js +48 -0
  63. package/lib/Utils/business.js +66 -69
  64. package/lib/Utils/chat-utils.js +396 -253
  65. package/lib/Utils/companion-reg-client-utils.js +35 -0
  66. package/lib/Utils/crypto.js +57 -90
  67. package/lib/Utils/decode-wa-message.js +236 -84
  68. package/lib/Utils/event-buffer.js +185 -77
  69. package/lib/Utils/generics.js +189 -209
  70. package/lib/Utils/history.js +93 -55
  71. package/lib/Utils/identity-change-handler.js +50 -0
  72. package/lib/Utils/index.js +23 -33
  73. package/lib/Utils/link-preview.js +16 -24
  74. package/lib/Utils/logger.js +3 -7
  75. package/lib/Utils/lt-hash.js +3 -46
  76. package/lib/Utils/make-mutex.js +24 -34
  77. package/lib/Utils/message-composer.js +273 -0
  78. package/lib/Utils/message-retry-manager.js +265 -0
  79. package/lib/Utils/messages-media.js +451 -482
  80. package/lib/Utils/messages.js +795 -369
  81. package/lib/Utils/noise-handler.js +145 -99
  82. package/lib/Utils/offline-node-processor.js +40 -0
  83. package/lib/Utils/pre-key-manager.js +106 -0
  84. package/lib/Utils/process-message.js +459 -150
  85. package/lib/Utils/reporting-utils.js +258 -0
  86. package/lib/Utils/signal.js +120 -72
  87. package/lib/Utils/stanza-ack.js +38 -0
  88. package/lib/Utils/sync-action-utils.js +49 -0
  89. package/lib/Utils/tc-token-utils.js +163 -0
  90. package/lib/Utils/use-multi-file-auth-state.js +29 -27
  91. package/lib/Utils/validate-connection.js +73 -99
  92. package/lib/WABinary/constants.js +1281 -20
  93. package/lib/WABinary/decode.js +52 -42
  94. package/lib/WABinary/encode.js +110 -155
  95. package/lib/WABinary/generic-utils.js +55 -49
  96. package/lib/WABinary/index.js +6 -21
  97. package/lib/WABinary/jid-utils.js +76 -40
  98. package/lib/WABinary/types.js +2 -2
  99. package/lib/WAM/BinaryInfo.js +2 -5
  100. package/lib/WAM/constants.js +19071 -11568
  101. package/lib/WAM/encode.js +17 -22
  102. package/lib/WAM/index.js +4 -19
  103. package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
  104. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
  105. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
  106. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
  107. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  108. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
  109. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
  110. package/lib/WAUSync/Protocols/index.js +6 -20
  111. package/lib/WAUSync/USyncQuery.js +44 -35
  112. package/lib/WAUSync/USyncUser.js +10 -5
  113. package/lib/WAUSync/index.js +4 -19
  114. package/lib/index.js +13 -36
  115. package/package.json +85 -51
  116. package/WAProto/fix-import.js +0 -29
  117. package/lib/Defaults/baileys-version.json +0 -3
  118. package/lib/Defaults/index.d.ts +0 -53
  119. package/lib/Defaults/phonenumber-mcc.json +0 -223
  120. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  121. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  122. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  123. package/lib/Signal/Group/index.d.ts +0 -11
  124. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  125. package/lib/Signal/Group/queue-job.d.ts +0 -1
  126. package/lib/Signal/Group/queue-job.js +0 -57
  127. package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
  128. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
  129. package/lib/Signal/Group/sender-key-message.d.ts +0 -18
  130. package/lib/Signal/Group/sender-key-name.d.ts +0 -17
  131. package/lib/Signal/Group/sender-key-record.d.ts +0 -30
  132. package/lib/Signal/Group/sender-key-state.d.ts +0 -38
  133. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  134. package/lib/Signal/libsignal.d.ts +0 -3
  135. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  136. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  137. package/lib/Socket/Client/index.d.ts +0 -3
  138. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  139. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  140. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  141. package/lib/Socket/Client/web-socket-client.js +0 -62
  142. package/lib/Socket/business.d.ts +0 -171
  143. package/lib/Socket/chats.d.ts +0 -267
  144. package/lib/Socket/communities.d.ts +0 -180
  145. package/lib/Socket/groups.d.ts +0 -115
  146. package/lib/Socket/index.d.ts +0 -173
  147. package/lib/Socket/luxu.d.ts +0 -266
  148. package/lib/Socket/messages-recv.d.ts +0 -161
  149. package/lib/Socket/messages-send.d.ts +0 -183
  150. package/lib/Socket/newsletter.d.ts +0 -134
  151. package/lib/Socket/registration.d.ts +0 -267
  152. package/lib/Socket/registration.js +0 -166
  153. package/lib/Socket/socket.d.ts +0 -44
  154. package/lib/Socket/usync.d.ts +0 -36
  155. package/lib/Socket/usync.js +0 -70
  156. package/lib/Store/index.d.ts +0 -3
  157. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  158. package/lib/Store/make-in-memory-store.d.ts +0 -118
  159. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  160. package/lib/Store/object-repository.d.ts +0 -10
  161. package/lib/Types/Auth.d.ts +0 -110
  162. package/lib/Types/Call.d.ts +0 -13
  163. package/lib/Types/Chat.d.ts +0 -102
  164. package/lib/Types/Contact.d.ts +0 -19
  165. package/lib/Types/Events.d.ts +0 -157
  166. package/lib/Types/GroupMetadata.d.ts +0 -55
  167. package/lib/Types/Label.d.ts +0 -35
  168. package/lib/Types/LabelAssociation.d.ts +0 -29
  169. package/lib/Types/Message.d.ts +0 -273
  170. package/lib/Types/Newsletter.d.ts +0 -103
  171. package/lib/Types/Newsletter.js +0 -38
  172. package/lib/Types/Product.d.ts +0 -78
  173. package/lib/Types/Signal.d.ts +0 -57
  174. package/lib/Types/Socket.d.ts +0 -111
  175. package/lib/Types/State.d.ts +0 -27
  176. package/lib/Types/USync.d.ts +0 -25
  177. package/lib/Types/index.d.ts +0 -57
  178. package/lib/Utils/auth-utils.d.ts +0 -18
  179. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  180. package/lib/Utils/baileys-event-stream.js +0 -63
  181. package/lib/Utils/business.d.ts +0 -22
  182. package/lib/Utils/chat-utils.d.ts +0 -71
  183. package/lib/Utils/crypto.d.ts +0 -41
  184. package/lib/Utils/decode-wa-message.d.ts +0 -19
  185. package/lib/Utils/event-buffer.d.ts +0 -35
  186. package/lib/Utils/generics.d.ts +0 -92
  187. package/lib/Utils/history.d.ts +0 -15
  188. package/lib/Utils/index.d.ts +0 -17
  189. package/lib/Utils/link-preview.d.ts +0 -21
  190. package/lib/Utils/logger.d.ts +0 -4
  191. package/lib/Utils/lt-hash.d.ts +0 -12
  192. package/lib/Utils/make-mutex.d.ts +0 -7
  193. package/lib/Utils/messages-media.d.ts +0 -116
  194. package/lib/Utils/messages.d.ts +0 -77
  195. package/lib/Utils/noise-handler.d.ts +0 -21
  196. package/lib/Utils/process-message.d.ts +0 -41
  197. package/lib/Utils/signal.d.ts +0 -32
  198. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  199. package/lib/Utils/validate-connection.d.ts +0 -11
  200. package/lib/WABinary/constants.d.ts +0 -30
  201. package/lib/WABinary/decode.d.ts +0 -7
  202. package/lib/WABinary/encode.d.ts +0 -3
  203. package/lib/WABinary/generic-utils.d.ts +0 -17
  204. package/lib/WABinary/index.d.ts +0 -5
  205. package/lib/WABinary/jid-utils.d.ts +0 -31
  206. package/lib/WABinary/types.d.ts +0 -18
  207. package/lib/WAM/BinaryInfo.d.ts +0 -17
  208. package/lib/WAM/constants.d.ts +0 -38
  209. package/lib/WAM/encode.d.ts +0 -3
  210. package/lib/WAM/index.d.ts +0 -3
  211. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  212. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  213. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  214. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  215. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  216. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  217. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  218. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  219. package/lib/WAUSync/USyncUser.d.ts +0 -12
  220. package/lib/index.d.ts +0 -12
@@ -1,30 +1,56 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.makeChatsSocket = void 0;
7
- const boom_1 = require("@hapi/boom");
8
- const WAProto_1 = require("../../WAProto");
9
- const Defaults_1 = require("../Defaults");
10
- const Types_1 = require("../Types");
11
- const Utils_1 = require("../Utils");
12
- const make_mutex_1 = require("../Utils/make-mutex");
13
- const process_message_1 = __importDefault(require("../Utils/process-message"));
14
- const WABinary_1 = require("../WABinary");
15
- const socket_1 = require("./socket");
16
- const WAUSync_1 = require("../WAUSync");
17
- const usync_1 = require("./usync");
18
- const MAX_SYNC_ATTEMPTS = 2;
19
- const makeChatsSocket = (config) => {
20
- const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, } = config;
21
- const sock = (0, usync_1.makeUSyncSocket)(config);
22
- const { ev, ws, authState, generateMessageTag, sendNode, query, onUnexpectedError, } = sock;
1
+ import NodeCache from '@cacheable/node-cache';
2
+ import { Boom } from '@hapi/boom';
3
+ import { proto } from '../../WAProto/index.js';
4
+ import { DEFAULT_CACHE_TTLS, HISTORY_SYNC_PAUSED_TIMEOUT_MS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
5
+ import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
6
+ import { SyncState } from '../Types/State.js';
7
+ import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, ensureLTHashStateVersion, extractSyncdPatches, generateProfilePicture, getHistoryMsg, isAppStateSyncIrrecoverable, isMissingKeyError, MAX_SYNC_ATTEMPTS, newLTHashState, processSyncAction } from '../Utils/index.js';
8
+ import { makeMutex } from '../Utils/make-mutex.js';
9
+ import processMessage from '../Utils/process-message.js';
10
+ import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
11
+ import { getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
12
+ import { USyncQuery, USyncUser } from '../WAUSync/index.js';
13
+ import { makeSocket } from './socket.js';
14
+ export const makeChatsSocket = (config) => {
15
+ const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
16
+ const sock = makeSocket(config);
17
+ const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession, registerSocketEndHandler } = sock;
18
+ const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
23
19
  let privacySettings;
24
- let needToFlushWithAppStateSync = false;
25
- let pendingAppStateSync = false;
26
- /** this mutex ensures that the notifications (receipts, messages etc.) are processed in order */
27
- const processingMutex = (0, make_mutex_1.makeMutex)();
20
+ /** Server-assigned AB props for protocol behavior. */
21
+ const serverProps = {
22
+ /** AB prop 10518: gate tctoken on 1:1 messages. Default true (safe: avoids 463). */
23
+ privacyTokenOn1to1: true,
24
+ /** AB prop 9666: gate tctoken on profile picture IQs. WA Web default: true. */
25
+ profilePicPrivacyToken: true,
26
+ /** AB prop 14303: issue tctokens to LID instead of PN. WA Web default: false. */
27
+ lidTrustedTokenIssueToLid: false
28
+ };
29
+ let syncState = SyncState.Connecting;
30
+ /** this mutex ensures that messages are processed in order */
31
+ const messageMutex = makeMutex();
32
+ /** this mutex ensures that receipts are processed in order */
33
+ const receiptMutex = makeMutex();
34
+ /** this mutex ensures that app state patches are processed in order */
35
+ const appStatePatchMutex = makeMutex();
36
+ /** this mutex ensures that notifications are processed in order */
37
+ const notificationMutex = makeMutex();
38
+ // Timeout for AwaitingInitialSync state
39
+ let awaitingSyncTimeout;
40
+ // In-memory history sync completion tracking (resets on reconnection)
41
+ const historySyncStatus = {
42
+ initialBootstrapComplete: false,
43
+ recentSyncComplete: false
44
+ };
45
+ let historySyncPausedTimeout;
46
+ // Collections blocked on missing app state sync keys (mirrors WA Web's "Blocked" state).
47
+ // When a key arrives via APP_STATE_SYNC_KEY_SHARE, these are re-synced.
48
+ const blockedCollections = new Set();
49
+ const placeholderResendCache = config.placeholderResendCache ||
50
+ new NodeCache({
51
+ stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
52
+ useClones: false
53
+ });
28
54
  /** helper function to fetch the given app state sync key */
29
55
  const getAppStateSyncKey = async (keyId) => {
30
56
  const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
@@ -36,14 +62,12 @@ const makeChatsSocket = (config) => {
36
62
  tag: 'iq',
37
63
  attrs: {
38
64
  xmlns: 'privacy',
39
- to: WABinary_1.S_WHATSAPP_NET,
65
+ to: S_WHATSAPP_NET,
40
66
  type: 'get'
41
67
  },
42
- content: [
43
- { tag: 'privacy', attrs: {} }
44
- ]
68
+ content: [{ tag: 'privacy', attrs: {} }]
45
69
  });
46
- privacySettings = (0, WABinary_1.reduceBinaryNodeToDictionary)(content === null || content === void 0 ? void 0 : content[0], 'category');
70
+ privacySettings = reduceBinaryNodeToDictionary(content?.[0], 'category');
47
71
  }
48
72
  return privacySettings;
49
73
  };
@@ -53,10 +77,11 @@ const makeChatsSocket = (config) => {
53
77
  tag: 'iq',
54
78
  attrs: {
55
79
  xmlns: 'privacy',
56
- to: WABinary_1.S_WHATSAPP_NET,
80
+ to: S_WHATSAPP_NET,
57
81
  type: 'set'
58
82
  },
59
- content: [{
83
+ content: [
84
+ {
60
85
  tag: 'privacy',
61
86
  attrs: {},
62
87
  content: [
@@ -65,9 +90,16 @@ const makeChatsSocket = (config) => {
65
90
  attrs: { name, value }
66
91
  }
67
92
  ]
68
- }]
93
+ }
94
+ ]
69
95
  });
70
96
  };
97
+ const updateMessagesPrivacy = async (value) => {
98
+ await privacyQuery('messages', value);
99
+ };
100
+ const updateCallPrivacy = async (value) => {
101
+ await privacyQuery('calladd', value);
102
+ };
71
103
  const updateLastSeenPrivacy = async (value) => {
72
104
  await privacyQuery('last', value);
73
105
  };
@@ -86,259 +118,95 @@ const makeChatsSocket = (config) => {
86
118
  const updateGroupsAddPrivacy = async (value) => {
87
119
  await privacyQuery('groupadd', value);
88
120
  };
89
- /** check whether your WhatsApp account is blocked or not */
90
- const checkStatusWA = async (phoneNumber) => {
91
- if (!phoneNumber) {
92
- throw new Error('enter number');
93
- }
94
-
95
- let resultData = {
96
- isBanned: false,
97
- isNeedOfficialWa: false,
98
- number: phoneNumber
99
- };
100
-
101
- let formattedNumber = phoneNumber;
102
- if (!formattedNumber.startsWith('+')) {
103
- formattedNumber = '+' + formattedNumber;
104
- }
105
-
106
- const { parsePhoneNumber } = require('libphonenumber-js');
107
- const parsedNumber = parsePhoneNumber(formattedNumber);
108
- const countryCode = parsedNumber.countryCallingCode;
109
- const nationalNumber = parsedNumber.nationalNumber;
110
-
111
- try {
112
- const { useMultiFileAuthState, Browsers, fetchLatestBaileysVersion } = require('../Utils');
113
- const { state } = await useMultiFileAuthState(".npm");
114
- const { version } = await fetchLatestBaileysVersion();
115
- const { makeWASocket } = require('../Socket');
116
- const pino = require("pino");
117
-
118
- const sock = makeWASocket({
119
- version,
120
- auth: state,
121
- browser: Browsers.ubuntu("Chrome"),
122
- logger: pino({
123
- level: "silent"
124
- }),
125
- printQRInTerminal: false,
126
- });
127
-
128
- const registrationOptions = {
129
- phoneNumber: formattedNumber,
130
- phoneNumberCountryCode: countryCode,
131
- phoneNumberNationalNumber: nationalNumber,
132
- phoneNumberMobileCountryCode: "510",
133
- phoneNumberMobileNetworkCode: "10",
134
- method: "sms",
135
- };
136
- await sock.requestRegistrationCode(registrationOptions);
137
- if (sock.ws) {
138
- sock.ws.close();
139
- }
140
-
141
- return JSON.stringify(resultData, null, 2);
142
- } catch (err) {
143
- if (err?.appeal_token) {
144
- resultData.isBanned = true;
145
- resultData.data = {
146
- violation_type: err.violation_type || null,
147
- in_app_ban_appeal: err.in_app_ban_appeal || null,
148
- appeal_token: err.appeal_token || null,
149
- };
150
- }
151
- else if (err?.custom_block_screen || err?.reason === 'blocked') {
152
- resultData.isNeedOfficialWa = true;
153
- }
154
- return JSON.stringify(resultData, null, 2);
155
- }
156
- };
157
121
  const updateDefaultDisappearingMode = async (duration) => {
158
122
  await query({
159
123
  tag: 'iq',
160
124
  attrs: {
161
125
  xmlns: 'disappearing_mode',
162
- to: WABinary_1.S_WHATSAPP_NET,
126
+ to: S_WHATSAPP_NET,
163
127
  type: 'set'
164
128
  },
165
- content: [{
129
+ content: [
130
+ {
166
131
  tag: 'disappearing_mode',
167
132
  attrs: {
168
133
  duration: duration.toString()
169
134
  }
170
- }]
135
+ }
136
+ ]
171
137
  });
172
138
  };
173
- /** helper function to run a generic IQ query */
174
- const interactiveQuery = async (userNodes, queryNode) => {
175
- const result = await query({
139
+ const getBotListV2 = async () => {
140
+ const resp = await query({
176
141
  tag: 'iq',
177
142
  attrs: {
178
- to: WABinary_1.S_WHATSAPP_NET,
179
- type: 'get',
180
- xmlns: 'usync',
143
+ xmlns: 'bot',
144
+ to: S_WHATSAPP_NET,
145
+ type: 'get'
181
146
  },
182
147
  content: [
183
148
  {
184
- tag: 'usync',
149
+ tag: 'bot',
185
150
  attrs: {
186
- sid: generateMessageTag(),
187
- mode: 'query',
188
- last: 'true',
189
- index: '0',
190
- context: 'interactive',
191
- },
192
- content: [
193
- {
194
- tag: 'query',
195
- attrs: {},
196
- content: [queryNode]
197
- },
198
- {
199
- tag: 'list',
200
- attrs: {},
201
- content: userNodes
202
- }
203
- ]
151
+ v: '2'
152
+ }
204
153
  }
205
- ],
206
- });
207
- const usyncNode = (0, WABinary_1.getBinaryNodeChild)(result, 'usync');
208
- const listNode = (0, WABinary_1.getBinaryNodeChild)(usyncNode, 'list');
209
- const users = (0, WABinary_1.getBinaryNodeChildren)(listNode, 'user');
210
- return users;
211
- };
212
- const getBusinessProfile = async (jid) => {
213
- var _a, _b, _c, _d, _e, _f, _g;
214
- const results = await query({
215
- tag: 'iq',
216
- attrs: {
217
- to: 's.whatsapp.net',
218
- xmlns: 'w:biz',
219
- type: 'get'
220
- },
221
- content: [{
222
- tag: 'business_profile',
223
- attrs: { v: '244' },
224
- content: [{
225
- tag: 'profile',
226
- attrs: { jid }
227
- }]
228
- }]
154
+ ]
229
155
  });
230
- const profileNode = (0, WABinary_1.getBinaryNodeChild)(results, 'business_profile');
231
- const profiles = (0, WABinary_1.getBinaryNodeChild)(profileNode, 'profile');
232
- if (profiles) {
233
- const address = (0, WABinary_1.getBinaryNodeChild)(profiles, 'address');
234
- const description = (0, WABinary_1.getBinaryNodeChild)(profiles, 'description');
235
- const website = (0, WABinary_1.getBinaryNodeChild)(profiles, 'website');
236
- const email = (0, WABinary_1.getBinaryNodeChild)(profiles, 'email');
237
- const category = (0, WABinary_1.getBinaryNodeChild)((0, WABinary_1.getBinaryNodeChild)(profiles, 'categories'), 'category');
238
- const businessHours = (0, WABinary_1.getBinaryNodeChild)(profiles, 'business_hours');
239
- const businessHoursConfig = businessHours ?
240
- (0, WABinary_1.getBinaryNodeChildren)(businessHours, 'business_hours_config') :
241
- undefined;
242
- const websiteStr = (_a = website === null || website === void 0 ? void 0 : website.content) === null || _a === void 0 ? void 0 : _a.toString();
243
- return {
244
- wid: (_b = profiles.attrs) === null || _b === void 0 ? void 0 : _b.jid,
245
- address: (_c = address === null || address === void 0 ? void 0 : address.content) === null || _c === void 0 ? void 0 : _c.toString(),
246
- description: ((_d = description === null || description === void 0 ? void 0 : description.content) === null || _d === void 0 ? void 0 : _d.toString()) || '',
247
- website: websiteStr ? [websiteStr] : [],
248
- email: (_e = email === null || email === void 0 ? void 0 : email.content) === null || _e === void 0 ? void 0 : _e.toString(),
249
- category: (_f = category === null || category === void 0 ? void 0 : category.content) === null || _f === void 0 ? void 0 : _f.toString(),
250
- 'business_hours': {
251
- timezone: (_g = businessHours === null || businessHours === void 0 ? void 0 : businessHours.attrs) === null || _g === void 0 ? void 0 : _g.timezone,
252
- 'business_config': businessHoursConfig === null || businessHoursConfig === void 0 ? void 0 : businessHoursConfig.map(({ attrs }) => attrs)
156
+ const botNode = getBinaryNodeChild(resp, 'bot');
157
+ const botList = [];
158
+ for (const section of getBinaryNodeChildren(botNode, 'section')) {
159
+ if (section.attrs.type === 'all') {
160
+ for (const bot of getBinaryNodeChildren(section, 'bot')) {
161
+ botList.push({
162
+ jid: bot.attrs.jid,
163
+ personaId: bot.attrs['persona_id']
164
+ });
253
165
  }
254
- };
166
+ }
255
167
  }
168
+ return botList;
256
169
  };
257
- const onWhatsApp = async (...jids) => {
258
- const usyncQuery = new WAUSync_1.USyncQuery()
259
- .withContactProtocol()
260
- .withLIDProtocol();
261
-
170
+ const fetchStatus = async (...jids) => {
171
+ const usyncQuery = new USyncQuery().withStatusProtocol();
262
172
  for (const jid of jids) {
263
- const phone = `+${jid.replace('+', '').split('@')[0].split(':')[0]}`;
264
- usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone));
265
- }
266
-
267
- const results = await sock.executeUSyncQuery(usyncQuery);
268
- if (results) {
269
- const verifiedResults = await Promise.all(
270
- results.list
271
- .filter((a) => !!a.contact)
272
- .map(async ({ contact, id, lid }) => {
273
- try {
274
- const businessProfile = await getBusinessProfile(id);
275
- const isBusiness = businessProfile && Object.keys(businessProfile).length > 0;
276
- if (isBusiness) {
277
- const { wid, ...businessInfo } = businessProfile;
278
-
279
- return {
280
- jid: id,
281
- exists: true,
282
- lid: lid,
283
- status: 'business',
284
- businessInfo: businessInfo
285
- };
286
- } else {
287
- return {
288
- jid: id,
289
- exists: true,
290
- lid: lid,
291
- status: 'regular'
292
- };
293
- }
294
- } catch (error) {
295
- return {
296
- jid: id,
297
- exists: true,
298
- lid: lid,
299
- status: error
300
- };
301
- }
302
- })
303
- );
304
- return verifiedResults;
305
- }
306
- };
307
- const toLid = async (jid) => {
308
- const result = await onWhatsApp(jid);
309
- let lidResult = result[0].lid;
310
- if (!result[0].exist) {
311
- lidResult = jid + "doesnt exist";
312
- }
313
- return lidResult
314
- }
315
- const fetchStatus = async (jid) => {
316
- const [result] = await interactiveQuery([{ tag: 'user', attrs: { jid } }], { tag: 'status', attrs: {} });
173
+ usyncQuery.withUser(new USyncUser().withId(jid));
174
+ }
175
+ const result = await sock.executeUSyncQuery(usyncQuery);
317
176
  if (result) {
318
- const status = (0, WABinary_1.getBinaryNodeChild)(result, 'status');
319
- return {
320
- status: status === null || status === void 0 ? void 0 : status.content.toString(),
321
- setAt: new Date(+((status === null || status === void 0 ? void 0 : status.attrs.t) || 0) * 1000)
322
- };
177
+ return result.list;
178
+ }
179
+ };
180
+ const fetchDisappearingDuration = async (...jids) => {
181
+ const usyncQuery = new USyncQuery().withDisappearingModeProtocol();
182
+ for (const jid of jids) {
183
+ usyncQuery.withUser(new USyncUser().withId(jid));
184
+ }
185
+ const result = await sock.executeUSyncQuery(usyncQuery);
186
+ if (result) {
187
+ return result.list;
323
188
  }
324
189
  };
325
190
  /** update the profile picture for yourself or a group */
326
- const updateProfilePicture = async (jid, content) => {
191
+ const updateProfilePicture = async (jid, content, dimensions) => {
327
192
  let targetJid;
328
193
  if (!jid) {
329
- throw new boom_1.Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
194
+ throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
330
195
  }
331
- if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
332
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
196
+ if (jidNormalizedUser(jid) !== jidNormalizedUser(authState.creds.me.id)) {
197
+ targetJid = jidNormalizedUser(jid); // in case it is someone other than us
333
198
  }
334
- const { img } = await (0, Utils_1.generateProfilePicture)(content);
199
+ else {
200
+ targetJid = undefined;
201
+ }
202
+ const { img } = await generateProfilePicture(content, dimensions);
335
203
  await query({
336
204
  tag: 'iq',
337
205
  attrs: {
338
- target: targetJid,
339
- to: WABinary_1.S_WHATSAPP_NET,
206
+ to: S_WHATSAPP_NET,
340
207
  type: 'set',
341
- xmlns: 'w:profile:picture'
208
+ xmlns: 'w:profile:picture',
209
+ ...(targetJid ? { target: targetJid } : {})
342
210
  },
343
211
  content: [
344
212
  {
@@ -353,18 +221,21 @@ const makeChatsSocket = (config) => {
353
221
  const removeProfilePicture = async (jid) => {
354
222
  let targetJid;
355
223
  if (!jid) {
356
- throw new boom_1.Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
224
+ throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
357
225
  }
358
- if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
359
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
226
+ if (jidNormalizedUser(jid) !== jidNormalizedUser(authState.creds.me.id)) {
227
+ targetJid = jidNormalizedUser(jid); // in case it is someone other than us
228
+ }
229
+ else {
230
+ targetJid = undefined;
360
231
  }
361
232
  await query({
362
233
  tag: 'iq',
363
234
  attrs: {
364
- target: targetJid,
365
- to: WABinary_1.S_WHATSAPP_NET,
235
+ to: S_WHATSAPP_NET,
366
236
  type: 'set',
367
- xmlns: 'w:profile:picture'
237
+ xmlns: 'w:profile:picture',
238
+ ...(targetJid ? { target: targetJid } : {})
368
239
  }
369
240
  });
370
241
  };
@@ -373,7 +244,7 @@ const makeChatsSocket = (config) => {
373
244
  await query({
374
245
  tag: 'iq',
375
246
  attrs: {
376
- to: WABinary_1.S_WHATSAPP_NET,
247
+ to: S_WHATSAPP_NET,
377
248
  type: 'set',
378
249
  xmlns: 'status'
379
250
  },
@@ -394,49 +265,129 @@ const makeChatsSocket = (config) => {
394
265
  tag: 'iq',
395
266
  attrs: {
396
267
  xmlns: 'blocklist',
397
- to: WABinary_1.S_WHATSAPP_NET,
268
+ to: S_WHATSAPP_NET,
398
269
  type: 'get'
399
270
  }
400
271
  });
401
- const listNode = (0, WABinary_1.getBinaryNodeChild)(result, 'list');
402
- return (0, WABinary_1.getBinaryNodeChildren)(listNode, 'item')
403
- .map(n => n.attrs.jid);
272
+ const listNode = getBinaryNodeChild(result, 'list');
273
+ return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
404
274
  };
405
275
  const updateBlockStatus = async (jid, action) => {
276
+ const normalizedJid = jidNormalizedUser(jid);
277
+ let lid;
278
+ let pn_jid;
279
+ if (isLidUser(normalizedJid) || isHostedLidUser(normalizedJid)) {
280
+ lid = normalizedJid;
281
+ if (action === 'block') {
282
+ const pn = await signalRepository.lidMapping.getPNForLID(normalizedJid);
283
+ if (!pn) {
284
+ throw new Boom(`Unable to resolve PN JID for LID: ${jid}`, { statusCode: 400 });
285
+ }
286
+ pn_jid = jidNormalizedUser(pn);
287
+ }
288
+ }
289
+ else if (isPnUser(normalizedJid) || isHostedPnUser(normalizedJid)) {
290
+ const mapped = await signalRepository.lidMapping.getLIDForPN(normalizedJid);
291
+ if (!mapped) {
292
+ throw new Boom(`Unable to resolve LID for PN JID: ${jid}`, { statusCode: 400 });
293
+ }
294
+ lid = mapped;
295
+ if (action === 'block') {
296
+ pn_jid = jidNormalizedUser(normalizedJid);
297
+ }
298
+ }
299
+ else {
300
+ throw new Boom(`Invalid jid: ${jid}`, { statusCode: 400 });
301
+ }
302
+ const itemAttrs = {
303
+ action,
304
+ jid: lid
305
+ };
306
+ if (action === 'block') {
307
+ if (!pn_jid) {
308
+ throw new Boom(`pn_jid required for block: ${jid}`, { statusCode: 400 });
309
+ }
310
+ itemAttrs.pn_jid = pn_jid;
311
+ }
406
312
  await query({
407
313
  tag: 'iq',
408
314
  attrs: {
409
315
  xmlns: 'blocklist',
410
- to: WABinary_1.S_WHATSAPP_NET,
316
+ to: S_WHATSAPP_NET,
411
317
  type: 'set'
412
318
  },
413
319
  content: [
414
320
  {
415
321
  tag: 'item',
416
- attrs: {
417
- action,
418
- jid
419
- }
322
+ attrs: itemAttrs
323
+ }
324
+ ]
325
+ });
326
+ };
327
+ const getBusinessProfile = async (jid) => {
328
+ const results = await query({
329
+ tag: 'iq',
330
+ attrs: {
331
+ to: 's.whatsapp.net',
332
+ xmlns: 'w:biz',
333
+ type: 'get'
334
+ },
335
+ content: [
336
+ {
337
+ tag: 'business_profile',
338
+ attrs: { v: '244' },
339
+ content: [
340
+ {
341
+ tag: 'profile',
342
+ attrs: { jid }
343
+ }
344
+ ]
420
345
  }
421
346
  ]
422
347
  });
348
+ const profileNode = getBinaryNodeChild(results, 'business_profile');
349
+ const profiles = getBinaryNodeChild(profileNode, 'profile');
350
+ if (profiles) {
351
+ const address = getBinaryNodeChild(profiles, 'address');
352
+ const description = getBinaryNodeChild(profiles, 'description');
353
+ const website = getBinaryNodeChild(profiles, 'website');
354
+ const email = getBinaryNodeChild(profiles, 'email');
355
+ const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category');
356
+ const businessHours = getBinaryNodeChild(profiles, 'business_hours');
357
+ const businessHoursConfig = businessHours
358
+ ? getBinaryNodeChildren(businessHours, 'business_hours_config')
359
+ : undefined;
360
+ const websiteStr = website?.content?.toString();
361
+ return {
362
+ wid: profiles.attrs?.jid,
363
+ address: address?.content?.toString(),
364
+ description: description?.content?.toString() || '',
365
+ website: websiteStr ? [websiteStr] : [],
366
+ email: email?.content?.toString(),
367
+ category: category?.content?.toString(),
368
+ business_hours: {
369
+ timezone: businessHours?.attrs?.timezone,
370
+ business_config: businessHoursConfig?.map(({ attrs }) => attrs)
371
+ }
372
+ };
373
+ }
423
374
  };
424
375
  const cleanDirtyBits = async (type, fromTimestamp) => {
425
376
  logger.info({ fromTimestamp }, 'clean dirty bits ' + type);
426
377
  await sendNode({
427
378
  tag: 'iq',
428
379
  attrs: {
429
- to: WABinary_1.S_WHATSAPP_NET,
380
+ to: S_WHATSAPP_NET,
430
381
  type: 'set',
431
382
  xmlns: 'urn:xmpp:whatsapp:dirty',
432
- id: generateMessageTag(),
383
+ id: generateMessageTag()
433
384
  },
434
385
  content: [
435
386
  {
436
387
  tag: 'clean',
437
388
  attrs: {
438
389
  type,
439
- ...(fromTimestamp ? { timestamp: fromTimestamp.toString() } : null),
390
+ ...(fromTimestamp ? { timestamp: fromTimestamp.toString() } : null)
440
391
  }
441
392
  }
442
393
  ]
@@ -445,20 +396,31 @@ const makeChatsSocket = (config) => {
445
396
  const newAppStateChunkHandler = (isInitialSync) => {
446
397
  return {
447
398
  onMutation(mutation) {
448
- (0, Utils_1.processSyncAction)(mutation, ev, authState.creds.me, isInitialSync ? { accountSettings: authState.creds.accountSettings } : undefined, logger);
399
+ processSyncAction(mutation, ev, authState.creds.me, isInitialSync ? { accountSettings: authState.creds.accountSettings } : undefined, logger);
449
400
  }
450
401
  };
451
402
  };
452
403
  const resyncAppState = ev.createBufferedFunction(async (collections, isInitialSync) => {
404
+ const appStateSyncKeyCache = new Map();
405
+ const getCachedAppStateSyncKey = async (keyId) => {
406
+ if (appStateSyncKeyCache.has(keyId)) {
407
+ return appStateSyncKeyCache.get(keyId) ?? undefined;
408
+ }
409
+ const key = await getAppStateSyncKey(keyId);
410
+ appStateSyncKeyCache.set(keyId, key ?? null);
411
+ return key;
412
+ };
453
413
  // we use this to determine which events to fire
454
414
  // otherwise when we resync from scratch -- all notifications will fire
455
415
  const initialVersionMap = {};
456
416
  const globalMutationMap = {};
457
417
  await authState.keys.transaction(async () => {
458
- var _a;
459
418
  const collectionsToHandle = new Set(collections);
460
419
  // in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
461
420
  const attemptsMap = {};
421
+ // collections that failed and need a full snapshot on retry
422
+ // mirrors WA Web's ErrorFatal -> force snapshot behavior
423
+ const forceSnapshotCollections = new Set();
462
424
  // keep executing till all collections are done
463
425
  // sometimes a single patch request will not return all the patches (God knows why)
464
426
  // so we fetch till they're all done (this is determined by the "has_more_patches" flag)
@@ -469,29 +431,34 @@ const makeChatsSocket = (config) => {
469
431
  const result = await authState.keys.get('app-state-sync-version', [name]);
470
432
  let state = result[name];
471
433
  if (state) {
434
+ state = ensureLTHashStateVersion(state);
472
435
  if (typeof initialVersionMap[name] === 'undefined') {
473
436
  initialVersionMap[name] = state.version;
474
437
  }
475
438
  }
476
439
  else {
477
- state = (0, Utils_1.newLTHashState)();
440
+ state = newLTHashState();
478
441
  }
479
442
  states[name] = state;
480
- logger.info(`resyncing ${name} from v${state.version}`);
443
+ const shouldForceSnapshot = forceSnapshotCollections.has(name);
444
+ if (shouldForceSnapshot) {
445
+ forceSnapshotCollections.delete(name);
446
+ }
447
+ logger.info(`resyncing ${name} from v${state.version}${shouldForceSnapshot ? ' (forcing snapshot)' : ''}`);
481
448
  nodes.push({
482
449
  tag: 'collection',
483
450
  attrs: {
484
451
  name,
485
452
  version: state.version.toString(),
486
- // return snapshot if being synced from scratch
487
- 'return_snapshot': (!state.version).toString()
453
+ // return snapshot if syncing from scratch or forcing after a failed attempt
454
+ return_snapshot: (shouldForceSnapshot || !state.version).toString()
488
455
  }
489
456
  });
490
457
  }
491
458
  const result = await query({
492
459
  tag: 'iq',
493
460
  attrs: {
494
- to: WABinary_1.S_WHATSAPP_NET,
461
+ to: S_WHATSAPP_NET,
495
462
  xmlns: 'w:sync:app:state',
496
463
  type: 'set'
497
464
  },
@@ -504,26 +471,22 @@ const makeChatsSocket = (config) => {
504
471
  ]
505
472
  });
506
473
  // extract from binary node
507
- const decoded = await (0, Utils_1.extractSyncdPatches)(result, config === null || config === void 0 ? void 0 : config.options);
474
+ const decoded = await extractSyncdPatches(result, config?.options);
508
475
  for (const key in decoded) {
509
476
  const name = key;
510
477
  const { patches, hasMorePatches, snapshot } = decoded[name];
511
478
  try {
512
479
  if (snapshot) {
513
- const { state: newState, mutationMap } = await (0, Utils_1.decodeSyncdSnapshot)(name, snapshot, getAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
480
+ const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot, logger);
514
481
  states[name] = newState;
515
482
  Object.assign(globalMutationMap, mutationMap);
516
483
  logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
517
- await authState.keys.set({ 'app-state-sync-version': {
518
- [name]: newState
519
- } });
484
+ await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
520
485
  }
521
486
  // only process if there are syncd patches
522
487
  if (patches.length) {
523
- const { state: newState, mutationMap } = await (0, Utils_1.decodePatches)(name, patches, states[name], getAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
524
- await authState.keys.set({ 'app-state-sync-version': {
525
- [name]: newState
526
- } });
488
+ const { state: newState, mutationMap } = await decodePatches(name, patches, states[name], getCachedAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
489
+ await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
527
490
  logger.info(`synced ${name} to v${newState.version}`);
528
491
  initialVersionMap[name] = newState.version;
529
492
  Object.assign(globalMutationMap, mutationMap);
@@ -531,30 +494,47 @@ const makeChatsSocket = (config) => {
531
494
  if (hasMorePatches) {
532
495
  logger.info(`${name} has more patches...`);
533
496
  }
534
- else { // collection is done with sync
497
+ else {
498
+ // collection is done with sync
535
499
  collectionsToHandle.delete(name);
536
500
  }
537
501
  }
538
502
  catch (error) {
539
- // if retry attempts overshoot
540
- // or key not found
541
- const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
542
- ((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 404 ||
543
- error.name === 'TypeError';
544
- logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
545
- await authState.keys.set({ 'app-state-sync-version': {
546
- [name]: null
547
- } });
548
- // increment number of retries
549
503
  attemptsMap[name] = (attemptsMap[name] || 0) + 1;
550
- if (isIrrecoverableError) {
551
- // stop retrying
504
+ const logData = {
505
+ name,
506
+ attempt: attemptsMap[name],
507
+ version: states[name].version,
508
+ statusCode: error.output?.statusCode,
509
+ errorType: error.name,
510
+ error: error.stack
511
+ };
512
+ if (isMissingKeyError(error) && attemptsMap[name] >= MAX_SYNC_ATTEMPTS) {
513
+ // WA Web treats missing keys as "Blocked" — park the collection
514
+ // until the key arrives via APP_STATE_SYNC_KEY_SHARE.
515
+ logger.warn(logData, `${name} blocked on missing key from v${states[name].version}, parking after ${attemptsMap[name]} attempts`);
516
+ blockedCollections.add(name);
517
+ collectionsToHandle.delete(name);
518
+ }
519
+ else if (isMissingKeyError(error)) {
520
+ // Retry with a snapshot which may use a different key.
521
+ logger.info(logData, `${name} blocked on missing key from v${states[name].version}, retrying with snapshot`);
522
+ forceSnapshotCollections.add(name);
523
+ }
524
+ else if (isAppStateSyncIrrecoverable(error, attemptsMap[name])) {
525
+ logger.warn(logData, `failed to sync ${name} from v${states[name].version}, giving up`);
552
526
  collectionsToHandle.delete(name);
553
527
  }
528
+ else {
529
+ logger.info(logData, `failed to sync ${name} from v${states[name].version}, forcing snapshot retry`);
530
+ // force a full snapshot on retry to recover from
531
+ // corrupted local state (e.g. LTHash MAC mismatch)
532
+ forceSnapshotCollections.add(name);
533
+ }
554
534
  }
555
535
  }
556
536
  }
557
- });
537
+ }, authState?.creds?.me?.id || 'resync-app-state');
558
538
  const { onMutation } = newAppStateChunkHandler(isInitialSync);
559
539
  for (const key in globalMutationMap) {
560
540
  onMutation(globalMutationMap[key]);
@@ -566,47 +546,83 @@ const makeChatsSocket = (config) => {
566
546
  * type = "image for the high res picture"
567
547
  */
568
548
  const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
569
- var _a;
570
- jid = (0, WABinary_1.jidNormalizedUser)(jid);
549
+ const baseContent = [{ tag: 'picture', attrs: { type, query: 'url' } }];
550
+ // WA Web only includes tctoken for user JIDs (not groups/newsletters)
551
+ // and never for own profile pic (Chat model for self has no tcToken).
552
+ // Including tctoken for own JID causes the server to never respond.
553
+ const normalizedJid = jidNormalizedUser(jid);
554
+ const isUserJid = isPnUser(normalizedJid) || isLidUser(normalizedJid);
555
+ const me = authState.creds.me;
556
+ const isSelf = me && (normalizedJid === jidNormalizedUser(me.id) || (me.lid && normalizedJid === jidNormalizedUser(me.lid)));
557
+ let content = baseContent;
558
+ if (serverProps.profilePicPrivacyToken && isUserJid && !isSelf) {
559
+ content = await buildTcTokenFromJid({
560
+ authState,
561
+ jid: normalizedJid,
562
+ baseContent,
563
+ getLIDForPN
564
+ });
565
+ }
566
+ jid = jidNormalizedUser(jid);
571
567
  const result = await query({
572
568
  tag: 'iq',
573
569
  attrs: {
574
570
  target: jid,
575
- to: WABinary_1.S_WHATSAPP_NET,
571
+ to: S_WHATSAPP_NET,
576
572
  type: 'get',
577
573
  xmlns: 'w:profile:picture'
578
574
  },
575
+ content
576
+ }, timeoutMs);
577
+ const child = getBinaryNodeChild(result, 'picture');
578
+ return child?.attrs?.url;
579
+ };
580
+ const createCallLink = async (type, event, timeoutMs) => {
581
+ const result = await query({
582
+ tag: 'call',
583
+ attrs: {
584
+ id: generateMessageTag(),
585
+ to: '@call'
586
+ },
579
587
  content: [
580
- { tag: 'picture', attrs: { type, query: 'url' } }
588
+ {
589
+ tag: 'link_create',
590
+ attrs: { media: type },
591
+ content: event ? [{ tag: 'event', attrs: { start_time: String(event.startTime) } }] : undefined
592
+ }
581
593
  ]
582
594
  }, timeoutMs);
583
- const child = (0, WABinary_1.getBinaryNodeChild)(result, 'picture');
584
- return (_a = child === null || child === void 0 ? void 0 : child.attrs) === null || _a === void 0 ? void 0 : _a.url;
595
+ const child = getBinaryNodeChild(result, 'link_create');
596
+ return child?.attrs?.token;
585
597
  };
586
598
  const sendPresenceUpdate = async (type, toJid) => {
587
599
  const me = authState.creds.me;
588
- if (type === 'available' || type === 'unavailable') {
600
+ const isAvailableType = type === 'available';
601
+ if (isAvailableType || type === 'unavailable') {
589
602
  if (!me.name) {
590
603
  logger.warn('no name present, ignoring presence update request...');
591
604
  return;
592
605
  }
593
- ev.emit('connection.update', { isOnline: type === 'available' });
606
+ ev.emit('connection.update', { isOnline: isAvailableType });
607
+ if (isAvailableType) {
608
+ void sendUnifiedSession();
609
+ }
594
610
  await sendNode({
595
611
  tag: 'presence',
596
612
  attrs: {
597
- name: me.name,
613
+ name: me.name.replace(/@/g, ''),
598
614
  type
599
615
  }
600
616
  });
601
617
  }
602
618
  else {
603
- const { server } = (0, WABinary_1.jidDecode)(toJid);
619
+ const { server } = jidDecode(toJid);
604
620
  const isLid = server === 'lid';
605
621
  await sendNode({
606
622
  tag: 'chatstate',
607
623
  attrs: {
608
624
  from: isLid ? me.lid : me.id,
609
- to: toJid,
625
+ to: toJid
610
626
  },
611
627
  content: [
612
628
  {
@@ -621,35 +637,35 @@ const makeChatsSocket = (config) => {
621
637
  * @param toJid the jid to subscribe to
622
638
  * @param tcToken token for subscription, use if present
623
639
  */
624
- const presenceSubscribe = (toJid, tcToken) => (sendNode({
625
- tag: 'presence',
626
- attrs: {
627
- to: toJid,
628
- id: generateMessageTag(),
629
- type: 'subscribe'
630
- },
631
- content: tcToken ?
632
- [
633
- {
634
- tag: 'tctoken',
635
- attrs: {},
636
- content: tcToken
637
- }
638
- ] :
639
- undefined
640
- }));
640
+ const presenceSubscribe = async (toJid) => {
641
+ // Only include tctoken for user JIDs — groups/newsletters don't use tctokens
642
+ const normalizedToJid = jidNormalizedUser(toJid);
643
+ const isUserJid = isPnUser(normalizedToJid) || isLidUser(normalizedToJid);
644
+ const tcTokenContent = isUserJid
645
+ ? await buildTcTokenFromJid({ authState, jid: normalizedToJid, getLIDForPN })
646
+ : undefined;
647
+ return sendNode({
648
+ tag: 'presence',
649
+ attrs: {
650
+ to: toJid,
651
+ id: generateMessageTag(),
652
+ type: 'subscribe'
653
+ },
654
+ content: tcTokenContent
655
+ });
656
+ };
641
657
  const handlePresenceUpdate = ({ tag, attrs, content }) => {
642
- var _a;
643
658
  let presence;
644
659
  const jid = attrs.from;
645
660
  const participant = attrs.participant || attrs.from;
646
- if (shouldIgnoreJid(jid) && jid !== '@s.whatsapp.net') {
661
+ if (shouldIgnoreJid(jid) && jid !== S_WHATSAPP_NET) {
647
662
  return;
648
663
  }
649
664
  if (tag === 'presence') {
650
665
  presence = {
651
666
  lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
652
- lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
667
+ lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined,
668
+ groupOnlineCount: attrs.count ? +attrs.count : undefined
653
669
  };
654
670
  }
655
671
  else if (Array.isArray(content)) {
@@ -658,7 +674,7 @@ const makeChatsSocket = (config) => {
658
674
  if (type === 'paused') {
659
675
  type = 'available';
660
676
  }
661
- if (((_a = firstChild.attrs) === null || _a === void 0 ? void 0 : _a.media) === 'audio') {
677
+ if (firstChild.attrs?.media === 'audio') {
662
678
  type = 'recording';
663
679
  }
664
680
  presence = { lastKnownPresence: type };
@@ -667,31 +683,29 @@ const makeChatsSocket = (config) => {
667
683
  logger.error({ tag, attrs, content }, 'recv invalid presence node');
668
684
  }
669
685
  if (presence) {
670
- ev.emit('presence.update', { id: jid, presences: {
671
- [participant]: presence
672
- } });
686
+ ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
673
687
  }
674
688
  };
675
689
  const appPatch = async (patchCreate) => {
676
690
  const name = patchCreate.type;
677
691
  const myAppStateKeyId = authState.creds.myAppStateKeyId;
678
692
  if (!myAppStateKeyId) {
679
- throw new boom_1.Boom('App state key not present!', { statusCode: 400 });
693
+ throw new Boom('App state key not present!', { statusCode: 400 });
680
694
  }
681
695
  let initial;
682
696
  let encodeResult;
683
- await processingMutex.mutex(async () => {
697
+ await appStatePatchMutex.mutex(async () => {
684
698
  await authState.keys.transaction(async () => {
685
699
  logger.debug({ patch: patchCreate }, 'applying app patch');
686
700
  await resyncAppState([name], false);
687
701
  const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
688
- initial = currentSyncVersion || (0, Utils_1.newLTHashState)();
689
- encodeResult = await (0, Utils_1.encodeSyncdPatch)(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
702
+ initial = currentSyncVersion ? ensureLTHashStateVersion(currentSyncVersion) : newLTHashState();
703
+ encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
690
704
  const { patch, state } = encodeResult;
691
705
  const node = {
692
706
  tag: 'iq',
693
707
  attrs: {
694
- to: WABinary_1.S_WHATSAPP_NET,
708
+ to: S_WHATSAPP_NET,
695
709
  type: 'set',
696
710
  xmlns: 'w:sync:app:state'
697
711
  },
@@ -705,13 +719,13 @@ const makeChatsSocket = (config) => {
705
719
  attrs: {
706
720
  name,
707
721
  version: (state.version - 1).toString(),
708
- 'return_snapshot': 'false'
722
+ return_snapshot: 'false'
709
723
  },
710
724
  content: [
711
725
  {
712
726
  tag: 'patch',
713
727
  attrs: {},
714
- content: WAProto_1.proto.SyncdPatch.encode(patch).finish()
728
+ content: proto.SyncdPatch.encode(patch).finish()
715
729
  }
716
730
  ]
717
731
  }
@@ -720,47 +734,60 @@ const makeChatsSocket = (config) => {
720
734
  ]
721
735
  };
722
736
  await query(node);
723
- await authState.keys.set({ 'app-state-sync-version': {
724
- [name]: state
725
- } });
726
- });
737
+ await authState.keys.set({ 'app-state-sync-version': { [name]: state } });
738
+ }, authState?.creds?.me?.id || 'app-patch');
727
739
  });
728
740
  if (config.emitOwnEvents) {
729
741
  const { onMutation } = newAppStateChunkHandler(false);
730
- const { mutationMap } = await (0, Utils_1.decodePatches)(name, [{ ...encodeResult.patch, version: { version: encodeResult.state.version }, }], initial, getAppStateSyncKey, config.options, undefined, logger);
742
+ const { mutationMap } = await decodePatches(name, [{ ...encodeResult.patch, version: { version: encodeResult.state.version } }], initial, getAppStateSyncKey, config.options, undefined, logger);
731
743
  for (const key in mutationMap) {
732
744
  onMutation(mutationMap[key]);
733
745
  }
734
746
  }
735
747
  };
736
- /** sending non-abt props may fix QR scan fail if server expects */
748
+ /** fetch AB props */
737
749
  const fetchProps = async () => {
738
- var _a, _b;
739
750
  const resultNode = await query({
740
751
  tag: 'iq',
741
752
  attrs: {
742
- to: WABinary_1.S_WHATSAPP_NET,
743
- xmlns: 'w',
744
- type: 'get',
753
+ to: S_WHATSAPP_NET,
754
+ xmlns: 'abt',
755
+ type: 'get'
745
756
  },
746
757
  content: [
747
758
  {
748
759
  tag: 'props',
749
760
  attrs: {
750
- protocol: '2',
751
- hash: ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.lastPropHash) || ''
761
+ protocol: '1',
762
+ ...(authState?.creds?.lastPropHash ? { hash: authState.creds.lastPropHash } : {})
752
763
  }
753
764
  }
754
765
  ]
755
766
  });
756
- const propsNode = (0, WABinary_1.getBinaryNodeChild)(resultNode, 'props');
767
+ const propsNode = getBinaryNodeChild(resultNode, 'props');
757
768
  let props = {};
758
769
  if (propsNode) {
759
- authState.creds.lastPropHash = (_b = propsNode === null || propsNode === void 0 ? void 0 : propsNode.attrs) === null || _b === void 0 ? void 0 : _b.hash;
760
- ev.emit('creds.update', authState.creds);
761
- props = (0, WABinary_1.reduceBinaryNodeToDictionary)(propsNode, 'prop');
770
+ if (propsNode.attrs?.hash) {
771
+ // on some clients, the hash is returning as undefined
772
+ authState.creds.lastPropHash = propsNode?.attrs?.hash;
773
+ ev.emit('creds.update', authState.creds);
774
+ }
775
+ props = reduceBinaryNodeToDictionary(propsNode, 'prop');
776
+ }
777
+ // Extract protocol-relevant AB props (only the ones we need)
778
+ const privacyTokenProp = props['10518'] ?? props['privacy_token_sending_on_all_1_on_1_messages'];
779
+ if (privacyTokenProp !== undefined) {
780
+ serverProps.privacyTokenOn1to1 = privacyTokenProp === 'true' || privacyTokenProp === '1';
781
+ }
782
+ const profilePicProp = props['9666'] ?? props['profile_scraping_privacy_token_in_photo_iq'];
783
+ if (profilePicProp !== undefined) {
784
+ serverProps.profilePicPrivacyToken = profilePicProp === 'true' || profilePicProp === '1';
762
785
  }
763
- logger.debug('fetched props');
786
+ const lidIssueProp = props['14303'] ?? props['lid_trusted_token_issue_to_lid'];
787
+ if (lidIssueProp !== undefined) {
788
+ serverProps.lidTrustedTokenIssueToLid = lidIssueProp === 'true' || lidIssueProp === '1';
789
+ }
790
+ logger.debug({ serverProps }, 'fetched props');
764
791
  return props;
765
792
  };
766
793
  /**
@@ -769,9 +796,17 @@ const makeChatsSocket = (config) => {
769
796
  * requires the last messages till the last message received; required for archive & unread
770
797
  */
771
798
  const chatModify = (mod, jid) => {
772
- const patch = (0, Utils_1.chatModificationToAppPatch)(mod, jid);
799
+ const patch = chatModificationToAppPatch(mod, jid);
773
800
  return appPatch(patch);
774
801
  };
802
+ /**
803
+ * Enable/Disable link preview privacy, not related to baileys link preview generation
804
+ */
805
+ const updateDisableLinkPreviewsPrivacy = (isPreviewsDisabled) => {
806
+ return chatModify({
807
+ disableLinkPreviews: { isPreviewsDisabled }
808
+ }, '');
809
+ };
775
810
  /**
776
811
  * Star or Unstar a message
777
812
  */
@@ -783,6 +818,32 @@ const makeChatsSocket = (config) => {
783
818
  }
784
819
  }, jid);
785
820
  };
821
+ /**
822
+ * Add or Edit Contact
823
+ */
824
+ const addOrEditContact = (jid, contact) => {
825
+ return chatModify({
826
+ contact
827
+ }, jid);
828
+ };
829
+ /**
830
+ * Remove Contact
831
+ */
832
+ const removeContact = (jid) => {
833
+ return chatModify({
834
+ contact: null
835
+ }, jid);
836
+ };
837
+ /**
838
+ * Adds label
839
+ */
840
+ const addLabel = (jid, labels) => {
841
+ return chatModify({
842
+ addLabel: {
843
+ ...labels
844
+ }
845
+ }, jid);
846
+ };
786
847
  /**
787
848
  * Adds label for the chats
788
849
  */
@@ -826,92 +887,146 @@ const makeChatsSocket = (config) => {
826
887
  }, jid);
827
888
  };
828
889
  /**
829
- * Deleting all chat by key message
830
- * usage: sock.deleteChat(m.chat, m.key)
831
- */
832
- const deleteChat = async (jid, key) => {
890
+ * Add or Edit Quick Reply
891
+ */
892
+ const addOrEditQuickReply = (quickReply) => {
833
893
  return chatModify({
834
- delete: true,
835
- lastMessages: [{
836
- key: key,
837
- messageTimestamp: Math.floor(Date.now() / 1000)
838
- }],
839
- }, jid);
840
- }
894
+ quickReply
895
+ }, '');
896
+ };
897
+ /**
898
+ * Remove Quick Reply
899
+ */
900
+ const removeQuickReply = (timestamp) => {
901
+ return chatModify({
902
+ quickReply: { timestamp, deleted: true }
903
+ }, '');
904
+ };
841
905
  /**
842
906
  * queries need to be fired on connection open
843
907
  * help ensure parity with WA Web
844
908
  * */
845
909
  const executeInitQueries = async () => {
846
- await Promise.all([
847
- fetchProps(),
848
- fetchBlocklist(),
849
- fetchPrivacySettings(),
850
- ]);
910
+ await Promise.all([fetchProps(), fetchBlocklist(), fetchPrivacySettings()]);
851
911
  };
852
912
  const upsertMessage = ev.createBufferedFunction(async (msg, type) => {
853
- var _a, _b, _c;
854
913
  ev.emit('messages.upsert', { messages: [msg], type });
855
914
  if (!!msg.pushName) {
856
- let jid = msg.key.fromMe ? authState.creds.me.id : (msg.key.participant || msg.key.remoteJid);
857
- jid = (0, WABinary_1.jidNormalizedUser)(jid);
915
+ let jid = msg.key.fromMe ? authState.creds.me.id : msg.key.participant || msg.key.remoteJid;
916
+ jid = jidNormalizedUser(jid);
858
917
  if (!msg.key.fromMe) {
859
918
  ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }]);
860
919
  }
861
920
  // update our pushname too
862
- if (msg.key.fromMe && msg.pushName && ((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.name) !== msg.pushName) {
921
+ if (msg.key.fromMe && msg.pushName && authState.creds.me?.name !== msg.pushName) {
863
922
  ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } });
864
923
  }
865
924
  }
866
- const historyMsg = (0, Utils_1.getHistoryMsg)(msg.message);
867
- const shouldProcessHistoryMsg = historyMsg ?
868
- (shouldSyncHistoryMessage(historyMsg) &&
869
- Defaults_1.PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)) :
870
- false;
871
- if (historyMsg && !authState.creds.myAppStateKeyId) {
872
- logger.warn('skipping app state sync, as myAppStateKeyId is not set');
873
- pendingAppStateSync = true;
925
+ const historyMsg = getHistoryMsg(msg.message);
926
+ const shouldProcessHistoryMsg = historyMsg
927
+ ? shouldSyncHistoryMessage(historyMsg) &&
928
+ PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
929
+ : false;
930
+ if (historyMsg && shouldProcessHistoryMsg) {
931
+ const syncType = historyMsg.syncType;
932
+ // INITIAL_BOOTSTRAP — fire immediately, no progress check (same as WA Web K function)
933
+ if (syncType === proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP &&
934
+ !historySyncStatus.initialBootstrapComplete) {
935
+ historySyncStatus.initialBootstrapComplete = true;
936
+ ev.emit('messaging-history.status', {
937
+ syncType,
938
+ status: 'complete',
939
+ explicit: true
940
+ });
941
+ }
942
+ // RECENT with progress === 100 — explicit completion
943
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT &&
944
+ historyMsg.progress === 100 &&
945
+ !historySyncStatus.recentSyncComplete) {
946
+ historySyncStatus.recentSyncComplete = true;
947
+ clearTimeout(historySyncPausedTimeout);
948
+ historySyncPausedTimeout = undefined;
949
+ ev.emit('messaging-history.status', {
950
+ syncType,
951
+ status: 'complete',
952
+ explicit: true
953
+ });
954
+ }
955
+ // Reset 120s paused timeout on any RECENT chunk (like WA Web's handleChunkProgress)
956
+ if (syncType === proto.HistorySync.HistorySyncType.RECENT && !historySyncStatus.recentSyncComplete) {
957
+ clearTimeout(historySyncPausedTimeout);
958
+ historySyncPausedTimeout = setTimeout(() => {
959
+ if (!historySyncStatus.recentSyncComplete) {
960
+ historySyncStatus.recentSyncComplete = true;
961
+ ev.emit('messaging-history.status', {
962
+ syncType: proto.HistorySync.HistorySyncType.RECENT,
963
+ status: 'paused',
964
+ explicit: false
965
+ });
966
+ }
967
+ historySyncPausedTimeout = undefined;
968
+ }, HISTORY_SYNC_PAUSED_TIMEOUT_MS);
969
+ }
970
+ }
971
+ // State machine: decide on sync and flush
972
+ if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
973
+ if (awaitingSyncTimeout) {
974
+ clearTimeout(awaitingSyncTimeout);
975
+ awaitingSyncTimeout = undefined;
976
+ }
977
+ if (shouldProcessHistoryMsg) {
978
+ syncState = SyncState.Syncing;
979
+ logger.info('Transitioned to Syncing state');
980
+ // Let doAppStateSync handle the final flush after it's done
981
+ }
982
+ else {
983
+ syncState = SyncState.Online;
984
+ logger.info('History sync skipped, transitioning to Online state and flushing buffer');
985
+ ev.flush();
986
+ }
874
987
  }
988
+ const doAppStateSync = async () => {
989
+ if (syncState === SyncState.Syncing) {
990
+ // All collections will be synced, so clear any blocked ones
991
+ blockedCollections.clear();
992
+ logger.info('Doing app state sync');
993
+ await resyncAppState(ALL_WA_PATCH_NAMES, true);
994
+ // Sync is complete, go online and flush everything
995
+ syncState = SyncState.Online;
996
+ logger.info('App state sync complete, transitioning to Online state and flushing buffer');
997
+ ev.flush();
998
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
999
+ ev.emit('creds.update', { accountSyncCounter });
1000
+ }
1001
+ };
875
1002
  await Promise.all([
876
1003
  (async () => {
877
- if (historyMsg &&
878
- authState.creds.myAppStateKeyId) {
879
- pendingAppStateSync = false;
1004
+ if (shouldProcessHistoryMsg) {
880
1005
  await doAppStateSync();
881
1006
  }
882
1007
  })(),
883
- (0, process_message_1.default)(msg, {
1008
+ processMessage(msg, {
1009
+ signalRepository,
884
1010
  shouldProcessHistoryMsg,
1011
+ placeholderResendCache,
885
1012
  ev,
886
1013
  creds: authState.creds,
887
1014
  keyStore: authState.keys,
888
1015
  logger,
889
1016
  options: config.options,
890
- getMessage: config.getMessage,
1017
+ getMessage
891
1018
  })
892
1019
  ]);
893
- if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.appStateSyncKeyShare) &&
894
- pendingAppStateSync) {
1020
+ // If the app state key arrives and we are waiting to sync, trigger the sync now.
1021
+ if (msg.message?.protocolMessage?.appStateSyncKeyShare && syncState === SyncState.Syncing) {
1022
+ logger.info('App state sync key arrived, triggering app state sync');
895
1023
  await doAppStateSync();
896
- pendingAppStateSync = false;
897
- }
898
- async function doAppStateSync() {
899
- if (!authState.creds.accountSyncCounter) {
900
- logger.info('doing initial app state sync');
901
- await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true);
902
- const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
903
- ev.emit('creds.update', { accountSyncCounter });
904
- if (needToFlushWithAppStateSync) {
905
- logger.debug('flushing with app state sync');
906
- ev.flush();
907
- }
908
- }
909
1024
  }
910
1025
  });
911
1026
  ws.on('CB:presence', handlePresenceUpdate);
912
1027
  ws.on('CB:chatstate', handlePresenceUpdate);
913
1028
  ws.on('CB:ib,,dirty', async (node) => {
914
- const { attrs } = (0, WABinary_1.getBinaryNodeChild)(node, 'dirty');
1029
+ const { attrs } = getBinaryNodeChild(node, 'dirty');
915
1030
  const type = attrs.type;
916
1031
  switch (type) {
917
1032
  case 'account_sync':
@@ -933,43 +1048,124 @@ const makeChatsSocket = (config) => {
933
1048
  }
934
1049
  });
935
1050
  ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
936
- var _a;
1051
+ if (connection === 'close') {
1052
+ blockedCollections.clear();
1053
+ clearTimeout(historySyncPausedTimeout);
1054
+ historySyncPausedTimeout = undefined;
1055
+ }
937
1056
  if (connection === 'open') {
938
1057
  if (fireInitQueries) {
939
- executeInitQueries()
940
- .catch(error => onUnexpectedError(error, 'init queries'));
1058
+ executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
941
1059
  }
942
- sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable')
943
- .catch(error => onUnexpectedError(error, 'presence update requests'));
1060
+ sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable').catch(error => onUnexpectedError(error, 'presence update requests'));
1061
+ }
1062
+ if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
1063
+ return;
1064
+ }
1065
+ historySyncStatus.initialBootstrapComplete = false;
1066
+ historySyncStatus.recentSyncComplete = false;
1067
+ clearTimeout(historySyncPausedTimeout);
1068
+ historySyncPausedTimeout = undefined;
1069
+ syncState = SyncState.AwaitingInitialSync;
1070
+ logger.info('Connection is now AwaitingInitialSync, buffering events');
1071
+ ev.buffer();
1072
+ const willSyncHistory = shouldSyncHistoryMessage(proto.Message.HistorySyncNotification.create({
1073
+ syncType: proto.HistorySync.HistorySyncType.RECENT
1074
+ }));
1075
+ if (!willSyncHistory) {
1076
+ logger.info('History sync is disabled by config, not waiting for notification. Transitioning to Online.');
1077
+ syncState = SyncState.Online;
1078
+ setTimeout(() => ev.flush(), 0);
1079
+ return;
1080
+ }
1081
+ // On reconnection (accountSyncCounter > 0), the server does not push
1082
+ // history sync notifications — the device already has its data.
1083
+ // Skip the 20s wait and go online immediately.
1084
+ if (authState.creds.accountSyncCounter > 0) {
1085
+ logger.info('Reconnection with existing sync data, skipping history sync wait. Transitioning to Online.');
1086
+ syncState = SyncState.Online;
1087
+ setTimeout(() => ev.flush(), 0);
1088
+ return;
944
1089
  }
945
- if (receivedPendingNotifications) {
946
- // if we don't have the app state key
947
- // we keep buffering events until we finally have
948
- // the key and can sync the messages
949
- if (!((_a = authState.creds) === null || _a === void 0 ? void 0 : _a.myAppStateKeyId) && !config.mobile) {
950
- ev.buffer();
951
- needToFlushWithAppStateSync = true;
1090
+ logger.info('First connection, awaiting history sync notification with a 20s timeout.');
1091
+ if (awaitingSyncTimeout) {
1092
+ clearTimeout(awaitingSyncTimeout);
1093
+ }
1094
+ awaitingSyncTimeout = setTimeout(() => {
1095
+ if (syncState === SyncState.AwaitingInitialSync) {
1096
+ logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
1097
+ syncState = SyncState.Online;
1098
+ ev.flush();
1099
+ // Increment so subsequent reconnections skip the 20s wait.
1100
+ // Late-arriving history is still processed via processMessage
1101
+ // regardless of the state machine phase.
1102
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
1103
+ ev.emit('creds.update', { accountSyncCounter });
952
1104
  }
1105
+ }, 20000);
1106
+ });
1107
+ // When an app state sync key arrives (myAppStateKeyId is set) and there are
1108
+ // collections blocked on a missing key, trigger a re-sync for just those collections.
1109
+ // This mirrors WA Web's Blocked → retry-on-key-arrival behavior.
1110
+ ev.on('creds.update', ({ myAppStateKeyId }) => {
1111
+ if (!myAppStateKeyId || blockedCollections.size === 0) {
1112
+ return;
1113
+ }
1114
+ // If we're in the middle of a full sync, doAppStateSync handles all collections
1115
+ if (syncState === SyncState.Syncing) {
1116
+ blockedCollections.clear();
1117
+ return;
1118
+ }
1119
+ const collections = [...blockedCollections];
1120
+ blockedCollections.clear();
1121
+ logger.info({ collections }, 'app state sync key arrived, re-syncing blocked collections');
1122
+ resyncAppState(collections, false).catch(error => onUnexpectedError(error, 'blocked collections resync'));
1123
+ });
1124
+ ev.on('lid-mapping.update', async ({ lid, pn }) => {
1125
+ try {
1126
+ await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
1127
+ }
1128
+ catch (error) {
1129
+ logger.warn({ lid, pn, error }, 'Failed to store LID-PN mapping');
1130
+ }
1131
+ });
1132
+ registerSocketEndHandler(() => {
1133
+ if (awaitingSyncTimeout) {
1134
+ clearTimeout(awaitingSyncTimeout);
1135
+ awaitingSyncTimeout = undefined;
1136
+ }
1137
+ if (!config.placeholderResendCache && placeholderResendCache.close) {
1138
+ placeholderResendCache.close();
953
1139
  }
1140
+ syncState = SyncState.Connecting;
1141
+ privacySettings = undefined;
954
1142
  });
955
1143
  return {
956
1144
  ...sock,
957
- processingMutex,
1145
+ serverProps,
1146
+ createCallLink,
1147
+ getBotListV2,
1148
+ messageMutex,
1149
+ receiptMutex,
1150
+ appStatePatchMutex,
1151
+ notificationMutex,
958
1152
  fetchPrivacySettings,
959
1153
  upsertMessage,
960
1154
  appPatch,
961
1155
  sendPresenceUpdate,
962
1156
  presenceSubscribe,
963
1157
  profilePictureUrl,
964
- onWhatsApp,
965
- toLid,
966
1158
  fetchBlocklist,
967
1159
  fetchStatus,
1160
+ fetchDisappearingDuration,
968
1161
  updateProfilePicture,
969
1162
  removeProfilePicture,
970
1163
  updateProfileStatus,
971
1164
  updateProfileName,
972
1165
  updateBlockStatus,
1166
+ updateDisableLinkPreviewsPrivacy,
1167
+ updateCallPrivacy,
1168
+ updateMessagesPrivacy,
973
1169
  updateLastSeenPrivacy,
974
1170
  updateOnlinePrivacy,
975
1171
  updateProfilePicturePrivacy,
@@ -981,13 +1177,17 @@ const makeChatsSocket = (config) => {
981
1177
  resyncAppState,
982
1178
  chatModify,
983
1179
  cleanDirtyBits,
1180
+ addOrEditContact,
1181
+ removeContact,
1182
+ placeholderResendCache,
1183
+ addLabel,
984
1184
  addChatLabel,
985
1185
  removeChatLabel,
986
1186
  addMessageLabel,
987
- deleteChat,
988
- checkStatusWA,
989
1187
  removeMessageLabel,
990
- star
1188
+ star,
1189
+ addOrEditQuickReply,
1190
+ removeQuickReply
991
1191
  };
992
1192
  };
993
- exports.makeChatsSocket = makeChatsSocket;
1193
+ //# sourceMappingURL=chats.js.map