@nexustechpro/baileys 2.0.5 → 2.0.6

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.
package/WAProto/index.js CHANGED
@@ -12,14 +12,18 @@ function longToString(value, unsigned) {
12
12
  if (typeof value === "number") {
13
13
  return String(value);
14
14
  }
15
- if (!$util.Long) {
16
- return String(value);
15
+ // Fast path: convert Long {low, high} directly via native BigInt
16
+ // BigInt.toString() is a native C++ operation, much faster than Long's pure JS division loops
17
+ if (value && typeof value.low === "number" && typeof value.high === "number") {
18
+ const lo = BigInt(value.low >>> 0);
19
+ const hi = BigInt(value.high >>> 0);
20
+ const combined = (hi << 32n) | lo;
21
+ if (!unsigned && value.high < 0) {
22
+ return (combined - (1n << 64n)).toString();
23
+ }
24
+ return combined.toString();
17
25
  }
18
- const normalized = $util.Long.fromValue(value);
19
- const prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"
20
- ? normalized.toUnsigned()
21
- : normalized;
22
- return prepared.toString();
26
+ return String(value);
23
27
  }
24
28
 
25
29
  function longToNumber(value, unsigned) {
@@ -27,19 +31,19 @@ function longToNumber(value, unsigned) {
27
31
  return value;
28
32
  }
29
33
  if (typeof value === "string") {
30
- const numeric = Number(value);
31
- return numeric;
32
- }
33
- if (!$util.Long) {
34
34
  return Number(value);
35
35
  }
36
- const normalized = $util.Long.fromValue(value);
37
- const prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"
38
- ? normalized.toUnsigned()
39
- : typeof normalized.toSigned === "function"
40
- ? normalized.toSigned()
41
- : normalized;
42
- return prepared.toNumber();
36
+ // Fast path: convert Long {low, high} directly via native BigInt
37
+ if (value && typeof value.low === "number" && typeof value.high === "number") {
38
+ const lo = BigInt(value.low >>> 0);
39
+ const hi = BigInt(value.high >>> 0);
40
+ const combined = (hi << 32n) | lo;
41
+ if (!unsigned && value.high < 0) {
42
+ return Number(combined - (1n << 64n));
43
+ }
44
+ return Number(combined);
45
+ }
46
+ return Number(value);
43
47
  }
44
48
 
45
49
  export const proto = $root.proto = (() => {
@@ -2,6 +2,6 @@
2
2
  "version": [
3
3
  2,
4
4
  3000,
5
- 1036200034
5
+ 1040069233
6
6
  ]
7
7
  }
@@ -7,7 +7,7 @@ import logger from '../Utils/logger.js';
7
7
  const require = createRequire(import.meta.url);
8
8
  const PHONENUMBER_MCC = require('./phonenumber-mcc.json');
9
9
  export { PHONENUMBER_MCC };
10
- const version = [2, 3000, 1036200034];
10
+ const version = [2, 3000, 1040069233];
11
11
 
12
12
  export const UNAUTHORIZED_CODES = [401, 403, 419];
13
13
 
@@ -55,19 +55,20 @@ export const PROCESSABLE_HISTORY_TYPES = [
55
55
  ];
56
56
  export const MOBILE_ENDPOINT = 'g.whatsapp.net';
57
57
  export const MOBILE_PORT = 443;
58
-
59
- const WA_VERSION = '2.25.23.24';
60
- const WA_VERSION_HASH = createHash('md5').update(WA_VERSION).digest('hex');
61
-
58
+ export const WA_VERSION = '2.2413.51'
59
+ export const WA_VERSION_HASH = createHash('md5').update(WA_VERSION).digest('hex');
62
60
  export const MOBILE_TOKEN = Buffer.from('0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM' + WA_VERSION_HASH);
63
61
  export const MOBILE_REGISTRATION_ENDPOINT = 'https://v.whatsapp.net/v2';
64
62
  export const MOBILE_USERAGENT = `WhatsApp/${WA_VERSION} iOS/17.5.1 Device/Apple-iPhone_13`;
65
-
63
+ export const GRAPHQL_ENDPOINT = 'https://graph.whatsapp.com/graphql'
64
+ export const GRAPHQL_ACCESS_TOKEN = 'WA|1015890928915437|3201f239340c1c8ec6262a6dad04200e'
65
+ export const GRAPHQL_BAN_STATUS_DOC_ID = '25573756098908502'
66
66
  export const REGISTRATION_PUBLIC_KEY = Buffer.from([
67
67
  5, 142, 140, 15, 116, 195, 235, 197, 215, 166, 134, 92, 108, 60, 132, 56, 86, 176, 97, 33, 204, 232, 234, 119, 77,
68
68
  34, 251, 111, 18, 37, 18, 48, 45,
69
69
  ]);
70
70
 
71
+
71
72
  export const PROTOCOL_VERSION = [5, 2];
72
73
  export const MOBILE_NOISE_HEADER = Buffer.concat([Buffer.from('WA'), Buffer.from(PROTOCOL_VERSION)]);
73
74
 
@@ -25,7 +25,7 @@ const jidToAddr = (jid) => {
25
25
 
26
26
  const jidToSenderKeyName = (group, user) => new SenderKeyName(group, jidToAddr(user))
27
27
 
28
- const v2Key = (addr) => `${addr}:v2` // v2 slot holds the actual serialized SessionRecord bytes
28
+ const v2Key = (addr) => `${addr}:v2`
29
29
 
30
30
  // ─── Identity Extraction ──────────────────────────────────────────────────────
31
31
 
@@ -56,7 +56,6 @@ function extractIdentityFromPkmsg(ciphertext) {
56
56
 
57
57
  // ─── Buffer Utils ─────────────────────────────────────────────────────────────
58
58
 
59
- // universal deserializer — handles all shapes written by any previous version
60
59
  const toBuffer = (raw) => {
61
60
  if (!raw) return null
62
61
  if (raw instanceof Uint8Array) return raw
@@ -68,7 +67,6 @@ const toBuffer = (raw) => {
68
67
  return null
69
68
  }
70
69
 
71
- // detects old libsignal JS JSON format — not deserializable by whatsapp-rust-bridge
72
70
  const isOldJson = (raw) => {
73
71
  if (!raw || raw instanceof Uint8Array || Buffer.isBuffer(raw)) return false
74
72
  if (typeof raw === 'object') return 'version' in raw || '_sessions' in raw
@@ -97,6 +95,28 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
97
95
  return txn(() => new GroupSessionBuilder(storage).process(senderName, senderMsg), item.groupId)
98
96
  },
99
97
 
98
+ async encryptGroupMessage({ group, meId, data }) {
99
+ const senderName = jidToSenderKeyName(group, meId)
100
+ const skdm = await new GroupSessionBuilder(storage).create(senderName)
101
+ const plaintext = data instanceof Uint8Array && data.constructor === Uint8Array
102
+ ? data
103
+ : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
104
+ const ciphertext = await new GroupCipher(storage, group, jidToAddr(meId)).encrypt(plaintext)
105
+ return { ciphertext, senderKeyDistributionMessage: skdm.serialize() }
106
+ },
107
+
108
+ async getSenderKeyDistributionMessage({ group, meId }) {
109
+ const senderName = jidToSenderKeyName(group, meId)
110
+ const skdm = await new GroupSessionBuilder(storage).create(senderName)
111
+ return skdm.serialize()
112
+ },
113
+
114
+ async hasSenderKey({ group, meId }) {
115
+ const name = jidToSenderKeyName(group, meId).toString()
116
+ const { [name]: key } = await parsedKeys.get('sender-key', [name])
117
+ return !!toBuffer(key)
118
+ },
119
+
100
120
  async decryptMessage({ jid, type, ciphertext }) {
101
121
  const addr = jidToAddr(jid)
102
122
  const cipher = new SessionCipher(storage, addr)
@@ -107,15 +127,14 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
107
127
  if (changed) logger?.info?.({ jid }, '[Signal] Identity key changed, session cleared')
108
128
  }
109
129
  }
110
- const doDecrypt = (c, t) => {
111
- if (t === 'pkmsg') return c.decryptPreKeyWhisperMessage(ciphertext)
112
- if (t === 'msg') return c.decryptWhisperMessage(ciphertext)
113
- throw new Error(`Unknown type: ${t}`)
114
- }
115
130
  try {
116
- return await txn(() => doDecrypt(cipher, type), jid)
131
+ return await txn(() => {
132
+ if (type === 'pkmsg') return cipher.decryptPreKeyWhisperMessage(ciphertext)
133
+ if (type === 'msg') return cipher.decryptWhisperMessage(ciphertext)
134
+ throw new Error(`Unknown type: ${type}`)
135
+ }, jid)
117
136
  } catch (e) {
118
- if (e?.message?.includes('DuplicatedMessage')) { logger?.debug?.({ jid }, '[Signal] Duplicate message ignored — offline replay'); return null }
137
+ if (e?.message?.includes('DuplicatedMessage')) { logger?.debug?.({ jid }, '[Signal] Duplicate message ignored'); return null }
119
138
  throw e
120
139
  }
121
140
  },
@@ -127,14 +146,6 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
127
146
  }, jid)
128
147
  },
