@badzz88/baileys 8.5.4 → 8.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +1 -1
  2. package/WAProto/WAProto.proto +75 -1256
  3. package/WAProto/index.d.ts +19729 -36122
  4. package/WAProto/index.js +132193 -178538
  5. package/engine-requirements.js +15 -7
  6. package/lib/Defaults/index.js +14 -22
  7. package/lib/Signal/Group/group_cipher.js +5 -5
  8. package/lib/Signal/Group/keyhelper.js +4 -4
  9. package/lib/Signal/Group/sender-chain-key.js +2 -2
  10. package/lib/Signal/Group/sender-key-distribution-message.js +1 -1
  11. package/lib/Signal/Group/sender-key-message.js +3 -3
  12. package/lib/Signal/Group/sender-key-record.js +1 -1
  13. package/lib/Signal/Group/sender-message-key.js +5 -5
  14. package/lib/Signal/libsignal.js +28 -39
  15. package/lib/Signal/lid-mapping.js +8 -28
  16. package/lib/Socket/aigroups.js +5 -5
  17. package/lib/Socket/business.js +11 -3
  18. package/lib/Socket/chats.js +319 -668
  19. package/lib/Socket/communities.js +89 -85
  20. package/lib/Socket/graphql.js +228 -435
  21. package/lib/Socket/groups.js +211 -132
  22. package/lib/Socket/index.js +7 -9
  23. package/lib/Socket/interactive-handler.js +60 -117
  24. package/lib/Socket/interop.js +175 -56
  25. package/lib/Socket/luxu.js +387 -0
  26. package/lib/Socket/managed-account.js +48 -79
  27. package/lib/Socket/messages-recv.js +340 -898
  28. package/lib/Socket/messages-send.js +160 -462
  29. package/lib/Socket/mex.js +53 -40
  30. package/lib/Socket/newsletter.js +295 -291
  31. package/lib/Socket/privacy.js +265 -77
  32. package/lib/Socket/registration.js +157 -164
  33. package/lib/Socket/socket.js +199 -181
  34. package/lib/Socket/text-router.js +83 -0
  35. package/lib/Socket/username.js +227 -144
  36. package/lib/Store/keyed-db.js +108 -0
  37. package/lib/Store/make-cache-manager-store.js +2 -2
  38. package/lib/Store/make-in-memory-store.js +141 -25
  39. package/lib/Types/Auth.js +3 -3
  40. package/lib/Types/Label.js +1 -1
  41. package/lib/Types/LabelAssociation.js +1 -1
  42. package/lib/Types/Mex.js +112 -0
  43. package/lib/Types/Newsletter.js +65 -96
  44. package/lib/Types/State.js +4 -4
  45. package/lib/Types/index.js +1 -1
  46. package/lib/Utils/auth-utils.js +57 -52
  47. package/lib/Utils/browser-utils.js +1 -1
  48. package/lib/Utils/business.js +6 -2
  49. package/lib/Utils/chat-utils.js +38 -102
  50. package/lib/Utils/command-loader.d.ts +31 -0
  51. package/lib/Utils/command-loader.js +100 -0
  52. package/lib/Utils/companion-reg-client-utils.js +42 -0
  53. package/lib/Utils/crypto.js +84 -54
  54. package/lib/Utils/curve25519-js.js +275 -0
  55. package/lib/Utils/decode-wa-message.js +83 -316
  56. package/lib/Utils/event-buffer.js +61 -37
  57. package/lib/Utils/generics.js +103 -157
  58. package/lib/Utils/group-history.js +12 -3
  59. package/lib/Utils/history.js +15 -15
  60. package/lib/Utils/index.js +5 -1
  61. package/lib/Utils/link-preview.js +8 -3
  62. package/lib/Utils/lt-hash.js +35 -2
  63. package/lib/Utils/make-mutex.js +1 -1
  64. package/lib/Utils/message-retry-manager.js +92 -27
  65. package/lib/Utils/messages-media.js +130 -159
  66. package/lib/Utils/messages.js +566 -144
  67. package/lib/Utils/meta-ai-msmsg.js +202 -62
  68. package/lib/Utils/native-bridge.js +82 -0
  69. package/lib/Utils/noise-handler.js +21 -19
  70. package/lib/Utils/offline-node-processor.js +8 -3
  71. package/lib/Utils/pre-key-manager.js +23 -13
  72. package/lib/Utils/process-message.js +106 -197
  73. package/lib/Utils/reporting-utils.js +2 -2
  74. package/lib/Utils/session-pool.d.ts +16 -0
  75. package/lib/Utils/session-pool.js +94 -0
  76. package/lib/Utils/signal.js +63 -28
  77. package/lib/Utils/stanza-ack.js +12 -39
  78. package/lib/Utils/sticker.d.ts +17 -0
  79. package/lib/Utils/sticker.js +145 -0
  80. package/lib/Utils/sync-action-utils.js +7 -4
  81. package/lib/Utils/tc-token-utils.js +25 -20
  82. package/lib/Utils/use-multi-file-auth-state.js +14 -30
  83. package/lib/Utils/validate-connection.js +19 -59
  84. package/lib/Utils/view-once-cache.d.ts +9 -0
  85. package/lib/Utils/view-once-cache.js +79 -0
  86. package/lib/WABinary/decode.js +16 -50
  87. package/lib/WABinary/encode.js +224 -54
  88. package/lib/WABinary/generic-utils.js +97 -7
  89. package/lib/WABinary/jid-utils.js +14 -27
  90. package/lib/WAM/encode.js +7 -7
  91. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +1 -58
  92. package/lib/WAUSync/Protocols/USyncContactProtocol.js +1 -7
  93. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +5 -13
  94. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +4 -1
  95. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +7 -20
  96. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +1 -1
  97. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +2 -2
  98. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -7
  99. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +1 -1
  100. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +1 -2
  101. package/lib/WAUSync/Protocols/index.js +0 -1
  102. package/lib/WAUSync/USyncQuery.js +6 -77
  103. package/lib/WAUSync/USyncUser.js +8 -16
  104. package/lib/WAUSync/index.js +0 -1
  105. package/lib/antiban.js +854 -608
  106. package/lib/index.js +1 -1
  107. package/package.json +20 -16
