@nexustechpro/baileys 2.1.3 → 2.1.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.
@@ -2,17 +2,30 @@ import { Mutex } from 'async-mutex'
2
2
  import { mkdir, readFile, rename, stat, unlink, writeFile, readdir } from 'fs/promises'
3
3
  import { join } from 'path'
4
4
  import { createHash } from 'crypto'
5
+ import { Keyv } from 'keyv'
5
6
  import { proto } from '../../WAProto/index.js'
6
7
  import { initAuthCreds } from './auth-utils.js'
7
8
  import { BufferJSON } from './generics.js'
9
+ import { PROTOCOL_ADAPTERS } from '../WABinary/index.js'
8
10
 
9
- // ─── Constants ────────────────────────────────────────────────────────────────
10
11
  const CURRENT_VERSION = 1
11
12
  const DEFAULT_PREKEY_RETENTION = 150
12
13
  const DEFAULT_CLEANUP_THRESHOLD = 50
13
14
  const CLEANUP_INTERVAL_MS = 10 * 60 * 1000
14
15
 
15
- // ─── File Lock Registry ───────────────────────────────────────────────────────
16
+ const bootstrapCreds = (raw) => {
17
+ const c = raw ?? initAuthCreds()
18
+ if (!c.__version || c.__version < CURRENT_VERSION) c.__version = CURRENT_VERSION
19
+ return c
20
+ }
21
+
22
+ const patchAppStateKey = (type, v) =>
23
+ type === 'app-state-sync-key' && v ? proto.Message.AppStateSyncKeyData.fromObject(v) : v
24
+
25
+ const computeChecksum = (data) => createHash('sha256').update(data).digest('hex')
26
+
27
+ // ─── File-based auth state ────────────────────────────────────────────────────
28
+
16
29
  const fileLocks = new Map()