129
148
 
130
- encryptGroupMessage({ group, meId, data }) {
131
- return txn(async () => {
132
- const senderName = jidToSenderKeyName(group, meId)
133
- const senderKeyDistributionMessage = await new GroupSessionBuilder(storage).create(senderName)
134
- return { ciphertext: await new GroupCipher(storage, group, jidToAddr(meId)).encrypt(data), senderKeyDistributionMessage: senderKeyDistributionMessage.serialize() }
135
- }, group)
136
- },
137
-
138
149
  injectE2ESession({ jid, session }) {
139
150
  return txn(() => new SessionBuilder(storage, jidToAddr(jid)).processPreKeyBundle(session), jid)
140
151
  },
@@ -147,7 +158,7 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
147
158
  try {
148
159
  const addr = jidToAddr(jid).toString()
149
160
  const batch = await migrateIndexKey(parsedKeys, 'session')
150
- const raw = toBuffer(batch[v2Key(addr)]) || toBuffer(batch[addr]) // v2 slot first, fall back to plain
161
+ const raw = toBuffer(batch[v2Key(addr)]) || toBuffer(batch[addr])
151
162
  if (!raw || isOldJson(raw)) return { exists: false, reason: 'no session' }
152
163
  const sess = SessionRecord.deserialize(raw)
153
164
  if (!sess.haveOpenSession()) return { exists: false, reason: 'no open session' }
@@ -160,7 +171,7 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
160
171
  return txn(async () => {
161
172
  const batch = await migrateIndexKey(parsedKeys, 'session')
162
173
  for (const jid of jids) { const addr = jidToAddr(jid).toString(); delete batch[addr]; delete batch[v2Key(addr)] }
163
- await parsedKeys.set({ session: { 'index': batch } })
174
+ await parsedKeys.set({ session: { index: batch } })
164
175
  }, `del-${jids.length}`)
165
176
  },
