@badzz88/baileys 8.5.6 → 8.5.8

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 (225) hide show
  1. package/README.md +337 -1055
  2. package/WAProto/WAProto.proto +28 -1189
  3. package/WAProto/fix-imports.js +79 -69
  4. package/WAProto/index.d.ts +71491 -15254
  5. package/WAProto/index.js +126436 -19814
  6. package/engine-requirements.js +8 -15
  7. package/lib/Defaults/index.js +130 -0
  8. package/{src → lib}/Signal/Group/ciphertext-message.js +2 -5
  9. package/lib/Signal/Group/group-session-builder.js +30 -0
  10. package/{src → lib}/Signal/Group/group_cipher.js +11 -11
  11. package/lib/Signal/Group/index.js +12 -0
  12. package/lib/Signal/Group/keyhelper.js +18 -0
  13. package/{src → lib}/Signal/Group/sender-chain-key.js +6 -9
  14. package/{src → lib}/Signal/Group/sender-key-distribution-message.js +6 -9
  15. package/{src → lib}/Signal/Group/sender-key-message.js +9 -12
  16. package/{src → lib}/Signal/Group/sender-key-name.js +2 -5
  17. package/{src → lib}/Signal/Group/sender-key-record.js +8 -11
  18. package/{src → lib}/Signal/Group/sender-key-state.js +6 -9
  19. package/lib/Signal/Group/sender-message-key.js +26 -0
  20. package/{src → lib}/Signal/libsignal.js +131 -155
  21. package/{src → lib}/Signal/lid-mapping.js +27 -23
  22. package/lib/Socket/Client/index.js +3 -0
  23. package/lib/Socket/Client/types.js +11 -0
  24. package/{src → lib}/Socket/Client/websocket.js +11 -18
  25. package/{src → lib}/Socket/business.js +35 -67
  26. package/{src → lib}/Socket/chats.js +294 -550
  27. package/{src → lib}/Socket/communities.js +82 -114
  28. package/lib/Socket/graphql.js +716 -0
  29. package/lib/Socket/groups.js +374 -0
  30. package/lib/Socket/index.js +18 -0
  31. package/lib/Socket/interop.js +463 -0
  32. package/{src → lib}/Socket/luxu.js +120 -82
  33. package/lib/Socket/messages-recv.js +1916 -0
  34. package/lib/Socket/messages-send.js +1436 -0
  35. package/lib/Socket/mex.js +54 -0
  36. package/lib/Socket/newsletter.js +757 -0
  37. package/lib/Socket/privacy.js +318 -0
  38. package/{src → lib}/Socket/socket.js +356 -244
  39. package/lib/Socket/username.js +236 -0
  40. package/lib/Store/index.js +10 -0
  41. package/{src → lib}/Store/keyed-db.js +11 -21
  42. package/lib/Store/make-cache-manager-store.js +85 -0
  43. package/lib/Store/make-in-memory-store.js +244 -0
  44. package/{src → lib}/Store/make-ordered-dictionary.js +19 -25
  45. package/{src → lib}/Store/object-repository.js +11 -5
  46. package/lib/Types/Auth.js +2 -0
  47. package/lib/Types/Bussines.js +2 -0
  48. package/lib/Types/Call.js +2 -0
  49. package/lib/Types/Chat.js +8 -0
  50. package/lib/Types/Contact.js +2 -0
  51. package/lib/Types/Events.js +2 -0
  52. package/lib/Types/GroupMetadata.js +2 -0
  53. package/lib/Types/Label.js +25 -0
  54. package/lib/Types/LabelAssociation.js +7 -0
  55. package/lib/Types/Message.js +11 -0
  56. package/lib/Types/Mex.js +111 -0
  57. package/lib/Types/Product.js +2 -0
  58. package/lib/Types/Signal.js +2 -0
  59. package/lib/Types/Socket.js +3 -0
  60. package/lib/Types/State.js +56 -0
  61. package/lib/Types/USync.js +2 -0
  62. package/lib/Types/index.js +26 -0
  63. package/{src → lib}/Utils/auth-utils.js +91 -43
  64. package/lib/Utils/browser-utils.js +48 -0
  65. package/lib/Utils/business.js +231 -0
  66. package/lib/Utils/chat-utils.js +872 -0
  67. package/lib/Utils/companion-reg-client-utils.js +35 -0
  68. package/lib/Utils/crypto.js +118 -0
  69. package/lib/Utils/decode-wa-message.js +350 -0
  70. package/{src → lib}/Utils/event-buffer.js +81 -39
  71. package/lib/Utils/generics.js +403 -0
  72. package/lib/Utils/history.js +134 -0
  73. package/{src → lib}/Utils/identity-change-handler.js +9 -11
  74. package/lib/Utils/index.js +23 -0
  75. package/lib/Utils/link-preview.js +85 -0
  76. package/lib/Utils/logger.js +3 -0
  77. package/lib/Utils/lt-hash.js +8 -0
  78. package/{src → lib}/Utils/make-mutex.js +7 -10
  79. package/lib/Utils/message-composer.js +273 -0
  80. package/{src → lib}/Utils/message-retry-manager.js +76 -28
  81. package/lib/Utils/messages-media.js +870 -0
  82. package/lib/Utils/messages.js +1337 -0
  83. package/lib/Utils/noise-handler.js +201 -0
  84. package/{src → lib}/Utils/offline-node-processor.js +10 -4
  85. package/{src → lib}/Utils/pre-key-manager.js +27 -11
  86. package/lib/Utils/process-message.js +630 -0
  87. package/{src → lib}/Utils/reporting-utils.js +12 -15
  88. package/lib/Utils/signal.js +201 -0
  89. package/{src → lib}/Utils/stanza-ack.js +12 -4
  90. package/lib/Utils/sticker.js +110 -0
  91. package/{src → lib}/Utils/sync-action-utils.js +14 -10
  92. package/{src → lib}/Utils/tc-token-utils.js +48 -43
  93. package/{src → lib}/Utils/use-multi-file-auth-state.js +35 -25
  94. package/lib/Utils/validate-connection.js +203 -0
  95. package/{src → lib}/WABinary/constants.js +9 -12
  96. package/{src → lib}/WABinary/decode.js +38 -118
  97. package/{src → lib}/WABinary/encode.js +6 -11
  98. package/lib/WABinary/generic-utils.js +204 -0
  99. package/lib/WABinary/index.js +6 -0
  100. package/lib/WABinary/jid-utils.js +98 -0
  101. package/lib/WABinary/types.js +2 -0
  102. package/{src → lib}/WAM/BinaryInfo.js +2 -5
  103. package/{src → lib}/WAM/constants.js +4 -16635
  104. package/{src → lib}/WAM/encode.js +18 -17
  105. package/lib/WAM/index.js +4 -0
  106. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
  107. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  108. package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
  109. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  110. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  111. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
  112. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
  113. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  114. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
  115. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
  116. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  117. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
  118. package/lib/WAUSync/Protocols/index.js +12 -0
  119. package/lib/WAUSync/USyncQuery.js +151 -0
  120. package/lib/WAUSync/USyncUser.js +56 -0
  121. package/lib/WAUSync/index.js +3 -0
  122. package/{src → lib}/index.js +16 -51
  123. package/package.json +129 -99
  124. package/LICENSE +0 -21
  125. package/src/Defaults/index.js +0 -186
  126. package/src/Defaults/phonenumber-mcc.json +0 -223
  127. package/src/Signal/Group/group-session-builder.js +0 -86
  128. package/src/Signal/Group/index.js +0 -140
  129. package/src/Signal/Group/keyhelper.js +0 -77
  130. package/src/Signal/Group/sender-message-key.js +0 -29
  131. package/src/Socket/Client/index.js +0 -31
  132. package/src/Socket/Client/types.js +0 -13
  133. package/src/Socket/aigroups.js +0 -221
  134. package/src/Socket/graphql.js +0 -523
  135. package/src/Socket/groups.js +0 -516
  136. package/src/Socket/index.js +0 -31
  137. package/src/Socket/interactive-handler.js +0 -527
  138. package/src/Socket/interop.js +0 -339
  139. package/src/Socket/managed-account.js +0 -98
  140. package/src/Socket/messages-recv.js +0 -2685
  141. package/src/Socket/messages-send.js +0 -2047
  142. package/src/Socket/mex.js +0 -57
  143. package/src/Socket/newsletter.js +0 -455
  144. package/src/Socket/privacy.js +0 -125
  145. package/src/Socket/registration.js +0 -236
  146. package/src/Socket/text-router.js +0 -65
  147. package/src/Socket/username.js +0 -130
  148. package/src/Store/index.js +0 -33
  149. package/src/Store/make-cache-manager-store.js +0 -84
  150. package/src/Store/make-in-memory-store.js +0 -551
  151. package/src/Types/Auth.js +0 -31
  152. package/src/Types/Bussines.js +0 -2
  153. package/src/Types/Call.js +0 -2
  154. package/src/Types/Chat.js +0 -4
  155. package/src/Types/Contact.js +0 -2
  156. package/src/Types/Events.js +0 -2
  157. package/src/Types/GroupMetadata.js +0 -2
  158. package/src/Types/Label.js +0 -26
  159. package/src/Types/LabelAssociation.js +0 -8
  160. package/src/Types/Message.js +0 -93
  161. package/src/Types/Mex.js +0 -112
  162. package/src/Types/Newsletter.js +0 -109
  163. package/src/Types/Product.js +0 -2
  164. package/src/Types/Signal.js +0 -2
  165. package/src/Types/Socket.js +0 -2
  166. package/src/Types/State.js +0 -62
  167. package/src/Types/USync.js +0 -2
  168. package/src/Types/index.js +0 -56
  169. package/src/Utils/browser-utils.js +0 -112
  170. package/src/Utils/business.js +0 -240
  171. package/src/Utils/chat-utils.js +0 -1230
  172. package/src/Utils/command-loader.d.ts +0 -27
  173. package/src/Utils/command-loader.js +0 -89
  174. package/src/Utils/companion-reg-client-utils.js +0 -40
  175. package/src/Utils/consumer-application.js +0 -105
  176. package/src/Utils/crypto.js +0 -118
  177. package/src/Utils/curve25519-js.js +0 -242
  178. package/src/Utils/decode-wa-message.js +0 -529
  179. package/src/Utils/generics.js +0 -483
  180. package/src/Utils/group-history.js +0 -44
  181. package/src/Utils/history.js +0 -232
  182. package/src/Utils/index.js +0 -58
  183. package/src/Utils/jid-display-normalization.js +0 -195
  184. package/src/Utils/link-preview.js +0 -135
  185. package/src/Utils/logger.js +0 -8
  186. package/src/Utils/lt-hash.js +0 -25
  187. package/src/Utils/message-composer.js +0 -471
  188. package/src/Utils/messages-media.js +0 -843
  189. package/src/Utils/messages.js +0 -2817
  190. package/src/Utils/meta-ai-msmsg.js +0 -222
  191. package/src/Utils/native-bridge.js +0 -68
  192. package/src/Utils/noise-handler.js +0 -169
  193. package/src/Utils/process-message.js +0 -950
  194. package/src/Utils/session-pool.d.ts +0 -14
  195. package/src/Utils/session-pool.js +0 -70
  196. package/src/Utils/signal.js +0 -217
  197. package/src/Utils/sticker.d.ts +0 -13
  198. package/src/Utils/sticker.js +0 -123
  199. package/src/Utils/validate-connection.js +0 -209
  200. package/src/Utils/view-once-cache.d.ts +0 -12
  201. package/src/Utils/view-once-cache.js +0 -63
  202. package/src/Utils/voip-rekey.js +0 -22
  203. package/src/WABinary/generic-utils.js +0 -238
  204. package/src/WABinary/index.js +0 -34
  205. package/src/WABinary/jid-utils.js +0 -351
  206. package/src/WABinary/types.js +0 -2
  207. package/src/WAM/index.js +0 -32
  208. package/src/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -53
  209. package/src/WAUSync/Protocols/USyncBusinessProtocol.js +0 -44
  210. package/src/WAUSync/Protocols/USyncContactProtocol.js +0 -55
  211. package/src/WAUSync/Protocols/USyncDeviceProtocol.js +0 -55
  212. package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +0 -31
  213. package/src/WAUSync/Protocols/USyncFeatureProtocol.js +0 -54
  214. package/src/WAUSync/Protocols/USyncLIDProtocol.js +0 -32
  215. package/src/WAUSync/Protocols/USyncNewsletterProtocol.js +0 -473
  216. package/src/WAUSync/Protocols/USyncPictureProtocol.js +0 -34
  217. package/src/WAUSync/Protocols/USyncSidelistProtocol.js +0 -29
  218. package/src/WAUSync/Protocols/USyncStatusProtocol.js +0 -42
  219. package/src/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -38
  220. package/src/WAUSync/Protocols/USyncUsernameProtocol.js +0 -28
  221. package/src/WAUSync/Protocols/index.js +0 -40
  222. package/src/WAUSync/USyncQuery.js +0 -126
  223. package/src/WAUSync/USyncUser.js +0 -50
  224. package/src/WAUSync/index.js +0 -32
  225. package/src/antiban.js +0 -4152
