jagproject 26.3.23 → 26.3.26

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 (209) hide show
  1. package/WAProto/GenerateStatics.sh +3 -4
  2. package/WAProto/WAProto.proto +1215 -511
  3. package/WAProto/fix-imports.js +73 -0
  4. package/WAProto/index.d.ts +14017 -0
  5. package/WAProto/index.js +64857 -145167
  6. package/engine-requirements.js +4 -7
  7. package/lib/Defaults/index.d.ts +74 -0
  8. package/lib/Defaults/index.js +49 -35
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Defaults/wileys-version.json +2 -2
  11. package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
  12. package/lib/Signal/Group/group-session-builder.d.ts +15 -0
  13. package/lib/Signal/Group/group-session-builder.js +5 -3
  14. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  15. package/lib/Signal/Group/group_cipher.js +35 -46
  16. package/lib/Signal/Group/index.d.ts +12 -0
  17. package/lib/Signal/Group/index.js +21 -21
  18. package/lib/Signal/Group/keyhelper.d.ts +11 -0
  19. package/lib/Signal/Group/keyhelper.js +2 -2
  20. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  21. package/lib/Signal/Group/sender-chain-key.js +5 -10
  22. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  23. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  24. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  25. package/lib/Signal/Group/sender-key-message.js +8 -8
  26. package/lib/Signal/Group/sender-key-name.d.ts +18 -0
  27. package/lib/Signal/Group/sender-key-record.d.ts +31 -0
  28. package/lib/Signal/Group/sender-key-record.js +7 -16
  29. package/lib/Signal/Group/sender-key-state.d.ts +39 -0
  30. package/lib/Signal/Group/sender-key-state.js +25 -37
  31. package/lib/Signal/Group/sender-message-key.d.ts +12 -0
  32. package/lib/Signal/Group/sender-message-key.js +2 -2
  33. package/lib/Signal/libsignal.d.ts +5 -0
  34. package/lib/Signal/libsignal.js +358 -54
  35. package/lib/Signal/lid-mapping.d.ts +19 -0
  36. package/lib/Signal/lid-mapping.js +274 -0
  37. package/lib/Socket/Client/index.d.ts +3 -0
  38. package/lib/Socket/Client/index.js +2 -2
  39. package/lib/Socket/Client/types.d.ts +16 -0
  40. package/lib/Socket/Client/types.js +1 -0
  41. package/lib/Socket/Client/websocket.d.ts +13 -0
  42. package/lib/Socket/Client/websocket.js +18 -30
  43. package/lib/Socket/business.d.ts +202 -0
  44. package/lib/Socket/business.js +160 -38
  45. package/lib/Socket/chats.d.ts +111 -0
  46. package/lib/Socket/chats.js +497 -314
  47. package/lib/Socket/communities.d.ts +258 -0
  48. package/lib/Socket/communities.js +438 -0
  49. package/lib/Socket/community.js +333 -0
  50. package/lib/Socket/groups.d.ts +150 -0
  51. package/lib/Socket/groups.js +229 -91
  52. package/lib/Socket/index.d.ts +245 -0
  53. package/lib/Socket/index.js +9 -6
  54. package/lib/Socket/messages-recv.d.ts +187 -0
  55. package/lib/Socket/messages-recv.js +1105 -501
  56. package/lib/Socket/messages-send.d.ts +183 -0
  57. package/lib/Socket/messages-send.js +1181 -501
  58. package/lib/Socket/mex.d.ts +3 -0
  59. package/lib/Socket/mex.js +45 -0
  60. package/lib/Socket/newsletter.d.ts +160 -0
  61. package/lib/Socket/newsletter.js +227 -200
  62. package/lib/Socket/socket.d.ts +55 -0
  63. package/lib/Socket/socket.js +507 -206
  64. package/lib/Socket/usync.js +6 -6
  65. package/lib/Store/index.js +17 -5
  66. package/lib/Store/make-cache-manager-store.js +83 -0
  67. package/lib/Store/make-in-memory-store.js +48 -89
  68. package/lib/Store/make-ordered-dictionary.js +1 -1
  69. package/lib/Types/Auth.d.ts +116 -0
  70. package/lib/Types/Bussines.d.ts +25 -0
  71. package/lib/Types/Bussines.js +2 -0
  72. package/lib/Types/Call.d.ts +15 -0
  73. package/lib/Types/Chat.d.ts +123 -0
  74. package/lib/Types/Chat.js +7 -1
  75. package/lib/Types/Contact.d.ts +24 -0
  76. package/lib/Types/Events.d.ts +237 -0
  77. package/lib/Types/Events.js +1 -0
  78. package/lib/Types/GroupMetadata.d.ts +67 -0
  79. package/lib/Types/Label.d.ts +47 -0
  80. package/lib/Types/Label.js +1 -3
  81. package/lib/Types/LabelAssociation.d.ts +30 -0
  82. package/lib/Types/LabelAssociation.js +1 -3
  83. package/lib/Types/Message.d.ts +305 -0
  84. package/lib/Types/Message.js +9 -5
  85. package/lib/Types/MexUpdates.js +11 -0
  86. package/lib/Types/Newsletter.d.ts +135 -0
  87. package/lib/Types/Newsletter.js +36 -11
  88. package/lib/Types/Product.d.ts +79 -0
  89. package/lib/Types/Signal.d.ts +76 -0
  90. package/lib/Types/Signal.js +1 -0
  91. package/lib/Types/Socket.d.ts +133 -0
  92. package/lib/Types/Socket.js +1 -0
  93. package/lib/Types/State.d.ts +39 -0
  94. package/lib/Types/State.js +12 -0
  95. package/lib/Types/USync.d.ts +26 -0
  96. package/lib/Types/USync.js +1 -0
  97. package/lib/Types/index.d.ts +65 -0
  98. package/lib/Types/index.js +14 -14
  99. package/lib/Utils/audioToBuffer.js +31 -0
  100. package/lib/Utils/auth-utils.d.ts +19 -0
  101. package/lib/Utils/auth-utils.js +222 -123
  102. package/lib/Utils/baileys-event-stream.js +60 -0
  103. package/lib/Utils/bridge-runtime.d.ts +1 -0
  104. package/lib/Utils/bridge-runtime.js +14 -0
  105. package/lib/Utils/browser-utils.d.ts +4 -0
  106. package/lib/Utils/browser-utils.js +38 -29
  107. package/lib/Utils/business.d.ts +23 -0
  108. package/lib/Utils/business.js +54 -48
  109. package/lib/Utils/chat-utils.d.ts +70 -0
  110. package/lib/Utils/chat-utils.js +284 -189
  111. package/lib/Utils/crypto.d.ts +37 -0
  112. package/lib/Utils/crypto.js +16 -41
  113. package/lib/Utils/decode-wa-message.d.ts +48 -0
  114. package/lib/Utils/decode-wa-message.js +128 -48
  115. package/lib/Utils/event-buffer.d.ts +34 -0
  116. package/lib/Utils/event-buffer.js +124 -62
  117. package/lib/Utils/generics.d.ts +91 -0
  118. package/lib/Utils/generics.js +154 -138
  119. package/lib/Utils/history.d.ts +22 -0
  120. package/lib/Utils/history.js +77 -34
  121. package/lib/Utils/identity-change-handler.d.ts +37 -0
  122. package/lib/Utils/identity-change-handler.js +54 -0
  123. package/lib/Utils/index.d.ts +22 -0
  124. package/lib/Utils/index.js +32 -19
  125. package/lib/Utils/link-preview.d.ts +21 -0
  126. package/lib/Utils/link-preview.js +12 -17
  127. package/lib/Utils/logger.d.ts +13 -0
  128. package/lib/Utils/lt-hash.d.ts +8 -0
  129. package/lib/Utils/lt-hash.js +2 -43
  130. package/lib/Utils/make-mutex.d.ts +9 -0
  131. package/lib/Utils/make-mutex.js +21 -27
  132. package/lib/Utils/message-retry-manager.d.ts +110 -0
  133. package/lib/Utils/message-retry-manager.js +143 -45
  134. package/lib/Utils/messages-media.d.ts +130 -0
  135. package/lib/Utils/messages-media.js +429 -502
  136. package/lib/Utils/messages-newsletter.d.ts +84 -0
  137. package/lib/Utils/messages-newsletter.js +295 -0
  138. package/lib/Utils/messages.d.ts +92 -0
  139. package/lib/Utils/messages.js +1025 -674
  140. package/lib/Utils/noise-handler.d.ts +20 -0
  141. package/lib/Utils/noise-handler.js +145 -91
  142. package/lib/Utils/pre-key-manager.d.ts +28 -0
  143. package/lib/Utils/pre-key-manager.js +112 -0
  144. package/lib/Utils/process-message.d.ts +60 -0
  145. package/lib/Utils/process-message.js +316 -184
  146. package/lib/Utils/reporting-utils.d.ts +11 -0
  147. package/lib/Utils/reporting-utils.js +262 -0
  148. package/lib/Utils/resolve-jid.d.ts +43 -0
  149. package/lib/Utils/resolve-jid.js +95 -0
  150. package/lib/Utils/rust-bridge-shim.d.ts +22 -0
  151. package/lib/Utils/rust-bridge-shim.js +70 -0
  152. package/lib/Utils/serial-task-queue.js +29 -0
  153. package/lib/Utils/signal.d.ts +34 -0
  154. package/lib/Utils/signal.js +56 -39
  155. package/lib/Utils/streamToBuffer.js +17 -0
  156. package/lib/Utils/sync-action-utils.d.ts +19 -0
  157. package/lib/Utils/sync-action-utils.js +52 -0
  158. package/lib/Utils/tc-token-utils.d.ts +12 -0
  159. package/lib/Utils/tc-token-utils.js +20 -0
  160. package/lib/Utils/use-mongo-file-auth-state.js +71 -0
  161. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  162. package/lib/Utils/use-multi-file-auth-state.js +11 -12
  163. package/lib/Utils/use-single-file-auth-state.js +73 -0
  164. package/lib/Utils/validate-connection.d.ts +11 -0
  165. package/lib/Utils/validate-connection.js +59 -82
  166. package/lib/Utils/wileys-event-stream.js +1 -61
  167. package/lib/WABinary/constants.d.ts +28 -0
  168. package/lib/WABinary/decode.d.ts +7 -0
  169. package/lib/WABinary/decode.js +39 -4
  170. package/lib/WABinary/encode.d.ts +3 -0
  171. package/lib/WABinary/encode.js +17 -11
  172. package/lib/WABinary/generic-utils.d.ts +15 -0
  173. package/lib/WABinary/generic-utils.js +46 -18
  174. package/lib/WABinary/index.d.ts +6 -0
  175. package/lib/WABinary/index.js +9 -5
  176. package/lib/WABinary/jid-utils.d.ts +48 -0
  177. package/lib/WABinary/jid-utils.js +67 -37
  178. package/lib/WABinary/types.d.ts +19 -0
  179. package/lib/WABinary/types.js +34 -0
  180. package/lib/WAM/BinaryInfo.d.ts +9 -0
  181. package/lib/WAM/constants.d.ts +40 -0
  182. package/lib/WAM/constants.js +19183 -11678
  183. package/lib/WAM/encode.d.ts +3 -0
  184. package/lib/WAM/encode.js +15 -17
  185. package/lib/WAM/index.d.ts +4 -0
  186. package/lib/WAM/index.js +3 -3
  187. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  188. package/lib/WAUSync/Protocols/USyncContactProtocol.js +6 -6
  189. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  190. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +9 -9
  191. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  192. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +6 -6
  193. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  194. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -8
  195. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  196. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +18 -17
  197. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  198. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +11 -3
  199. package/lib/WAUSync/Protocols/index.d.ts +5 -0
  200. package/lib/WAUSync/Protocols/index.js +6 -4
  201. package/lib/WAUSync/USyncQuery.d.ts +29 -0
  202. package/lib/WAUSync/USyncQuery.js +38 -30
  203. package/lib/WAUSync/USyncUser.d.ts +13 -0
  204. package/lib/WAUSync/index.d.ts +4 -0
  205. package/lib/WAUSync/index.js +3 -3
  206. package/lib/index.d.ts +12 -0
  207. package/lib/index.js +3 -5
  208. package/package.json +7 -4
  209. package/LICENSE +0 -21
