@alannxd/baileys 6.0.6 → 6.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +341 -286
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.d.ts +79257 -0
  7. package/WAProto/index.js +205861 -60565
  8. package/engine-requirements.js +1 -1
  9. package/lib/Defaults/index.js +119 -136
  10. package/lib/Signal/Group/ciphertext-message.js +2 -5
  11. package/lib/Signal/Group/group-session-builder.js +7 -41
  12. package/lib/Signal/Group/group_cipher.js +37 -51
  13. package/lib/Signal/Group/index.js +12 -57
  14. package/lib/Signal/Group/keyhelper.js +7 -44
  15. package/lib/Signal/Group/sender-chain-key.js +7 -15
  16. package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
  17. package/lib/Signal/Group/sender-key-message.js +9 -12
  18. package/lib/Signal/Group/sender-key-name.js +2 -5
  19. package/lib/Signal/Group/sender-key-record.js +9 -21
  20. package/lib/Signal/Group/sender-key-state.js +27 -42
  21. package/lib/Signal/Group/sender-message-key.js +4 -7
  22. package/lib/Signal/libsignal.js +347 -90
  23. package/lib/Signal/lid-mapping.js +277 -0
  24. package/lib/Socket/Client/index.js +3 -19
  25. package/lib/Socket/Client/types.js +11 -0
  26. package/lib/Socket/Client/websocket.js +54 -0
  27. package/lib/Socket/business.js +162 -43
  28. package/lib/Socket/chats.js +627 -427
  29. package/lib/Socket/communities.js +90 -80
  30. package/lib/Socket/groups.js +154 -161
  31. package/lib/Socket/index.js +11 -10
  32. package/lib/Socket/luxu.js +315 -469
  33. package/lib/Socket/messages-recv.js +1421 -615
  34. package/lib/Socket/messages-send.js +1150 -799
  35. package/lib/Socket/mex.js +42 -0
  36. package/lib/Socket/newsletter.js +152 -204
  37. package/lib/Socket/socket.js +544 -313
  38. package/lib/Store/index.js +10 -10
  39. package/lib/Store/keyed-db.js +108 -0
  40. package/lib/Store/make-cache-manager-store.js +43 -41
  41. package/lib/Store/make-in-memory-store.js +112 -341
  42. package/lib/Store/make-ordered-dictionary.js +14 -20
  43. package/lib/Store/object-repository.js +11 -6
  44. package/lib/Types/Auth.js +2 -2
  45. package/lib/Types/Bussines.js +2 -0
  46. package/lib/Types/Call.js +2 -2
  47. package/lib/Types/Chat.js +8 -4
  48. package/lib/Types/Contact.js +2 -2
  49. package/lib/Types/Events.js +2 -2
  50. package/lib/Types/GroupMetadata.js +2 -2
  51. package/lib/Types/Label.js +3 -5
  52. package/lib/Types/LabelAssociation.js +3 -5
  53. package/lib/Types/Message.js +11 -9
  54. package/lib/Types/Mex.js +37 -0
  55. package/lib/Types/Product.js +2 -2
  56. package/lib/Types/Signal.js +2 -2
  57. package/lib/Types/Socket.js +3 -2
  58. package/lib/Types/State.js +56 -2
  59. package/lib/Types/USync.js +2 -2
  60. package/lib/Types/index.js +15 -31
  61. package/lib/Utils/auth-utils.js +239 -143
  62. package/lib/Utils/browser-utils.js +48 -0
  63. package/lib/Utils/business.js +66 -69
  64. package/lib/Utils/chat-utils.js +396 -253
  65. package/lib/Utils/companion-reg-client-utils.js +35 -0
  66. package/lib/Utils/crypto.js +57 -90
  67. package/lib/Utils/decode-wa-message.js +236 -84
  68. package/lib/Utils/event-buffer.js +185 -77
  69. package/lib/Utils/generics.js +189 -209
  70. package/lib/Utils/history.js +93 -55
  71. package/lib/Utils/identity-change-handler.js +50 -0
  72. package/lib/Utils/index.js +23 -33
  73. package/lib/Utils/link-preview.js +16 -24
  74. package/lib/Utils/logger.js +3 -7
  75. package/lib/Utils/lt-hash.js +3 -46
  76. package/lib/Utils/make-mutex.js +24 -34
  77. package/lib/Utils/message-composer.js +273 -0
  78. package/lib/Utils/message-retry-manager.js +265 -0
  79. package/lib/Utils/messages-media.js +451 -482
  80. package/lib/Utils/messages.js +795 -369
  81. package/lib/Utils/noise-handler.js +145 -99
  82. package/lib/Utils/offline-node-processor.js +40 -0
  83. package/lib/Utils/pre-key-manager.js +106 -0
  84. package/lib/Utils/process-message.js +459 -150
  85. package/lib/Utils/reporting-utils.js +258 -0
  86. package/lib/Utils/signal.js +120 -72
  87. package/lib/Utils/stanza-ack.js +38 -0
  88. package/lib/Utils/sync-action-utils.js +49 -0
  89. package/lib/Utils/tc-token-utils.js +163 -0
  90. package/lib/Utils/use-multi-file-auth-state.js +29 -27
  91. package/lib/Utils/validate-connection.js +73 -99
  92. package/lib/WABinary/constants.js +1281 -20
  93. package/lib/WABinary/decode.js +52 -42
  94. package/lib/WABinary/encode.js +110 -155
  95. package/lib/WABinary/generic-utils.js +55 -49
  96. package/lib/WABinary/index.js +6 -21
  97. package/lib/WABinary/jid-utils.js +76 -40
  98. package/lib/WABinary/types.js +2 -2
  99. package/lib/WAM/BinaryInfo.js +2 -5
  100. package/lib/WAM/constants.js +19071 -11568
  101. package/lib/WAM/encode.js +17 -22
  102. package/lib/WAM/index.js +4 -19
  103. package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
  104. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
  105. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -12
  106. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
  107. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  108. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
  109. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
  110. package/lib/WAUSync/Protocols/index.js +6 -20
  111. package/lib/WAUSync/USyncQuery.js +44 -35
  112. package/lib/WAUSync/USyncUser.js +10 -5
  113. package/lib/WAUSync/index.js +4 -19
  114. package/lib/index.js +13 -36
  115. package/package.json +85 -51
  116. package/WAProto/fix-import.js +0 -29
  117. package/lib/Defaults/baileys-version.json +0 -3
  118. package/lib/Defaults/index.d.ts +0 -53
  119. package/lib/Defaults/phonenumber-mcc.json +0 -223
  120. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  121. package/lib/Signal/Group/group-session-builder.d.ts +0 -14
  122. package/lib/Signal/Group/group_cipher.d.ts +0 -17
  123. package/lib/Signal/Group/index.d.ts +0 -11
  124. package/lib/Signal/Group/keyhelper.d.ts +0 -10
  125. package/lib/Signal/Group/queue-job.d.ts +0 -1
  126. package/lib/Signal/Group/queue-job.js +0 -57
  127. package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
  128. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
  129. package/lib/Signal/Group/sender-key-message.d.ts +0 -18
  130. package/lib/Signal/Group/sender-key-name.d.ts +0 -17
  131. package/lib/Signal/Group/sender-key-record.d.ts +0 -30
  132. package/lib/Signal/Group/sender-key-state.d.ts +0 -38
  133. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  134. package/lib/Signal/libsignal.d.ts +0 -3
  135. package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
  136. package/lib/Socket/Client/abstract-socket-client.js +0 -13
  137. package/lib/Socket/Client/index.d.ts +0 -3
  138. package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
  139. package/lib/Socket/Client/mobile-socket-client.js +0 -65
  140. package/lib/Socket/Client/web-socket-client.d.ts +0 -12
  141. package/lib/Socket/Client/web-socket-client.js +0 -62
  142. package/lib/Socket/business.d.ts +0 -171
  143. package/lib/Socket/chats.d.ts +0 -267
  144. package/lib/Socket/communities.d.ts +0 -180
  145. package/lib/Socket/groups.d.ts +0 -115
  146. package/lib/Socket/index.d.ts +0 -173
  147. package/lib/Socket/luxu.d.ts +0 -266
  148. package/lib/Socket/messages-recv.d.ts +0 -161
  149. package/lib/Socket/messages-send.d.ts +0 -183
  150. package/lib/Socket/newsletter.d.ts +0 -134
  151. package/lib/Socket/registration.d.ts +0 -267
  152. package/lib/Socket/registration.js +0 -166
  153. package/lib/Socket/socket.d.ts +0 -44
  154. package/lib/Socket/usync.d.ts +0 -36
  155. package/lib/Socket/usync.js +0 -70
  156. package/lib/Store/index.d.ts +0 -3
  157. package/lib/Store/make-cache-manager-store.d.ts +0 -13
  158. package/lib/Store/make-in-memory-store.d.ts +0 -118
  159. package/lib/Store/make-ordered-dictionary.d.ts +0 -13
  160. package/lib/Store/object-repository.d.ts +0 -10
  161. package/lib/Types/Auth.d.ts +0 -110
  162. package/lib/Types/Call.d.ts +0 -13
  163. package/lib/Types/Chat.d.ts +0 -102
  164. package/lib/Types/Contact.d.ts +0 -19
  165. package/lib/Types/Events.d.ts +0 -157
  166. package/lib/Types/GroupMetadata.d.ts +0 -55
  167. package/lib/Types/Label.d.ts +0 -35
  168. package/lib/Types/LabelAssociation.d.ts +0 -29
  169. package/lib/Types/Message.d.ts +0 -273
  170. package/lib/Types/Newsletter.d.ts +0 -103
  171. package/lib/Types/Newsletter.js +0 -38
  172. package/lib/Types/Product.d.ts +0 -78
  173. package/lib/Types/Signal.d.ts +0 -57
  174. package/lib/Types/Socket.d.ts +0 -111
  175. package/lib/Types/State.d.ts +0 -27
  176. package/lib/Types/USync.d.ts +0 -25
  177. package/lib/Types/index.d.ts +0 -57
  178. package/lib/Utils/auth-utils.d.ts +0 -18
  179. package/lib/Utils/baileys-event-stream.d.ts +0 -16
  180. package/lib/Utils/baileys-event-stream.js +0 -63
  181. package/lib/Utils/business.d.ts +0 -22
  182. package/lib/Utils/chat-utils.d.ts +0 -71
  183. package/lib/Utils/crypto.d.ts +0 -41
  184. package/lib/Utils/decode-wa-message.d.ts +0 -19
  185. package/lib/Utils/event-buffer.d.ts +0 -35
  186. package/lib/Utils/generics.d.ts +0 -92
  187. package/lib/Utils/history.d.ts +0 -15
  188. package/lib/Utils/index.d.ts +0 -17
  189. package/lib/Utils/link-preview.d.ts +0 -21
  190. package/lib/Utils/logger.d.ts +0 -4
  191. package/lib/Utils/lt-hash.d.ts +0 -12
  192. package/lib/Utils/make-mutex.d.ts +0 -7
  193. package/lib/Utils/messages-media.d.ts +0 -116
  194. package/lib/Utils/messages.d.ts +0 -77
  195. package/lib/Utils/noise-handler.d.ts +0 -21
  196. package/lib/Utils/process-message.d.ts +0 -41
  197. package/lib/Utils/signal.d.ts +0 -32
  198. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  199. package/lib/Utils/validate-connection.d.ts +0 -11
  200. package/lib/WABinary/constants.d.ts +0 -30
  201. package/lib/WABinary/decode.d.ts +0 -7
  202. package/lib/WABinary/encode.d.ts +0 -3
  203. package/lib/WABinary/generic-utils.d.ts +0 -17
  204. package/lib/WABinary/index.d.ts +0 -5
  205. package/lib/WABinary/jid-utils.d.ts +0 -31
  206. package/lib/WABinary/types.d.ts +0 -18
  207. package/lib/WAM/BinaryInfo.d.ts +0 -17
  208. package/lib/WAM/constants.d.ts +0 -38
  209. package/lib/WAM/encode.d.ts +0 -3
  210. package/lib/WAM/index.d.ts +0 -3
  211. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
  212. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
  213. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
  214. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
  215. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
  216. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
  217. package/lib/WAUSync/Protocols/index.d.ts +0 -4
  218. package/lib/WAUSync/USyncQuery.d.ts +0 -28
  219. package/lib/WAUSync/USyncUser.d.ts +0 -12
  220. package/lib/index.d.ts +0 -12