@@ -1,56 +1,66 @@
1
- 'use strict';
2
- Object.defineProperty(exports, '__esModule', { value: true });
3
- exports.makeSocket = void 0;
4
- const boom_1 = require('@hapi/boom');
5
- const crypto_1 = require('crypto');
6
- const url_1 = require('url');
7
- const util_1 = require('util');
8
- const index_js_1 = require('../../WAProto/index.js');
9
- const Defaults_1 = require('../Defaults');
10
- const Types_1 = require('../Types');
11
- const Utils_1 = require('../Utils');
12
- const browser_utils_1 = require('../Utils/browser-utils');
13
- const WABinary_1 = require('../WABinary');
14
- const BinaryInfo_js_1 = require('../WAM/BinaryInfo.js');
15
- const WAUSync_1 = require('../WAUSync/');
16
- const Client_1 = require('./Client');
17
- const mex_1 = require('./mex');
18
- const makeSocket = config => {
1
+ import { Boom } from '@hapi/boom';
2
+ import { randomBytes } from 'crypto';
3
+ import { URL } from 'url';
4
+ import { promisify } from 'util';
5
+ import { proto } from '../../WAProto/index.js';
6
+ import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT, NOISE_WA_HEADER, PROCESSABLE_HISTORY_TYPES, TimeMs, UPLOAD_TIMEOUT } from '../Defaults/index.js';
7
+ import { QueryIds, ReachoutTimelockEnforcementType } from '../Types/index.js';
8
+ import { DisconnectReason, XWAPaths } from '../Types/index.js';
9
+ import { addTransactionCapability, aesEncryptCTR, bindWaitForConnectionUpdate, buildPairingQRData, bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getCompanionPlatformId, getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler, promiseTimeout, signedKeyPair, xmppSignedPreKey } from '../Utils/index.js';
10
+ import { assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildren, isLidUser, jidDecode, jidEncode, S_WHATSAPP_NET } from '../WABinary/index.js';
11
+ import { BinaryInfo } from '../WAM/BinaryInfo.js';
12
+ import { USyncQuery, USyncUser } from '../WAUSync/index.js';
13
+ import { WebSocketClient } from './Client/index.js';
14
+ import { executeWMexQuery } from './mex.js';
15
+ /**
16
+ * Connects to WA servers and performs:
17
+ * - simple queries (no retry mechanism, wait for connection establishment)
18
+ * - listen to messages and emit events
19
+ * - query phone connection
20
+ */
21
+ export const makeSocket = (config) => {
19
22
  const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config;
20
- const publicWAMBuffer = new BinaryInfo_js_1.BinaryInfo();
23
+ const publicWAMBuffer = new BinaryInfo();
21
24
  let serverTimeOffsetMs = 0;
22
- const uqTagId = (0, Utils_1.generateMdTagPrefix)();
23
- const generateMessageTag = () => `${uqTagId}${epoch++}`;
25
+ const uqTagId = generateMdTagPrefix();
26
+ const generateMessageTag = () => `VINNXSYNC-${epoch++}`;
27
+ if (browser[1].toLocaleLowerCase().includes('android')) {
28
+ logger.warn('⚠️ Using the Android browser is experimental and may lead to unexpected behavior. Use at your own risk.');
29
+ }
24
30
  if (printQRInTerminal) {
25
31
  logger.warn({}, '⚠️ The printQRInTerminal option has been deprecated. You will no longer receive QR codes in the terminal automatically. Please listen to the connection.update event yourself and handle the QR your way. You can remove this message by removing this opttion. This message will be removed in a future version.');
26
32
  }
27
- const syncDisabled = Defaults_1.PROCESSABLE_HISTORY_TYPES.map(syncType => config.shouldSyncHistoryMessage({ syncType })).filter(x => x === false).length === Defaults_1.PROCESSABLE_HISTORY_TYPES.length;
33
+ const syncDisabled = PROCESSABLE_HISTORY_TYPES.map(syncType => config.shouldSyncHistoryMessage({ syncType })).filter(x => x === false)
34
+ .length === PROCESSABLE_HISTORY_TYPES.length;
28
35
  if (syncDisabled) {
29
36
  logger.warn('⚠️ DANGER: DISABLING ALL SYNC BY shouldSyncHistoryMsg PREVENTS BAILEYS FROM ACCESSING INITIAL LID MAPPINGS, LEADING TO INSTABILIY AND SESSION ERRORS');
30
37
  }
31
- const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
38
+ const url = typeof waWebSocketUrl === 'string' ? new URL(waWebSocketUrl) : waWebSocketUrl;
32
39
  if (config.mobile || url.protocol === 'tcp:') {
33
- throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut });
40
+ throw new Boom('Mobile API is not supported anymore', { statusCode: DisconnectReason.loggedOut });
34
41
  }