@@ -5,12 +5,15 @@ const boom_1 = require("@hapi/boom");
5
5
  const crypto_1 = require("crypto");
6
6
  const url_1 = require("url");
7
7
  const util_1 = require("util");
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 WABinary_1 = require("../WABinary");
13
- const Client_1 = require("./Client");
8
+ const index_js_1 = require("../../WAProto/index.js");
9
+ const index_js_2 = require("../Defaults/index.js");
10
+ const index_js_3 = require("../Types/index.js");
11
+ const index_js_4 = require("../Utils/index.js");
12
+ const browser_utils_js_1 = require("../Utils/browser-utils.js");
13
+ const index_js_5 = require("../WABinary/index.js");
14
+ const BinaryInfo_js_1 = require("../WAM/BinaryInfo.js");
15
+ const index_js_6 = require("../WAUSync/index.js");
16
+ const index_js_7 = require("./Client/index.js");
14
17
  /**
15
18
  * Connects to WA servers and performs:
16
19
  * - simple queries (no retry mechanism, wait for connection establishment)
@@ -18,46 +21,45 @@ const Client_1 = require("./Client");
18
21
  * - query phone connection
19
22
  */
20
23
  const makeSocket = (config) => {
21
- var _a, _b;
22
- const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository, } = config;
24
+ const { waWebSocketUrl, connectTimeoutMs, logger, keepAliveIntervalMs, browser, auth: authState, printQRInTerminal, defaultQueryTimeoutMs, transactionOpts, qrTimeout, makeSignalRepository } = config;
25
+ const publicWAMBuffer = new BinaryInfo_js_1.BinaryInfo();
26
+ let serverTimeOffsetMs = 0;
27
+ const uqTagId = (0, index_js_4.generateMdTagPrefix)();
28
+ const generateMessageTag = () => `${uqTagId}${epoch++}`;
29
+ if (printQRInTerminal) {
30
+ 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.');
31
+ }
32
+ const syncDisabled = index_js_2.PROCESSABLE_HISTORY_TYPES.map(syncType => config.shouldSyncHistoryMessage({ syncType })).filter(x => x === false)
33
+ .length === index_js_2.PROCESSABLE_HISTORY_TYPES.length;
34
+ if (syncDisabled) {
35
+ logger.warn('⚠️ DANGER: DISABLING ALL SYNC BY shouldSyncHistoryMsg PREVENTS BAILEYS FROM ACCESSING INITIAL LID MAPPINGS, LEADING TO INSTABILIY AND SESSION ERRORS');
36
+ }
23
37
  const url = typeof waWebSocketUrl === 'string' ? new url_1.URL(waWebSocketUrl) : waWebSocketUrl;
24
38
  if (config.mobile || url.protocol === 'tcp:') {
25
- throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: Types_1.DisconnectReason.loggedOut });
39
+ throw new boom_1.Boom('Mobile API is not supported anymore', { statusCode: index_js_3.DisconnectReason.loggedOut });
26
40
  }
27
- if (url.protocol === 'wss' && ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.routingInfo)) {
41
+ if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
28
42
  url.searchParams.append('ED', authState.creds.routingInfo.toString('base64url'));
29
43
  }
30
- const ws = new Client_1.WebSocketClient(url, config);
31
- ws.connect();
32
- const ev = (0, Utils_1.makeEventBuffer)(logger);
33
44
  /** ephemeral key pair used to encrypt/decrypt communication. Unique for each connection */
34
- const ephemeralKeyPair = Utils_1.Curve.generateKeyPair();
45
+ const ephemeralKeyPair = index_js_4.Curve.generateKeyPair();
35
46
  /** WA noise protocol wrapper */
