@areumtecnologia/wasockets 1.1.5 → 2.0.0-alpha.1

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.
@@ -0,0 +1,17 @@
1
+ export declare namespace proto {
2
+ interface IMessage {
3
+ [key: string]: any
4
+ }
5
+ interface IHistorySyncNotification {
6
+ [key: string]: any
7
+ }
8
+ interface IWebMessageInfo {
9
+ [key: string]: any
10
+ }
11
+ }
12
+
13
+ export declare const proto: {
14
+ [key: string]: any
15
+ }
16
+
17
+ export default proto
@@ -7,6 +7,33 @@ const { default: logger } = require("../Utils/logger")
7
7
  const { makeLibSignalRepository } = require("../Signal/libsignal")
8
8
  const { version } = require("./baileys-version.json")
9
9
 
10
+ const createGroupMetadataCache = (ttlMs = 300000, maxSize = 250) => {
11
+ const cache = new Map()
12
+
13
+ const get = async (jid) => {
14
+ const item = cache.get(jid)
15
+ if (!item) return undefined
16
+ if (Date.now() - item.time > ttlMs) {
17
+ cache.delete(jid)
18
+ return undefined
19
+ }
20
+ return item.metadata
21
+ }
22
+
23
+ get.set = (jid, metadata) => {
24
+ if (cache.size >= maxSize) {
25
+ const oldestKey = cache.keys().next().value
26
+ if (oldestKey) cache.delete(oldestKey)
27
+ }
28
+ cache.set(jid, { metadata, time: Date.now() })
29
+ }
30
+
31
+ get.delete = (jid) => cache.delete(jid)
32
+ get.clear = () => cache.clear()
33
+
34
+ return get
35
+ }
36
+
10
37
  const DEFAULT_CONNECTION_CONFIG = {
11
38
  version,
12
39
  browser: Browsers.windows('Chrome'),
@@ -35,6 +62,10 @@ const DEFAULT_CONNECTION_CONFIG = {
35
62
  generateHighQualityLinkPreview: false,
36
63
  enableAutoSessionRecreation: true,
37
64
  enableRecentMessageCache: true,
65
+ enableMessageQueue: true,
66
+ messageQueueTtlMs: 300000,
67
+ maxReconnectAttempts: 15,
68
+ enableGroupCache: true,
38
69
  options: {},
39
70
  appStateMacVerification: {
40
71
  patch: false,
@@ -42,10 +73,11 @@ const DEFAULT_CONNECTION_CONFIG = {
42
73
  },
43
74
  countryCode: 'US',
44
75
  getMessage: async () => undefined,
45
- cachedGroupMetadata: async () => undefined,
76
+ cachedGroupMetadata: createGroupMetadataCache(),
46
77
  makeSignalRepository: makeLibSignalRepository
47
78
  }
48
79
 
49
80
  module.exports = {
50
- DEFAULT_CONNECTION_CONFIG
81
+ DEFAULT_CONNECTION_CONFIG,
82
+ createGroupMetadataCache
51
83
  }
@@ -0,0 +1,6 @@
1
+ import { Browsers } from '../Utils'
2
+ import { UserFacingSocketConfig } from '../index'
3
+
4
+ export { Browsers }
5
+ export declare const DEFAULT_CONNECTION_CONFIG: UserFacingSocketConfig
6
+ export declare function createGroupMetadataCache(ttlMs?: number, maxSize?: number): any
@@ -0,0 +1,33 @@
1
+ import { WASocket } from '../index'
2
+
3
+ export interface PluginMetadata {
4
+ name: string
5
+ version?: string
6
+ description?: string
7
+ author?: string
8
+ install?: (sock: WASocket, options?: any, manager?: PluginManager) => void
9
+ }
10
+
11
+ export type PluginFunction = (sock: WASocket, options?: any, manager?: PluginManager) => void
12
+ export type Plugin = PluginMetadata | PluginFunction
13
+
14
+ export type MiddlewareHook =
15
+ | 'beforeSendMessage'
16
+ | 'afterSendMessage'
17
+ | 'beforeRecvMessage'
18
+ | 'afterRecvMessage'
19
+ | 'connectionUpdate'
20
+
21
+ export declare class PluginManager {
22
+ constructor(sock: WASocket)
23
+ sock: WASocket
24
+ plugins: Map<string, any>
25
+ middlewares: Record<string, Function[]>
26
+
27
+ use(plugin: Plugin, options?: any): this
28
+ registerMiddleware(hook: MiddlewareHook, fn: (context: any, sock: WASocket) => Promise<boolean | void> | boolean | void): () => void
29
+ runMiddlewares(hook: string, context: any): Promise<boolean>
30
+ hasPlugin(name: string): boolean
31
+ getPlugin(name: string): any
32
+ listPlugins(): Array<{ name: string; registeredAt: number; version: string; description: string }>
33
+ }
@@ -0,0 +1,125 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ /**
6
+ * Plugin and Middleware Manager for WaSockets
7
+ * Enables modular extensions, event interception, and pipeline middleware.
8
+ */
9
+ class PluginManager {
10
+ constructor(sock) {
11
+ this.sock = sock
12
+ this.plugins = new Map()
13
+ this.middlewares = {
14
+ beforeSendMessage: [],
15
+ afterSendMessage: [],
16
+ beforeRecvMessage: [],
17
+ afterRecvMessage: [],
18
+ connectionUpdate: []
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Install a plugin
24
+ * @param {Object|Function} plugin - Plugin object with install() or function (sock, options)
25
+ * @param {Object} [options={}] - Options passed to plugin
26
+ */
27
+ use(plugin, options = {}) {
28
+ if (!plugin) return this
29
+
30
+ if (typeof plugin === 'function') {
31
+ plugin(this.sock, options, this)
32
+ return this
33
+ }
34
+
35
+ const name = plugin.name || `plugin_${this.plugins.size + 1}`
36
+ if (this.plugins.has(name)) {
37
+ throw new Error(`Plugin with name "${name}" is already registered`)
38
+ }
39
+
40
+ this.plugins.set(name, {
41
+ plugin,
42
+ options,
43
+ registeredAt: Date.now()
44
+ })
45
+
46
+ if (typeof plugin.install === 'function') {
47
+ plugin.install(this.sock, options, this)
48
+ }
49
+
50
+ return this
51
+ }
52
+
53
+ /**
54
+ * Register a middleware hook
55
+ * @param {'beforeSendMessage'|'afterSendMessage'|'beforeRecvMessage'|'afterRecvMessage'|'connectionUpdate'} hook
56
+ * @param {Function} fn - Async middleware function
57
+ * @returns {Function} Unregister function
58
+ */
59
+ registerMiddleware(hook, fn) {
60
+ if (!this.middlewares[hook]) {
61
+ this.middlewares[hook] = []
62
+ }
63
+ this.middlewares[hook].push(fn)
64
+ return () => {
65
+ this.middlewares[hook] = this.middlewares[hook].filter(f => f !== fn)
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Execute all middlewares for a specific hook
71
+ * @param {string} hook
72
+ * @param {Object} context
73
+ * @returns {Promise<boolean>} returns false if any middleware explicitly returned false (cancelled)
74
+ */
75
+ async runMiddlewares(hook, context) {
76
+ const hooks = this.middlewares[hook] || []
77
+ for (const fn of hooks) {
78
+ try {
79
+ const result = await fn(context, this.sock)
80
+ if (result === false) {
81
+ return false
82
+ }
83
+ } catch (error) {
84
+ if (this.sock.logger) {
85
+ this.sock.logger.error({ error, hook }, 'Error executing plugin middleware')
86
+ } else {
87
+ console.error(`[PluginManager] Error executing middleware on hook ${hook}:`, error)
88
+ }
89
+ }
90
+ }
91
+ return true
92
+ }
93
+
94
+ /**
95
+ * Check if a plugin is installed
96
+ * @param {string} name
97
+ */
98
+ hasPlugin(name) {
99
+ return this.plugins.has(name)
100
+ }
101
+
102
+ /**
103
+ * Retrieve an installed plugin
104
+ * @param {string} name
105
+ */
106
+ getPlugin(name) {
107
+ return this.plugins.get(name)
108
+ }
109
+
110
+ /**
111
+ * List all installed plugins
112
+ */
113
+ listPlugins() {
114
+ return Array.from(this.plugins.entries()).map(([name, data]) => ({
115
+ name,
116
+ registeredAt: data.registeredAt,
117
+ version: data.plugin?.version || '1.0.0',
118
+ description: data.plugin?.description || ''
119
+ }))
120
+ }
121
+ }
122
+
123
+ module.exports = {
124
+ PluginManager
125
+ }
@@ -7,6 +7,7 @@ const {
7
7
  parseCatalogNode,
8
8
  parseCollectionsNode,
9
9
  parseOrderDetailsNode,
10
+ parseProductNode,
10
11
  getRawMediaUploadData,
11
12
  uploadingNecessaryImagesOfProduct
12
13
  } = require("../Utils")
@@ -408,12 +409,44 @@ const makeBusinessSocket = (config) => {
408
409
  deleted: +(productCatalogDelNode?.attrs?.deleted_count || 0)
409
410
  }
410
411
  }
412
+ const getProduct = async (jid, productId) => {
413
+ jid = jid || authState.creds.me?.id
414
+ jid = jidNormalizedUser(jid)
415
+
416
+ const result = await query({
417
+ tag: 'iq',
418
+ attrs: {
419
+ to: S_WHATSAPP_NET,
420
+ type: 'get',
421
+ xmlns: 'w:biz:catalog'
422
+ },
423
+ content: [
424
+ {
425
+ tag: 'product',
426
+ attrs: {
427
+ jid
428
+ },
429
+ content: [
430
+ {
431
+ tag: 'id',
432
+ attrs: {},
433
+ content: Buffer.from(productId)
434
+ }
435
+ ]
436
+ }
437
+ ]
438
+ })
439
+ const productNode = getBinaryNodeChild(result, 'product')
440
+ return productNode ? parseProductNode(productNode) : null
441
+ }
442
+
411
443
  return {
412
444
  ...suki,
413
445
  logger: config.logger,
414
446
  getOrderDetails,
415
447
  getCatalog,
416
448
  getCollections,
449
+ getProduct,
417
450
  productCreate,
418
451
  productDelete,
419
452
  productUpdate,
@@ -30,6 +30,7 @@ const {
30
30
  const { makeMutex } = require("../Utils/make-mutex")
31
31
  const {
32
32
  isPnUser,
33
+ isLidUser,
33
34
  getBinaryNodeChild,
34
35
  getBinaryNodeChildren,
35
36
  jidDecode,
@@ -252,11 +253,141 @@ const makeChatsSocket = (config) => {
252
253
 
253
254
  const result = await suki.executeUSyncQuery(usyncQuery)
254
255
 
255
- if (result) {
256
+ if (result && result.list) {
257
+ const mappingsToStore = []
258
+ for (const item of result.list) {
259
+ const lid = item.lid || item.val
260
+ if (lid && isPnUser(targetJid)) {
261
+ mappingsToStore.push({ lid, pn: targetJid })
262
+ }
263
+ }
264
+ if (mappingsToStore.length && signalRepository?.lidMapping?.storeLIDPNMappings) {
265
+ await signalRepository.lidMapping.storeLIDPNMappings(mappingsToStore).catch(err => {
266
+ logger.debug({ err }, 'Failed to auto-store LID-PN mapping in getLidUser')
267
+ })
268
+ }
256
269
  return result.list
257
270
  }
258
271
  }
259
272
 
273
+ const getPnUser = async (jid) => {
274
+ if (!jid) {
275
+ throw new Boom('Please input a jid user')
276
+ }
277
+
278
+ if (!isLidUser(jid)) {
279
+ throw new Boom('Invalid JID: Not a LID user!')
280
+ }
281
+
282
+ const targetJid = jidNormalizedUser(jid)
283
+
284
+ const usyncQuery = new USyncQuery()
285
+ usyncQuery.protocols.push({
286
+ name: 'phone_number',
287
+ getQueryElement: () => ({
288
+ tag: 'phone_number',
289
+ attrs: {},
290
+ content: undefined
291
+ }),
292
+ getUserElement: () => null,
293
+ parser: (node) => node.attrs.phone_number || node.attrs.val
294
+ })
295
+ usyncQuery.users.push({
296
+ id: targetJid
297
+ })
298
+
299
+ const result = await suki.executeUSyncQuery(usyncQuery)
300
+
301
+ if (result && result.list) {
302
+ const mappingsToStore = []
303
+ for (const item of result.list) {
304
+ const rawPhone = item.phone_number || item.val
305
+ if (rawPhone && isLidUser(targetJid)) {
306
+ const cleanPhone = rawPhone.replace('+', '')
307
+ const pnJid = `${cleanPhone}@s.whatsapp.net`
308
+ mappingsToStore.push({ lid: targetJid, pn: pnJid })
309
+ }
310
+ }
311
+ if (mappingsToStore.length && signalRepository?.lidMapping?.storeLIDPNMappings) {
312
+ await signalRepository.lidMapping.storeLIDPNMappings(mappingsToStore).catch(err => {
313
+ logger.debug({ err }, 'Failed to auto-store LID-PN mapping in getPnUser')
314
+ })
315
+ }
316
+ return result.list
317
+ }
318
+ }
319
+
320
+ const toPn = async (jid, fetchIfMissing = false) => {
321
+ if (!jid) return null
322
+ if (isPnUser(jid)) return jidNormalizedUser(jid)
323
+ if (!isLidUser(jid)) return jidNormalizedUser(jid)
324
+
325
+ const normLid = jidNormalizedUser(jid)
326
+ let pn = await signalRepository?.lidMapping?.getPNForLID(normLid)
327
+ if (pn) return jidNormalizedUser(pn)
328
+
329
+ if (fetchIfMissing) {
330
+ try {
331
+ const list = await getPnUser(normLid)
332
+ if (list && list.length > 0) {
333
+ const phone = list[0].phone_number || list[0].val
334
+ if (phone) {
335
+ return `${phone.replace('+', '')}@s.whatsapp.net`
336
+ }
337
+ }
338
+ } catch (err) {
339
+ logger.debug({ err, jid }, 'Failed to fetch PN for LID via USync')
340
+ }
341
+ }
342
+ return null
343
+ }
344
+
345
+ const toLid = async (jid, fetchIfMissing = false) => {
346
+ if (!jid) return null
347
+ if (isLidUser(jid)) return jidNormalizedUser(jid)
348
+ if (!isPnUser(jid)) return jidNormalizedUser(jid)
349
+
350
+ const normPn = jidNormalizedUser(jid)
351
+ let lid = await signalRepository?.lidMapping?.getLIDForPN(normPn)
352
+ if (lid) return jidNormalizedUser(lid)
353
+
354
+ if (fetchIfMissing) {
355
+ try {
356
+ const list = await getLidUser(normPn)
357
+ if (list && list.length > 0) {
358
+ const foundLid = list[0].lid || list[0].val
359
+ if (foundLid) {
360
+ return jidNormalizedUser(foundLid)
361
+ }
362
+ }
363
+ } catch (err) {
364
+ logger.debug({ err, jid }, 'Failed to fetch LID for PN via USync')
365
+ }
366
+ }
367
+ return null
368
+ }
369
+
370
+ const resolveJid = async (jid, fetchIfMissing = false) => {
371
+ if (!jid) return { pn: null, lid: null, jid: null }
372
+ if (isPnUser(jid)) {
373
+ const pn = jidNormalizedUser(jid)
374
+ const lid = await toLid(pn, fetchIfMissing)
375
+ return { pn, lid, jid: pn }
376
+ }
377
+ if (isLidUser(jid)) {
378
+ const lid = jidNormalizedUser(jid)
379
+ const pn = await toPn(lid, fetchIfMissing)
380
+ return { pn, lid, jid: lid }
381
+ }
382
+ return { pn: null, lid: null, jid }
383
+ }
384
+
385
+ const storeLidPnMapping = async (pn, lid) => {
386
+ if (!pn || !lid || !signalRepository?.lidMapping) return false
387
+ await signalRepository.lidMapping.storeLIDPNMappings([{ pn, lid }])
388
+ return true
389
+ }
390
+
260
391
  const fetchStatus = async (...jids) => {
261
392
  const usyncQuery = new USyncQuery().withStatusProtocol()
262
393
 
@@ -914,6 +1045,39 @@ const makeChatsSocket = (config) => {
914
1045
  }, jid)
915
1046
  }
916
1047
 
1048
+ /**
1049
+ * Set or unset a chat as Favorite
1050
+ */
1051
+ const updateFavorite = (jid, favorite = true) => {
1052
+ return chatModify({
1053
+ favorite
1054
+ }, jid)
1055
+ }
1056
+
1057
+ /**
1058
+ * Add or update a note for a chat (contact notes)
1059
+ */
1060
+ const updateChatNote = (jid, text) => {
1061
+ return chatModify({
1062
+ note: {
1063
+ text,
1064
+ deleted: false,
1065
+ createdAt: Date.now()
1066
+ }
1067
+ }, jid)
1068
+ }
1069
+
1070
+ /**
1071
+ * Remove note for a chat
1072
+ */
1073
+ const removeChatNote = (jid) => {
1074
+ return chatModify({
1075
+ note: {
1076
+ deleted: true
1077
+ }
1078
+ }, jid)
1079
+ }
1080
+
917
1081
  /**
918
1082
  * Adds label
919
1083
  */
@@ -1257,6 +1421,14 @@ const makeChatsSocket = (config) => {
1257
1421
  appStatePatchMutex,
1258
1422
  notificationMutex,
1259
1423
  getLidUser,
1424
+ getPnUser,
1425
+ toPn,
1426
+ toLid,
1427
+ resolveJid,
1428
+ storeLidPnMapping,
1429
+ updateFavorite,
1430
+ updateChatNote,
1431
+ removeChatNote,
1260
1432
  fetchBlocklist,
1261
1433
  fetchStatus,
1262
1434
  fetchDisappearingDuration,