17
30
  const getFileLock = (path) => {
18
31
  if (!fileLocks.has(path)) fileLocks.set(path, new Mutex())
@@ -22,31 +35,13 @@ const releaseFileLock = (path) => {
22
35
  if (fileLocks.has(path) && !fileLocks.get(path).isLocked()) fileLocks.delete(path)
23
36
  }
24
37
 
25
- // ─── Checksum ─────────────────────────────────────────────────────────────────
26
- const computeChecksum = (data) => createHash('sha256').update(data).digest('hex')
27
-
28
- /**
29
- * Production-grade multi-file auth state for Baileys.
30
- * Atomic writes, checksum integrity, and smart prekey cleanup.
31
- * Compatible with standard Baileys auth folder format.
32
- *
33
- * @param {string} folder - Directory to store auth files
34
- * @param {object} [options] - Configuration options
35
- * @param {number} [options.preKeyRetention=150] - How many recent prekeys to keep
36
- * @param {number} [options.cleanupThreshold=50] - How many new prekeys trigger a cleanup
37
- * @param {object} [options.logger] - Optional logger with .info/.warn methods
38
- */
39
38
  export const useMultiFileAuthState = async (folder, options = {}) => {
40
- const {
41
- preKeyRetention = DEFAULT_PREKEY_RETENTION,
42
- cleanupThreshold = DEFAULT_CLEANUP_THRESHOLD,
43
- logger,
44
- } = options
39
+ const { preKeyRetention = DEFAULT_PREKEY_RETENTION, cleanupThreshold = DEFAULT_CLEANUP_THRESHOLD, logger } = options
40
+
45
41
  const fixFileName = (file) => file?.replace(/\//g, '__')?.replace(/:/g, '-')
46
42
  const filePath = (file) => join(folder, fixFileName(file))
47
43
  const tmpPath = (file) => filePath(file) + '.tmp'
48
44
 
49
- // ─── Folder Bootstrap ───────────────────────────────────────────────────────
50
45
  const folderInfo = await stat(folder).catch(() => null)
51
46
  if (folderInfo) {
52
47
  if (!folderInfo.isDirectory()) throw new Error(`Path exists but is not a directory: ${folder}`)
@@ -54,16 +49,13 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
54
49
  await mkdir(folder, { recursive: true })
55
50
  }
56
51
 
57
- // ─── Atomic Write ────────────────────────────────────────────────────────────
58
52
  const writeData = async (data, file) => {
59
53
  const fp = filePath(file)
60
54
  const tp = tmpPath(file)
61
- const mutex = getFileLock(fp)
62
- const release = await mutex.acquire()
55
+ const release = await getFileLock(fp).acquire()
63
56
  try {
64
57
  const serialized = JSON.stringify(data, BufferJSON.replacer)
65
- const checksum = computeChecksum(serialized)
66
- const payload = JSON.stringify({ data: JSON.parse(serialized), __checksum: checksum })
58
+ const payload = JSON.stringify({ data: JSON.parse(serialized), __checksum: computeChecksum(serialized) })
67
59
  await writeFile(tp, payload)
68
60
  try {
69
61
  await rename(tp, fp)
@@ -77,11 +69,9 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
77
69
  }
78
70
  }
79
71
 
80
- // ─── Read with Checksum Verification ─────────────────────────────────────────
81
72
  const readData = async (file) => {
82
73
  const fp = filePath(file)
83
- const mutex = getFileLock(fp)
84
- const release = await mutex.acquire()
74
+ const release = await getFileLock(fp).acquire()
85
75
  try {
86
76
  const raw = await readFile(fp, { encoding: 'utf-8' }).catch(() => null)
87
77
  if (!raw) return null
@@ -92,28 +82,26 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
92
82
  if (expected !== parsed.__checksum) {
93
83
  logger?.warn({ file }, 'checksum mismatch — reinitializing file')
94
84
  await writeFile(fp, JSON.stringify({ data: parsed.data, __checksum: computeChecksum(JSON.stringify(parsed.data)) })).catch(() => { })
95
- return JSON.parse(JSON.stringify(parsed.data), BufferJSON.reviver)
96
85
  }
97
86
  return JSON.parse(JSON.stringify(parsed.data), BufferJSON.reviver)
98
87
  }
99
- // legacy file — rewrite with checksum
100
88
  const reserialized = JSON.stringify(JSON.parse(raw, BufferJSON.reviver), BufferJSON.replacer)
101
- const checksum = computeChecksum(reserialized)
102
- await writeFile(fp, JSON.stringify({ data: JSON.parse(reserialized), __checksum: checksum })).catch(() => { })
89
+ await writeFile(fp, JSON.stringify({ data: JSON.parse(reserialized), __checksum: computeChecksum(reserialized) })).catch(() => { })
103
90
  return JSON.parse(raw, BufferJSON.reviver)
104
91
  } catch (err) {
105
92
  logger?.warn({ file, err: err.message }, 'failed to read auth file — reinitializing')
106
93
  await unlink(fp).catch(() => { })
107
94
  return null
108
95
  }
109
- } finally { release(); releaseFileLock(fp) }
96
+ } finally {
97
+ release()
98
+ releaseFileLock(fp)
99
+ }
110
100
  }
111
101
 
112
- // ─── Remove File ────────────────────────────────────────────────────────────
113
102
  const removeData = async (file) => {
114
103
  const fp = filePath(file)
115
- const mutex = getFileLock(fp)
116
- const release = await mutex.acquire()
104
+ const release = await getFileLock(fp).acquire()
117
105
  try {
118
106
  await unlink(fp).catch(() => { })
119
107
  } finally {
@@ -122,34 +110,23 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
122
110
  }
123
111
  }
124
112
 
125
- // ─── Credentials Bootstrap ──────────────────────────────────────────────────
126
- let creds = (await readData('creds.json')) || initAuthCreds()
127
- if (!creds.__version) {
128
- creds.__version = CURRENT_VERSION
129
- } else if (creds.__version < CURRENT_VERSION) {
130
- creds.__version = CURRENT_VERSION
131
- }
132
-
133
- // ─── Prekey Cleanup ─────────────────────────────────────────────────────────
113
+ let creds = bootstrapCreds(await readData('creds.json'))
134
114
  let cleanupRunning = false
135
115
  let lastCleanupAt = 0
136
116
  let lastCleanedPreKeyId = creds.nextPreKeyId
137
117
 
138
118
  const cleanOldPreKeys = async () => {
139
119
  const now = Date.now()
140
- if (cleanupRunning) return
141
- if (now - lastCleanupAt < CLEANUP_INTERVAL_MS) return
120
+ if (cleanupRunning || now - lastCleanupAt < CLEANUP_INTERVAL_MS) return
142
121
  cleanupRunning = true
143
122
  try {
144
123
  const minId = creds.nextPreKeyId - preKeyRetention
145
124
  if (minId <= 0) return
146
125
  const files = await readdir(folder)
147
- const targets = []
148
- for (const file of files) {
149
- const match = file.match(/^pre-key-(\d+)\.json(\.tmp)?$/)
150
- if (!match) continue
151
- if (parseInt(match[1], 10) < minId) targets.push(join(folder, file))
152
- }
126
+ const targets = files
127
+ .map(f => f.match(/^pre-key-(\d+)\.json(\.tmp)?$/))
128
+ .filter(m => m && parseInt(m[1], 10) < minId)
129
+ .map(m => join(folder, m[0]))
153
130
  if (!targets.length) return
154
131
  await Promise.all(targets.map(f => unlink(f).catch(() => { })))
155
132
  lastCleanupAt = Date.now()
@@ -164,7 +141,6 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
164
141
 
165
142
  cleanOldPreKeys().catch(() => { })
166
143
 
167
- // ─── Stats ──────────────────────────────────────────────────────────────────
168
144
  const getStats = async () => {
169
145
  const files = await readdir(folder).catch(() => [])
170
146
  const preKeyFiles = files.filter(f => /^pre-key-\d+\.json$/.test(f))
@@ -184,9 +160,7 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
184
160
  const data = {}
185
161
  await Promise.all(ids.map(async (id) => {
186
162
  let value = await readData(`${type}-${id}.json`)
187
- if (type === 'app-state-sync-key' && value) {
188
- value = proto.Message.AppStateSyncKeyData.fromObject(value)
189
- }
163
+ if (type === 'app-state-sync-key' && value) value = proto.Message.AppStateSyncKeyData.fromObject(value)
190
164
  data[id] = value
191
165
  }))
192
166
  return data
@@ -204,11 +178,185 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
204
178
  },
205
179
  },
206
180
  saveCreds: async () => {
207
- if (creds.nextPreKeyId - lastCleanedPreKeyId >= cleanupThreshold) {
208
- cleanOldPreKeys().catch(() => { })
209
- }
181
+ if (creds.nextPreKeyId - lastCleanedPreKeyId >= cleanupThreshold) cleanOldPreKeys().catch(() => { })
210
182
  return writeData(creds, 'creds.json')
211
183
  },
212
184
  getStats,
213
185
  }
214
- }
186
+ }
187
+
188
+ // ─── Keyv-backed auth state ───────────────────────────────────────────────────
189
+
190
+ const ser = (v) => {
191
+ if (v == null) return null
192
+ const serialized = JSON.stringify(v, BufferJSON.replacer)
193
+ return { data: JSON.parse(serialized), __checksum: computeChecksum(serialized) }
194
+ }
195
+
196
+ const unwrapNestedValue = (obj) => {
197
+ let cur = obj
198
+ while (cur && typeof cur === 'object' && !Array.isArray(cur) && Object.keys(cur).length === 1 && 'value' in cur) cur = cur.value
199
+ return cur
200
+ }
201
+
202
+ const deser = (raw, logger, onRewrite) => {
203
+ if (raw == null) return null
204
+ let parsed
205
+ if (typeof raw === 'string') {
206
+ try { parsed = JSON.parse(raw) } catch (err) {
207
+ logger?.warn?.({ err: err.message }, '[Auth] failed to parse stored value — treating as missing')
208
+ return null
209
+ }
210
+ } else {
211
+ parsed = raw
212
+ }
213
+ parsed = unwrapNestedValue(parsed)
214
+ if (parsed == null) return null
215
+ if (typeof parsed === 'object' && '__checksum' in parsed) {
216
+ const innerData = unwrapNestedValue(parsed.data)
217
+ const serializedInner = JSON.stringify(innerData)
218
+ const expected = computeChecksum(serializedInner)
219
+ if (expected !== parsed.__checksum) {
220
+ logger?.warn?.('[Auth] checksum mismatch or legacy-wrapped value — reinitializing')
221
+ onRewrite?.(JSON.stringify({ data: innerData, __checksum: expected }))
222
+ }
223
+ return JSON.parse(serializedInner, BufferJSON.reviver)
224
+ }
225
+ return JSON.parse(JSON.stringify(parsed), BufferJSON.reviver)
226
+ }
227
+
228
+ // Maps our unified collectionName option to each adapter's actual constructor key
229
+ const COLLECTION_OPTION_KEY = {
230
+ '@keyv/mongo': 'collection',
231
+ '@keyv/postgres': 'table',
232
+ '@keyv/mysql': 'table',
233
+ '@keyv/sqlite': 'table',
234
+ }
235
+
236
+ const _adapterCache = new Map()
237
+ export const clearAdapterCache = () => _adapterCache.clear()
238
+
239
+ const resolveAdapter = async (connectionString, collectionName) => {
240
+ const cacheKey = collectionName ? `${connectionString}::${collectionName}` : connectionString
241
+ if (_adapterCache.has(cacheKey)) return _adapterCache.get(cacheKey)
242
+ let protocol
243
+ try { protocol = new URL(connectionString).protocol } catch { throw new Error(`[Auth] Invalid connection string: "${connectionString}"`) }
244
+ const pkg = PROTOCOL_ADAPTERS[protocol]
245
+ if (!pkg) throw new Error(`[Auth] Unsupported protocol "${protocol}" — supported: redis, mongodb, postgresql, mysql, sqlite, etcd, memcache. Pass a pre-built KeyvStoreAdapter instance for anything else.`)
246
+ let mod
247
+ try { mod = await import(pkg) } catch (e) {
248
+ if (e.code === 'ERR_MODULE_NOT_FOUND') throw new Error(`[Auth] "${pkg}" is required for this backend — install it: npm i ${pkg}`)
249
+ throw e
250
+ }
251
+ const Adapter = mod.default ?? mod[Object.keys(mod)[0]]
252
+ const optionKey = COLLECTION_OPTION_KEY[pkg]
253
+ // Pass one merged options object — Postgres/MySQL silently ignore a second positional argument
254
+ const adapter = (collectionName && optionKey)
255
+ ? new Adapter({ url: connectionString, uri: connectionString, [optionKey]: collectionName })
256
+ : new Adapter(connectionString)
257
+ adapter.setMaxListeners?.(0)
258
+ _adapterCache.set(cacheKey, adapter)
259
+ return adapter
260
+ }
261
+
262
+ const isAdapterLike = (v) => v && typeof v === 'object' && typeof v.get === 'function' && typeof v.set === 'function' && typeof v.delete === 'function' && typeof v.clear === 'function'
263
+
264
+ const resolveStore = async (backend, collectionName) => {
265
+ if (backend == null) return null
266
+ if (typeof backend === 'string') return resolveAdapter(backend, collectionName)
267
+ if (backend instanceof Keyv) return backend.opts?.store ?? backend.store ?? null
268
+ if (isAdapterLike(backend)) return backend
269
+ throw new Error('[Auth] backend must be a connection string, Keyv instance, or KeyvStoreAdapter')
270
+ }
271
+
272
+ export const useKeyvAuthState = async (sessionId, backend, opts = {}) => {
273
+ const { preKeyRetention = DEFAULT_PREKEY_RETENTION, cleanupThreshold = DEFAULT_CLEANUP_THRESHOLD, logger, collectionName } = opts
274
+
275
+ const store = await resolveStore(backend, collectionName)
276
+ const keyv = store ? new Keyv({ store, namespace: sessionId }) : new Keyv({ namespace: sessionId })
277
+ keyv.on('error', (err) => logger?.warn?.({ err: err?.message }, '[Auth] store error'))
278
+
279
+ const keyName = (type, id) => `${type}-${id}`
280
+
281
+ let creds = bootstrapCreds(deser(await keyv.get('creds'), logger, (fixed) => keyv.set('creds', fixed)))
282
+ let cleanupRunning = false
283
+ let lastCleanupAt = 0
284
+ let lastCleanedPreKeyId = creds.nextPreKeyId
285
+
286
+ const cleanOldPreKeys = async () => {
287
+ const now = Date.now()
288
+ if (cleanupRunning || now - lastCleanupAt < CLEANUP_INTERVAL_MS) return
289
+ cleanupRunning = true
290
+ try {
291
+ const minId = creds.nextPreKeyId - preKeyRetention
292
+ if (minId <= 0) return
293
+ const ids = []
294
+ for (let id = Math.max(0, lastCleanedPreKeyId - preKeyRetention); id < minId; id++) ids.push(keyName('pre-key', id))
295
+ if (!ids.length) return
296
+ await Promise.all(ids.map((k) => keyv.delete(k).catch(() => { })))
297
+ lastCleanupAt = Date.now()
298
+ lastCleanedPreKeyId = creds.nextPreKeyId
299
+ logger?.info?.({ deleted: ids.length, minId }, '[Auth] prekey cleanup done')
300
+ } catch (e) {
301
+ logger?.warn?.({ err: e.message }, '[Auth] prekey cleanup failed')
302
+ } finally {
303
+ cleanupRunning = false
304
+ }
305
+ }
306
+
307
+ cleanOldPreKeys().catch(() => { })
308
+
309
+ const keys = {
310
+ get: async (type, ids) => {
311
+ const data = {}
312
+ if (!ids.length) return data
313
+ const rawKeys = ids.map((id) => keyName(type, id))
314
+ const rawValues = await keyv.getMany(rawKeys)
315
+ const rewrites = []
316
+ ids.forEach((id, i) => {
317
+ data[id] = patchAppStateKey(type, deser(rawValues[i], logger, (fixed) => rewrites.push(keyv.set(rawKeys[i], fixed))))
318
+ })
319
+ if (rewrites.length) await Promise.all(rewrites).catch(() => { })
320
+ return data
321
+ },
322
+ set: async (data) => {
323
+ const setEntries = []
324
+ const delKeys = []
325
+ for (const type in data) {
326
+ for (const id in data[type]) {
327
+ const value = data[type][id]
328
+ const key = keyName(type, id)
329
+ if (value != null) setEntries.push({ key, value: ser(value) })
330
+ else delKeys.push(key)
331
+ }
332
+ }
333
+ await Promise.all([
334
+ setEntries.length ? keyv.setMany(setEntries) : null,
335
+ delKeys.length ? keyv.deleteMany(delKeys) : null,
336
+ ])
337
+ },
338
+ }
339
+
340
+ const saveCreds = async () => {
341
+ if (creds.nextPreKeyId - lastCleanedPreKeyId >= cleanupThreshold) cleanOldPreKeys().catch(() => { })
342
+ await keyv.set('creds', ser(creds))
343
+ }
344
+
345
+ const clearSession = async () => {
346
+ const store = keyv.opts?.store ?? keyv.store
347
+ if (store && typeof store.deleteMany === 'function' && typeof store.iterator === 'function') {
348
+ const toDelete = []
349
+ for await (const [key] of store.iterator(sessionId)) toDelete.push(key)
350
+ if (toDelete.length) await store.deleteMany(toDelete)
351
+ } else {
352
+ await keyv.clear()
353
+ }
354
+ await close()
355
+ }
356
+
357
+ const close = async () => { keyv.removeAllListeners?.() }
358
+
359
+ return { state: { creds, keys }, saveCreds, clearSession }
360
+ }
361
+
362
+ export { Keyv }
@@ -13,7 +13,9 @@ const getUserAgent = (config) => {
13
13
  secondary: config.version[1],
14
14
  tertiary: config.version[2]
15
15
  },