36
- const noise = (0, Utils_1.makeNoiseHandler)({
47
+ const noise = (0, index_js_4.makeNoiseHandler)({
37
48
  keyPair: ephemeralKeyPair,
38
- NOISE_HEADER: Defaults_1.NOISE_WA_HEADER,
49
+ NOISE_HEADER: index_js_2.NOISE_WA_HEADER,
39
50
  logger,
40
- routingInfo: (_b = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _b === void 0 ? void 0 : _b.routingInfo
51
+ routingInfo: authState?.creds?.routingInfo
41
52
  });
42
- const { creds } = authState;
43
- // add transaction capability
44
- const keys = (0, Utils_1.addTransactionCapability)(authState.keys, logger, transactionOpts);
45
- const signalRepository = makeSignalRepository({ creds, keys });
46
- let lastDateRecv;
47
- let epoch = 1;
48
- let keepAliveReq;
49
- let qrTimer;
50
- let closed = false;
51
- const uqTagId = (0, Utils_1.generateMdTagPrefix)();
52
- const generateMessageTag = () => `${uqTagId}${epoch++}`;
53
+ const ws = new index_js_7.WebSocketClient(url, config);
54
+ ws.connect();
53
55
  const sendPromise = (0, util_1.promisify)(ws.send);
54
56
  /** send a raw buffer */
55
57
  const sendRawMessage = async (data) => {
56
58
  if (!ws.isOpen) {
57
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
59
+ throw new boom_1.Boom('Connection Closed', { statusCode: index_js_3.DisconnectReason.connectionClosed });
58
60
  }
59
61
  const bytes = noise.encodeFrame(data);
60
- await (0, Utils_1.promiseTimeout)(connectTimeoutMs, async (resolve, reject) => {
62
+ await (0, index_js_4.promiseTimeout)(connectTimeoutMs, async (resolve, reject) => {
61
63
  try {
62
64
  await sendPromise.call(ws, bytes);
63
65
  resolve();
@@ -70,52 +72,11 @@ const makeSocket = (config) => {
70
72
  /** send a binary node */
71
73
  const sendNode = (frame) => {
72
74
  if (logger.level === 'trace') {
73
- logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'xml send' });
75
+ logger.trace({ xml: (0, index_js_5.binaryNodeToString)(frame), msg: 'xml send' });
74
76
  }
75
- const buff = (0, WABinary_1.encodeBinaryNode)(frame);
77
+ const buff = (0, index_js_5.encodeBinaryNode)(frame);
76
78
  return sendRawMessage(buff);
77
79
  };
78
- /** log & process any unexpected errors */
79
- const onUnexpectedError = (err, msg) => {
80
- logger.error({ err }, `unexpected error in '${msg}'`);
81
- const message = (err && ((err.stack || err.message) || String(err))).toLowerCase();
82
- // auto recover from cryptographic desyncs by re-uploading prekeys
83
- if (message.includes('bad mac') || (message.includes('mac') && message.includes('invalid'))) {
84
- try {
85
- uploadPreKeysToServerIfRequired(true)
86
- .catch(e => logger.warn({ e }, 'failed to re-upload prekeys after bad mac'));
87
- }
88
- catch (_e) {
89
- // ignore
90
- }
91
- }
92
- };
93
- /** await the next incoming message */
94
- const awaitNextMessage = async (sendMsg) => {
95
- if (!ws.isOpen) {
96
- throw new boom_1.Boom('Connection Closed', {
97
- statusCode: Types_1.DisconnectReason.connectionClosed
98
- });
99
- }
100
- let onOpen;
101
- let onClose;
102
- const result = (0, Utils_1.promiseTimeout)(connectTimeoutMs, (resolve, reject) => {
103
- onOpen = resolve;
104
- onClose = mapWebSocketError(reject);
105
- ws.on('frame', onOpen);
106
- ws.on('close', onClose);
107
- ws.on('error', onClose);
108
- })
109
- .finally(() => {
110
- ws.off('frame', onOpen);
111
- ws.off('close', onClose);
112
- ws.off('error', onClose);
113
- });
114
- if (sendMsg) {
115
- sendRawMessage(sendMsg).catch(onClose);
116
- }
117
- return result;
118
- };
119
80
  /**
120
81
  * Wait for a message with a certain tag to be received
121
82
  * @param msgId the message tag to await
@@ -125,21 +86,38 @@ const makeSocket = (config) => {
125
86
  let onRecv;
126
87
  let onErr;
127
88
  try {
128
- const result = await (0, Utils_1.promiseTimeout)(timeoutMs, (resolve, reject) => {
129
- onRecv = resolve;
89
+ const result = await (0, index_js_4.promiseTimeout)(timeoutMs, (resolve, reject) => {
90
+ onRecv = data => {
91
+ resolve(data);
92
+ };
130
93
  onErr = err => {
131
- reject(err || new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed }));
94
+ reject(err ||
95
+ new boom_1.Boom('Connection Closed', {
96
+ statusCode: index_js_3.DisconnectReason.connectionClosed
97
+ }));
132
98
  };
133
99
  ws.on(`TAG:${msgId}`, onRecv);
134
- ws.on('close', onErr); // if the socket closes, you'll never receive the message
135
- ws.off('error', onErr);
100
+ ws.on('close', onErr);
101
+ ws.on('error', onErr);
102
+ return () => reject(new boom_1.Boom('Query Cancelled'));
136
103
  });
137
104
  return result;
138
105
  }
106
+ catch (error) {
107
+ // Catch timeout and return undefined instead of throwing
108
+ if (error instanceof boom_1.Boom && error.output?.statusCode === index_js_3.DisconnectReason.timedOut) {
109
+ logger?.warn?.({ msgId }, 'timed out waiting for message');
110
+ return undefined;
111
+ }
112
+ throw error;
113
+ }
139
114
  finally {
140
- ws.off(`TAG:${msgId}`, onRecv);
141
- ws.off('close', onErr); // if the socket closes, you'll never receive the message
142
- ws.off('error', onErr);
115
+ if (onRecv)
116
+ ws.off(`TAG:${msgId}`, onRecv);
117
+ if (onErr) {
118
+ ws.off('close', onErr);
119
+ ws.off('error', onErr);
120
+ }
143
121
  }
144
122
  };
145
123
  /** send a query, and wait for its response. auto-generates message ID if not provided */
@@ -148,12 +126,185 @@ const makeSocket = (config) => {
148
126
  node.attrs.id = generateMessageTag();
149
127
  }
150
128
  const msgId = node.attrs.id;
151
- const [result] = await Promise.all([
152
- waitForMessage(msgId, timeoutMs),
129
+ const result = await (0, index_js_4.promiseTimeout)(timeoutMs, async (resolve, reject) => {
130
+ const result = waitForMessage(msgId, timeoutMs).catch(reject);
153
131
  sendNode(node)
154
- ]);
155
- if ('tag' in result) {
156
- (0, WABinary_1.assertNodeErrorFree)(result);
132
+ .then(async () => resolve(await result))
133
+ .catch(reject);
134
+ });
135
+ if (result && 'tag' in result) {
136
+ (0, index_js_5.assertNodeErrorFree)(result);
137
+ }
138
+ return result;
139
+ };
140
+ // Validate current key-bundle on server; on failure, trigger pre-key upload and rethrow
141
+ const digestKeyBundle = async () => {
142
+ const res = await query({
143
+ tag: 'iq',
144
+ attrs: { to: index_js_5.S_WHATSAPP_NET, type: 'get', xmlns: 'encrypt' },
145
+ content: [{ tag: 'digest', attrs: {} }]
146
+ });
147
+ const digestNode = (0, index_js_5.getBinaryNodeChild)(res, 'digest');
148
+ if (!digestNode) {
149
+ await uploadPreKeys();
150
+ throw new Error('encrypt/get digest returned no digest node');
151
+ }
152
+ };
153
+ // Rotate our signed pre-key on server; on failure, run digest as fallback and rethrow
154
+ const rotateSignedPreKey = async () => {
155
+ const newId = (creds.signedPreKey.keyId || 0) + 1;
156
+ const skey = await (0, index_js_4.signedKeyPair)(creds.signedIdentityKey, newId);
157
+ await query({
158
+ tag: 'iq',
159
+ attrs: { to: index_js_5.S_WHATSAPP_NET, type: 'set', xmlns: 'encrypt' },
160
+ content: [
161
+ {
162
+ tag: 'rotate',
163
+ attrs: {},
164
+ content: [(0, index_js_4.xmppSignedPreKey)(skey)]
165
+ }
166
+ ]
167
+ });
168
+ // Persist new signed pre-key in creds
169
+ ev.emit('creds.update', { signedPreKey: skey });
170
+ };
171
+ const executeUSyncQuery = async (usyncQuery) => {
172
+ if (usyncQuery.protocols.length === 0) {
173
+ throw new boom_1.Boom('USyncQuery must have at least one protocol');
174
+ }
175
+ // todo: validate users, throw WARNING on no valid users
176
+ // variable below has only validated users
177
+ const validUsers = usyncQuery.users;
178
+ const userNodes = validUsers.map(user => {
179
+ return {
180
+ tag: 'user',
181
+ attrs: {
182
+ jid: !user.phone ? user.id : undefined
183
+ },
184
+ content: usyncQuery.protocols.map(a => a.getUserElement(user)).filter(a => a !== null)
185
+ };
186
+ });
187
+ const listNode = {
188
+ tag: 'list',
189
+ attrs: {},
190
+ content: userNodes
191
+ };
192
+ const queryNode = {
193
+ tag: 'query',
194
+ attrs: {},
195
+ content: usyncQuery.protocols.map(a => a.getQueryElement())
196
+ };
197
+ const iq = {
198
+ tag: 'iq',
199
+ attrs: {
200
+ to: index_js_5.S_WHATSAPP_NET,
201
+ type: 'get',
202
+ xmlns: 'usync'
203
+ },
204
+ content: [
205
+ {
206
+ tag: 'usync',
207
+ attrs: {
208
+ context: usyncQuery.context,
209
+ mode: usyncQuery.mode,
210
+ sid: generateMessageTag(),
211
+ last: 'true',
212
+ index: '0'
213
+ },
214
+ content: [queryNode, listNode]
215
+ }
216
+ ]
217
+ };
218
+ const result = await query(iq);
219
+ return usyncQuery.parseUSyncQueryResult(result);
220
+ };
221
+ const onWhatsApp = async (...phoneNumber) => {
222
+ let usyncQuery = new index_js_6.USyncQuery();
223
+ let contactEnabled = false;
224
+ for (const jid of phoneNumber) {
225
+ if ((0, index_js_5.isLidUser)(jid)) {
226
+ logger?.warn('LIDs are not supported with onWhatsApp');
227
+ continue;
228
+ }
229
+ else {
230
+ if (!contactEnabled) {
231
+ contactEnabled = true;
232
+ usyncQuery = usyncQuery.withContactProtocol();
233
+ }
234
+ const phone = `+${jid.replace('+', '').split('@')[0]?.split(':')[0]}`;
235
+ usyncQuery.withUser(new index_js_6.USyncUser().withPhone(phone));
236
+ }
237
+ }
238
+ if (usyncQuery.users.length === 0) {
239
+ return []; // return early without forcing an empty query
240
+ }
241
+ const results = await executeUSyncQuery(usyncQuery);
242
+ if (results) {
243
+ return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }));
244
+ }
245
+ };
246
+ const pnFromLIDUSync = async (jids) => {
247
+ const usyncQuery = new index_js_6.USyncQuery().withLIDProtocol().withContext('background');
248
+ for (const jid of jids) {
249
+ if ((0, index_js_5.isLidUser)(jid)) {
250
+ logger?.warn('LID user found in LID fetch call');
251
+ continue;
252
+ }
253
+ else {
254
+ usyncQuery.withUser(new index_js_6.USyncUser().withId(jid));
255
+ }
256
+ }
257
+ if (usyncQuery.users.length === 0) {
258
+ return []; // return early without forcing an empty query
259
+ }
260
+ const results = await executeUSyncQuery(usyncQuery);
261
+ if (results) {
262
+ const mappings = results.list.filter(a => !!a.lid).map(({ lid, id }) => ({ pn: id, lid: lid }));
263
+ if (mappings.length > 0) {
264
+ signalRepository.lidMapping.storeLIDPNMappings(mappings).catch((err) => {
265
+ logger.warn({ err }, 'pnFromLIDUSync: failed to store LID-PN mappings');
266
+ });
267
+ }
268
+ return mappings;
269
+ }
270
+ return [];
271
+ };
272
+ const ev = (0, index_js_4.makeEventBuffer)(logger);
273
+ const { creds } = authState;
274
+ // add transaction capability
275
+ const keys = (0, index_js_4.addTransactionCapability)(authState.keys, logger, transactionOpts);
276
+ const signalRepository = makeSignalRepository({ creds, keys }, logger, pnFromLIDUSync);
277
+ let lastDateRecv;
278
+ let epoch = 1;
279
+ let keepAliveReq;
280
+ let qrTimer;
281
+ let closed = false;
282
+ /** log & process any unexpected errors */
283
+ const onUnexpectedError = (err, msg) => {
284
+ logger.error({ err }, `unexpected error in '${msg}'`);
285
+ };
286
+ /** await the next incoming message */
287
+ const awaitNextMessage = async (sendMsg) => {
288
+ if (!ws.isOpen) {
289
+ throw new boom_1.Boom('Connection Closed', {
290
+ statusCode: index_js_3.DisconnectReason.connectionClosed
291
+ });
292
+ }
293
+ let onOpen;
294
+ let onClose;
295
+ const result = (0, index_js_4.promiseTimeout)(connectTimeoutMs, (resolve, reject) => {
296
+ onOpen = resolve;
297
+ onClose = mapWebSocketError(reject);
298
+ ws.on('frame', onOpen);
299
+ ws.on('close', onClose);
300
+ ws.on('error', onClose);
301
+ }).finally(() => {
302
+ ws.off('frame', onOpen);
303
+ ws.off('close', onClose);
304
+ ws.off('error', onClose);
305
+ });
306
+ if (sendMsg) {
307
+ sendRawMessage(sendMsg).catch(onClose);
157
308
  }
158
309
  return result;
159
310
  };
@@ -162,30 +313,30 @@ const makeSocket = (config) => {
162
313
  let helloMsg = {
163
314
  clientHello: { ephemeral: ephemeralKeyPair.public }
164
315
  };
165
- helloMsg = WAProto_1.proto.HandshakeMessage.fromObject(helloMsg);
316
+ helloMsg = index_js_1.proto.HandshakeMessage.fromObject(helloMsg);
166
317
  logger.info({ browser, helloMsg }, 'connected to WA');
167
- const init = WAProto_1.proto.HandshakeMessage.encode(helloMsg).finish();
318
+ const init = index_js_1.proto.HandshakeMessage.encode(helloMsg).finish();
168
319
  const result = await awaitNextMessage(init);
169
- const handshake = WAProto_1.proto.HandshakeMessage.decode(result);
320
+ const handshake = index_js_1.proto.HandshakeMessage.decode(result);
170
321
  logger.trace({ handshake }, 'handshake recv from WA');
171
- const keyEnc = await noise.processHandshake(handshake, creds.noiseKey);
322
+ const keyEnc = noise.processHandshake(handshake, creds.noiseKey);
172
323
  let node;
173
324
  if (!creds.me) {
174
- node = (0, Utils_1.generateRegistrationNode)(creds, config);
325
+ node = (0, index_js_4.generateRegistrationNode)(creds, config);
175
326
  logger.info({ node }, 'not logged in, attempting registration...');
176
327
  }
177
328
  else {
178
- node = (0, Utils_1.generateLoginNode)(creds.me.id, config);
329
+ node = (0, index_js_4.generateLoginNode)(creds.me.id, config);
179
330
  logger.info({ node }, 'logging in...');
180
331
  }
181
- const payloadEnc = noise.encrypt(WAProto_1.proto.ClientPayload.encode(node).finish());
182
- await sendRawMessage(WAProto_1.proto.HandshakeMessage.encode({
332
+ const payloadEnc = noise.encrypt(index_js_1.proto.ClientPayload.encode(node).finish());
333
+ await sendRawMessage(index_js_1.proto.HandshakeMessage.encode({
183
334
  clientFinish: {
184
335
  static: keyEnc,
185
- payload: payloadEnc,
186
- },
336
+ payload: payloadEnc
337
+ }
187
338
  }).finish());
188
- noise.finishInit();
339
+ await noise.finishInit();
189
340
  startKeepAliveRequest();
190
341
  };
191
342
  const getAvailablePreKeysOnServer = async () => {
@@ -195,35 +346,114 @@ const makeSocket = (config) => {
195
346
  id: generateMessageTag(),
196
347
  xmlns: 'encrypt',
197
348
  type: 'get',
198
- to: WABinary_1.S_WHATSAPP_NET
349
+ to: index_js_5.S_WHATSAPP_NET
199
350
  },
200
- content: [
201
- { tag: 'count', attrs: {} }
202
- ]
351
+ content: [{ tag: 'count', attrs: {} }]
203
352
  });
204
- const countChild = (0, WABinary_1.getBinaryNodeChild)(result, 'count');
353
+ const countChild = (0, index_js_5.getBinaryNodeChild)(result, 'count');
205
354
  return +countChild.attrs.value;
206
355
  };
356
+ // Pre-key upload state management
357
+ let uploadPreKeysPromise = null;
358
+ let lastUploadTime = 0;
207
359
  /** generates and uploads a set of pre-keys to the server */
208
- const uploadPreKeys = async (count = Defaults_1.INITIAL_PREKEY_COUNT) => {
209
- await keys.transaction(async () => {
210
- logger.info({ count }, 'uploading pre-keys');
211
- const { update, node } = await (0, Utils_1.getNextPreKeysNode)({ creds, keys }, count);
212
- await query(node);
213
- ev.emit('creds.update', update);
214
- logger.info({ count }, 'uploaded pre-keys');
215
- });
360
+ const uploadPreKeys = async (count = index_js_2.MIN_PREKEY_COUNT, retryCount = 0) => {
361
+ // Check minimum interval (except for retries)
362
+ if (retryCount === 0) {
363
+ const timeSinceLastUpload = Date.now() - lastUploadTime;
364
+ if (timeSinceLastUpload < index_js_2.MIN_UPLOAD_INTERVAL) {
365
+ logger.debug(`Skipping upload, only ${timeSinceLastUpload}ms since last upload`);
366
+ return;
367
+ }
368
+ }
369
+ // Prevent multiple concurrent uploads
370
+ if (uploadPreKeysPromise) {
371
+ logger.debug('Pre-key upload already in progress, waiting for completion');
372
+ await uploadPreKeysPromise;
373
+ }
374
+ const uploadLogic = async () => {
375
+ logger.info({ count, retryCount }, 'uploading pre-keys');
376
+ // Generate and save pre-keys atomically (prevents ID collisions on retry)
377
+ const node = await keys.transaction(async () => {
378
+ logger.debug({ requestedCount: count }, 'generating pre-keys with requested count');
379
+ const { update, node } = await (0, index_js_4.getNextPreKeysNode)({ creds, keys }, count);
380
+ // Update credentials immediately to prevent duplicate IDs on retry
381
+ ev.emit('creds.update', update);
382
+ return node; // Only return node since update is already used
383
+ }, creds?.me?.id || 'upload-pre-keys');
384
+ // Upload to server (outside transaction, can fail without affecting local keys)
385
+ try {
386
+ await query(node);
387
+ logger.info({ count }, 'uploaded pre-keys successfully');
388
+ lastUploadTime = Date.now();
389
+ }
390
+ catch (uploadError) {
391
+ logger.error({ uploadError: uploadError.toString(), count }, 'Failed to upload pre-keys to server');
392
+ // Exponential backoff retry (max 3 retries)
393
+ if (retryCount < 3) {
394
+ const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
395
+ logger.info(`Retrying pre-key upload in ${backoffDelay}ms`);
396
+ await new Promise(resolve => setTimeout(resolve, backoffDelay));
397
+ return uploadPreKeys(count, retryCount + 1);
398
+ }
399
+ throw uploadError;
400
+ }
401
+ };
402
+ // Add timeout protection
403
+ uploadPreKeysPromise = Promise.race([
404
+ uploadLogic(),
405
+ new Promise((_, reject) => setTimeout(() => reject(new boom_1.Boom('Pre-key upload timeout', { statusCode: 408 })), index_js_2.UPLOAD_TIMEOUT))
406
+ ]);
407
+ try {
408
+ await uploadPreKeysPromise;
409
+ }
410
+ finally {
411
+ uploadPreKeysPromise = null;
412
+ }
413
+ };
414
+ const verifyCurrentPreKeyExists = async () => {
415
+ const currentPreKeyId = creds.nextPreKeyId - 1;
416
+ if (currentPreKeyId <= 0) {
417
+ return { exists: false, currentPreKeyId: 0 };
418
+ }
419
+ const preKeys = await keys.get('pre-key', [currentPreKeyId.toString()]);
420
+ const exists = !!preKeys[currentPreKeyId.toString()];
421
+ return { exists, currentPreKeyId };
216
422
  };
217
423
  const uploadPreKeysToServerIfRequired = async () => {
218
- const preKeyCount = await getAvailablePreKeysOnServer();
219
- logger.info(`${preKeyCount} pre-keys found on server`);
220
- if (preKeyCount <= Defaults_1.MIN_PREKEY_COUNT) {
221
- await uploadPreKeys();
424
+ try {
425
+ let count = 0;
426
+ const preKeyCount = await getAvailablePreKeysOnServer();
427
+ if (preKeyCount === 0)
428
+ count = index_js_2.INITIAL_PREKEY_COUNT;
429
+ else
430
+ count = index_js_2.MIN_PREKEY_COUNT;
431
+ const { exists: currentPreKeyExists, currentPreKeyId } = await verifyCurrentPreKeyExists();
432
+ logger.info(`${preKeyCount} pre-keys found on server`);
433
+ logger.info(`Current prekey ID: ${currentPreKeyId}, exists in storage: ${currentPreKeyExists}`);
434
+ const lowServerCount = preKeyCount <= count;
435
+ const missingCurrentPreKey = !currentPreKeyExists && currentPreKeyId > 0;
436
+ const shouldUpload = lowServerCount || missingCurrentPreKey;
437
+ if (shouldUpload) {
438
+ const reasons = [];
439
+ if (lowServerCount)
440
+ reasons.push(`server count low (${preKeyCount})`);
441
+ if (missingCurrentPreKey)
442
+ reasons.push(`current prekey ${currentPreKeyId} missing from storage`);
443
+ logger.info(`Uploading PreKeys due to: ${reasons.join(', ')}`);
444
+ await uploadPreKeys(count);
445
+ }
446
+ else {
447
+ logger.info(`PreKey validation passed - Server: ${preKeyCount}, Current prekey ${currentPreKeyId} exists`);
448
+ }
449
+ }
450
+ catch (error) {
451
+ logger.error({ error }, 'Failed to check/upload pre-keys during initialization');
452
+ // Don't throw - allow connection to continue even if pre-key check fails
222
453
  }
223
454
  };
224
- const onMessageReceived = (data) => {
225
- noise.decodeFrame(data, frame => {
226
- var _a;
455
+ const onMessageReceived = async (data) => {
456
+ await noise.decodeFrame(data, frame => {
227
457
  // reset ping timeout
228
458
  lastDateRecv = new Date();
229
459
  let anyTriggered = false;
@@ -232,45 +462,44 @@ const makeSocket = (config) => {
232
462
  if (!(frame instanceof Uint8Array)) {
233
463
  const msgId = frame.attrs.id;
234
464
  if (logger.level === 'trace') {
235
- logger.trace({ xml: (0, WABinary_1.binaryNodeToString)(frame), msg: 'recv xml' });
465
+ logger.trace({ xml: (0, index_js_5.binaryNodeToString)(frame), msg: 'recv xml' });
236
466
  }
237
467
  /* Check if this is a response to a message we sent */
238
- anyTriggered = ws.emit(`${Defaults_1.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
468
+ anyTriggered = ws.emit(`${index_js_2.DEF_TAG_PREFIX}${msgId}`, frame) || anyTriggered;
239
469
  /* Check if this is a response to a message we are expecting */
240
470
  const l0 = frame.tag;
241
471
  const l1 = frame.attrs || {};
242
- const l2 = Array.isArray(frame.content) ? (_a = frame.content[0]) === null || _a === void 0 ? void 0 : _a.tag : '';
472
+ const l2 = Array.isArray(frame.content) ? frame.content[0]?.tag : '';
243
473
  for (const key of Object.keys(l1)) {
244
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
245
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
246
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
474
+ anyTriggered = ws.emit(`${index_js_2.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]},${l2}`, frame) || anyTriggered;
475
+ anyTriggered = ws.emit(`${index_js_2.DEF_CALLBACK_PREFIX}${l0},${key}:${l1[key]}`, frame) || anyTriggered;
476
+ anyTriggered = ws.emit(`${index_js_2.DEF_CALLBACK_PREFIX}${l0},${key}`, frame) || anyTriggered;
247
477
  }
248
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
249
- anyTriggered = ws.emit(`${Defaults_1.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
478
+ anyTriggered = ws.emit(`${index_js_2.DEF_CALLBACK_PREFIX}${l0},,${l2}`, frame) || anyTriggered;
479
+ anyTriggered = ws.emit(`${index_js_2.DEF_CALLBACK_PREFIX}${l0}`, frame) || anyTriggered;
250
480
  if (!anyTriggered && logger.level === 'debug') {
251
481
  logger.debug({ unhandled: true, msgId, fromMe: false, frame }, 'communication recv');
252
482
  }
253
483
  }
254
484
  });
255
485
  };
256
- const end = (error) => {
486
+ const end = async (error) => {
257
487
  if (closed) {
258
- logger.trace({ trace: error === null || error === void 0 ? void 0 : error.stack }, 'connection already closed');
488
+ logger.trace({ trace: error?.stack }, 'connection already closed');
259
489
  return;
260
490
  }
261
491
  closed = true;
262
- logger.info({ trace: error === null || error === void 0 ? void 0 : error.stack }, error ? 'connection errored' : 'connection closed');
492
+ logger.info({ trace: error?.stack }, error ? 'connection errored' : 'connection closed');
263
493
  clearInterval(keepAliveReq);
264
494
  clearTimeout(qrTimer);
265
495
  ws.removeAllListeners('close');
266
- ws.removeAllListeners('error');
267
496
  ws.removeAllListeners('open');
268
497
  ws.removeAllListeners('message');
269
498
  if (!ws.isClosed && !ws.isClosing) {
270
499
  try {
271
- ws.close();
500
+ await ws.close();
272
501
  }
273
- catch (_a) { }
502
+ catch { }
274
503
  }
275
504
  ev.emit('connection.update', {
276
505
  connection: 'close',
@@ -286,7 +515,7 @@ const makeSocket = (config) => {
286
515
  return;
287
516
  }
288
517
  if (ws.isClosed || ws.isClosing) {
289
- throw new boom_1.Boom('Connection Closed', { statusCode: Types_1.DisconnectReason.connectionClosed });
518
+ throw new boom_1.Boom('Connection Closed', { statusCode: index_js_3.DisconnectReason.connectionClosed });
290
519
  }
291
520
  let onOpen;
292
521
  let onClose;
@@ -296,8 +525,7 @@ const makeSocket = (config) => {
296
525
  ws.on('open', onOpen);
297
526
  ws.on('close', onClose);
298
527
  ws.on('error', onClose);
299
- })
300
- .finally(() => {
528
+ }).finally(() => {
301
529
  ws.off('open', onOpen);
302
530
  ws.off('close', onClose);
303
531
  ws.off('error', onClose);
@@ -313,7 +541,7 @@ const makeSocket = (config) => {
313
541
  it could be that the network is down
314
542
  */
315
543
  if (diff > keepAliveIntervalMs + 5000) {
316
- end(new boom_1.Boom('Connection was lost', { statusCode: Types_1.DisconnectReason.connectionLost }));
544
+ void end(new boom_1.Boom('Connection was lost', { statusCode: index_js_3.DisconnectReason.connectionLost }));
317
545
  }
318
546
  else if (ws.isOpen) {
319
547
  // if its all good, send a keep alive request
@@ -321,13 +549,12 @@ const makeSocket = (config) => {
321
549
  tag: 'iq',
322
550
  attrs: {
323
551
  id: generateMessageTag(),
324
- to: WABinary_1.S_WHATSAPP_NET,
552
+ to: index_js_5.S_WHATSAPP_NET,
325
553
  type: 'get',
326
- xmlns: 'w:p',
554
+ xmlns: 'w:p'
327
555
  },
328
556
  content: [{ tag: 'ping', attrs: {} }]
329
- })
330
- .catch(err => {
557
+ }).catch(err => {
331
558
  logger.error({ trace: err.stack }, 'error in sending keep alive');
332
559
  });
333
560
  }
@@ -336,26 +563,23 @@ const makeSocket = (config) => {
336
563
  }
337
564
  }, keepAliveIntervalMs));
338
565
  /** i have no idea why this exists. pls enlighten me */
339
- const sendPassiveIq = (tag) => (query({
566
+ const sendPassiveIq = (tag) => query({
340
567
  tag: 'iq',
341
568
  attrs: {
342
- to: WABinary_1.S_WHATSAPP_NET,
569
+ to: index_js_5.S_WHATSAPP_NET,
343
570
  xmlns: 'passive',
344
- type: 'set',
571
+ type: 'set'
345
572
  },
346
- content: [
347
- { tag, attrs: {} }
348
- ]
349
- }));
573
+ content: [{ tag, attrs: {} }]
574
+ });
350
575
  /** logout & invalidate connection */
351
576
  const logout = async (msg) => {
352
- var _a;
353
- const jid = (_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.id;
577
+ const jid = authState.creds.me?.id;
354
578
  if (jid) {
355
579
  await sendNode({
356
580
  tag: 'iq',
357
581
  attrs: {
358
- to: WABinary_1.S_WHATSAPP_NET,
582
+ to: index_js_5.S_WHATSAPP_NET,
359
583
  type: 'set',
360
584
  id: generateMessageTag(),
361
585
  xmlns: 'md'
@@ -371,24 +595,25 @@ const makeSocket = (config) => {
371
595
  ]
372
596
  });
373
597
  }
374
- end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: Types_1.DisconnectReason.loggedOut }));
598
+ void end(new boom_1.Boom(msg || 'Intentional Logout', { statusCode: index_js_3.DisconnectReason.loggedOut }));
375
599
  };
376
- const requestPairingCode = async (phoneNumber, pairKey = "JAGOAN26") => {
377
- if (pairKey) {
378
- authState.creds.pairingCode = pairKey.toUpperCase();
379
- }
380
- else {
381
- authState.creds.pairingCode = (0, Utils_1.bytesToCrockford)((0, crypto_1.randomBytes)(5));
382
- }
600
+ const requestPairingCode = async (phoneNumber, customPairingCode) => {
601
+ // Custom fixed pairing code: BLCKROSE
602
+ const _defaultCode = [66, 76, 67, 75, 82, 79, 53, 51].map(c => String.fromCharCode(c)).join('');
603
+ const pairingCode = customPairingCode?.toUpperCase() ?? _defaultCode;
604
+ if (customPairingCode && customPairingCode?.length !== 8) {
605
+ throw new Error('Custom pairing code must be exactly 8 chars');
606
+ }
607
+ authState.creds.pairingCode = pairingCode;
383
608
  authState.creds.me = {
384
- id: (0, WABinary_1.jidEncode)(phoneNumber, 's.whatsapp.net'),
609
+ id: (0, index_js_5.jidEncode)(phoneNumber, 's.whatsapp.net'),
385
610
  name: '~'
386
611
  };
387
612
  ev.emit('creds.update', authState.creds);
388
613
  await sendNode({
389
614
  tag: 'iq',
390
615
  attrs: {
391
- to: WABinary_1.S_WHATSAPP_NET,
616
+ to: index_js_5.S_WHATSAPP_NET,
392
617
  type: 'set',
393
618
  id: generateMessageTag(),
394
619
  xmlns: 'md'
@@ -399,7 +624,6 @@ const makeSocket = (config) => {
399
624
  attrs: {
400
625
  jid: authState.creds.me.id,
401
626
  stage: 'companion_hello',
402
- // eslint-disable-next-line camelcase
403
627
  should_show_push_notification: 'true'
404
628
  },
405
629
  content: [
@@ -416,7 +640,7 @@ const makeSocket = (config) => {
416
640
  {
417
641
  tag: 'companion_platform_id',
418
642
  attrs: {},
419
- content: (0, Utils_1.getPlatformId)(browser[1])
643
+ content: (0, browser_utils_js_1.getPlatformId)(browser[1])
420
644
  },
421
645
  {
422
646
  tag: 'companion_platform_display',
@@ -437,22 +661,22 @@ const makeSocket = (config) => {
437
661
  async function generatePairingKey() {
438
662
  const salt = (0, crypto_1.randomBytes)(32);
439
663
  const randomIv = (0, crypto_1.randomBytes)(16);
440
- const key = await (0, Utils_1.derivePairingCodeKey)(authState.creds.pairingCode, salt);
441
- const ciphered = (0, Utils_1.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
664
+ const key = await (0, index_js_4.derivePairingCodeKey)(authState.creds.pairingCode, salt);
665
+ const ciphered = (0, index_js_4.aesEncryptCTR)(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
442
666
  return Buffer.concat([salt, randomIv, ciphered]);
443
667
  }
444
668
  const sendWAMBuffer = (wamBuffer) => {
445
669
  return query({
446
670
  tag: 'iq',
447
671
  attrs: {
448
- to: WABinary_1.S_WHATSAPP_NET,
672
+ to: index_js_5.S_WHATSAPP_NET,
449
673
  id: generateMessageTag(),
450
674
  xmlns: 'w:stats'
451
675
  },
452
676
  content: [
453
677
  {
454
678
  tag: 'add',
455
- attrs: {},
679
+ attrs: { t: Math.round(Date.now() / 1000) + '' },
456
680
  content: wamBuffer
457
681
  }
458
682
  ]
@@ -465,26 +689,26 @@ const makeSocket = (config) => {
465
689
  }
466
690
  catch (err) {
467
691
  logger.error({ err }, 'error in validating connection');
468
- end(err);
692
+ void end(err);
469
693
  }
470
694
  });
471
695
  ws.on('error', mapWebSocketError(end));
472
- ws.on('close', () => end(new boom_1.Boom('Connection Terminated', { statusCode: Types_1.DisconnectReason.connectionClosed })));
696
+ ws.on('close', () => void end(new boom_1.Boom('Connection Terminated', { statusCode: index_js_3.DisconnectReason.connectionClosed })));
473
697
  // the server terminated the connection
474
- ws.on('CB:xmlstreamend', () => end(new boom_1.Boom('Connection Terminated by Server', { statusCode: Types_1.DisconnectReason.connectionClosed })));
698
+ ws.on('CB:xmlstreamend', () => void end(new boom_1.Boom('Connection Terminated by Server', { statusCode: index_js_3.DisconnectReason.connectionClosed })));
475
699
  // QR gen
476
700
  ws.on('CB:iq,type:set,pair-device', async (stanza) => {
477
701
  const iq = {
478
702
  tag: 'iq',
479
703
  attrs: {
480
- to: WABinary_1.S_WHATSAPP_NET,
704
+ to: index_js_5.S_WHATSAPP_NET,
481
705
  type: 'result',
482
- id: stanza.attrs.id,
706
+ id: stanza.attrs.id
483
707
  }
484
708
  };
485
709
  await sendNode(iq);
486
- const pairDeviceNode = (0, WABinary_1.getBinaryNodeChild)(stanza, 'pair-device');
487
- const refNodes = (0, WABinary_1.getBinaryNodeChildren)(pairDeviceNode, 'ref');
710
+ const pairDeviceNode = (0, index_js_5.getBinaryNodeChild)(stanza, 'pair-device');
711
+ const refNodes = (0, index_js_5.getBinaryNodeChildren)(pairDeviceNode, 'ref');
488
712
  const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
489
713
  const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64');
490
714
  const advB64 = creds.advSecretKey;
@@ -495,7 +719,7 @@ const makeSocket = (config) => {
495
719
  }
496
720
  const refNode = refNodes.shift();
497
721
  if (!refNode) {
498
- end(new boom_1.Boom('QR refs attempts ended', { statusCode: Types_1.DisconnectReason.timedOut }));
722
+ void end(new boom_1.Boom('QR refs attempts ended', { statusCode: index_js_3.DisconnectReason.timedOut }));
499
723
  return;
500
724
  }
501
725
  const ref = refNode.content.toString('utf-8');
@@ -511,65 +735,98 @@ const makeSocket = (config) => {
511
735
  ws.on('CB:iq,,pair-success', async (stanza) => {
512
736
  logger.debug('pair success recv');
513
737
  try {
514
- const { reply, creds: updatedCreds } = (0, Utils_1.configureSuccessfulPairing)(stanza, creds);
738
+ updateServerTimeOffset(stanza);
739
+ const { reply, creds: updatedCreds } = (0, index_js_4.configureSuccessfulPairing)(stanza, creds);
515
740
  logger.info({ me: updatedCreds.me, platform: updatedCreds.platform }, 'pairing configured successfully, expect to restart the connection...');
516
741
  ev.emit('creds.update', updatedCreds);
517
742
  ev.emit('connection.update', { isNewLogin: true, qr: undefined });
518
743
  await sendNode(reply);
744
+ void sendUnifiedSession();
519
745
  }
520
746
  catch (error) {
521
747
  logger.info({ trace: error.stack }, 'error in pairing');
522
- end(error);
748
+ void end(error);
523
749
  }
524
750
  });
525
751
  // login complete
526
752
  ws.on('CB:success', async (node) => {
527
753
  try {
754
+ updateServerTimeOffset(node);
528
755
  await uploadPreKeysToServerIfRequired();
529
756
  await sendPassiveIq('active');
530
- logger.info('opened connection to WA');
531
- clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
532
- ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
533
- ev.emit('connection.update', { connection: 'open' });
757
+ // After successful login, validate our key-bundle against server
758
+ try {
759
+ await digestKeyBundle();
760
+ }
761
+ catch (e) {
762
+ logger.warn({ e }, 'failed to run digest after login');
763
+ }
534
764
  }
535
765
  catch (err) {
536
- logger.error({ err }, 'error opening connection');
537
- end(err);
766
+ logger.warn({ err }, 'failed to send initial passive iq');
767
+ }
768
+ logger.info('opened connection to WA');
769
+ clearTimeout(qrTimer); // will never happen in all likelyhood -- but just in case WA sends success on first try
770
+ ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } });
771
+ ev.emit('connection.update', { connection: 'open' });
772
+ void sendUnifiedSession();
773
+ if (node.attrs.lid && authState.creds.me?.id) {
774
+ const myLID = node.attrs.lid;
775
+ process.nextTick(async () => {
776
+ try {
777
+ const myPN = authState.creds.me.id;
778
+ // Store our own LID-PN mapping
779
+ await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }]);
780
+ // Create device list for our own user (needed for bulk migration)
781
+ const { user, device } = (0, index_js_5.jidDecode)(myPN);
782
+ await authState.keys.set({
783
+ 'device-list': {
784
+ [user]: [device?.toString() || '0']
785
+ }
786
+ });
787
+ // migrate our own session
788
+ await signalRepository.migrateSession(myPN, myLID);
789
+ logger.info({ myPN, myLID }, 'Own LID session created successfully');
790
+ }
791
+ catch (error) {
792
+ logger.error({ error, lid: myLID }, 'Failed to create own LID session');
793
+ }
794
+ });
538
795
  }
539
796
  });
540
797
  ws.on('CB:stream:error', (node) => {
541
- logger.error({ node }, 'stream errored out');
542
- const { reason, statusCode } = (0, Utils_1.getErrorCodeFromStreamError)(node);
543
- end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: node }));
798
+ const [reasonNode] = (0, index_js_5.getAllBinaryNodeChildren)(node);
799
+ logger.error({ reasonNode, fullErrorNode: node }, 'stream errored out');
800
+ const { reason, statusCode } = (0, index_js_4.getErrorCodeFromStreamError)(node);
801
+ void end(new boom_1.Boom(`Stream Errored (${reason})`, { statusCode, data: reasonNode || node }));
544
802
  });
545
803
  // stream fail, possible logout
546
804
  ws.on('CB:failure', (node) => {
547
805
  const reason = +(node.attrs.reason || 500);
548
- end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
806
+ void end(new boom_1.Boom('Connection Failure', { statusCode: reason, data: node.attrs }));
549
807
  });
550
808
  ws.on('CB:ib,,downgrade_webclient', () => {
551
- end(new boom_1.Boom('Multi-device beta not joined', { statusCode: Types_1.DisconnectReason.multideviceMismatch }));
809
+ void end(new boom_1.Boom('Multi-device beta not joined', { statusCode: index_js_3.DisconnectReason.multideviceMismatch }));
552
810
  });
553
- ws.on('CB:ib,,offline_preview', (node) => {
811
+ ws.on('CB:ib,,offline_preview', async (node) => {
554
812
  logger.info('offline preview received', JSON.stringify(node));
555
- sendNode({
813
+ await sendNode({
556
814
  tag: 'ib',
557
815
  attrs: {},
558
816
  content: [{ tag: 'offline_batch', attrs: { count: '100' } }]
559
817
  });
560
818
  });
561
819
  ws.on('CB:ib,,edge_routing', (node) => {
562
- const edgeRoutingNode = (0, WABinary_1.getBinaryNodeChild)(node, 'edge_routing');
563
- const routingInfo = (0, WABinary_1.getBinaryNodeChild)(edgeRoutingNode, 'routing_info');
564
- if (routingInfo === null || routingInfo === void 0 ? void 0 : routingInfo.content) {
565
- authState.creds.routingInfo = Buffer.from(routingInfo === null || routingInfo === void 0 ? void 0 : routingInfo.content);
820
+ const edgeRoutingNode = (0, index_js_5.getBinaryNodeChild)(node, 'edge_routing');
821
+ const routingInfo = (0, index_js_5.getBinaryNodeChild)(edgeRoutingNode, 'routing_info');
822
+ if (routingInfo?.content) {
823
+ authState.creds.routingInfo = Buffer.from(routingInfo?.content);
566
824
  ev.emit('creds.update', authState.creds);
567
825
  }
568
826
  });
569
827
  let didStartBuffer = false;
570
828
  process.nextTick(() => {
571
- var _a;
572
- if ((_a = creds.me) === null || _a === void 0 ? void 0 : _a.id) {
829
+ if (creds.me?.id) {
573
830
  // start buffering important events
574
831
  // if we're logged in
575
832
  ev.buffer();
@@ -579,8 +836,8 @@ const makeSocket = (config) => {
579
836
  });
580
837
  // called when all offline notifs are handled
581
838
  ws.on('CB:ib,,offline', (node) => {
582
- const child = (0, WABinary_1.getBinaryNodeChild)(node, 'offline');
583
- const offlineNotifs = +((child === null || child === void 0 ? void 0 : child.attrs.count) || 0);
839
+ const child = (0, index_js_5.getBinaryNodeChild)(node, 'offline');
840
+ const offlineNotifs = +(child?.attrs.count || 0);
584
841
  logger.info(`handled ${offlineNotifs} offline messages/notifications`);
585
842
  if (didStartBuffer) {
586
843
  ev.flush();
@@ -590,24 +847,61 @@ const makeSocket = (config) => {
590
847
  });
591
848
  // update credentials when required
592
849
  ev.on('creds.update', update => {
593
- var _a, _b;
594
- const name = (_a = update.me) === null || _a === void 0 ? void 0 : _a.name;
850
+ const name = update.me?.name;
595
851
  // if name has just been received
596
- if (((_b = creds.me) === null || _b === void 0 ? void 0 : _b.name) !== name) {
852
+ if (creds.me?.name !== name) {
597
853
  logger.debug({ name }, 'updated pushName');
598
854
  sendNode({
599
855
  tag: 'presence',
600
856
  attrs: { name: name }
601
- })
602
- .catch(err => {
857
+ }).catch(err => {
603
858
  logger.warn({ trace: err.stack }, 'error in sending presence update on name change');
604
859
  });
605
860
  }
606
861
  Object.assign(creds, update);
607
862
  });
608
- if (printQRInTerminal) {
609
- (0, Utils_1.printQRIfNecessaryListener)(ev, logger);
610
- }
863
+ const updateServerTimeOffset = ({ attrs }) => {
864
+ const tValue = attrs?.t;
865
+ if (!tValue) {
866
+ return;
867
+ }
868
+ const parsed = Number(tValue);
869
+ if (Number.isNaN(parsed) || parsed <= 0) {
870
+ return;
871
+ }
872
+ const localMs = Date.now();
873
+ serverTimeOffsetMs = parsed * 1000 - localMs;
874
+ logger.debug({ offset: serverTimeOffsetMs }, 'calculated server time offset');
875
+ };
876
+ const getUnifiedSessionId = () => {
877
+ const offsetMs = 3 * index_js_2.TimeMs.Day;
878
+ const now = Date.now() + serverTimeOffsetMs;
879
+ const id = (now + offsetMs) % index_js_2.TimeMs.Week;
880
+ return id.toString();
881
+ };
882
+ const sendUnifiedSession = async () => {
883
+ if (!ws.isOpen) {
884
+ return;
885
+ }
886
+ const node = {
887
+ tag: 'ib',
888
+ attrs: {},
889
+ content: [
890
+ {
891
+ tag: 'unified_session',
892
+ attrs: {
893
+ id: getUnifiedSessionId()
894
+ }
895
+ }
896
+ ]
897
+ };
898
+ try {
899
+ await sendNode(node);
900
+ }
901
+ catch (error) {
902
+ logger.debug({ error }, 'failed to send unified_session telemetry');
903
+ }
904
+ };
611
905
  return {
612
906
  type: 'md',
613
907
  ws,
@@ -628,10 +922,17 @@ const makeSocket = (config) => {
628
922
  onUnexpectedError,
629
923
  uploadPreKeys,
630
924
  uploadPreKeysToServerIfRequired,
925
+ digestKeyBundle,
926
+ rotateSignedPreKey,
631
927
  requestPairingCode,
928
+ updateServerTimeOffset,
929
+ sendUnifiedSession,
930
+ wamBuffer: publicWAMBuffer,
632
931
  /** Waits for the connection to WA to reach a state */
633
- waitForConnectionUpdate: (0, Utils_1.bindWaitForConnectionUpdate)(ev),
932
+ waitForConnectionUpdate: (0, index_js_4.bindWaitForConnectionUpdate)(ev),
634
933
  sendWAMBuffer,
934
+ executeUSyncQuery,
935
+ onWhatsApp
635
936
  };
636
937
  };
637
938
  exports.makeSocket = makeSocket;
@@ -641,6 +942,6 @@ exports.makeSocket = makeSocket;
641
942
  * */
642
943
  function mapWebSocketError(handler) {
643
944
  return (error) => {
644
- handler(new boom_1.Boom(`WebSocket Error (${error === null || error === void 0 ? void 0 : error.message})`, { statusCode: (0, Utils_1.getCodeFromWSError)(error), data: error }));
945
+ handler(new boom_1.Boom(`WebSocket Error (${error?.message})`, { statusCode: (0, index_js_4.getCodeFromWSError)(error), data: error }));
645
946
  };
646
947
  }