@@ -1,51 +1,44 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processSyncAction = exports.chatModificationToAppPatch = exports.decodePatches = exports.decodeSyncdSnapshot = exports.downloadExternalPatch = exports.downloadExternalBlob = exports.extractSyncdPatches = exports.decodeSyncdPatch = exports.decodeSyncdMutations = exports.encodeSyncdPatch = exports.newLTHashState = void 0;
4
- const boom_1 = require("@hapi/boom");
5
- const WAProto_1 = require("../../WAProto");
6
- const LabelAssociation_1 = require("../Types/LabelAssociation");
7
- const WABinary_1 = require("../WABinary");
8
- const crypto_1 = require("./crypto");
9
- const generics_1 = require("./generics");
10
- const lt_hash_1 = require("./lt-hash");
11
- const messages_media_1 = require("./messages-media");
1
+ import { Boom } from '@hapi/boom';
2
+ import { expandAppStateKeys } from 'whatsapp-rust-bridge';
3
+ import { proto } from '../../WAProto/index.js';
4
+ import { LabelAssociationType } from '../Types/LabelAssociation.js';
5
+ import { getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, jidNormalizedUser } from '../WABinary/index.js';
6
+ import { aesDecrypt, aesEncrypt, hmacSign } from './crypto.js';
7
+ import { toNumber } from './generics.js';
8
+ import { LT_HASH_ANTI_TAMPERING } from './lt-hash.js';
9
+ import { downloadContentFromMessage } from './messages-media.js';
10
+ import { emitSyncActionResults, processContactAction } from './sync-action-utils.js';
12
11
  const mutationKeys = (keydata) => {
13
- const expanded = (0, crypto_1.hkdf)(keydata, 160, { info: 'WhatsApp Mutation Keys' });
12
+ const keys = expandAppStateKeys(keydata);
14
13
  return {
15
- indexKey: expanded.slice(0, 32),
16
- valueEncryptionKey: expanded.slice(32, 64),
17
- valueMacKey: expanded.slice(64, 96),
18
- snapshotMacKey: expanded.slice(96, 128),
19
- patchMacKey: expanded.slice(128, 160)
14
+ indexKey: keys.indexKey,
15
+ valueEncryptionKey: keys.valueEncryptionKey,
16
+ valueMacKey: keys.valueMacKey,
17
+ snapshotMacKey: keys.snapshotMacKey,
18
+ patchMacKey: keys.patchMacKey
20
19
  };
21
20
  };
22
21
  const generateMac = (operation, data, keyId, key) => {
23
- const getKeyData = () => {
24
- let r;
25
- switch (operation) {
26
- case WAProto_1.proto.SyncdMutation.SyncdOperation.SET:
27
- r = 0x01;
28
- break;
29
- case WAProto_1.proto.SyncdMutation.SyncdOperation.REMOVE:
30
- r = 0x02;
31
- break;
32
- }
33
- const buff = Buffer.from([r]);
34
- return Buffer.concat([buff, Buffer.from(keyId, 'base64')]);
35
- };
36
- const keyData = getKeyData();
37
- const last = Buffer.alloc(8); // 8 bytes
38
- last.set([keyData.length], last.length - 1);
39
- const total = Buffer.concat([keyData, data, last]);
40
- const hmac = (0, crypto_1.hmacSign)(total, key, 'sha512');
41
- return hmac.slice(0, 32);
22
+ const opByte = operation === proto.SyncdMutation.SyncdOperation.SET ? 0x01 : 0x02;
23
+ const keyIdBuffer = typeof keyId === 'string' ? Buffer.from(keyId, 'base64') : keyId;
24
+ const keyData = new Uint8Array(1 + keyIdBuffer.length);
25
+ keyData[0] = opByte;
26
+ keyData.set(keyIdBuffer, 1);
27
+ const last = new Uint8Array(8);
28
+ last[7] = keyData.length;
29
+ const total = new Uint8Array(keyData.length + data.length + last.length);
30
+ total.set(keyData, 0);
31
+ total.set(data, keyData.length);
32
+ total.set(last, keyData.length + data.length);
33
+ const hmac = hmacSign(total, key, 'sha512');
34
+ return hmac.subarray(0, 32);
42
35
  };