16
- platform: proto.ClientPayload.UserAgent.Platform.WEB,
16
+ platform: config.browser[1].toLocaleLowerCase().includes('android')
17
+ ? proto.ClientPayload.UserAgent.Platform.MACOS
18
+ : proto.ClientPayload.UserAgent.Platform.WEB,
17
19
  releaseChannel: proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
18
20
  osVersion: '0.1',
19
21
  device: 'Desktop',
@@ -43,7 +45,9 @@ const getClientPayload = (config) => {
43
45
  connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
44
46
  userAgent: getUserAgent(config)
45
47
  };
46
- payload.webInfo = getWebInfo(config);
48
+ if (!config.browser[1].toLowerCase().includes('android')) {
49
+ payload.webInfo = getWebInfo(config)
50
+ }
47
51
  return payload;
48
52
  };
49
53
  export const generateLoginNode = (userJid, config) => {
@@ -61,6 +65,9 @@ export const generateLoginNode = (userJid, config) => {
61
65
  };
62
66
  const getPlatformType = (platform) => {
63
67
  const platformType = platform.toUpperCase();
68
+ if (platformType === 'ANDROID') {
69
+ return proto.DeviceProps.PlatformType.ANDROID_PHONE;
70
+ }
64
71
  return (proto.DeviceProps.PlatformType[platformType] ||
65
72
  proto.DeviceProps.PlatformType.CHROME);
66
73
  };
@@ -77,6 +84,7 @@ export const generateRegistrationNode = ({ registrationId, signedPreKey, signedI
77
84
  historySyncConfig: {
78
85
  storageQuotaMb: 569150,
79
86
  inlineInitialPayloadInE2EeMsg: true,
87
+ recentSyncDaysLimit: undefined,
80
88
  supportCallLogHistory: false,
81
89
  supportBotUserAgentChatHistory: true,
82
90
  supportCagReactionsAndPolls: true,
@@ -84,7 +92,11 @@ export const generateRegistrationNode = ({ registrationId, signedPreKey, signedI
84
92
  supportRecentSyncChunkMessageCountTuning: true,
85
93
  supportHostedGroupMsg: true,
86
94
  supportFbidBotChatHistory: true,
87
- supportMessageAssociation: true
95
+ supportAddOnHistorySyncMigration: undefined,
96
+ supportMessageAssociation: true,
97
+ supportGroupHistory: false,
98
+ onDemandReady: undefined,
99
+ supportGuestChat: undefined
88
100
  },
89
101
  version: {
90
102
  primary: 10,
@@ -23,6 +23,20 @@ export const VIOLATION_TYPES = {
23
23
  '18': 'Terms of Service Violation',
24
24
  '20': 'Illegal Content'
25
25
  };
26
+
27
+ export const PROTOCOL_ADAPTERS = {
28
+ 'redis:': '@keyv/redis',
29
+ 'rediss:': '@keyv/redis',
30
+ 'mongodb:': '@keyv/mongo',
31
+ 'mongodb+srv:': '@keyv/mongo',
32
+ 'postgresql:': '@keyv/postgres',
33
+ 'postgres:': '@keyv/postgres',
34
+ 'mysql:': '@keyv/mysql',
35
+ 'sqlite:': '@keyv/sqlite',
36
+ 'etcd:': '@keyv/etcd',
37
+ 'memcache:': '@keyv/memcache',
38
+ 'memcached:': '@keyv/memcache',
39
+ }
26
40
  export const DOUBLE_BYTE_TOKENS = [
27
41
  [
28
42
  'read-self',
package/lib/index.js CHANGED
@@ -31,7 +31,7 @@ const banner = `
31
31
  const info = `
32
32
  ┌───────────────────────────────────────────────────────────────────────┐
33
33
  │ 📦 Package: @nexustechpro/baileys │
34
- │ 🔖 Version: 2.1.3
34
+ │ 🔖 Version: 2.1.6
35
35
  │ ⚡ Status: Production Ready │
36
36
  ├───────────────────────────────────────────────────────────────────────┤
37
37
  │ 🚀 Advanced WhatsApp Web API Client │
package/package.json CHANGED
@@ -2,9 +2,18 @@
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@nexustechpro/baileys",
4
4
  "type": "module",
5
- "version": "2.1.3",
5
+ "version": "2.1.6",
6
6
  "description": "Advanced WhatsApp Web API built on Baileys — interactive messages, buttons, carousels, products, events, payments, polls, albums, sticker packs and more.",
7
7
  "keywords": [
8
+ "baileys",
9
+ "baileys-mod",
10
+ "baileys-fork",
11
+ "nexus",
12
+ "nexusbot",
13
+ "nexustech",
14
+ "nexustechpro",
15
+ "baileys-advanced",
16
+ "whiskeysockets",
8
17
  "whatsapp",
9
18
  "whatsapp-api",
10
19
  "whatsapp-web",
@@ -24,17 +33,9 @@
24
33
  "whatsapp-channel",
25
34
  "whatsapp-status",
26
35
  "whatsapp-pairing",
27
- "baileys",
28
- "baileys-mod",
29
- "baileys-fork",
30
- "baileys-advanced",
31
- "whiskeysockets",
32
36
  "wa-api",
33
37
  "wa-bot",
34
38
  "wa-web",
35
- "nexus",
36
- "nexusbot",
37
- "nexustechpro",
38
39
  "automation",
39
40
  "bot",
40
41
  "chatbot",
@@ -101,22 +102,32 @@
101
102
  "@adiwajshing/keyed-db": "^0.2.4",
102
103
  "@cacheable/node-cache": "^1.4.0",
103
104
  "@hapi/boom": "^9.1.3",
105
+ "@keyv/etcd": "^2.1.1",
106
+ "@keyv/memcache": "^2.0.2",
107
+ "@keyv/mongo": "^3.1.0",
108
+ "@keyv/mysql": "^2.1.10",
109
+ "@keyv/postgres": "^2.2.3",
110
+ "@keyv/redis": "^5.1.6",
111
+ "@keyv/sqlite": "^4.0.8",
104
112
  "@microlink/mql": "^0.16.1",
105
113
  "async-mutex": "^0.5.0",
106
114
  "axios": "^1.6.0",
107
115
  "cache-manager": "latest",
108
116
  "chalk": "^4.1.2",
109
117
  "fflate": "^0.8.2",
118
+ "ffmpeg-static": "^5.3.0",
110
119
  "gradient-string": "^2.0.2",
120
+ "keyv": "^5.6.0",
111
121
  "libphonenumber-js": "^1.13.3",
112
122
  "link-preview-js": "^4.0.3",
113
123
  "lru-cache": "^11.1.0",
114
124
  "music-metadata": "^11.7.0",
125
+ "node-cache": "^5.1.2",
115
126
  "p-queue": "^9.0.0",
116
127
  "pino": "^9.6",
128
+ "prismjs": "^1.30.0",
117
129
  "protobufjs": "latest",
118
130
  "qrcode-terminal": "^0.12.0",
119
- "sharp": "^0.32.0",
120
131
  "url-regex-safe": "^4.0.0",
121
132
  "uuid": "latest",
122
133
  "whatsapp-rust-bridge": "latest",
@@ -157,8 +168,9 @@
157
168
  },
158
169
  "peerDependencies": {
159
170
  "audio-decode": "^2.1.3",
160
- "jimp": "^1.6.0",
161
- "link-preview-js": "^4.0.3"
171
+ "jimp": "*",
172
+ "link-preview-js": "^4.0.3",
173
+ "sharp": "*"
162
174
  },
163
175
  "peerDependenciesMeta": {
164
176
  "audio-decode": {
@@ -166,6 +178,9 @@
166
178
  },
167
179
  "jimp": {
168
180
  "optional": true
181
+ },
182
+ "sharp": {
183
+ "optional": true
169
184
  }
170
185
  },
171
186
  "packageManager": "yarn@4.9.2",