166
177
 
@@ -185,55 +196,44 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
185
196
  for (const { jid } of deviceJids) {
186
197
  const pnAddr = jidToAddr(jid).toString()
187
198
  const lidAddr = jidToAddr(transferDevice(jid, toJid)).toString()
188
- const raw = toBuffer(updated[v2Key(pnAddr)]) || toBuffer(updated[pnAddr]) // prefer v2 slot
199
+ const raw = toBuffer(updated[v2Key(pnAddr)]) || toBuffer(updated[pnAddr])
189
200
  if (!raw || isOldJson(raw)) continue
190
201
  const sess = SessionRecord.deserialize(raw)
191
202
  if (!sess.haveOpenSession()) continue
192
203
  updated[v2Key(lidAddr)] = sess.serialize()
193
- updated[lidAddr] = { version: 'v1', _sessions: {} } // plain slot marker for compat
204
+ updated[lidAddr] = { version: 'v1', _sessions: {} }
194
205
  delete updated[v2Key(pnAddr)]
195
206
  delete updated[pnAddr]
196
207
  migrated++
197
208
  migratedCache.set(`${user}.${jidDecode(jid).device || 0}`, true)
198
209
  }
199
- if (migrated > 0) await parsedKeys.set({ session: { 'index': updated } })
210
+ if (migrated > 0) await parsedKeys.set({ session: { index: updated } })
200
211
  return { migrated, skipped: deviceJids.length - migrated, total: deviceJids.length }