@@ -1,10 +1,18 @@
1
- const major = parseInt(process.versions.node.split('.')[0], 10);
1
+ const major = parseInt(process.versions.node.split(".")[0], 10);
2
2
 
3
3
  if (major < 20) {
4
- console.error(
5
- `\n❌ This package requires Node.js 20+ to run reliably.\n` +
6
- ` You are using Node.js ${process.versions.node}.\n` +
7
- ` Please upgrade to Node.js 20+ to proceed.\n`
8
- );
4
+ console.error(`
5
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━
6
+ 🚫 Unsupported Node.js Version
7
+
8
+ • Current : v${process.versions.node}
9
+ • Required : v20.0.0+
10
+
11
+ This package uses features available only in
12
+ Node.js 20 or newer.
13
+
14
+ Please update Node.js and try again.
15
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ `);
9
17
  process.exit(1);
10
- }
18
+ }
@@ -26,8 +26,6 @@ exports.VERSION =
26
26
  exports.PLACEHOLDER_MAX_AGE_SECONDS =
27
27
  exports.STATUS_EXPIRY_SECONDS =
28
28
  exports.WA_DEFAULT_EPHEMERAL =
29
- exports.WA_ADV_HOSTED_KEY_INDEX_LIST_SIG_PREFIX =
30
- exports.WA_ADV_KEY_INDEX_LIST_SIG_PREFIX =
31
29
  exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX =
32
30
  exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX =
33
31
  exports.WA_ADV_DEVICE_SIG_PREFIX =
@@ -44,8 +42,7 @@ const index_js_1 = require('../../WAProto/index.js')
44
42
  const libsignal_1 = require('../Signal/libsignal')
45
43
  const browser_utils_1 = require('../Utils/browser-utils')
46
44
  const logger_1 = __importDefault(require('../Utils/logger'))
47
-
48
- const version = [2, 3000, 1044798975]
45
+ const version = [2, 3000, 1041467552]
49
46
  exports.VERSION = version
50
47
  exports.UNAUTHORIZED_CODES = [401, 403, 419]
51
48
  exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com'
@@ -58,19 +55,13 @@ exports.WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0])
58
55
  exports.WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1])
59
56
  exports.WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5])
60
57
  exports.WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6])
61
-
62
- exports.WA_ADV_KEY_INDEX_LIST_SIG_PREFIX = Buffer.from([6, 2])
63
- exports.WA_ADV_HOSTED_KEY_INDEX_LIST_SIG_PREFIX = Buffer.from([6, 7])
64
58
  exports.WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60
65
-
66
59
  exports.STATUS_EXPIRY_SECONDS = 24 * 60 * 60
67
-
68
60
  exports.PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60
69
61
  exports.NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0'
70
62
  exports.DICT_VERSION = 3
71
63
  exports.KEY_BUNDLE_TYPE = Buffer.from([5])
72
- exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION])
73
-
64
+ exports.NOISE_WA_HEADER = Buffer.from([87, 65, 6, exports.DICT_VERSION])
74
65
  exports.URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g