35
42
  if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
36
43
  url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
37
44
  }
38
- const ephemeralKeyPair = Utils_1.Curve.generateKeyPair();
39
- const noise = (0, Utils_1.makeNoiseHandler)({
45
+ /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
46
+ const ephemeralKeyPair = Curve.generateKeyPair();
47
+ /** WA noise protocol wrapper */
48
+ const noise = makeNoiseHandler({
40
49
  keyPair: ephemeralKeyPair,
41
- NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
50
+ NOISE_HEADER: NOISE_WA_HEADER,
42
51
  logger,
43
52
  routingInfo: authState?.creds?.routingInfo
44
53
  });
45
- const ws = new Client_1.WebSocketClient(url, config);
54
+ const ws = new WebSocketClient(url, config);
46
55
  ws.connect();
47
- const sendPromise = (0, util_1.promisify)(ws.send);
56
+ const sendPromise = promisify(ws.send);
57
+ /** send a raw buffer */
48
58
  const sendRawMessage = async (data) => {
49
59
  if (!ws.isOpen) {
50
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
60
+ throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
51
61
  }
52
62
  const bytes = noise.encodeFrame(data);
53
- await (0, Utils_1.promiseTimeout)(connectTimeoutMs, async (resolve, reject) => {
63
+ await promiseTimeout(connectTimeoutMs, async (resolve, reject) => {
54
64
  try {
55
65
  await sendPromise.call(ws, bytes);
56
66
  resolve();
@@ -60,36 +70,43 @@ const makeSocket = config => {
60
70
  }
61
71
  });
62
72
  };
63
- const sendNode = frame => {
73
+ /** send a binary node */
74
+ const sendNode = (frame) => {
64
75
  if (logger.level === 'trace') {
65
- logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'xml send' });
76
+ logger.trace({ xml: binaryNodeToString(frame), msg: 'xml send' });
66
77
  }
67
- const buff = (0, WABinary_1.encodeBinaryNode)(frame);
78
+ const buff = encodeBinaryNode(frame);
68
79
  return sendRawMessage(buff);
69
80
  };
81
+ /**
82
+ * Wait for a message with a certain tag to be received
83
+ * @param msgId the message tag to await
84
+ * @param timeoutMs timeout after which the promise will reject
85
+ */
70
86
  const waitForMessage = async (msgId, timeoutMs = defaultQueryTimeoutMs) => {
71
87
  let onRecv;
72
88
  let onErr;
73
89
  try {
74
- const result = await (0, Utils_1.promiseTimeout)(timeoutMs, (resolve, reject) => {
90
+ const result = await promiseTimeout(timeoutMs, (resolve, reject) => {
75
91
  onRecv = data => {
76
92
  resolve(data);
77
93
  };
78
94
  onErr = err => {
79
95
  reject(err ||
80
- new boom_1.Boom('Connection Closed', {
81
- statusCode: Types_1.DisconnectReason.connectionClosed
96
+ new Boom('Connection Closed', {
97
+ statusCode: DisconnectReason.connectionClosed
82
98
  }));
83
99
  };
84
100
  ws.on(`TAG:${msgId}`, onRecv);
85
101
  ws.on('close', onErr);
86
102
  ws.on('error', onErr);
87
- return () => reject(new boom_1.Boom('Query Cancelled'));
103
+ return () => reject(new Boom('Query Cancelled'));
88
104
  });
89
105
  return result;
90
106
  }
91
107
  catch (error) {
92
- if (error instanceof boom_1.Boom && error.output?.statusCode === Types_1.DisconnectReason.timedOut) {
108
+ // Catch timeout and return undefined instead of throwing
109
+ if (error instanceof Boom && error.output?.statusCode === DisconnectReason.timedOut) {
93
110
  logger?.warn?.({ msgId }, 'timed out waiting for message');
94
111
  return undefined;
95
112
  }
@@ -104,55 +121,60 @@ const makeSocket = config => {
104
121
  }
105
122
  }
106
123
  };
124
+ /** send a query, and wait for its response. auto-generates message ID if not provided */
107
125
  const query = async (node, timeoutMs) => {
108
126
  if (!node.attrs.id) {
109
127
  node.attrs.id = generateMessageTag();
110
128
  }
111
129
  const msgId = node.attrs.id;
112
- const result = await (0, Utils_1.promiseTimeout)(timeoutMs, async (resolve, reject) => {
130
+ const result = await promiseTimeout(timeoutMs, async (resolve, reject) => {
113
131
  const result = waitForMessage(msgId, timeoutMs).catch(reject);
114
132
  sendNode(node)
115
133
  .then(async () => resolve(await result))
116
134
  .catch(reject);
117
135
  });
118
136
  if (result && 'tag' in result) {
119
- ;
120
- (0, WABinary_1.assertNodeErrorFree)(result);
137
+ assertNodeErrorFree(result);
121
138
  }
122
139
  return result;
123
140
  };
141
+ // Validate current key-bundle on server; on failure, trigger pre-key upload and rethrow
124
142
  const digestKeyBundle = async () => {
125
143
  const res = await query({
126
144
  tag: 'iq',
127
- attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
145
+ attrs: { to: S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
128
146
  content: [{ tag: 'digest', attrs: {} }]
129
147
  });
130
- const digestNode = (0, WABinary_1.getBinaryNodeChild)(res, 'digest');
148
+ const digestNode = getBinaryNodeChild(res, 'digest');
131
149
  if (!digestNode) {
132
150
  await uploadPreKeys();
133
151
  throw new Error('encrypt/get digest returned no digest node');
134
152
  }
135
153
  };
154
+ // Rotate our signed pre-key on server; on failure, run digest as fallback and rethrow
136
155
  const rotateSignedPreKey = async () => {
137
156
  const newId = (creds.signedPreKey.keyId || 0) + 1;
138
- const skey = await (0, Utils_1.signedKeyPair)(creds.signedIdentityKey, newId);
157
+ const skey = await signedKeyPair(creds.signedIdentityKey, newId);
139
158
  await query({
140
159
  tag: 'iq',
141
- attrs: { to: WABinary_1.S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
160
+ attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
142
161
  content: [
143
162
  {
144
163
  tag: 'rotate',
145
164
  attrs: {},
146
- content: [(0, Utils_1.xmppSignedPreKey)(skey)]
165
+ content: [xmppSignedPreKey(skey)]
147
166
  }
148
167
  ]
149
168
  });
169
+ // Persist new signed pre-key in creds
150
170
  ev.emit('creds.update', { signedPreKey: skey });
151
171
  };
152
172
  const executeUSyncQuery = async (usyncQuery) => {
153
173
  if (usyncQuery.protocols.length === 0) {
154
- throw new boom_1.Boom('USyncQuery must have at least one protocol');
174
+ throw new Boom('USyncQuery must have at least one protocol');
155
175
  }
176
+ // todo: validate users, throw WARNING on no valid users
177
+ // variable below has only validated users
156
178
  const validUsers = usyncQuery.users;
157
179
  const userNodes = validUsers.map(user => {
158
180
  return {
@@ -176,7 +198,7 @@ const makeSocket = config => {
176
198
  const iq = {
177
199
  tag: 'iq',
178
200
  attrs: {
179
- to: WABinary_1.S_WHATSAPP_NET,
201
+ to: S_WHATSAPP_NET,
180
202
  type: 'get',
181
203
  xmlns: 'usync'
182
204
  },
@@ -197,44 +219,75 @@ const makeSocket = config => {
197
219
  const result = await query(iq);
198
220
  return usyncQuery.parseUSyncQueryResult(result);
199
221
  };
200
- const onWhatsApp = async (...phoneNumber) => {
201
- let usyncQuery = new WAUSync_1.USyncQuery();
202
- let contactEnabled = false;
203
- for (const jid of phoneNumber) {
204
- if ((0, WABinary_1.isLidUser)(jid)) {
222
+ const buildAllProtocolsQuery = () => new USyncQuery()
223
+ .withContactProtocol()
224
+ .withLIDProtocol()
225
+ .withDeviceProtocol()
226
+ .withStatusProtocol()
227
+ .withDisappearingModeProtocol()
228
+ .withBotProfileProtocol()
229
+ .withUsernameProtocol()
230
+ .withBusinessProtocol()
231
+ .withPictureProtocol()
232
+ .withTextStatusProtocol()
233
+ .withSidelistProtocol()
234
+ .withFeatureProtocol();
235
+ const onWhatsApp = async (...pn) => {
236
+ const usyncQuery = buildAllProtocolsQuery();
237
+ for (const jid of pn) {
238
+ if (isLidUser(jid)) {
205
239
  logger?.warn('LIDs are not supported with onWhatsApp');
206
240
  continue;
207
241
  }
208
- else {
209
- if (!contactEnabled) {
210
- contactEnabled = true;
211
- usyncQuery = usyncQuery.withContactProtocol();
212
- }
213
- const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`;
214
- usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone));
215
- }
242
+ const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`;
243
+ usyncQuery.withUser(new USyncUser().withPhone(phone));
216
244
  }
217
245
  if (usyncQuery.users.length === 0) {
218
- return [];
246
+ return []; // return early without forcing an empty query
247
+ }
248
+ let results;
249
+ try {
250
+ results = await executeUSyncQuery(usyncQuery);
251
+ }
252
+ catch (err) {
253
+ logger?.warn({ err }, 'onWhatsApp: full usync query failed, retrying with contact+lid protocols only');
254
+ const fallbackQuery = new USyncQuery().withContactProtocol().withLIDProtocol();
255
+ fallbackQuery.users = usyncQuery.users;
256
+ results = await executeUSyncQuery(fallbackQuery);
219
257
  }
220
- const results = await executeUSyncQuery(usyncQuery);
221
258
  if (results) {
222
- return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }));
259
+ return results.list
260
+ .filter(a => !!a.contact)
261
+ .map(({ contact, id, lid, devices, status, disappearing_mode, bot, username, business, picture, text_status, sidelist, feature }) => ({
262
+ jid: id,
263
+ exists: contact,
264
+ lid: lid ?? null,
265
+ devices: devices ?? null,
266
+ status: status ?? null,
267
+ disappearingMode: disappearing_mode ?? null,
268
+ bot: bot ?? null,
269
+ username: username ?? null,
270
+ business: business ?? null,
271
+ picture: picture ?? null,
272
+ textStatus: text_status ?? null,
273
+ sidelist: sidelist ?? null,
274
+ feature: feature ?? null
275
+ }));
223
276
  }
224
277
  };
225
278
  const pnFromLIDUSync = async (jids) => {
226
- const usyncQuery = new WAUSync_1.USyncQuery().withLIDProtocol().withContext('background');
279
+ const usyncQuery = new USyncQuery().withLIDProtocol().withContext('background');
227
280
  for (const jid of jids) {
228
- if ((0, WABinary_1.isLidUser)(jid)) {
281
+ if (isLidUser(jid)) {
229
282
  logger?.warn('LID user found in LID fetch call');
230
283
  continue;
231
284
  }
232
285
  else {
233
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid));
286
+ usyncQuery.withUser(new USyncUser().withId(jid));
234
287
  }
235
288
  }
236
289
  if (usyncQuery.users.length === 0) {
237
- return [];
290
+ return []; // return early without forcing an empty query
238
291
  }
239
292
  const results = await executeUSyncQuery(usyncQuery);
240
293
  if (results) {
@@ -242,76 +295,99 @@ const makeSocket = config => {
242
295
  }
243
296
  return [];
244
297
  };
245
- const toPn = async (lid) => {
246
- const lids = Array.isArray(lid) ? lid : [lid];
247
- const usyncQuery = new WAUSync_1.USyncQuery().withContactProtocol().withLIDProtocol();
248
- for (const l of lids) {
249
- const decoded = (0, WABinary_1.jidDecode)(l);
250
- if (!decoded)
251
- continue;
252
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId((0, WABinary_1.jidEncode)(decoded.user, 's.whatsapp.net')).withLid(l));
253
- }
254
- const result = await executeUSyncQuery(usyncQuery);
255
- return lids.map(l => {
256
- const decoded = (0, WABinary_1.jidDecode)(l);
257
- if (!decoded)
258
- return { lid: l, pn: null };
259
- const match = result?.list?.find(entry => {
260
- const entryDecoded = (0, WABinary_1.jidDecode)(entry.id);
261
- return entryDecoded?.user === decoded.user;
262
- });
263
- if (!match?.contact)
264
- return { lid: l, pn: null };
265
- const pn = (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(match.id)?.user, 's.whatsapp.net');
266
- return { lid: l, pn: pn ?? null };
267
- });
268
- };
269
- const toLID = async (pn) => {
270
- const pns = Array.isArray(pn) ? pn : [pn];
271
- const usyncQuery = new WAUSync_1.USyncQuery().withContactProtocol().withLIDProtocol();
272
- for (const p of pns) {
273
- const decoded = (0, WABinary_1.jidDecode)(p);
274
- if (!decoded)
275
- continue;
276
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId((0, WABinary_1.jidEncode)(decoded.user, 's.whatsapp.net')));
277
- }
278
- const result = await executeUSyncQuery(usyncQuery);
279
- return pns.map(p => {
280
- const decoded = (0, WABinary_1.jidDecode)(p);
281
- if (!decoded)
282
- return { pn: p, lid: null };
283
- const match = result?.list?.find(entry => {
284
- return (0, WABinary_1.jidDecode)(entry.id)?.user === decoded.user;
285
- });
286
- if (!match?.contact)
287
- return { pn: p, lid: null };
288
- const lidVal = match?.lid ?? null;
289
- const lid = lidVal ? (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(lidVal)?.user ?? lidVal, 'lid') : null;
290
- return { pn: p, lid };
291
- });
292
- };
293
- const fetchUsername = async (username, pin) => {
294
- const usernames = Array.isArray(username) ? username : [username];
295
- const usyncQuery = new WAUSync_1.USyncQuery().withContactProtocol().withLIDProtocol();
296
- for (const u of usernames) {
297
- const user = new WAUSync_1.USyncUser().withUsername(u);
298
- if (pin)
299
- user.withUsernameKey(pin);
300
- usyncQuery.withUser(user);
301
- }
302
- const result = await executeUSyncQuery(usyncQuery);
303
- return usernames.map(u => {
304
- const match = result?.list?.find(entry => entry?.username === u);
305
- if (!match?.contact)
306
- return { username: u, pn: null, lid: null };
307
- const lid = match.lid;
308
- const pn = (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(match.id)?.user, 's.whatsapp.net');
309
- return { username: u, pn: pn ?? null, lid: lid ?? null };
310
- });
311
- };
312
- const ev = (0, Utils_1.makeEventBuffer)(logger);
298
+ /**
299
+ * @param {string | string[]} lid - @lid JID or array of @lid JID
300
+ * @returns {Promise<{ lid: string, pn: string | null }[]>}
301
+ */
302
+ const toPn = async lid => {
303
+ const lids = Array.isArray(lid) ? lid : [lid]
304
+ const usyncQuery = new USyncQuery()
305
+ .withContactProtocol()
306
+ .withLIDProtocol()
307
+ for (const l of lids) {
308
+ const decoded = jidDecode(l)
309
+ if (!decoded) continue
310
+ usyncQuery.withUser(
311
+ new USyncUser()
312
+ .withId(jidEncode(decoded.user, 's.whatsapp.net'))
313
+ .withLid(l)
314
+ )
315
+ }
316
+ const result = await executeUSyncQuery(usyncQuery)
317
+ return lids.map(l => {
318
+ const decoded = jidDecode(l)
319
+ if (!decoded) return { lid: l, pn: null }
320
+
321
+ const match = result?.list?.find(entry => {
322
+ const entryDecoded = jidDecode(entry.id)
323
+ return entryDecoded?.user === decoded.user
324
+ })
325
+
326
+ if (!match?.contact) return { lid: l, pn: null }
327
+
328
+ const pn = jidEncode(jidDecode(match.id)?.user, 's.whatsapp.net')
329
+ return { lid: l, pn: pn ?? null }
330
+ })
331
+ }
332
+ /**
333
+ * @param {string | string[]} s.whatsapp.net - @s.whatsapp.net JID or array of @s.whatsapp.net JID
334
+ * @returns {Promise<{ pn: string, lid: string | null }[]>}
335
+ */
336
+ const toLID = async pn => {
337
+ const pns = Array.isArray(pn) ? pn : [pn]
338
+ const usyncQuery = new USyncQuery()
339
+ .withContactProtocol()
340
+ .withLIDProtocol()
341
+ for (const p of pns) {
342
+ const decoded = jidDecode(p)
343
+ if (!decoded) continue
344
+ usyncQuery.withUser(
345
+ new USyncUser().withId(jidEncode(decoded.user, 's.whatsapp.net'))
346
+ )
347
+ }
348
+ const result = await executeUSyncQuery(usyncQuery)
349
+ return pns.map(p => {
350
+ const decoded = jidDecode(p)
351
+ if (!decoded) return { pn: p, lid: null }
352
+
353
+ const match = result?.list?.find(entry => {
354
+ return jidDecode(entry.id)?.user === decoded.user
355
+ })
356
+
357
+ if (!match?.contact) return { pn: p, lid: null }
358
+
359
+ const lidVal = match?.lid ?? null
360
+ const lid = lidVal ? jidEncode(jidDecode(lidVal)?.user ?? lidVal, 'lid') : null
361
+ return { pn: p, lid }
362
+ })
363
+ }
364
+ /**
365
+ * @param {string, pin} username - username to fetch, pin - pin of username if da user enable it
366
+ * @returns {Promise<{ username: string, pn: string | null, lid: string | null }[]>}
367
+ */
368
+ const fetchUsername = async (username, pin) => {
369
+ const usernames = Array.isArray(username) ? username : [username]
370
+ const usyncQuery = new USyncQuery()
371
+ .withContactProtocol()
372
+ .withLIDProtocol()
373
+ for (const u of usernames) {
374
+ const user = new USyncUser().withUsername(u)
375
+ if (pin) user.withUsernameKey(pin)
376
+ usyncQuery.withUser(user)
377
+ }
378
+ const result = await executeUSyncQuery(usyncQuery)
379
+ return usernames.map(u => {
380
+ const match = result?.list?.find(entry => entry?.username === u)
381
+ if (!match?.contact) return { username: u, pn: null, lid: null }
382
+ const lid = match.lid;
383
+ const pn = jidEncode(jidDecode(match.id)?.user, 's.whatsapp.net')
384
+ return { username: u, pn: pn ?? null, lid: lid ?? null }
385
+ })
386
+ }
387
+ const ev = makeEventBuffer(logger);
313
388
  const { creds } = authState;
314
- const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
389
+ // add transaction capability
390
+ const keys = addTransactionCapability(authState.keys, logger, transactionOpts);
315
391
  const signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync);
316
392
  let lastDateRecv;
317
393
  let epoch = 1;
@@ -319,18 +395,20 @@ const makeSocket = config => {
319
395
  let qrTimer;
320
396
  let closed = false;
321
397
  const socketEndHandlers = [];
398
+ /** log & process any unexpected errors */
322
399
  const onUnexpectedError = (err, msg) => {
323
400
  logger.error({ err }, `unexpected error in '${msg}'`);
324
401
  };
402
+ /** await the next incoming message */
325
403
  const awaitNextMessage = async (sendMsg) => {
326
404
  if (!ws.isOpen) {
327
- throw new boom_1.Boom('Connection Closed', {
328
- statusCode: Types_1.DisconnectReason.connectionClosed
405
+ throw new Boom('Connection Closed', {
406
+ statusCode: DisconnectReason.connectionClosed
329
407
  });
330
408
  }
331
409
  let onOpen;
332
410
  let onClose;
333
- const result = (0, Utils_1.promiseTimeout)(connectTimeoutMs, (resolve, reject) => {
411
+ const result = promiseTimeout(connectTimeoutMs, (resolve, reject) => {
334
412
  onOpen = resolve;
335
413
  onClose = mapWebSocketError(reject);
336
414
  ws.on('frame', onOpen);
@@ -346,28 +424,29 @@ const makeSocket = config => {
346
424
  }
347
425
  return result;
348
426
  };
427
+ /** connection handshake */
349
428
  const validateConnection = async () => {
350
429
  let helloMsg = {
351
430
  clientHello: { ephemeral: ephemeralKeyPair.public }
352
431
  };
353
- helloMsg = index_js_1.proto.HandshakeMessage.fromObject(helloMsg);
432
+ helloMsg = proto.HandshakeMessage.fromObject(helloMsg);
354
433
  logger.info({ browser, helloMsg }, 'connected to WA');
355
- const init = index_js_1.proto.HandshakeMessage.encode(helloMsg).finish();
434
+ const init = proto.HandshakeMessage.encode(helloMsg).finish();
356
435
  const result = await awaitNextMessage(init);
357
- const handshake = index_js_1.proto.HandshakeMessage.decode(result);
436
+ const handshake = proto.HandshakeMessage.decode(result);
358
437
  logger.trace({ handshake }, 'handshake recv from WA');
359
438
  const keyEnc = noise.processHandshake(handshake, creds.noiseKey);
360
439
  let node;
361
440
  if (!creds.me) {
362
- node = (0, Utils_1.generateRegistrationNode)(creds, config);
441
+ node = generateRegistrationNode(creds, config);
363
442
  logger.info({ node }, 'not logged in, attempting registration...');
364
443
  }
365
444
  else {
366
- node = (0, Utils_1.generateLoginNode)(creds.me.id, config, creds);
445
+ node = generateLoginNode(creds.me.id, config);
367
446
  logger.info({ node }, 'logging in...');
368
447
  }
369
- const payloadEnc = noise.encrypt(index_js_1.proto.ClientPayload.encode(node).finish());
370
- await sendRawMessage(index_js_1.proto.HandshakeMessage.encode({
448
+ const payloadEnc = noise.encrypt(proto.ClientPayload.encode(node).finish());
449
+ await sendRawMessage(proto.HandshakeMessage.encode({
371
450
  clientFinish: {
372
451
  static: keyEnc,
373
452
  payload: payloadEnc
@@ -383,54 +462,53 @@ const makeSocket = config => {
383
462
  id: generateMessageTag(),
384
463
  xmlns: 'encrypt',
385
464
  type: 'get',
386
- to: WABinary_1.S_WHATSAPP_NET
465
+ to: S_WHATSAPP_NET
387
466
  },
388
467
  content: [{ tag: 'count', attrs: {} }]
389
468
  });
390
- const countChild = (0, WABinary_1.getBinaryNodeChild)(result, 'count');
469
+ const countChild = getBinaryNodeChild(result, 'count');
391
470
  return +countChild.attrs.value;
392
471
  };
472
+ // WAWeb has no time throttle here; the server drives uploads via PreKeyLow notifications.
393
473
  let uploadPreKeysPromise = null;
394
- let lastUploadTime = 0;
395
- const uploadPreKeys = async (count = Defaults_1.MIN_PREKEY_COUNT, retryCount = 0) => {
396
- if (retryCount === 0) {
397
- const timeSinceLastUpload = Date.now() - lastUploadTime;
398
- if (timeSinceLastUpload < Defaults_1.MIN_UPLOAD_INTERVAL) {
399
- logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`);
400
- return;
401
- }
402
- }
474
+ /** generates and uploads a set of pre-keys to the server */
475
+ const uploadPreKeys = async (count = MIN_PREKEY_COUNT) => {
403
476
  if (uploadPreKeysPromise) {
404
477
  logger.debug('Pre-key upload already in progress, waiting for completion');
405
478
  await uploadPreKeysPromise;
479
+ return;
406
480
  }
407
- const uploadLogic = async () => {
481
+ const uploadLogic = async (retryCount) => {
408
482
  logger.info({ count, retryCount }, 'uploading pre-keys');
483
+ // Generate and save pre-keys atomically (prevents ID collisions on retry)
409
484
  const node = await keys.transaction(async () => {
410
485
  logger.debug({ requestedCount: count }, 'generating pre-keys with requested count');
411
- const { update, node } = await (0, Utils_1.getNextPreKeysNode)({ creds, keys }, count);
486
+ const { update, node } = await getNextPreKeysNode({ creds, keys }, count);
487
+ // Update credentials immediately to prevent duplicate IDs on retry
412
488
  ev.emit('creds.update', update);
413
489
  return node;
414
490
  }, creds?.me?.id || 'upload-pre-keys');
491
+ // Upload to server (outside transaction, can fail without affecting local keys)
415
492
  try {
416
493
  await query(node);
417
494
  logger.info({ count }, 'uploaded pre-keys successfully');
418
- lastUploadTime = Date.now();
419
495
  }
420
496
  catch (uploadError) {
421
497
  logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server');
498
+ // Recurse into uploadLogic; calling uploadPreKeys would await its own in-flight promise.
422
499
  if (retryCount < 3) {
423
500
  const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
424
501
  logger.info(`Retrying pre-key upload in ${backoffDelay}ms`);
425
502
  await new Promise(resolve => setTimeout(resolve, backoffDelay));
426
- return uploadPreKeys(count, retryCount + 1);
503
+ return uploadLogic(retryCount + 1);
427
504
  }
428
505
  throw uploadError;
429
506
  }
430
507
  };
508
+ // Add timeout protection
431
509
  uploadPreKeysPromise = Promise.race([
432
- uploadLogic(),
433
- new Promise((_, reject) => setTimeout(() => reject(new boom_1.Boom('Pre-key upload timeout', { statusCode: 408 })), Defaults_1.UPLOAD_TIMEOUT))
510
+ uploadLogic(0),
511
+ new Promise((_, reject) => setTimeout(() => reject(new Boom('Pre-key upload timeout', { statusCode: 408 })), UPLOAD_TIMEOUT))
434
512
  ]);
435
513
  try {
436
514
  await uploadPreKeysPromise;
@@ -453,9 +531,9 @@ const makeSocket = config => {
453
531
  let count = 0;
454
532
  const preKeyCount = await getAvailablePreKeysOnServer();
455
533
  if (preKeyCount === 0)
456
- count = Defaults_1.INITIAL_PREKEY_COUNT;
534
+ count = INITIAL_PREKEY_COUNT;
457
535
  else
458
- count = Defaults_1.MIN_PREKEY_COUNT;
536
+ count = MIN_PREKEY_COUNT;
459
537
  const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists();
460
538
  logger.info(`${preKeyCount} pre-keys found on server`);
461
539
  logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`);
@@ -477,30 +555,34 @@ const makeSocket = config => {
477
555
  }
478
556
  catch (error) {
479
557
  logger.error({ error }, 'Failed to check/upload pre-keys during initialization');
558
+ // Don't throw - allow connection to continue even if pre-key check fails
480
559
  }
481
560
  };
482
561
  const onMessageReceived = async (data) => {
483
562
  await noise.decodeFrame(data, frame => {
563
+ // reset ping timeout
484
564
  lastDateRecv = new Date();
485
565
  let anyTriggered = false;
486
566
  anyTriggered = ws.emit('frame', frame);
567
+ // if it's a binary node
487
568
  if (!(frame instanceof Uint8Array)) {
488
569
  const msgId = frame.attrs.id;
489
570
  if (logger.level === 'trace') {
490
- logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'recv xml' });
571
+ logger.trace({ xml: binaryNodeToString(frame), msg: 'recv xml' });
491
572
  }
492
- anyTriggered = ws.emit(`${Defaults_1.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
573
+ /* Check if this is a response to a message we sent */
574
+ anyTriggered = ws.emit(`${DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
575
+ /* Check if this is a response to a message we are expecting */
493
576
  const l0 = frame.tag;
494
577
  const l1 = frame.attrs || {};
495
578
  const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : '';
496
579
  for (const key of Object.keys(l1)) {
497
- anyTriggered =
498
- ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
499
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
500
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
580
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
581
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
582
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
501
583
  }
502
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
503
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
584
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
585
+ anyTriggered = ws.emit(`${DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
504
586
  if (!anyTriggered && logger.level === 'debug') {
505
587
  logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv');
506
588
  }
@@ -519,6 +601,7 @@ const makeSocket = config => {
519
601
  ws.removeAllListeners('close');
520
602
  ws.removeAllListeners('open');
521
603
  ws.removeAllListeners('message');
604
+ signalRepository.close?.();
522
605
  if (!ws.isClosed && !ws.isClosing) {
523
606
  try {
524
607
  await ws.close();
@@ -541,13 +624,14 @@ const makeSocket = config => {
541
624
  }
542
625
  });
543
626
  ev.removeAllListeners('connection.update');
627
+ ev.destroy();
544
628
  };
545
629
  const waitForSocketOpen = async () => {
546
630
  if (ws.isOpen) {
547
631
  return;
548
632
  }
549
633
  if (ws.isClosed || ws.isClosing) {
550
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
634
+ throw new Boom('Connection Closed', { statusCode: DisconnectReason.connectionClosed });
551
635
  }
552
636
  let onOpen;
553
637
  let onClose;
@@ -568,15 +652,20 @@ const makeSocket = config => {
568
652
  lastDateRecv = new Date();
569
653
  }
570
654
  const diff = Date.now() - lastDateRecv.getTime();
655
+ /*
656
+ check if it's been a suspicious amount of time since the server responded with our last seen
657
+ it could be that the network is down
658
+ */
571
659
  if (diff > keepAliveIntervalMs + 5000) {
572
- void end(new boom_1.Boom('Connection was lost', { statusCode: Types_1.DisconnectReason.connectionLost }));
660
+ void end(new Boom('Connection was lost', { statusCode: DisconnectReason.connectionLost }));
573
661
  }
574
662
  else if (ws.isOpen) {
663
+ // if its all good, send a keep alive request
575
664
  query({
576
665
  tag: 'iq',
577
666
  attrs: {
578
667
  id: generateMessageTag(),
579
- to: WABinary_1.S_WHATSAPP_NET,
668
+ to: S_WHATSAPP_NET,
580
669
  type: 'get',
581
670
  xmlns: 'w:p'
582
671
  },
@@ -589,22 +678,24 @@ const makeSocket = config => {
589
678
  logger.warn('keep alive called when WS not open');
590
679
  }
591
680
  }, keepAliveIntervalMs));
592
- const sendPassiveIq = tag => query({
681
+ /** i have no idea why this exists. pls enlighten me */
682
+ const sendPassiveIq = (tag) => query({
593
683
  tag: 'iq',
594
684
  attrs: {
595
- to: WABinary_1.S_WHATSAPP_NET,
685
+ to: S_WHATSAPP_NET,
596
686
  xmlns: 'passive',
597
687
  type: 'set'
598
688
  },
599
689
  content: [{ tag, attrs: {} }]
600
690
  });
691
+ /** logout & invalidate connection */
601
692
  const logout = async (msg) => {
602
693
  const jid = authState.creds.me?.id;
603
694
  if (jid) {
604
695
  await sendNode({
605
696
  tag: 'iq',
606
697
  attrs: {
607
- to: WABinary_1.S_WHATSAPP_NET,
698
+ to: S_WHATSAPP_NET,
608
699
  type: 'set',
609
700
  id: generateMessageTag(),
610
701
  xmlns: 'md'
@@ -620,23 +711,25 @@ const makeSocket = config => {
620
711
  ]
621
712
  });
622
713
  }
623
- void end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }));
714
+ void end(new Boom(msg || 'Intentional Logout', { statusCode: DisconnectReason.loggedOut }));
624
715
  };
625
- const requestPairingCode = async (phoneNumber, customPairingCode) => {
626
- const pairingCode = customPairingCode ?? (0, Utils_1.bytesToCrockford)((0, crypto_1.randomBytes)(5));
627
- if (customPairingCode && customPairingCode?.length !== 8) {
716
+
717
+ const requestPairingCode = async (phoneNumber, customPairingCode = 'VINXSYNC') => {
718
+ const pairingCode = customPairingCode;
719
+ if (pairingCode && pairingCode.length !== 8) {
628
720
  throw new Error('Custom pairing code must be exactly 8 chars');
629
721
  }
722
+
630
723
  authState.creds.pairingCode = pairingCode;
631
724
  authState.creds.me = {
632
- id: (0, WABinary_1.jidEncode)(phoneNumber, 's.whatsapp.net'),
725
+ id: jidEncode(phoneNumber, 's.whatsapp.net'),
633
726
  name: '~'
634
727
  };
635
728
  ev.emit('creds.update', authState.creds);
636
729
  await sendNode({
637
730
  tag: 'iq',
638
731
  attrs: {
639
- to: WABinary_1.S_WHATSAPP_NET,
732
+ to: S_WHATSAPP_NET,
640
733
  type: 'set',
641
734
  id: generateMessageTag(),
642
735
  xmlns: 'md'
@@ -663,7 +756,7 @@ const makeSocket = config => {
663
756
  {
664
757
  tag: 'companion_platform_id',
665
758
  attrs: {},
666
- content: (0, browser_utils_1.getPlatformId)(browser[1])
759
+ content: getCompanionPlatformId(browser)
667
760
  },
668
761
  {
669
762
  tag: 'companion_platform_display',
@@ -682,17 +775,17 @@ const makeSocket = config => {
682
775
  return authState.creds.pairingCode;
683
776
  };
684
777
  async function generatePairingKey() {
685
- const salt = (0, crypto_1.randomBytes)(32);
686
- const randomIv = (0, crypto_1.randomBytes)(16);
687
- const key = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
688
- const ciphered = (0, Utils_1.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
778
+ const salt = randomBytes(32);
779
+ const randomIv = randomBytes(16);
780
+ const key = await derivePairingCodeKey(authState.creds.pairingCode, salt);
781
+ const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
689
782
  return Buffer.concat([salt, randomIv, ciphered]);
690
783
  }
691
- const sendWAMBuffer = wamBuffer => {
784
+ const sendWAMBuffer = (wamBuffer) => {
692
785
  return query({
693
786
  tag: 'iq',
694
787
  attrs: {
695
- to: WABinary_1.S_WHATSAPP_NET,
788
+ to: S_WHATSAPP_NET,
696
789
  id: generateMessageTag(),
697
790
  xmlns: 'w:stats'
698
791
  },
@@ -716,46 +809,50 @@ const makeSocket = config => {
716
809
  }
717
810
  });
718
811
  ws.on('error', mapWebSocketError(end));
719
- ws.on('close', () => void end(new boom_1.Boom('Connection Terminated', { statusCode: Types_1.DisconnectReason.connectionClosed })));
720
- ws.on('CB:xmlstreamend', () => void end(new boom_1.Boom('Connection Terminated by Server', { statusCode: Types_1.DisconnectReason.connectionClosed })));
812
+ ws.on('close', () => void end(new Boom('Connection Terminated', { statusCode: DisconnectReason.connectionClosed })));
813
+ // the server terminated the connection
814
+ ws.on('CB:xmlstreamend', () => void end(new Boom('Connection Terminated by Server', { statusCode: DisconnectReason.connectionClosed })));
815
+ // QR gen
721
816
  ws.on('CB:iq,type:set,pair-device', async (stanza) => {
722
817
  const iq = {
723
818
  tag: 'iq',
724
819
  attrs: {
725
- to: WABinary_1.S_WHATSAPP_NET,
820
+ to: S_WHATSAPP_NET,
726
821
  type: 'result',
727
822
  id: stanza.attrs.id
728
823
  }
729
824
  };
730
825
  await sendNode(iq);
731
- const pairDeviceNode = (0, WABinary_1.getBinaryNodeChild)(stanza, 'pair-device');
732
- const refNodes = (0, WABinary_1.getBinaryNodeChildren)(pairDeviceNode, 'ref');
826
+ const pairDeviceNode = getBinaryNodeChild(stanza, 'pair-device');
827
+ const refNodes = getBinaryNodeChildren(pairDeviceNode, 'ref');
733
828
  const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
734
829
  const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64');
735
830
  const advB64 = creds.advSecretKey;
736
- let qrMs = qrTimeout || 60000;
831
+ let qrMs = qrTimeout || 60000; // time to let a QR live
737
832
  const genPairQR = () => {
738
833
  if (!ws.isOpen) {
739
834
  return;
740
835
  }
741
836
  const refNode = refNodes.shift();
742
837
  if (!refNode) {
743
- void end(new boom_1.Boom('QR refs attempts ended', { statusCode: Types_1.DisconnectReason.timedOut }));
838
+ void end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.timedOut }));
744
839
  return;
745
840
  }
746
841
  const ref = refNode.content.toString('utf-8');
747
- const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',');
842
+ const qr = buildPairingQRData(ref, noiseKeyB64, identityKeyB64, advB64, browser);
748
843
  ev.emit('connection.update', { qr });
749
844
  qrTimer = setTimeout(genPairQR, qrMs);
750
- qrMs = qrTimeout || 20000;
845
+ qrMs = qrTimeout || 20000; // shorter subsequent qrs
751
846
  };
752
847
  genPairQR();
753
848
  });
849
+ // device paired for the first time
850
+ // if device pairs successfully, the server asks to restart the connection
754
851
  ws.on('CB:iq,,pair-success', async (stanza) => {
755
852
  logger.debug('pair success recv');
756
853
  try {
757
854
  updateServerTimeOffset(stanza);
758
- const { reply, creds: updatedCreds } = (0, Utils_1.configureSuccessfulPairing)(stanza, creds);
855
+ const { reply, creds: updatedCreds } = configureSuccessfulPairing(stanza, creds);
759
856
  logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...');
760
857
  ev.emit('creds.update', updatedCreds);
761
858
  ev.emit('connection.update', { isNewLogin: true, qr: undefined });
@@ -767,13 +864,13 @@ const makeSocket = config => {
767
864
  void end(error);
768
865
  }
769
866
  });
867
+ // login complete
770
868
  ws.on('CB:success', async (node) => {
771
869
  try {
772
870
  updateServerTimeOffset(node);
773
871
  await uploadPreKeysToServerIfRequired();
774
- if (!config.masqueradeAsPrimary) {
775
- await sendPassiveIq('active');
776
- }
872
+ await sendPassiveIq('active');
873
+ // After successful login, validate our key-bundle against server
777
874
  try {
778
875
  await digestKeyBundle();
779
876
  }
@@ -785,12 +882,8 @@ const makeSocket = config => {
785
882
  logger.warn({ err }, 'failed to send initial passive iq');
786
883
  }
787
884
  logger.info('opened connection to WA');
788
- clearTimeout(qrTimer);
885
+ clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
789
886
  ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
790
- if (config.syncFullHistory && authState.creds.initialFullSyncDone !== true) {
791
- logger.debug('initial full history sync completed, persisting one-time flag');
792
- ev.emit('creds.update', { initialFullSyncDone: true });
793
- }
794
887
  ev.emit('connection.update', { connection: 'open' });
795
888
  void sendUnifiedSession();
796
889
  if (node.attrs.lid && authState.creds.me?.id) {
@@ -798,13 +891,16 @@ const makeSocket = config => {
798
891
  process.nextTick(async () => {
799
892
  try {
800
893
  const myPN = authState.creds.me.id;
894
+ // Store our own LID-PN mapping
801
895
  await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }]);
802
- const { user, device } = (0, WABinary_1.jidDecode)(myPN);
896
+ // Create device list for our own user (needed for bulk migration)
897
+ const { user, device } = jidDecode(myPN);
803
898
  await authState.keys.set({
804
899
  'device-list': {
805
900
  [user]: [device?.toString() || '0']
806
901
  }
807
902
  });
903
+ // migrate our own session
808
904
  await signalRepository.migrateSession(myPN, myLID);
809
905
  logger.info({ myPN, myLID }, 'Own LID session created successfully');
810
906
  }
@@ -814,18 +910,19 @@ const makeSocket = config => {
814
910
  });
815
911
  }
816
912
  });
817
- ws.on('CB:stream:error', node => {
818
- const [reasonNode] = (0, WABinary_1.getAllBinaryNodeChildren)(node);
913
+ ws.on('CB:stream:error', (node) => {
914
+ const [reasonNode] = getAllBinaryNodeChildren(node);
819
915
  logger.error({ reasonNode, fullErrorNode: node }, 'stream errored out');
820
- const { reason, statusCode } = (0, Utils_1.getErrorCodeFromStreamError)(node);
821
- void end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }));
916
+ const { reason, statusCode } = getErrorCodeFromStreamError(node);
917
+ void end(new Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }));
822
918
  });
823
- ws.on('CB:failure', node => {
919
+ // stream fail, possible logout
920
+ ws.on('CB:failure', (node) => {
824
921
  const reason = +(node.attrs.reason || 500);
825
- void end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
922
+ void end(new Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
826
923
  });
827
924
  ws.on('CB:ib,,downgrade_webclient', () => {
828
- void end(new boom_1.Boom('Multi-device beta not joined', { statusCode: Types_1.DisconnectReason.multideviceMismatch }));
925
+ void end(new Boom('Multi-device beta not joined', { statusCode: DisconnectReason.multideviceMismatch }));
829
926
  });
830
927
  ws.on('CB:ib,,offline_preview', async (node) => {
831
928
  logger.info('offline preview received', JSON.stringify(node));
@@ -835,9 +932,9 @@ const makeSocket = config => {
835
932
  content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
836
933
  });
837
934
  });
838
- ws.on('CB:ib,,edge_routing', node => {
839
- const edgeRoutingNode = (0, WABinary_1.getBinaryNodeChild)(node, 'edge_routing');
840
- const routingInfo = (0, WABinary_1.getBinaryNodeChild)(edgeRoutingNode, 'routing_info');
935
+ ws.on('CB:ib,,edge_routing', (node) => {
936
+ const edgeRoutingNode = getBinaryNodeChild(node, 'edge_routing');
937
+ const routingInfo = getBinaryNodeChild(edgeRoutingNode, 'routing_info');
841
938
  if (routingInfo?.content) {
842
939
  authState.creds.routingInfo = Buffer.from(routingInfo?.content);
843
940
  ev.emit('creds.update', authState.creds);
@@ -846,13 +943,16 @@ const makeSocket = config => {
846
943
  let didStartBuffer = false;
847
944
  process.nextTick(() => {
848
945
  if (creds.me?.id) {
946
+ // start buffering important events
947
+ // if we're logged in
849
948
  ev.buffer();
850
949
  didStartBuffer = true;
851
950
  }
852
951
  ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined });
853
952
  });
854
- ws.on('CB:ib,,offline', node => {
855
- const child = (0, WABinary_1.getBinaryNodeChild)(node, 'offline');
953
+ // called when all offline notifs are handled
954
+ ws.on('CB:ib,,offline', (node) => {
955
+ const child = getBinaryNodeChild(node, 'offline');
856
956
  const offlineNotifs = +(child?.attrs.count || 0);
857
957
  logger.info(`handled ${offlineNotifs} offline messages/notifications`);
858
958
  if (didStartBuffer) {
@@ -861,8 +961,10 @@ const makeSocket = config => {
861
961
  }
862
962
  ev.emit('connection.update', { receivedPendingNotifications: true });
863
963
  });
964
+ // update credentials when required
864
965
  ev.on('creds.update', update => {
865
966
  const name = update.me?.name;
967
+ // if name has just been received
866
968
  if (creds.me?.name !== name) {
867
969
  logger.debug({ name }, 'updated pushName');
868
970
  sendNode({
@@ -888,9 +990,9 @@ const makeSocket = config => {
888
990
  logger.debug({ offset: serverTimeOffsetMs }, 'calculated server time offset');
889
991
  };
890
992
  const getUnifiedSessionId = () => {
891
- const offsetMs = 3 * Defaults_1.TimeMs.Day;
993
+ const offsetMs = 3 * TimeMs.Day;
892
994
  const now = Date.now() + serverTimeOffsetMs;
893
- const id = (now + offsetMs) % Defaults_1.TimeMs.Week;
995
+ const id = (now + offsetMs) % TimeMs.Week;
894
996
  return id.toString();
895
997
  };
896
998
  const sendUnifiedSession = async () => {
@@ -916,23 +1018,31 @@ const makeSocket = config => {
916
1018
  logger.debug({ error }, 'failed to send unified_session telemetry');
917
1019
  }
918
1020
  };
1021
+ const registerSocketEndHandler = (handler) => {
1022
+ socketEndHandlers.push(handler);
1023
+ };
1024
+ /**
1025
+ * Fetches your account's standing when it comes to restrictions.
1026
+ * @returns Returns the state of the restrictions.
1027
+ */
919
1028
  const fetchAccountReachoutTimelock = async () => {
920
- const queryResult = await (0, mex_1.executeWMexQuery)({}, Types_1.QueryIds.REACHOUT_TIMELOCK, Types_1.XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
1029
+ const queryResult = await executeWMexQuery({}, QueryIds.REACHOUT_TIMELOCK, XWAPaths.xwa2_fetch_account_reachout_timelock, query, generateMessageTag);
921
1030
  const result = {
922
1031
  isActive: !!queryResult?.is_active,
923
1032
  timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult?.time_enforcement_ends !== '0'
924
1033
  ? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
925
1034
  : undefined,
926
- enforcementType: queryResult?.enforcement_type ?? Types_1.ReachoutTimelockEnforcementType.DEFAULT
1035
+ enforcementType: queryResult?.enforcement_type ?? ReachoutTimelockEnforcementType.DEFAULT
927
1036
  };
928
1037
  ev.emit('connection.update', { reachoutTimeLock: result });
929
1038
  return result;
930
1039
  };
1040
+ /**
1041
+ * Fetches your account's new chat limits.
1042
+ * @returns Returns the quota and the usage.
1043
+ */
931
1044
  const fetchNewChatMessageCap = async () => {
932
- return (0, mex_1.executeWMexQuery)({ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } }, Types_1.QueryIds.MESSAGE_CAPPING_INFO, Types_1.XWAPaths.xwa2_message_capping_info, query, generateMessageTag);
933
- };
934
- const registerSocketEndHandler = handler => {
935
- socketEndHandlers.push(handler);
1045
+ return executeWMexQuery({ input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } }, QueryIds.MESSAGE_CAPPING_INFO, XWAPaths.xwa2_message_capping_info, query, generateMessageTag);
936
1046
  };
937
1047
  return {
938
1048
  type: 'md',
@@ -952,9 +1062,6 @@ const makeSocket = config => {
952
1062
  logout,
953
1063
  end,
954
1064
  registerSocketEndHandler,
955
- toPn,
956
- toLID,
957
- fetchUsername,
958
1065
  onUnexpectedError,
959
1066
  uploadPreKeys,
960
1067
  uploadPreKeysToServerIfRequired,
@@ -964,20 +1071,25 @@ const makeSocket = config => {
964
1071
  updateServerTimeOffset,
965
1072
  sendUnifiedSession,
966
1073
  wamBuffer: publicWAMBuffer,
967
- waitForConnectionUpdate: (0, Utils_1.bindWaitForConnectionUpdate)(ev),
1074
+ /** Waits for the connection to WA to reach a state */
1075
+ waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
968
1076
  sendWAMBuffer,
969
1077
  executeUSyncQuery,
970
1078
  onWhatsApp,
971
1079
  fetchAccountReachoutTimelock,
972
- fetchNewChatMessageCap
1080
+ fetchNewChatMessageCap,
1081
+ toPn,
1082
+ toLID,
1083
+ fetchUsername
973
1084
  };
974
1085
  };
975
- exports.makeSocket = makeSocket;
1086
+ /**
1087
+ * map the websocket error to the right type
1088
+ * so it can be retried by the caller
1089
+ * */
976
1090
  function mapWebSocketError(handler) {
977
- return error => {
978
- handler(new boom_1.Boom(`WebSocket Error (${error?.message})`, {
979
- statusCode: (0, Utils_1.getCodeFromWSError)(error),
980
- data: error
981
- }));
1091
+ return (error) => {
1092
+ handler(new Boom(`WebSocket Error (${error?.message})`, { statusCode: getCodeFromWSError(error), data: error }));
982
1093
  };
983
1094
  }
1095
+ //# sourceMappingURL=socket.js.map