201
212
  }, `migrate-${deviceJids.length}`)
202
213
  },
203
214
 
204
- // Batch-migrate all PN-addressed sessions to their LID equivalents.
205
- // Called once on CB:success before offline messages are processed — one read, one remap, one write.
206
215
  async migrateAllPNSessionsToLID() {
207
216
  return txn(async () => {
208
217
  const sessionBatch = await migrateIndexKey(parsedKeys, 'session')
209
218
  const sessionKeys = Object.keys(sessionBatch)
210
219
  if (!sessionKeys.length) return 0
211
-
212
- // collect plain (non-v2) PN-domain keys only — v2 slots are handled via their plain counterpart
213
220
  const pnAddrs = sessionKeys.filter(addr => {
214
- if (addr.endsWith(':v2')) return false
215
- if (!addr.includes('.')) return false
216
- const [deviceId] = addr.split('.')
217
- const [, dt] = deviceId.split('_')
221
+ if (addr.endsWith(':v2') || !addr.includes('.')) return false
222
+ const [, dt] = addr.split('.')[0].split('_')
218
223
  const domainType = parseInt(dt || '0')
219
224
  return domainType === WAJIDDomains.WHATSAPP || domainType === WAJIDDomains.HOSTED
220
225
  })
221
226
  if (!pnAddrs.length) return 0
222
-
223
- // batch-fetch LID mappings directly from key store — same format storeLIDPNMappings writes
224
227
  const pnUserSet = new Set(pnAddrs.map(addr => addr.split('.')[0].split('_')[0]))
225
228
  const stored = await parsedKeys.get('lid-mapping', [...pnUserSet])
226
-
227
229
  const pnToLidUserMap = new Map()
228
230
  for (const pnUser of pnUserSet) {
229
231
  const lidUser = stored[pnUser]
230
232
  if (lidUser && typeof lidUser === 'string') pnToLidUserMap.set(pnUser, lidUser)
231
233
  }
232
234
  if (!pnToLidUserMap.size) return 0
233
-
234
235
  let migrated = 0
235
236
  const updated = { ...sessionBatch }
236
-
237
237
  for (const addr of pnAddrs) {
238
238
  const [deviceId, device] = addr.split('.')
239
239
  const [user, dt] = deviceId.split('_')
@@ -242,25 +242,34 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
242
242
  if (!lidUser) continue
243
243
  const lidDomainType = domainType === WAJIDDomains.HOSTED ? WAJIDDomains.HOSTED_LID : WAJIDDomains.LID
244
244
  const lidAddr = `${lidUser}_${lidDomainType}.${device}`
245
- if (updated[v2Key(lidAddr)]) continue // LID session already exists, skip
246
- const raw = toBuffer(updated[v2Key(addr)]) || toBuffer(updated[addr]) // prefer v2 slot
245
+ if (updated[v2Key(lidAddr)]) continue
246
+ const raw = toBuffer(updated[v2Key(addr)]) || toBuffer(updated[addr])
247
247
  if (!raw || isOldJson(raw)) continue
248
248
  const sess = SessionRecord.deserialize(raw)
249
249
  if (!sess.haveOpenSession()) continue
250
250
  updated[v2Key(lidAddr)] = sess.serialize()
251
- updated[lidAddr] = { version: 'v1', _sessions: {} } // plain slot marker for compat
251
+ updated[lidAddr] = { version: 'v1', _sessions: {} }
252
252
  delete updated[v2Key(addr)]
253
253
  delete updated[addr]
254
254
  migrated++
255
255
  migratedCache.set(`${user}.${device}`, true)
256
256
  }
257
-
258
257
  if (migrated > 0) {
259
- await parsedKeys.set({ session: { 'index': updated } })
258
+ await parsedKeys.set({ session: { index: updated } })
260
259
  logger?.info?.({ migrated, totalPN: pnAddrs.length, mappingsFound: pnToLidUserMap.size }, '[Signal] Batch-migrated PN sessions to LID on connect')
261
260
  }
262
261
  return migrated
263
262
  }, 'migrate-all-pn-to-lid')
263
+ },
264
+
265
+ deleteSenderKey(group, authorJid) {
266
+ const senderName = jidToSenderKeyName(group, authorJid).toString()
267
+ return parsedKeys.set({ 'sender-key': { [senderName]: null } })
268
+ },
269
+
270
+ close() {
271
+ migratedCache.clear()
272
+ lidMapping.close?.()
264
273
  }