43
36
  const to64BitNetworkOrder = (e) => {
44
37
  const buff = Buffer.alloc(8);
45
38
  buff.writeUint32BE(e, 4);
46
39
  return buff;
47
40
  };
48
- const makeLtHashGenerator = ({ indexValueMap, hash }) => {
41
+ export const makeLtHashGenerator = ({ indexValueMap, hash }) => {
49
42
  indexValueMap = { ...indexValueMap };
50
43
  const addBuffs = [];
51
44
  const subBuffs = [];
@@ -53,71 +46,85 @@ const makeLtHashGenerator = ({ indexValueMap, hash }) => {
53
46
  mix: ({ indexMac, valueMac, operation }) => {
54
47
  const indexMacBase64 = Buffer.from(indexMac).toString('base64');
55
48
  const prevOp = indexValueMap[indexMacBase64];
56
- if (operation === WAProto_1.proto.SyncdMutation.SyncdOperation.REMOVE) {
49
+ if (operation === proto.SyncdMutation.SyncdOperation.REMOVE) {
57
50
  if (!prevOp) {
58
- throw new boom_1.Boom('tried remove, but no previous op', { data: { indexMac, valueMac } });
51
+ // WA Web does not throw here it logs a warning and skips the subtract.
52
+ // The missing REMOVE will cause an LTHash mismatch, which is handled
53
+ // by the MAC validation layer (snapshot recovery or retry).
54
+ return;
59
55
  }
60
56
  // remove from index value mac, since this mutation is erased
61
57
  delete indexValueMap[indexMacBase64];
62
58
  }
63
59
  else {
64
- addBuffs.push(new Uint8Array(valueMac).buffer);
60
+ addBuffs.push(valueMac);
65
61
  // add this index into the history map
66
62
  indexValueMap[indexMacBase64] = { valueMac };
67
63
  }
68
64
  if (prevOp) {
69
- subBuffs.push(new Uint8Array(prevOp.valueMac).buffer);
65
+ subBuffs.push(prevOp.valueMac);
70
66
  }
71
67
  },
72
68
  finish: () => {
73
- const hashArrayBuffer = new Uint8Array(hash).buffer;
74
- const result = lt_hash_1.LT_HASH_ANTI_TAMPERING.subtractThenAdd(hashArrayBuffer, addBuffs, subBuffs);
75
- const buffer = Buffer.from(result);
69
+ const result = LT_HASH_ANTI_TAMPERING.subtractThenAdd(hash, subBuffs, addBuffs);
76
70
  return {
77
- hash: buffer,
71
+ hash: Buffer.from(result),
78
72
  indexValueMap
79
73
  };
80
74
  }
81
75
  };
82
76
  };
83
77
  const generateSnapshotMac = (lthash, version, name, key) => {
84
- const total = Buffer.concat([
85
- lthash,
86
- to64BitNetworkOrder(version),
87
- Buffer.from(name, 'utf-8')
88
- ]);
89
- return (0, crypto_1.hmacSign)(total, key, 'sha256');
78
+ const total = Buffer.concat([lthash, to64BitNetworkOrder(version), Buffer.from(name, 'utf-8')]);
79
+ return hmacSign(total, key, 'sha256');
90
80
  };
91
81
  const generatePatchMac = (snapshotMac, valueMacs, version, type, key) => {
92
- const total = Buffer.concat([
93
- snapshotMac,
94
- ...valueMacs,
95
- to64BitNetworkOrder(version),
96
- Buffer.from(type, 'utf-8')
97
- ]);
98
- return (0, crypto_1.hmacSign)(total, key);
82
+ const total = Buffer.concat([snapshotMac, ...valueMacs, to64BitNetworkOrder(version), Buffer.from(type, 'utf-8')]);
83
+ return hmacSign(total, key);
84
+ };
85
+ export const newLTHashState = () => ({ version: 0, hash: Buffer.alloc(128), indexValueMap: {} });
86
+ export const ensureLTHashStateVersion = (state) => {
87
+ if (typeof state.version !== 'number' || isNaN(state.version)) {
88
+ state.version = 0;
89
+ }
90
+ return state;
91
+ };
92
+ export const MAX_SYNC_ATTEMPTS = 2;
93
+ /**
94
+ * Check if an error is a missing app state sync key.
95
+ * WA Web treats these as "Blocked" (waits for key arrival), not fatal.
96
+ * In Baileys we retry with a snapshot which may use a different key.
97
+ */
98
+ export const isMissingKeyError = (error) => {
99
+ return error?.data?.isMissingKey === true;
100
+ };
101
+ /**
102
+ * Determines if an app state sync error is unrecoverable.
103
+ * TypeError indicates a WASM crash; otherwise we give up after MAX_SYNC_ATTEMPTS.
104
+ * Missing keys are NOT checked here — they are handled separately as "Blocked".
105
+ */
106
+ export const isAppStateSyncIrrecoverable = (error, attempts) => {
107
+ return attempts >= MAX_SYNC_ATTEMPTS || error?.name === 'TypeError';
99
108
  };
100
- const newLTHashState = () => ({ version: 0, hash: Buffer.alloc(128), indexValueMap: {} });
101
- exports.newLTHashState = newLTHashState;
102
- const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation }, myAppStateKeyId, state, getAppStateSyncKey) => {
109
+ export const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation }, myAppStateKeyId, state, getAppStateSyncKey) => {
103
110
  const key = !!myAppStateKeyId ? await getAppStateSyncKey(myAppStateKeyId) : undefined;
104
111
  if (!key) {
105
- throw new boom_1.Boom(`myAppStateKey ("${myAppStateKeyId}") not present`, { statusCode: 404 });
112
+ throw new Boom(`myAppStateKey ("${myAppStateKeyId}") not present`, { data: { isMissingKey: true } });
106
113
  }
107
114
  const encKeyId = Buffer.from(myAppStateKeyId, 'base64');
108
115
  state = { ...state, indexValueMap: { ...state.indexValueMap } };
109
116
  const indexBuffer = Buffer.from(JSON.stringify(index));
110
- const dataProto = WAProto_1.proto.SyncActionData.fromObject({
117
+ const dataProto = proto.SyncActionData.fromObject({
111
118
  index: indexBuffer,
112
119
  value: syncAction,
113
120
  padding: new Uint8Array(0),
114
121
  version: apiVersion
115
122
  });
116
- const encoded = WAProto_1.proto.SyncActionData.encode(dataProto).finish();
123
+ const encoded = proto.SyncActionData.encode(dataProto).finish();
117
124
  const keyValue = mutationKeys(key.keyData);
118
- const encValue = (0, crypto_1.aesEncrypt)(encoded, keyValue.valueEncryptionKey);
125
+ const encValue = aesEncrypt(encoded, keyValue.valueEncryptionKey);
119
126
  const valueMac = generateMac(operation, encValue, encKeyId, keyValue.valueMacKey);
120
- const indexMac = (0, crypto_1.hmacSign)(indexBuffer, keyValue.indexKey);
127
+ const indexMac = hmacSign(indexBuffer, keyValue.indexKey);
121
128
  // update LT hash
122
129
  const generator = makeLtHashGenerator(state);
123
130
  generator.mix({ indexMac, valueMac, operation });
@@ -147,33 +154,52 @@ const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation
147
154
  state.indexValueMap[base64Index] = { valueMac };
148
155
  return { patch, state };
149
156
  };
150
- exports.encodeSyncdPatch = encodeSyncdPatch;
151
- const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
157
+ export const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
152
158
  const ltGenerator = makeLtHashGenerator(initialState);
159
+ const derivedKeyCache = new Map();
153
160
  // indexKey used to HMAC sign record.index.blob
154
161
  // valueEncryptionKey used to AES-256-CBC encrypt record.value.blob[0:-32]
155
162
  // the remaining record.value.blob[0:-32] is the mac, it the HMAC sign of key.keyId + decoded proto data + length of bytes in keyId
156
163
  for (const msgMutation of msgMutations) {
157
164
  // if it's a syncdmutation, get the operation property
158
165
  // otherwise, if it's only a record -- it'll be a SET mutation
159
- const operation = 'operation' in msgMutation ? msgMutation.operation : WAProto_1.proto.SyncdMutation.SyncdOperation.SET;
160
- const record = ('record' in msgMutation && !!msgMutation.record) ? msgMutation.record : msgMutation;
161
- const key = await getKey(record.keyId.id);
162
- const content = Buffer.from(record.value.blob);
163
- const encContent = content.slice(0, -32);
164
- const ogValueMac = content.slice(-32);
166
+ const operation = 'operation' in msgMutation ? msgMutation.operation : proto.SyncdMutation.SyncdOperation.SET;
167
+ const record = 'record' in msgMutation && !!msgMutation.record ? msgMutation.record : msgMutation;
168
+ let key;
169
+ try {
170
+ key = await getKey(record.keyId.id);
171
+ }
172
+ catch (err) {
173
+ // Missing-key errors must propagate so the orchestrator can park the
174
+ // collection (Blocked) and retry when APP_STATE_SYNC_KEY_SHARE arrives.
175
+ // Other errors → individual record corruption, skip and keep going.
176
+ if (isMissingKeyError(err))
177
+ throw err;
178
+ continue;
179
+ }
180
+ const content = record.value.blob;
181
+ const encContent = content.subarray(0, -32);
182
+ const ogValueMac = content.subarray(-32);
165
183
  if (validateMacs) {
166
184
  const contentHmac = generateMac(operation, encContent, record.keyId.id, key.valueMacKey);
167
185
  if (Buffer.compare(contentHmac, ogValueMac) !== 0) {
168
- throw new boom_1.Boom('HMAC content verification failed');
186
+ // HMAC verification failed — skip this record
187
+ continue;
169
188
  }
170
189
  }
171
- const result = (0, crypto_1.aesDecrypt)(encContent, key.valueEncryptionKey);
172
- const syncAction = WAProto_1.proto.SyncActionData.decode(result);
190
+ let result;
191
+ try {
192
+ result = aesDecrypt(encContent, key.valueEncryptionKey);
193
+ }
194
+ catch {
195
+ // decrypt failed — skip this record instead of aborting
196
+ continue;
197
+ }
198
+ const syncAction = proto.SyncActionData.decode(result);
173
199
  if (validateMacs) {
174
- const hmac = (0, crypto_1.hmacSign)(syncAction.index, key.indexKey);
200
+ const hmac = hmacSign(syncAction.index, key.indexKey);
175
201
  if (Buffer.compare(hmac, record.index.blob) !== 0) {
176
- throw new boom_1.Boom('HMAC index verification failed');
202
+ throw new Boom('HMAC index verification failed');
177
203
  }
178
204
  }
179
205
  const indexStr = Buffer.from(syncAction.index).toString();
@@ -187,40 +213,46 @@ const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncK
187
213
  return ltGenerator.finish();
188
214
  async function getKey(keyId) {
189
215
  const base64Key = Buffer.from(keyId).toString('base64');
216
+ const cached = derivedKeyCache.get(base64Key);
217
+ if (cached) {
218
+ return cached;
219
+ }
190
220
  const keyEnc = await getAppStateSyncKey(base64Key);
191
221
  if (!keyEnc) {
192
- throw new boom_1.Boom(`failed to find key "${base64Key}" to decode mutation`, { statusCode: 404, data: { msgMutations } });
222
+ throw new Boom(`failed to find key "${base64Key}" to decode mutation`, {
223
+ data: { isMissingKey: true, msgMutations }
224
+ });
193
225
  }
194
- return mutationKeys(keyEnc.keyData);
226
+ const keys = mutationKeys(keyEnc.keyData);
227
+ derivedKeyCache.set(base64Key, keys);
228
+ return keys;
195
229
  }
196
230
  };
197
- exports.decodeSyncdMutations = decodeSyncdMutations;
198
- const decodeSyncdPatch = async (msg, name, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
231
+ export const decodeSyncdPatch = async (msg, name, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
199
232
  if (validateMacs) {
200
233
  const base64Key = Buffer.from(msg.keyId.id).toString('base64');
201
234
  const mainKeyObj = await getAppStateSyncKey(base64Key);
202
235
  if (!mainKeyObj) {
203
- throw new boom_1.Boom(`failed to find key "${base64Key}" to decode patch`, { statusCode: 404, data: { msg } });
236
+ throw new Boom(`failed to find key "${base64Key}" to decode patch`, { data: { isMissingKey: true, msg } });
204
237
  }
205
238
  const mainKey = mutationKeys(mainKeyObj.keyData);
206
239
  const mutationmacs = msg.mutations.map(mutation => mutation.record.value.blob.slice(-32));
207
- const patchMac = generatePatchMac(msg.snapshotMac, mutationmacs, (0, generics_1.toNumber)(msg.version.version), name, mainKey.patchMacKey);
240
+ const patchMac = generatePatchMac(msg.snapshotMac, mutationmacs, toNumber(msg.version.version), name, mainKey.patchMacKey);
208
241
  if (Buffer.compare(patchMac, msg.patchMac) !== 0) {
209
- throw new boom_1.Boom('Invalid patch mac');
242
+ throw new Boom('Invalid patch mac');
210
243
  }
211
244
  }
212
- const result = await (0, exports.decodeSyncdMutations)(msg.mutations, initialState, getAppStateSyncKey, onMutation, validateMacs);
245
+ const result = await decodeSyncdMutations(msg.mutations, initialState, getAppStateSyncKey, onMutation, validateMacs);
213
246
  return result;
214
247
  };
215
- exports.decodeSyncdPatch = decodeSyncdPatch;
216
- const extractSyncdPatches = async (result, options) => {
217
- const syncNode = (0, WABinary_1.getBinaryNodeChild)(result, 'sync');
218
- const collectionNodes = (0, WABinary_1.getBinaryNodeChildren)(syncNode, 'collection');
248
+ export const extractSyncdPatches = async (result, options) => {
249
+ const syncNode = getBinaryNodeChild(result, 'sync');
250
+ const collectionNodes = getBinaryNodeChildren(syncNode, 'collection');
219
251
  const final = {};
220
252
  await Promise.all(collectionNodes.map(async (collectionNode) => {
221
- const patchesNode = (0, WABinary_1.getBinaryNodeChild)(collectionNode, 'patches');
222
- const patches = (0, WABinary_1.getBinaryNodeChildren)(patchesNode || collectionNode, 'patch');
223
- const snapshotNode = (0, WABinary_1.getBinaryNodeChild)(collectionNode, 'snapshot');
253
+ const patchesNode = getBinaryNodeChild(collectionNode, 'patches');
254
+ const patches = getBinaryNodeChildren(patchesNode || collectionNode, 'patch');
255
+ const snapshotNode = getBinaryNodeChild(collectionNode, 'snapshot');
224
256
  const syncds = [];
225
257
  const name = collectionNode.attrs.name;
226
258
  const hasMorePatches = collectionNode.attrs.has_more_patches === 'true';
@@ -229,16 +261,16 @@ const extractSyncdPatches = async (result, options) => {
229
261
  if (!Buffer.isBuffer(snapshotNode)) {
230
262
  snapshotNode.content = Buffer.from(Object.values(snapshotNode.content));
231
263
  }
232
- const blobRef = WAProto_1.proto.ExternalBlobReference.decode(snapshotNode.content);
233
- const data = await (0, exports.downloadExternalBlob)(blobRef, options);
234
- snapshot = WAProto_1.proto.SyncdSnapshot.decode(data);
264
+ const blobRef = proto.ExternalBlobReference.decode(snapshotNode.content);
265
+ const data = await downloadExternalBlob(blobRef, options);
266
+ snapshot = proto.SyncdSnapshot.decode(data);
235
267
  }
236
268
  for (let { content } of patches) {
237
269
  if (content) {
238
270
  if (!Buffer.isBuffer(content)) {
239
271
  content = Buffer.from(Object.values(content));
240
272
  }
241
- const syncd = WAProto_1.proto.SyncdPatch.decode(content);
273
+ const syncd = proto.SyncdPatch.decode(content);
242
274
  if (!syncd.version) {
243
275
  syncd.version = { version: +collectionNode.attrs.version + 1 };
244
276
  }
@@ -249,32 +281,27 @@ const extractSyncdPatches = async (result, options) => {
249
281
  }));
250
282
  return final;
251
283
  };
252
- exports.extractSyncdPatches = extractSyncdPatches;
253
- const downloadExternalBlob = async (blob, options) => {
254
- const stream = await (0, messages_media_1.downloadContentFromMessage)(blob, 'md-app-state', { options });
284
+ export const downloadExternalBlob = async (blob, options) => {
285
+ const stream = await downloadContentFromMessage(blob, 'md-app-state', { options });
255
286
  const bufferArray = [];
256
287
  for await (const chunk of stream) {
257
288
  bufferArray.push(chunk);
258
289
  }
259
290
  return Buffer.concat(bufferArray);
260
291
  };
261
- exports.downloadExternalBlob = downloadExternalBlob;
262
- const downloadExternalPatch = async (blob, options) => {
263
- const buffer = await (0, exports.downloadExternalBlob)(blob, options);
264
- const syncData = WAProto_1.proto.SyncdMutations.decode(buffer);
292
+ export const downloadExternalPatch = async (blob, options) => {
293
+ const buffer = await downloadExternalBlob(blob, options);
294
+ const syncData = proto.SyncdMutations.decode(buffer);
265
295
  return syncData;
266
296
  };
267
- exports.downloadExternalPatch = downloadExternalPatch;
268
- const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVersionNumber, validateMacs = true) => {
269
- const newState = (0, exports.newLTHashState)();
270
- newState.version = (0, generics_1.toNumber)(snapshot.version.version);
297
+ export const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVersionNumber, validateMacs = true, logger) => {
298
+ const newState = newLTHashState();
299
+ newState.version = toNumber(snapshot.version.version);
271
300
  const mutationMap = {};
272
- const areMutationsRequired = typeof minimumVersionNumber === 'undefined'
273
- || newState.version > minimumVersionNumber;
274
- const { hash, indexValueMap } = await (0, exports.decodeSyncdMutations)(snapshot.records, newState, getAppStateSyncKey, areMutationsRequired
275
- ? (mutation) => {
276
- var _a;
277
- const index = (_a = mutation.syncAction.index) === null || _a === void 0 ? void 0 : _a.toString();
301
+ const areMutationsRequired = typeof minimumVersionNumber === 'undefined' || newState.version > minimumVersionNumber;
302
+ const { hash, indexValueMap } = await decodeSyncdMutations(snapshot.records, newState, getAppStateSyncKey, areMutationsRequired
303
+ ? mutation => {
304
+ const index = mutation.syncAction.index?.toString();
278
305
  mutationMap[index] = mutation;
279
306
  }
280
307
  : () => { }, validateMacs);
@@ -284,12 +311,17 @@ const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVe
284
311
  const base64Key = Buffer.from(snapshot.keyId.id).toString('base64');
285
312
  const keyEnc = await getAppStateSyncKey(base64Key);
286
313
  if (!keyEnc) {
287
- throw new boom_1.Boom(`failed to find key "${base64Key}" to decode mutation`);
314
+ throw new Boom(`failed to find key "${base64Key}" to decode mutation`, { data: { isMissingKey: true } });
288
315
  }
289
316
  const result = mutationKeys(keyEnc.keyData);
290
317
  const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey);
291
318
  if (Buffer.compare(snapshot.mac, computedSnapshotMac) !== 0) {
292
- throw new boom_1.Boom(`failed to verify LTHash at ${newState.version} of ${name} from snapshot`);
319
+ // LTHash verification may fail when decodeSyncdMutations skipped undecryptable
320
+ // records (poisoned server-side snapshot); the aggregate client hash diverges
321
+ // from the server-computed mac. Fall through with a warning so the session stays
322
+ // alive with partial state, symmetric to how decodePatches handles its own
323
+ // LTHash mismatch a few lines below.
324
+ logger?.warn({ name, version: newState.version }, 'LTHash verification failed on snapshot, continuing with partial state');
293
325
  }
294
326
  }
295
327
  return {
@@ -297,45 +329,51 @@ const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVe
297
329
  mutationMap
298
330
  };
299
331
  };
300
- exports.decodeSyncdSnapshot = decodeSyncdSnapshot;
301
- const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options, minimumVersionNumber, logger, validateMacs = true) => {
302
- var _a;
332
+ export const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options, minimumVersionNumber, logger, validateMacs = true) => {
303
333
  const newState = {
304
334
  ...initial,
305
335
  indexValueMap: { ...initial.indexValueMap }
306
336
  };
307
337
  const mutationMap = {};
308
- for (let i = 0; i < syncds.length; i++) {
309
- const syncd = syncds[i];
338
+ for (const syncd of syncds) {
310
339
  const { version, keyId, snapshotMac } = syncd;
311
340
  if (syncd.externalMutations) {
312
- logger === null || logger === void 0 ? void 0 : logger.trace({ name, version }, 'downloading external patch');
313
- const ref = await (0, exports.downloadExternalPatch)(syncd.externalMutations, options);
314
- logger === null || logger === void 0 ? void 0 : logger.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch');
315
- (_a = syncd.mutations) === null || _a === void 0 ? void 0 : _a.push(...ref.mutations);
341
+ logger?.trace({ name, version }, 'downloading external patch');
342
+ const ref = await downloadExternalPatch(syncd.externalMutations, options);
343
+ logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch');
344
+ syncd.mutations?.push(...ref.mutations);
316
345
  }
317
- const patchVersion = (0, generics_1.toNumber)(version.version);
346
+ const patchVersion = toNumber(version.version);
318
347
  newState.version = patchVersion;
319
348
  const shouldMutate = typeof minimumVersionNumber === 'undefined' || patchVersion > minimumVersionNumber;
320
- const decodeResult = await (0, exports.decodeSyncdPatch)(syncd, name, newState, getAppStateSyncKey, shouldMutate
321
- ? mutation => {
322
- var _a;
323
- const index = (_a = mutation.syncAction.index) === null || _a === void 0 ? void 0 : _a.toString();
324
- mutationMap[index] = mutation;
325
- }
326
- : (() => { }), true);
349
+ let decodeResult;
350
+ try {
351
+ decodeResult = await decodeSyncdPatch(syncd, name, newState, getAppStateSyncKey, shouldMutate
352
+ ? mutation => {
353
+ const index = mutation.syncAction.index?.toString();
354
+ mutationMap[index] = mutation;
355
+ }
356
+ : () => { }, validateMacs);
357
+ }
358
+ catch (err) {
359
+ if (isMissingKeyError(err))
360
+ throw err;
361
+ logger?.warn({ name, version: patchVersion, error: err.message }, 'failed to decode patch, skipping');
362
+ continue;
363
+ }
327
364
  newState.hash = decodeResult.hash;
328
365
  newState.indexValueMap = decodeResult.indexValueMap;
329
366
  if (validateMacs) {
330
367
  const base64Key = Buffer.from(keyId.id).toString('base64');
331
368
  const keyEnc = await getAppStateSyncKey(base64Key);
332
369
  if (!keyEnc) {
333
- throw new boom_1.Boom(`failed to find key "${base64Key}" to decode mutation`);
370
+ throw new Boom(`failed to find key "${base64Key}" to decode mutation`, { data: { isMissingKey: true } });
334
371
  }
335
372
  const result = mutationKeys(keyEnc.keyData);
336
373
  const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey);
337
374
  if (Buffer.compare(snapshotMac, computedSnapshotMac) !== 0) {
338
- throw new boom_1.Boom(`failed to verify LTHash at ${newState.version} of ${name}`);
375
+ logger?.warn({ name, version: newState.version }, 'LTHash verification failed, skipping remaining patches');
376
+ break;
339
377
  }
340
378
  }
341
379
  // clear memory used up by the mutations
@@ -343,31 +381,31 @@ const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options,
343
381
  }
344
382
  return { state: newState, mutationMap };
345
383
  };
346
- exports.decodePatches = decodePatches;
347
- const chatModificationToAppPatch = (mod, jid) => {
348
- const OP = WAProto_1.proto.SyncdMutation.SyncdOperation;
384
+ export const chatModificationToAppPatch = (mod, jid) => {
385
+ const OP = proto.SyncdMutation.SyncdOperation;
349
386
  const getMessageRange = (lastMessages) => {
350
387
  let messageRange;
351
388
  if (Array.isArray(lastMessages)) {
352
389
  const lastMsg = lastMessages[lastMessages.length - 1];
353
390
  messageRange = {
354
- lastMessageTimestamp: lastMsg === null || lastMsg === void 0 ? void 0 : lastMsg.messageTimestamp,
355
- messages: (lastMessages === null || lastMessages === void 0 ? void 0 : lastMessages.length) ? lastMessages.map(m => {
356
- var _a, _b;
357
- if (!((_a = m.key) === null || _a === void 0 ? void 0 : _a.id) || !((_b = m.key) === null || _b === void 0 ? void 0 : _b.remoteJid)) {
358
- throw new boom_1.Boom('Incomplete key', { statusCode: 400, data: m });
359
- }
360
- if ((0, WABinary_1.isJidGroup)(m.key.remoteJid) && !m.key.fromMe && !m.key.participant) {
361
- throw new boom_1.Boom('Expected not from me message to have participant', { statusCode: 400, data: m });
362
- }
363
- if (!m.messageTimestamp || !(0, generics_1.toNumber)(m.messageTimestamp)) {
364
- throw new boom_1.Boom('Missing timestamp in last message list', { statusCode: 400, data: m });
365
- }
366
- if (m.key.participant) {
367
- m.key.participant = (0, WABinary_1.jidNormalizedUser)(m.key.participant);
368
- }
369
- return m;
370
- }) : undefined
391
+ lastMessageTimestamp: lastMsg?.messageTimestamp,
392
+ messages: lastMessages?.length
393
+ ? lastMessages.map(m => {
394
+ if (!m.key?.id || !m.key?.remoteJid) {
395
+ throw new Boom('Incomplete key', { statusCode: 400, data: m });
396
+ }
397
+ if (isJidGroup(m.key.remoteJid) && !m.key.fromMe && !m.key.participant) {
398
+ throw new Boom('Expected not from me message to have participant', { statusCode: 400, data: m });
399
+ }
400
+ if (!m.messageTimestamp || !toNumber(m.messageTimestamp)) {
401
+ throw new Boom('Missing timestamp in last message list', { statusCode: 400, data: m });
402
+ }
403
+ if (m.key.participant) {
404
+ m.key.participant = jidNormalizedUser(m.key.participant);
405
+ }
406
+ return m;
407
+ })
408
+ : undefined
371
409
  };
372
410
  }
373
411
  else {
@@ -418,25 +456,33 @@ const chatModificationToAppPatch = (mod, jid) => {
418
456
  operation: OP.SET
419
457
  };
420
458
  }
459
+ else if ('deleteForMe' in mod) {
460
+ const { timestamp, key, deleteMedia } = mod.deleteForMe;
461
+ patch = {
462
+ syncAction: {
463
+ deleteMessageForMeAction: {
464
+ deleteMedia,
465
+ messageTimestamp: timestamp
466
+ }
467
+ },
468
+ index: ['deleteMessageForMe', jid, key.id, key.fromMe ? '1' : '0', '0'],
469
+ type: 'regular_high',
470
+ apiVersion: 3,
471
+ operation: OP.SET
472
+ };
473
+ }
421
474
  else if ('clear' in mod) {
422
- if (mod.clear === 'all') {
423
- throw new boom_1.Boom('not supported');
424
- }
425
- else {
426
- const key = mod.clear.messages[0];
427
- patch = {
428
- syncAction: {
429
- deleteMessageForMeAction: {
430
- deleteMedia: false,
431
- messageTimestamp: key.timestamp
432
- }
433
- },
434
- index: ['deleteMessageForMe', jid, key.id, key.fromMe ? '1' : '0', '0'],
435
- type: 'regular_high',
436
- apiVersion: 3,
437
- operation: OP.SET
438
- };
439
- }
475
+ patch = {
476
+ syncAction: {
477
+ clearChatAction: {
478
+ messageRange: getMessageRange(mod.lastMessages)
479
+ }
480
+ },
481
+ index: ['clearChat', jid, '1' /*the option here is 0 when keep starred messages is enabled*/, '0'],
482
+ type: 'regular_high',
483
+ apiVersion: 6,
484
+ operation: OP.SET
485
+ };
440
486
  }
441
487
  else if ('pin' in mod) {
442
488
  patch = {
@@ -451,6 +497,28 @@ const chatModificationToAppPatch = (mod, jid) => {
451
497
  operation: OP.SET
452
498
  };
453
499
  }
500
+ else if ('contact' in mod) {
501
+ patch = {
502
+ syncAction: {
503
+ contactAction: mod.contact || {}
504
+ },
505
+ index: ['contact', jid],
506
+ type: 'critical_unblock_low',
507
+ apiVersion: 2,
508
+ operation: mod.contact ? OP.SET : OP.REMOVE
509
+ };
510
+ }
511
+ else if ('disableLinkPreviews' in mod) {
512
+ patch = {
513
+ syncAction: {
514
+ privacySettingDisableLinkPreviewsAction: mod.disableLinkPreviews || {}
515
+ },
516
+ index: ['setting_disableLinkPreviews'],
517
+ type: 'regular',
518
+ apiVersion: 8,
519
+ operation: OP.SET
520
+ };
521
+ }
454
522
  else if ('star' in mod) {
455
523
  const key = mod.star.messages[0];
456
524
  patch = {
@@ -469,7 +537,7 @@ const chatModificationToAppPatch = (mod, jid) => {
469
537
  patch = {
470
538
  syncAction: {
471
539
  deleteChatAction: {
472
- messageRange: getMessageRange(mod.lastMessages),
540
+ messageRange: getMessageRange(mod.lastMessages)
473
541
  }
474
542
  },
475
543
  index: ['deleteChat', jid, '1'],
@@ -488,64 +556,90 @@ const chatModificationToAppPatch = (mod, jid) => {
488
556
  index: ['setting_pushName'],
489
557
  type: 'critical_block',
490
558
  apiVersion: 1,
491
- operation: OP.SET,
559
+ operation: OP.SET
560
+ };
561
+ }
562
+ else if ('quickReply' in mod) {
563
+ patch = {
564
+ syncAction: {
565
+ quickReplyAction: {
566
+ count: 0,
567
+ deleted: mod.quickReply.deleted || false,
568
+ keywords: [],
569
+ message: mod.quickReply.message || '',
570
+ shortcut: mod.quickReply.shortcut || ''
571
+ }
572
+ },
573
+ index: ['quick_reply', mod.quickReply.timestamp || String(Math.floor(Date.now() / 1000))],
574
+ type: 'regular',
575
+ apiVersion: 2,
576
+ operation: OP.SET
577
+ };
578
+ }
579
+ else if ('addLabel' in mod) {
580
+ patch = {
581
+ syncAction: {
582
+ labelEditAction: {
583
+ name: mod.addLabel.name,
584
+ color: mod.addLabel.color,
585
+ predefinedId: mod.addLabel.predefinedId,
586
+ deleted: mod.addLabel.deleted
587
+ }
588
+ },
589
+ index: ['label_edit', mod.addLabel.id],
590
+ type: 'regular',
591
+ apiVersion: 3,
592
+ operation: OP.SET
492
593
  };
493
594
  }
494
595
  else if ('addChatLabel' in mod) {
495
596
  patch = {
496
597
  syncAction: {
497
598
  labelAssociationAction: {
498
- labeled: true,
599
+ labeled: true
499
600
  }
500
601
  },
501
- index: [LabelAssociation_1.LabelAssociationType.Chat, mod.addChatLabel.labelId, jid],
602
+ index: [LabelAssociationType.Chat, mod.addChatLabel.labelId, jid],
502
603
  type: 'regular',
503
604
  apiVersion: 3,
504
- operation: OP.SET,
605
+ operation: OP.SET
505
606
  };
506
607
  }
507
608
  else if ('removeChatLabel' in mod) {
508
609
  patch = {
509
610
  syncAction: {
510
611
  labelAssociationAction: {
511
- labeled: false,
612
+ labeled: false
512
613
  }
513
614
  },
514
- index: [LabelAssociation_1.LabelAssociationType.Chat, mod.removeChatLabel.labelId, jid],
615
+ index: [LabelAssociationType.Chat, mod.removeChatLabel.labelId, jid],
515
616
  type: 'regular',
516
617
  apiVersion: 3,
517
- operation: OP.SET,
618
+ operation: OP.SET
518
619
  };
519
620
  }
520
621
  else if ('addMessageLabel' in mod) {
521
622
  patch = {
522
623
  syncAction: {
523
624
  labelAssociationAction: {
524
- labeled: true,
625
+ labeled: true
525
626
  }
526
627
  },
527
- index: [
528
- LabelAssociation_1.LabelAssociationType.Message,
529
- mod.addMessageLabel.labelId,
530
- jid,
531
- mod.addMessageLabel.messageId,
532
- '0',
533
- '0'
534
- ],
628
+ index: [LabelAssociationType.Message, mod.addMessageLabel.labelId, jid, mod.addMessageLabel.messageId, '0', '0'],
535
629
  type: 'regular',
536
630
  apiVersion: 3,
537
- operation: OP.SET,
631
+ operation: OP.SET
538
632
  };
539
633
  }
540
634
  else if ('removeMessageLabel' in mod) {
541
635
  patch = {
542
636
  syncAction: {
543
637
  labelAssociationAction: {
544
- labeled: false,
638
+ labeled: false
545
639
  }
546
640
  },
547
641
  index: [
548
- LabelAssociation_1.LabelAssociationType.Message,
642
+ LabelAssociationType.Message,
549
643
  mod.removeMessageLabel.labelId,
550
644
  jid,
551
645
  mod.removeMessageLabel.messageId,
@@ -554,34 +648,30 @@ const chatModificationToAppPatch = (mod, jid) => {
554
648
  ],
555
649
  type: 'regular',
556
650
  apiVersion: 3,
557
- operation: OP.SET,
651
+ operation: OP.SET
558
652
  };
559
653
  }
560
654
  else {
561
- throw new boom_1.Boom('not supported');
655
+ throw new Boom('not supported');
562
656
  }
563
657
  patch.syncAction.timestamp = Date.now();
564
658
  return patch;
565
659
  };
566
- exports.chatModificationToAppPatch = chatModificationToAppPatch;
567
- const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
568
- var _a, _b, _c, _d;
660
+ export const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
569
661
  const isInitialSync = !!initialSyncOpts;
570
- const accountSettings = initialSyncOpts === null || initialSyncOpts === void 0 ? void 0 : initialSyncOpts.accountSettings;
571
- logger === null || logger === void 0 ? void 0 : logger.trace({ syncAction, initialSync: !!initialSyncOpts }, 'processing sync action');
662
+ const accountSettings = initialSyncOpts?.accountSettings;
663
+ logger?.trace({ syncAction, initialSync: !!initialSyncOpts }, 'processing sync action');
572
664
  const { syncAction: { value: action }, index: [type, id, msgId, fromMe] } = syncAction;
573
- if (action === null || action === void 0 ? void 0 : action.muteAction) {
665
+ if (action?.muteAction) {
574
666
  ev.emit('chats.update', [
575
667
  {
576
668
  id,
577
- muteEndTime: ((_a = action.muteAction) === null || _a === void 0 ? void 0 : _a.muted)
578
- ? (0, generics_1.toNumber)(action.muteAction.muteEndTimestamp)
579
- : null,
669
+ muteEndTime: action.muteAction?.muted ? toNumber(action.muteAction.muteEndTimestamp) : null,
580
670
  conditional: getChatUpdateConditional(id, undefined)
581
671
  }
582
672
  ]);
583
673
  }
584
- else if ((action === null || action === void 0 ? void 0 : action.archiveChatAction) || type === 'archive' || type === 'unarchive') {
674
+ else if (action?.archiveChatAction || type === 'archive' || type === 'unarchive') {
585
675
  // okay so we've to do some annoying computation here
586
676
  // when we're initially syncing the app state
587
677
  // there are a few cases we need to handle
@@ -592,36 +682,38 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
592
682
  // we compare the timestamp of latest message from the other person to determine this
593
683
  // 2. if the account unarchiveChats setting is false -- then it doesn't matter,
594
684
  // it'll always take an app state action to mark in unarchived -- which we'll get anyway
595
- const archiveAction = action === null || action === void 0 ? void 0 : action.archiveChatAction;
596
- const isArchived = archiveAction
597
- ? archiveAction.archived
598
- : type === 'archive';
685
+ const archiveAction = action?.archiveChatAction;
686
+ const isArchived = archiveAction ? archiveAction.archived : type === 'archive';
599
687
  // // basically we don't need to fire an "archive" update if the chat is being marked unarchvied
600
688
  // // this only applies for the initial sync
601
689
  // if(isInitialSync && !isArchived) {
602
690
  // isArchived = false
603
691
  // }
604
- const msgRange = !(accountSettings === null || accountSettings === void 0 ? void 0 : accountSettings.unarchiveChats) ? undefined : archiveAction === null || archiveAction === void 0 ? void 0 : archiveAction.messageRange;
692
+ const msgRange = !accountSettings?.unarchiveChats ? undefined : archiveAction?.messageRange;
605
693
  // logger?.debug({ chat: id, syncAction }, 'message range archive')
606
- ev.emit('chats.update', [{
694
+ ev.emit('chats.update', [
695
+ {
607
696
  id,
608
697
  archived: isArchived,
609
698
  conditional: getChatUpdateConditional(id, msgRange)
610
- }]);
699
+ }
700
+ ]);
611
701
  }
612
- else if (action === null || action === void 0 ? void 0 : action.markChatAsReadAction) {
702
+ else if (action?.markChatAsReadAction) {
613
703
  const markReadAction = action.markChatAsReadAction;
614
704
  // basically we don't need to fire an "read" update if the chat is being marked as read
615
705
  // because the chat is read by default
616
706
  // this only applies for the initial sync
617
707
  const isNullUpdate = isInitialSync && markReadAction.read;
618
- ev.emit('chats.update', [{
708
+ ev.emit('chats.update', [
709
+ {
619
710
  id,
620
- unreadCount: isNullUpdate ? null : !!(markReadAction === null || markReadAction === void 0 ? void 0 : markReadAction.read) ? 0 : -1,
621
- conditional: getChatUpdateConditional(id, markReadAction === null || markReadAction === void 0 ? void 0 : markReadAction.messageRange)
622
- }]);
711
+ unreadCount: isNullUpdate ? null : !!markReadAction?.read ? 0 : -1,
712
+ conditional: getChatUpdateConditional(id, markReadAction?.messageRange)
713
+ }
714
+ ]);
623
715
  }
624
- else if ((action === null || action === void 0 ? void 0 : action.deleteMessageForMeAction) || type === 'deleteMessageForMe') {
716
+ else if (action?.deleteMessageForMeAction || type === 'deleteMessageForMe') {
625
717
  ev.emit('messages.delete', {
626
718
  keys: [
627
719
  {
@@ -632,37 +724,35 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
632
724
  ]
633
725
  });
634
726
  }
635
- else if (action === null || action === void 0 ? void 0 : action.contactAction) {
636
- ev.emit('contacts.upsert', [{
637
- id: id,
638
- name: action.contactAction.fullName,
639
- lid: action.contactAction.lidJid || undefined,
640
- jid: (0, WABinary_1.isJidUser)(id) ? id : undefined
641
- }]);
642
- }
643
- else if (action === null || action === void 0 ? void 0 : action.pushNameSetting) {
644
- const name = (_b = action === null || action === void 0 ? void 0 : action.pushNameSetting) === null || _b === void 0 ? void 0 : _b.name;
645
- if (name && (me === null || me === void 0 ? void 0 : me.name) !== name) {
727
+ else if (action?.contactAction) {
728
+ const results = processContactAction(action.contactAction, id, logger);
729
+ emitSyncActionResults(ev, results);
730
+ }
731
+ else if (action?.pushNameSetting) {
732
+ const name = action?.pushNameSetting?.name;
733
+ if (name && me?.name !== name) {
646
734
  ev.emit('creds.update', { me: { ...me, name } });
647
735
  }
648
736
  }
649
- else if (action === null || action === void 0 ? void 0 : action.pinAction) {
650
- ev.emit('chats.update', [{
737
+ else if (action?.pinAction) {
738
+ ev.emit('chats.update', [
739
+ {
651
740
  id,
652
- pinned: ((_c = action.pinAction) === null || _c === void 0 ? void 0 : _c.pinned) ? (0, generics_1.toNumber)(action.timestamp) : null,
741
+ pinned: action.pinAction?.pinned ? toNumber(action.timestamp) : null,
653
742
  conditional: getChatUpdateConditional(id, undefined)
654
- }]);
743
+ }
744
+ ]);
655
745
  }
656
- else if (action === null || action === void 0 ? void 0 : action.unarchiveChatsSetting) {
746
+ else if (action?.unarchiveChatsSetting) {
657
747
  const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats;
658
748
  ev.emit('creds.update', { accountSettings: { unarchiveChats } });
659
- logger === null || logger === void 0 ? void 0 : logger.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`);
749
+ logger?.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`);
660
750
  if (accountSettings) {
661
751
  accountSettings.unarchiveChats = unarchiveChats;
662
752
  }
663
753
  }
664
- else if ((action === null || action === void 0 ? void 0 : action.starAction) || type === 'star') {
665
- let starred = (_d = action === null || action === void 0 ? void 0 : action.starAction) === null || _d === void 0 ? void 0 : _d.starred;
754
+ else if (action?.starAction || type === 'star') {
755
+ let starred = action?.starAction?.starred;
666
756
  if (typeof starred !== 'boolean') {
667
757
  starred = syncAction.index[syncAction.index.length - 1] === '1';
668
758
  }
@@ -673,46 +763,99 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
673
763
  }
674
764
  ]);
675
765
  }
676
- else if ((action === null || action === void 0 ? void 0 : action.deleteChatAction) || type === 'deleteChat') {
766
+ else if (action?.deleteChatAction || type === 'deleteChat') {
677
767
  if (!isInitialSync) {
678
768
  ev.emit('chats.delete', [id]);
679
769
  }
680
770
  }
681
- else if (action === null || action === void 0 ? void 0 : action.labelEditAction) {
771
+ else if (action?.labelEditAction) {
682
772
  const { name, color, deleted, predefinedId } = action.labelEditAction;
683
773
  ev.emit('labels.edit', {
684
- id,
774
+ id: id,
685
775
  name: name,
686
776
  color: color,
687
777
  deleted: deleted,
688
778
  predefinedId: predefinedId ? String(predefinedId) : undefined
689
779
  });
690
780
  }
691
- else if (action === null || action === void 0 ? void 0 : action.labelAssociationAction) {
781
+ else if (action?.labelAssociationAction) {
692
782
  ev.emit('labels.association', {
693
- type: action.labelAssociationAction.labeled
694
- ? 'add'
695
- : 'remove',
696
- association: type === LabelAssociation_1.LabelAssociationType.Chat
783
+ type: action.labelAssociationAction.labeled ? 'add' : 'remove',
784
+ association: type === LabelAssociationType.Chat
697
785
  ? {
698
- type: LabelAssociation_1.LabelAssociationType.Chat,
786
+ type: LabelAssociationType.Chat,
699
787
  chatId: syncAction.index[2],
700
788
  labelId: syncAction.index[1]
701
789
  }
702
790
  : {
703
- type: LabelAssociation_1.LabelAssociationType.Message,
791
+ type: LabelAssociationType.Message,
704
792
  chatId: syncAction.index[2],
705
793
  messageId: syncAction.index[3],
706
794
  labelId: syncAction.index[1]
707
795
  }
708
796
  });
709
797
  }
798
+ else if (action?.localeSetting?.locale) {
799
+ ev.emit('settings.update', { setting: 'locale', value: action.localeSetting.locale });
800
+ }
801
+ else if (action?.timeFormatAction) {
802
+ ev.emit('settings.update', { setting: 'timeFormat', value: action.timeFormatAction });
803
+ }
804
+ else if (action?.pnForLidChatAction) {
805
+ if (action.pnForLidChatAction.pnJid) {
806
+ ev.emit('lid-mapping.update', { lid: id, pn: action.pnForLidChatAction.pnJid });
807
+ }
808
+ }
809
+ else if (action?.privacySettingRelayAllCalls) {
810
+ ev.emit('settings.update', {
811
+ setting: 'privacySettingRelayAllCalls',
812
+ value: action.privacySettingRelayAllCalls
813
+ });
814
+ }
815
+ else if (action?.statusPrivacy) {
816
+ ev.emit('settings.update', { setting: 'statusPrivacy', value: action.statusPrivacy });
817
+ }
818
+ else if (action?.lockChatAction) {
819
+ ev.emit('chats.lock', { id: id, locked: !!action.lockChatAction.locked });
820
+ }
821
+ else if (action?.privacySettingDisableLinkPreviewsAction) {
822
+ ev.emit('settings.update', {
823
+ setting: 'disableLinkPreviews',
824
+ value: action.privacySettingDisableLinkPreviewsAction
825
+ });
826
+ }
827
+ else if (action?.notificationActivitySettingAction?.notificationActivitySetting) {
828
+ ev.emit('settings.update', {
829
+ setting: 'notificationActivitySetting',
830
+ value: action.notificationActivitySettingAction.notificationActivitySetting
831
+ });
832
+ }
833
+ else if (action?.lidContactAction) {
834
+ ev.emit('contacts.upsert', [
835
+ {
836
+ id: id,
837
+ name: action.lidContactAction.fullName ||
838
+ action.lidContactAction.firstName ||
839
+ action.lidContactAction.username ||
840
+ undefined,
841
+ username: action.lidContactAction.username || undefined,
842
+ lid: id,
843
+ phoneNumber: undefined
844
+ }
845
+ ]);
846
+ }
847
+ else if (action?.privacySettingChannelsPersonalisedRecommendationAction) {
848
+ ev.emit('settings.update', {
849
+ setting: 'channelsPersonalisedRecommendation',
850
+ value: action.privacySettingChannelsPersonalisedRecommendationAction
851
+ });
852
+ }
710
853
  else {
711
- logger === null || logger === void 0 ? void 0 : logger.debug({ syncAction, id }, 'unprocessable update');
854
+ logger?.debug({ syncAction, id }, 'unprocessable update');
712
855
  }
713
856
  function getChatUpdateConditional(id, msgRange) {
714
857
  return isInitialSync
715
- ? (data) => {
858
+ ? data => {
716
859
  const chat = data.historySets.chats[id] || data.chatUpserts[id];
717
860
  if (chat) {
718
861
  return msgRange ? isValidPatchBasedOnMessageRange(chat, msgRange) : true;
@@ -721,9 +864,9 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
721
864
  : undefined;
722
865
  }
723
866
  function isValidPatchBasedOnMessageRange(chat, msgRange) {
724
- const lastMsgTimestamp = Number((msgRange === null || msgRange === void 0 ? void 0 : msgRange.lastMessageTimestamp) || (msgRange === null || msgRange === void 0 ? void 0 : msgRange.lastSystemMessageTimestamp) || 0);
725
- const chatLastMsgTimestamp = Number((chat === null || chat === void 0 ? void 0 : chat.lastMessageRecvTimestamp) || 0);
867
+ const lastMsgTimestamp = Number(msgRange?.lastMessageTimestamp || msgRange?.lastSystemMessageTimestamp || 0);
868
+ const chatLastMsgTimestamp = Number(chat?.lastMessageRecvTimestamp || 0);
726
869
  return lastMsgTimestamp >= chatLastMsgTimestamp;
727
870
  }
728
871
  };
729
- exports.processSyncAction = processSyncAction;
872
+ //# sourceMappingURL=chat-utils.js.map