75
66
  exports.WA_CERT_DETAILS = {
76
67
  SERIAL: 0,
@@ -89,10 +80,11 @@ exports.PROCESSABLE_HISTORY_TYPES = [
89
80
  ]
90
81
  exports.DEFAULT_CONNECTION_CONFIG = {
91
82
  version: version,
92
- browser: browser_utils_1.Browsers.windows('Desktop'),
83
+ browser: browser_utils_1.Browsers.windows('Firefox'),
93
84
  waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
94
85
  connectTimeoutMs: 20000,
95
86
  keepAliveIntervalMs: 30000,
87
+ aiLabel: true,
96
88
  logger: logger_1.default.child({ class: 'baileys' }),
97
89
  emitOwnEvents: true,
98
90
  defaultQueryTimeoutMs: 60000,
@@ -173,17 +165,17 @@ exports.MEDIA_HKDF_KEY_MAPPING = {
173
165
  exports.MEDIA_KEYS = Object.keys(exports.MEDIA_PATH_MAP)
174
166
  exports.MIN_PREKEY_COUNT = 5
175
167
  exports.INITIAL_PREKEY_COUNT = 812
176
- exports.UPLOAD_TIMEOUT = 30000
177
- exports.MIN_UPLOAD_INTERVAL = 5000
168
+ exports.UPLOAD_TIMEOUT = 30000
169
+ exports.MIN_UPLOAD_INTERVAL = 5000
178
170
  exports.DEFAULT_CACHE_TTLS = {
179
- SIGNAL_STORE: 5 * 60,
180
- MSG_RETRY: 60 * 60,
181
- CALL_OFFER: 5 * 60,
182
- USER_DEVICES: 5 * 60,
183
- GROUP_METADATA: 30 * 60,
184
- CALL_SESSION: 10 * 60,
185
- USYNC_RESULTS: 10 * 60,
186
- IDENTITY_PROOF: 60 * 60
171
+ SIGNAL_STORE: 5 * 60,
172
+ MSG_RETRY: 60 * 60,
173
+ CALL_OFFER: 5 * 60,
174
+ USER_DEVICES: 5 * 60,
175
+ GROUP_METADATA: 30 * 60,
176
+ CALL_SESSION: 10 * 60,
177
+ USYNC_RESULTS: 10 * 60,
178
+ IDENTITY_PROOF: 60 * 60
187
179
  }
188
180
  exports.TimeMs = {
189
181
  Second: 1000,
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.GroupCipher = void 0
4
- const rb = require('whatsapp-rust-bridge')
4
+ const Crypto_1 = require('../../Utils/crypto')
5
5
  const sender_key_message_1 = require('./sender-key-message')
6
6
  class GroupCipher {
7
7
  constructor(senderKeyStore, senderKeyName) {
@@ -73,15 +73,15 @@ class GroupCipher {
73
73
  }
74
74
  async getPlainText(iv, key, ciphertext) {
75
75
  try {
76
- return Buffer.from(rb.aesDecryptWithIV(ciphertext, key, iv))
77
- } catch {
76
+ return Buffer.from(Crypto_1.aesDecryptWithIV(ciphertext, key, iv))
77
+ } catch (e) {
78
78
  throw new Error('InvalidMessageException')
79
79
  }
80
80
  }
81
81
  async getCipherText(iv, key, plaintext) {
82
82
  try {
83
- return Buffer.from(rb.aesEncrypWithIV(plaintext, key, iv))
84
- } catch {
83
+ return Buffer.from(Crypto_1.aesEncrypWithIV(plaintext, key, iv))
84
+ } catch (e) {
85
85
  throw new Error('InvalidMessageException')
86
86
  }
87
87
  }
@@ -55,7 +55,7 @@ exports.generateSenderKey = generateSenderKey
55
55
  exports.generateSenderKeyId = generateSenderKeyId
56
56
  exports.generateSenderSigningKey = generateSenderSigningKey
57
57
  const nodeCrypto = __importStar(require('crypto'))
58
- const rb = require('whatsapp-rust-bridge')
58
+ const Crypto_1 = require('../../Utils/crypto')
59
59
  function generateSenderKey() {
60
60
  return nodeCrypto.randomBytes(32)
61
61
  }
@@ -64,10 +64,10 @@ function generateSenderKeyId() {
64
64
  }
65
65
  function generateSenderSigningKey(key) {
66
66
  if (!key) {
67
- key = rb.generateKeyPair()
67
+ key = Crypto_1.Curve.generateKeyPair()
68
68
  }
69
69
  return {
70
- public: Buffer.from(key.pubKey),
71
- private: Buffer.from(key.privKey)
70
+ public: Crypto_1.generateSignalPubKey(key.public),
71
+ private: Buffer.from(key.private)
72
72
  }
73
73
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderChainKey = void 0
4
- const rb = require('whatsapp-rust-bridge')
4
+ const Crypto_1 = require('../../Utils/crypto')
5
5
  const sender_message_key_1 = require('./sender-message-key')
6
6
  class SenderChainKey {
7
7
  constructor(iteration, chainKey) {
@@ -26,7 +26,7 @@ class SenderChainKey {
26
26
  return this.chainKey
27
27
  }
28
28
  getDerivative(seed, key) {
29
- return Buffer.from(rb.hmacSign(seed, key))
29
+ return Buffer.from(Crypto_1.hmacSign(seed, key))
30
30
  }
31
31
  }
32
32
  exports.SenderChainKey = SenderChainKey
@@ -22,7 +22,7 @@ class SenderKeyDistributionMessage extends ciphertext_message_1.CiphertextMessag
22
22
  ? Buffer.from(distributionMessage.signingKey, 'base64')
23
23
  : distributionMessage.signingKey
24
24
  } catch (e) {
25
- throw e instanceof Error ? e : new Error(String(e))
25
+ throw new Error(String(e))
26
26
  }
27
27
  } else {
28
28
  const version = this.intsToByteHighAndLow(this.CURRENT_VERSION, this.CURRENT_VERSION)
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderKeyMessage = void 0
4
- const rb = require('whatsapp-rust-bridge')
4
+ const Crypto_1 = require('../../Utils/crypto')
5
5
  const index_js_1 = require('../../../WAProto/index.js')
6
6
  const ciphertext_message_1 = require('./ciphertext-message')
7
7
  class SenderKeyMessage extends ciphertext_message_1.CiphertextMessage {
@@ -53,11 +53,11 @@ class SenderKeyMessage extends ciphertext_message_1.CiphertextMessage {
53
53
  verifySignature(signatureKey) {
54
54
  const part1 = this.serialized.slice(0, this.serialized.length - this.SIGNATURE_LENGTH)
55
55
  const part2 = this.serialized.slice(-1 * this.SIGNATURE_LENGTH)
56
- const res = rb.verifySignature(signatureKey, part1, part2)
56
+ const res = Crypto_1.Curve.verify(signatureKey, part1, part2)
57
57
  if (!res) throw new Error('Invalid signature!')
58
58
  }
59
59
  getSignature(signatureKey, serialized) {
60
- return Buffer.from(rb.calculateSignature(signatureKey, serialized))
60
+ return Buffer.from(Crypto_1.Curve.sign(signatureKey, serialized))
61
61
  }
62
62
  serialize() {
63
63
  return this.serialized
@@ -36,7 +36,7 @@ class SenderKeyRecord {
36
36
  return this.senderKeyStates.map(state => state.getStructure())
37
37
  }
38
38
  static deserialize(data) {
39
- const str = Buffer.from(data).toString('utf8')
39
+ const str = Buffer.from(data).toString('utf-8')
40
40
  const parsed = JSON.parse(str, generics_1.BufferJSON.reviver)
41
41
  return new SenderKeyRecord(parsed)
42
42
  }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
  Object.defineProperty(exports, '__esModule', { value: true })
3
3
  exports.SenderMessageKey = void 0
4
- const rb = require('whatsapp-rust-bridge')
4
+ const Crypto_1 = require('../../Utils/crypto')
5
5
  class SenderMessageKey {
6
6
  constructor(iteration, seed) {
7
-
8
- const derived = Buffer.from(rb.hkdf(seed, 96, { salt: Buffer.alloc(32), info: 'WhisperGroup' }))
7
+ // HKDF(seed, 96, salt=0x00*32, info='WhisperGroup') → split into 3×32 byte chunks
8
+ const derived = Buffer.from(Crypto_1.hkdf(seed, 96, { salt: Buffer.alloc(32), info: 'WhisperGroup' }))
9
9
  const keys = new Uint8Array(32)
10
- keys.set(new Uint8Array(derived.slice(16, 32)))
11
- keys.set(new Uint8Array(derived.slice(32, 48)), 16)
10
+ keys.set(new Uint8Array(derived.slice(16, 32))) // bytes 16-31 of chunk 0
11
+ keys.set(new Uint8Array(derived.slice(32, 48)), 16) // bytes 0-15 of chunk 1
12
12
  this.iv = Buffer.from(derived.slice(0, 16))
13
13
  this.cipherKey = Buffer.from(keys.buffer)
14
14
  this.iteration = iteration
@@ -52,7 +52,7 @@ var __importStar =
52
52
  })()
53
53
  Object.defineProperty(exports, '__esModule', { value: true })
54
54
  exports.makeLibSignalRepository = makeLibSignalRepository
55
- const rb = require('whatsapp-rust-bridge')
55
+ const rb = require('../Utils/native-bridge').loadRustBridge()
56
56
  const lru_cache_1 = require('lru-cache')
57
57
  const Utils_1 = require('../Utils')
58
58
  const WABinary_1 = require('../WABinary')
@@ -60,18 +60,15 @@ const sender_key_name_1 = require('./Group/sender-key-name')
60
60
  const sender_key_record_1 = require('./Group/sender-key-record')
61
61
  const Group_1 = require('./Group')
62
62
  const lid_mapping_1 = require('./lid-mapping')
63
-
64
63
  function extractIdentityFromPkmsg(ciphertext) {
65
64
  try {
66
65
  if (!ciphertext || ciphertext.length < 2) {
67
66
  return undefined
68
67
  }
69
-
70
68
  const version = ciphertext[0]
71
69
  if ((version & 0xf) !== 3) {
72
70
  return undefined
73
71
  }
74
-
75
72
  const identityKeyArr = rb.getPreKeyMessageIdentityKey(ciphertext)
76
73
  if (identityKeyArr) {
77
74
  return identityKeyArr
@@ -82,11 +79,17 @@ function extractIdentityFromPkmsg(ciphertext) {
82
79
  }
83
80
  }
84
81
  function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
82
+ if (!rb) {
83
+ throw new Error(
84
+ 'The Signal session (Double Ratchet encryption) requires the "whatsapp-rust-bridge" native ' +
85
+ 'module, which failed to load. Make sure it is installed: npm install whatsapp-rust-bridge@0.5.4'
86
+ )
87
+ }
85
88
  const lidMapping = new lid_mapping_1.LIDMappingStore(auth.keys, logger, pnToLIDFunc)
86
89
  const storage = signalStorage(auth, lidMapping)
87
90
  const parsedKeys = auth.keys
88
91
  const migratedSessionCache = new lru_cache_1.LRUCache({
89
- ttl: 3 * 24 * 60 * 60 * 1000,
92
+ ttl: 3 * 24 * 60 * 60 * 1000,
90
93
  ttlAutopurge: true,
91
94
  updateAgeOnGet: true
92
95
  })
@@ -94,7 +97,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
94
97
  decryptGroupMessage({ group, authorJid, msg }) {
95
98
  const senderName = jidToSignalSenderKeyName(group, authorJid)
96
99
  const cipher = new Group_1.GroupCipher(storage, senderName)
97
-
98
100
  return parsedKeys.transaction(async () => {
99
101
  return cipher.decrypt(msg)
100
102
  }, group)
@@ -128,7 +130,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
128
130
  async decryptMessage({ jid, type, ciphertext }) {
129
131
  const addr = jidToSignalProtocolAddress(jid)
130
132
  const session = new rb.SessionCipher(storage, addr)
131
-
132
133
  if (type === 'pkmsg') {
133
134
  const identityKey = extractIdentityFromPkmsg(ciphertext)
134
135
  if (identityKey) {
@@ -151,8 +152,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
151
152
  }
152
153
  return result
153
154
  }
154
-
155
-
156
155
  return parsedKeys.transaction(async () => {
157
156
  return await doDecrypt()
158
157
  }, jid)
@@ -160,7 +159,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
160
159
  async encryptMessage({ jid, data }) {
161
160
  const addr = jidToSignalProtocolAddress(jid)
162
161
  const cipher = new rb.SessionCipher(storage, addr)
163
-
164
162
  return parsedKeys.transaction(async () => {
165
163
  const { type: sigType, body } = await cipher.encrypt(data)
166
164
  const type = sigType === 3 ? 'pkmsg' : 'msg'
@@ -192,10 +190,24 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
192
190
  await cipher.initOutgoing(session)
193
191
  }, jid)
194
192
  },
193
+ async getSessionInfo(jid) {
194
+ try {
195
+ const addr = jidToSignalProtocolAddress(jid)
196
+ const sessBytes = await storage.loadSession(addr.toString())
197
+ if (!sessBytes) return null
198
+ const session = rb.SessionRecord.deserialize(sessBytes)
199
+ const open = session.getOpenSession?.()
200
+ const baseKey = open?.indexInfo?.baseKey
201
+ const registrationId = open?.registrationId
202
+ if (!baseKey || typeof registrationId !== 'number') return null
203
+ return { baseKey: new Uint8Array(baseKey), registrationId }
204
+ } catch (error) {
205
+ return null
206
+ }
207
+ },
195
208
  jidToSignalProtocolAddress(jid) {
196
209
  return jidToSignalProtocolAddress(jid).toString()
197
210
  },
198
-
199
211
  lidMapping,
200
212
  async validateSession(jid) {
201
213
  try {
@@ -211,28 +223,23 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
211
223
  },
212
224
  async deleteSession(jids) {
213
225
  if (!jids.length) return
214
-
215
226
  const sessionUpdates = {}
216
227
  jids.forEach(jid => {
217
228
  const addr = jidToSignalProtocolAddress(jid)
218
229
  sessionUpdates[addr.toString()] = null
219
230
  })
220
-
221
231
  return parsedKeys.transaction(async () => {
222
232
  await auth.keys.set({ session: sessionUpdates })
223
233
  }, `delete-${jids.length}-sessions`)
224
234
  },
225
235
  async migrateSession(fromJid, toJid) {
226
-
227
236
  if (!fromJid || (!(0, WABinary_1.isLidUser)(toJid) && !(0, WABinary_1.isHostedLidUser)(toJid)))
228
237
  return { migrated: 0, skipped: 0, total: 0 }
229
-
230
238
  if (!(0, WABinary_1.isPnUser)(fromJid) && !(0, WABinary_1.isHostedPnUser)(fromJid)) {
231
239
  return { migrated: 0, skipped: 0, total: 1 }
232
240
  }
233
241
  const { user } = (0, WABinary_1.jidDecode)(fromJid)
234
242
  logger.debug({ fromJid }, 'bulk device migration - loading all user devices')
235
-
236
243
  const { [user]: userDevices } = await parsedKeys.get('device-list', [user])
237
244
  if (!userDevices) {
238
245
  return { migrated: 0, skipped: 0, total: 0 }
@@ -242,22 +249,18 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
242
249
  if (!userDevices.includes(fromDeviceStr)) {
243
250
  userDevices.push(fromDeviceStr)
244
251
  }
245
-
246
252
  const uncachedDevices = userDevices.filter(device => {
247
253
  const deviceKey = `${user}.${device}`
248
254
  return !migratedSessionCache.has(deviceKey)
249
255
  })
250
-
251
256
  const deviceSessionKeys = uncachedDevices.map(device => `${user}.${device}`)
252
257
  const existingSessions = await parsedKeys.get('session', deviceSessionKeys)
253
-
254
258
  const deviceJids = []
255
259
  for (const [sessionKey, sessionData] of Object.entries(existingSessions)) {
256
260
  if (sessionData) {
257
-
258
261
  const deviceStr = sessionKey.split('.')[1]
259
262
  if (!deviceStr) continue
260
- const deviceNum = parseInt(deviceStr, 10)
263
+ const deviceNum = parseInt(deviceStr)
261
264
  let jid = deviceNum === 0 ? `${user}@s.whatsapp.net` : `${user}:${deviceNum}@s.whatsapp.net`
262
265
  if (deviceNum === 99) {
263
266
  jid = `${user}:99@hosted`
@@ -274,7 +277,6 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
274
277
  },
275
278
  'bulk device migration complete - all user devices processed'
276
279
  )
277
-
278
280
  return parsedKeys.transaction(
279
281
  async () => {
280
282
  const migrationOps = deviceJids.map(jid => {
@@ -293,31 +295,25 @@ function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
293
295
  })
294
296
  const totalOps = migrationOps.length
295
297
  let migratedCount = 0
296
-
297
298
  const pnAddrStrings = Array.from(new Set(migrationOps.map(op => op.fromAddr.toString())))
298
299
  const pnSessions = await parsedKeys.get('session', pnAddrStrings)
299
-
300
300
  const sessionUpdates = {}
301
301
  for (const op of migrationOps) {
302
302
  const pnAddrStr = op.fromAddr.toString()
303
303
  const lidAddrStr = op.toAddr.toString()
304
304
  const pnSession = pnSessions[pnAddrStr]
305
305
  if (pnSession) {
306
-
307
306
  const fromSession = rb.SessionRecord.deserialize(pnSession)
308
307
  if (fromSession.haveOpenSession()) {
309
-
310
308
  sessionUpdates[lidAddrStr] = fromSession.serialize()
311
309
  sessionUpdates[pnAddrStr] = null
312
310
  migratedCount++
313
311
  }
314
312
  }
315
313
  }
316
-
317
314
  if (Object.keys(sessionUpdates).length > 0) {
318
315
  await parsedKeys.set({ session: sessionUpdates })
319
316
  logger.debug({ migratedSessions: migratedCount }, 'bulk session migration complete')
320
-
321
317
  for (const op of migrationOps) {
322
318
  if (sessionUpdates[op.toAddr.toString()]) {
323
319
  const deviceKey = `${op.pnUser}.${op.deviceId}`
@@ -353,12 +349,11 @@ const jidToSignalSenderKeyName = (group, user) => {
353
349
  return new sender_key_name_1.SenderKeyName(group, jidToSignalProtocolAddress(user))
354
350
  }
355
351
  function signalStorage({ creds, keys }, lidMapping) {
356
-
357
352
  const resolveLIDSignalAddress = async id => {
358
353
  if (id.includes('.')) {
359
354
  const [deviceId, device] = id.split('.')
360
355
  const [user, domainType_] = deviceId.split('_')
361
- const domainType = parseInt(domainType_ || '0', 10)
356
+ const domainType = parseInt(domainType_ || '0')
362
357
  if (
363
358
  domainType === WABinary_1.WAJIDDomains.LID ||
364
359
  domainType === WABinary_1.WAJIDDomains.HOSTED_LID ||
@@ -382,22 +377,19 @@ function signalStorage({ creds, keys }, lidMapping) {
382
377
  const fetched = await keys.get('session', keysToFetch)
383
378
  const sess = fetched[wireJid] || fetched[id]
384
379
  if (!sess) return null
385
-
386
380
  if (typeof sess === 'object' && !Buffer.isBuffer(sess) && !ArrayBuffer.isView(sess) && sess._sessions) {
387
381
  return null
388
382
  }
389
-
390
383
  return Buffer.isBuffer(sess) ? sess : Buffer.from(sess)
391
- } catch {
384
+ } catch (e) {
392
385
  return null
393
386
  }
394
387
  },
395
388
  storeSession: async (id, session) => {
396
-
397
389
  await keys.set({ session: { [id]: session.serialize() } })
398
390
  },
399
391
  isTrustedIdentity: () => {
400
- return true
392
+ return true
401
393
  },
402
394
  loadIdentityKey: async id => {
403
395
  const wireJid = await resolveLIDSignalAddress(id)
@@ -412,7 +404,6 @@ function signalStorage({ creds, keys }, lidMapping) {
412
404
  existingKey.length === identityKey.length &&
413
405
  existingKey.every((byte, i) => byte === identityKey[i])
414
406
  if (existingKey && !keysMatch) {
415
-
416
407
  await keys.set({
417
408
  session: { [wireJid]: null },
418
409
  'identity-key': { [wireJid]: identityKey }
@@ -420,7 +411,6 @@ function signalStorage({ creds, keys }, lidMapping) {
420
411
  return true
421
412
  }
422
413
  if (!existingKey) {
423
-
424
414
  await keys.set({ 'identity-key': { [wireJid]: identityKey } })
425
415
  return true
426
416
  }
@@ -441,8 +431,7 @@ function signalStorage({ creds, keys }, lidMapping) {
441
431
  const key = creds.signedPreKey
442
432
  return {
443
433
  privKey: Buffer.from(key.keyPair.private),
444
- pubKey: Buffer.from(key.keyPair.public),
445
- signature: key.signature ? Buffer.from(key.signature) : undefined
434
+ pubKey: Buffer.from(key.keyPair.public)
446
435
  }
447
436
  },
448
437
  loadSenderKey: async senderKeyName => {
@@ -6,7 +6,7 @@ const WABinary_1 = require('../WABinary')
6
6
  class LIDMappingStore {
7
7
  constructor(keys, logger, pnToLIDFunc) {
8
8
  this.mappingCache = new lru_cache_1.LRUCache({
9
- ttl: 3 * 24 * 60 * 60 * 1000,
9
+ ttl: 3 * 24 * 60 * 60 * 1000,
10
10
  ttlAutopurge: true,
11
11
  updateAgeOnGet: true
12
12
  })
@@ -20,10 +20,12 @@ class LIDMappingStore {
20
20
  if (pairs.length === 0) return
21
21
  const validatedPairs = []
22
22
  for (const { lid, pn } of pairs) {
23
- if (!(
24
- ((0, WABinary_1.isLidUser)(lid) && (0, WABinary_1.isPnUser)(pn)) ||
25
- ((0, WABinary_1.isPnUser)(lid) && (0, WABinary_1.isLidUser)(pn))
26
- )) {
23
+ if (
24
+ !(
25
+ ((0, WABinary_1.isLidUser)(lid) && (0, WABinary_1.isPnUser)(pn)) ||
26
+ ((0, WABinary_1.isPnUser)(lid) && (0, WABinary_1.isLidUser)(pn))
27
+ )
28
+ ) {
27
29
  this.logger.warn(`Invalid LID-PN mapping: ${lid}, ${pn}`)
28
30
  continue
29
31
  }
@@ -75,7 +77,6 @@ class LIDMappingStore {
75
77
  await this.keys.transaction(async () => {
76
78
  await this.keys.set({ 'lid-mapping': batchData })
77
79
  }, 'lid-mapping')
78
-
79
80
  for (const [pnUser, lidUser] of Object.entries(pairMap)) {
80
81
  this.mappingCache.set(`pn:${pnUser}`, lidUser)
81
82
  this.mappingCache.set(`lid:${lidUser}`, pnUser)
@@ -84,26 +85,6 @@ class LIDMappingStore {
84
85
  async getLIDForPN(pn) {
85
86
  return (await this.getLIDsForPNs([pn]))?.[0]?.lid || null
86
87
  }
87
-
88
-
89
- async getStoredLIDForPN(pn) {
90
- if (!(0, WABinary_1.isPnUser)(pn) && !(0, WABinary_1.isHostedPnUser)(pn)) return null
91
- const decoded = (0, WABinary_1.jidDecode)(pn)
92
- if (!decoded) return null
93
- const pnUser = decoded.user
94
- let lidUser = this.mappingCache.get(`pn:${pnUser}`)
95
- if (!lidUser || typeof lidUser !== 'string') {
96
- const stored = await this.keys.get('lid-mapping', [pnUser])
97
- lidUser = stored[pnUser]
98
- if (lidUser && typeof lidUser === 'string') {
99
- this.mappingCache.set(`pn:${pnUser}`, lidUser)
100
- this.mappingCache.set(`lid:${lidUser}`, pnUser)
101
- }
102
- }
103
- if (!lidUser || typeof lidUser !== 'string') return null
104
- const pnDevice = decoded.device !== undefined ? decoded.device : 0
105
- return `${lidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
106
- }
107
88
  async getLIDsForPNs(pns) {
108
89
  if (pns.length === 0) return null
109
90
  const sortedPns = [...new Set(pns)].sort()
@@ -131,7 +112,6 @@ class LIDMappingStore {
131
112
  this.logger.warn(`Invalid or empty LID user for PN ${pn}: lidUser = "${lidUser}"`)
132
113
  return false
133
114
  }
134
-
135
115
  const pnDevice = decoded.device !== undefined ? decoded.device : 0
136
116
  const deviceSpecificLid = `${normalizedLidUser}${!!pnDevice ? `:${pnDevice}` : ``}@${decoded.server === 'hosted' ? 'hosted.lid' : 'lid'}`
137
117
  this.logger.trace(`getLIDForPN: ${pn} → ${deviceSpecificLid} (user mapping with device ${pnDevice})`)
@@ -186,7 +166,7 @@ class LIDMappingStore {
186
166
  }
187
167
  }
188
168
  if (Object.keys(usyncFetch).length > 0) {
189
- const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch))
169
+ const result = await this.pnToLIDFunc?.(Object.keys(usyncFetch))
190
170
  if (result && result.length > 0) {
191
171
  await this.storeLIDPNMappings(result)
192
172
  for (const pair of result) {
@@ -10,7 +10,7 @@ const makeAIGroupsSocket = config => {
10
10
  const sock = (0, groups_1.makeGroupsSocket)(config)
11
11
  const { ev, query } = sock
12
12
 
13
-
13
+ /** Query helper for AI groups (w:gp2 namespace) */
14
14
  const aiGroupQuery = async (jid, type, content) =>
15
15
  query({
16
16
  tag: 'iq',
@@ -27,7 +27,7 @@ const makeAIGroupsSocket = config => {
27
27
  return (0, exports.extractAIGroupMetadata)(result)
28
28
  }
29
29
 
30
-
30
+ // Handle incoming w:gp2 notifications (create, promote, remove, add)
31
31
  sock.ws.on('CB:notification,w:gp2', async node => {
32
32
  const { attrs, content } = node
33
33
  if (!Array.isArray(content) || content.length === 0) return
@@ -44,12 +44,12 @@ const makeAIGroupsSocket = config => {
44
44
  if (!groupId) return
45
45
 
46
46
  if (tag === 'create') {
47
-
47
+ // New AI group created — emit groups.upsert
48
48
  try {
49
49
  const meta = await aiGroupMetadata(groupId)
50
50
  ev.emit('groups.upsert', [meta])
51
51
  } catch {
52
-
52
+ // metadata fetch may fail; emit minimal info
53
53
  ev.emit('groups.upsert', [{ id: groupId }])
54
54
  }
55
55
  } else if (tag === 'promote' || tag === 'demote' || tag === 'remove' || tag === 'add') {
@@ -189,7 +189,7 @@ const makeAIGroupsSocket = config => {
189
189
  exports.makeAIGroupsSocket = makeAIGroupsSocket
190
190
 
191
191
  const extractAIGroupMetadata = result => {
192
-
192
+ // IQ response nests group inside create node: result → create → group
193
193
  const createNode = (0, WABinary_1.getBinaryNodeChild)(result, 'create')
194
194
  const group =
195
195
  (0, WABinary_1.getBinaryNodeChild)(createNode || result, 'group') ||
@@ -268,7 +268,11 @@ const makeBusinessSocket = config => {
268
268
  })
269
269
  return (0, business_1.parseOrderDetailsNode)(result)
270
270
  }
271
-
271
+ /**
272
+ * Get linked Facebook/Instagram accounts (WhatsApp-as-a-page linking).
273
+ * Ported from WhatsApp Web's WASmaxBizLinkingGetLinkedAccountsRPC.
274
+ * @returns {Promise<{ pageInfo: object, linkState?: string, node: object } | undefined>}
275
+ */
272
276
  const getLinkedAccounts = async () => {
273
277
  const result = await query({
274
278
  tag: 'iq',
@@ -280,7 +284,11 @@ const makeBusinessSocket = config => {
280
284
  const button = (0, WABinary_1.getBinaryNodeChild)(fbPage, 'whatsapp_as_page_button')
281
285
  return { pageInfo: fbPage.attrs, linkState: button?.attrs?.state, node: fbPage }
282
286
  }
283
-
287
+ /**
288
+ * Get business eligibility for the given features (meta_verified / marketing_messages / genai).
289
+ * Ported from WhatsApp Web's WASmaxBizMarketingMessageGetBusinessEligibilityRPC.
290
+ * @param {{ metaVerified?: any, marketingMessages?: any, genai?: any }} [features]
291
+ */
284
292
  const getBusinessEligibility = async (features = {}) => {
285
293
  const attrs = {}
286
294
  if (features.metaVerified !== undefined) attrs.meta_verified = String(features.metaVerified)
@@ -329,7 +337,7 @@ const makeBusinessSocket = config => {
329
337
  return (0, business_1.parseProductNode)(productNode)
330
338
  }
331
339
  const productCreate = async create => {
332
-
340
+ // ensure isHidden is defined
333
341
  create.isHidden = !!create.isHidden
334
342
  create = await (0, business_1.uploadingNecessaryImagesOfProduct)(create, waUploadToServer)
335
343
  const createNode = (0, business_1.toProductNode)(undefined, create)