265
274
  }
266
275
  }
@@ -268,7 +277,7 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
268
277
  // ─── Storage Adapter ──────────────────────────────────────────────────────────
269
278
 
270
279
  function signalStorage({ creds, keys }, lidMapping, logger) {
271
- const lidCache = new LRUCache({ max: 500, ttl: 5 * 60 * 1000 }) // cache PN→LID resolutions for 5 min
280
+ const lidCache = new LRUCache({ max: 500, ttl: 5 * 60 * 1000 })
272
281
 
273
282
  const resolveLID = async (id) => {
274
283
  if (!id.includes('.')) return id
@@ -286,7 +295,7 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
286
295
  }
287
296
 
288
297
  const getIndex = () => migrateIndexKey(keys, 'session')
289
- const setIndex = (batch) => keys.set({ session: { 'index': batch } })
298
+ const setIndex = (batch) => keys.set({ session: { index: batch } })
290
299
 
291
300
  return {
292
301
  loadSession: async (id) => {
@@ -300,7 +309,7 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
300
309
  if (buf) return buf
301
310
  }
302
311
  const plain = batch[addr]
303
- if (!plain || isOldJson(plain)) { // old JS JSON format — not usable by rust bridge
312
+ if (!plain || isOldJson(plain)) {
304
313
  if (plain) logger?.debug?.(`[Signal] Old JSON session for ${addr}, will fresh handshake`)
305
314
  return null
306
315
  }
@@ -311,8 +320,8 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
311
320
  storeSession: async (id, session) => {
312
321
  const addr = await resolveLID(id)
313
322
  const batch = await getIndex()
314
- batch[v2Key(addr)] = session.serialize() // always write to v2 slot
315
- batch[addr] = { version: 'v1', _sessions: {} } // plain slot marker so old code sees something
323
+ batch[v2Key(addr)] = session.serialize()
324
+ batch[addr] = { version: 'v1', _sessions: {} }
316
325
  await setIndex(batch)
317
326
  },
318
327
 
@@ -352,7 +361,11 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
352
361
 
353
362
  loadSignedPreKey: () => {
354
363
  const { signedPreKey: key } = creds
355
- return { keyId: key.keyId, keyPair: { pubKey: new Uint8Array(Buffer.from(key.keyPair.public)), privKey: new Uint8Array(Buffer.from(key.keyPair.private)) }, signature: new Uint8Array(Buffer.from(key.signature)) }
364
+ return {
365
+ keyId: key.keyId,
366
+ keyPair: { pubKey: new Uint8Array(Buffer.from(key.keyPair.public)), privKey: new Uint8Array(Buffer.from(key.keyPair.private)) },
367
+ signature: new Uint8Array(Buffer.from(key.signature))
368
+ }
356
369
  },
357
370
 
358
371
  loadSenderKey: async (keyId) => {
@@ -365,15 +378,17 @@ function signalStorage({ creds, keys }, lidMapping, logger) {
365
378
 
366
379
  storeSenderKey: async (keyId, record) => {
367
380
  const id = keyId.toString()
368
- const bytes = record instanceof Uint8Array ? record : Buffer.isBuffer(record) ? record : record.serialize()
369
- await keys.set({ 'sender-key': { [id]: bytes } })
381
+ await keys.set({ 'sender-key': { [id]: Buffer.from(record) } })
370
382
  },
371
383
 
372
384
  getOurRegistrationId: () => creds.registrationId,
373
385
 
374
386
  getOurIdentity: () => {
375
387
  const { signedIdentityKey } = creds
376
- return { pubKey: new Uint8Array(generateSignalPubKey(Buffer.from(signedIdentityKey.public))), privKey: new Uint8Array(Buffer.from(signedIdentityKey.private)) }
388
+ return {
389
+ pubKey: new Uint8Array(generateSignalPubKey(Buffer.from(signedIdentityKey.public))),
390
+ privKey: new Uint8Array(Buffer.from(signedIdentityKey.private))
391
+ }
377
392
  }
378
393
  }
379
394
  }
@@ -1,7 +1,7 @@
1
1
  import NodeCache from '@cacheable/node-cache'
2
2
  import { Boom } from '@hapi/boom'
3
3
  import { proto } from '../../WAProto/index.js'
4
- import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js'
4
+ import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES, PHONENUMBER_MCC, MOBILE_TOKEN, MOBILE_USERAGENT, MOBILE_REGISTRATION_ENDPOINT } from '../Defaults/index.js'
5
5
  import { ALL_WA_PATCH_NAMES } from '../Types/index.js'
6
6
  import { SyncState } from '../Types/State.js'
7
7
  import {
@@ -25,7 +25,8 @@ import {
25
25
  jidDecode,
26
26
  jidNormalizedUser,
27
27
  reduceBinaryNodeToDictionary,
28
- S_WHATSAPP_NET
28
+ S_WHATSAPP_NET,
29
+ VIOLATION_TYPES
29
30
  } from '../WABinary/index.js'
30
31
  import { USyncQuery, USyncUser } from '../WAUSync/index.js'
31
32
  import { makeSocket } from './socket.js'
@@ -217,60 +218,6 @@ export const makeChatsSocket = (config) => {
217
218
  )
218
219
  }
219
220
 
220
- const checkStatusWA = async (phoneNumber) => {
221
- if (!phoneNumber) throw new Error('enter number')
222
-
223
- let resultData = { isBanned: false, isNeedOfficialWa: false, number: phoneNumber }
224
-
225
- let formattedNumber = phoneNumber.startsWith('+') ? phoneNumber : '+' + phoneNumber
226
-
227
- const { parsePhoneNumber } = await import('libphonenumber-js')
228
- const parsedNumber = parsePhoneNumber(formattedNumber)
229
- const countryCode = parsedNumber.countryCallingCode
230
- const nationalNumber = parsedNumber.nationalNumber
231
-
232
- try {
233
- const { useMultiFileAuthState, fetchLatestBaileysVersion, Browsers } = await import('../Utils/index.js')
234
- const { state } = await useMultiFileAuthState('.npm')
235
- const { version } = await fetchLatestBaileysVersion()
236
- const { makeWASocket } = await import('../Socket/index.js')
237
- const pino = (await import('pino')).default
238
-
239
- const tempSock = makeWASocket({
240
- version,
241
- auth: state,
242
- browser: Browsers.ubuntu('Chrome'),
243
- logger: pino({ level: 'silent' }),
244
- printQRInTerminal: false
245
- })
246
-
247
- await tempSock.requestRegistrationCode({
248
- phoneNumber: formattedNumber,
249
- phoneNumberCountryCode: countryCode,
250
- phoneNumberNationalNumber: nationalNumber,
251
- phoneNumberMobileCountryCode: '510',
252
- phoneNumberMobileNetworkCode: '10',
253
- method: 'sms'
254
- })
255
-
256
- if (tempSock.ws) tempSock.ws.close()
257
- return JSON.stringify(resultData, null, 2)
258
- } catch (err) {
259
- if (err?.appeal_token) {
260
- resultData.isBanned = true
261
- resultData.data = {
262
- violation_type: err.violation_type || null,
263
- in_app_ban_appeal: err.in_app_ban_appeal || null,
264
- appeal_token: err.appeal_token || null
265
- }
266
- } else if (err?.custom_block_screen || err?.reason === 'blocked') {
267
- resultData.isNeedOfficialWa = true
268
- }
269
- return JSON.stringify(resultData, null, 2)
270
- }
271
- }
272
-
273
-
274
221
  // ─── Profile ─────────────────────────────────────────────────────────────────
275
222
 
276
223
  const updateProfilePicture = async (jid, content) => {
@@ -906,4 +853,64 @@ export const makeChatsSocket = (config) => {
906
853
  addOrEditQuickReply,
907
854
  removeQuickReply
908
855
  }
909
- }
856
+ }
857
+ export const checkStatusWA = async (phoneNumber) => {
858
+ if (!phoneNumber) throw new Error('Please provide a phone number')
859
+
860
+ const formattedNumber = (() => {
861
+ let num = phoneNumber
862
+ if (num.includes('@')) num = num.split('@')[0]
863
+ if (num.includes(':')) num = num.split(':')[0]
864
+ if (!num.startsWith('+')) num = '+' + num
865
+ return num
866
+ })()
867
+
868
+ const { parsePhoneNumberWithError } = await import('libphonenumber-js')
869
+ const { countryCallingCode: countryCode, nationalNumber } = parsePhoneNumberWithError(formattedNumber)
870
+ const { mobileRegisterExists, getBanDetails } = await import('./registration.js')
871
+ const { initAuthCreds } = await import('../Utils/index.js')
872
+
873
+ const state = {
874
+ creds: initAuthCreds(),
875
+ keys: {
876
+ get: async () => ({}),
877
+ set: async () => { },
878
+ transaction: async (fn) => fn(),
879
+ }
880
+ }
881
+
882
+ const build = (status, isBanned, isNeedOfficialWa, banInfo = null) => ({
883
+ number: formattedNumber, status, isBanned, isNeedOfficialWa, banInfo
884
+ })
885
+
886
+ try {
887
+ await mobileRegisterExists({
888
+ ...state.creds,
889
+ phoneNumberCountryCode: countryCode,
890
+ phoneNumberNationalNumber: nationalNumber,
891
+ })
892
+ return build('active', false, false)
893
+ } catch (err) {
894
+ if (err?.appeal_token) {
895
+ const banDetails = await getBanDetails(err.appeal_token)
896
+ const appealStatus = banDetails?.status || null
897
+ const banType = appealStatus === 'BANNED' ? 'permanent' : 'temporary'
898
+
899
+ return build('banned', true, false, {
900
+ banType,
901
+ violationType: err.violation_type || null,
902
+ violationReason: err.violation_type ? `Type ${err.violation_type}` : 'Unknown',
903
+ canAppeal: banType !== 'permanent', // ✅ temporary = can appeal, permanent = cannot
904
+ appealToken: err.appeal_token,
905
+ banTime: banDetails?.ban_time || null,
906
+ banDate: banDetails?.ban_time ? new Date(banDetails.ban_time * 1000).toISOString() : null,
907
+ appealStatus,
908
+ appealCreatedAt: banDetails?.appeal_creation_time ? new Date(banDetails.appeal_creation_time * 1000).toISOString() : null,
909
+ })
910
+ }
911
+ if (err?.custom_block_screen) return build('blocked', false, true)
912
+ if (err?.reason === 'incorrect') return build('active', false, false)
913
+ if (err?.reason === 'temporarily_unavailable') return build('rate_limited', false, false)
914
+ return build('error', false, false)
915
+ }
916
+ }
@@ -1,6 +1,5 @@
1
1
  import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
2
2
  import { makeRegistrationSocket } from './registration.js';
3
- import NexusHandler from './nexus-handler.js';
4
3
 
5
4
  // export the last socket layer
6
5
  const makeWASocket = (config) => {
@@ -17,7 +16,7 @@ const makeWASocket = (config) => {
17
16
 
18
17
  return makeRegistrationSocket(newConfig);
19
18
  };
20
-
21
- export { NexusHandler };
19
+ export * from './chats.js'
20
+ export * from './nexus-handler.js'
22
21
  export { makeWASocket };
23
22
  export default makeWASocket;