@blurose/baileys 1.1.3 → 1.1.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.
package/README.md CHANGED
@@ -1,45 +1,72 @@
1
- <h1 align='center'><img alt="Baileys logo" src="https://veracloud.biz.id/LIXS.png" height="auto"/><br/>Baileys Newsletter (blurose/baileys)</h1>
1
+ <h1 align='center'><img alt="Baileys logo" src="https://veracloud.biz.id/LIXS.png" height="auto"/><br/>@blurose/baileys</h1>
2
2
 
3
- <div align='center'>A WebSockets-based TypeScript library for interacting with the WhatsApp Web API, customized for Newsletter/Channel Media support and built-in Advanced Interactive Message Builders (MessageBuilder v4.6).</div>
3
+ <div align='center'>A WebSockets-based TypeScript library for interacting with the WhatsApp Web API, customized for Newsletter/Channel Media support, built-in Advanced Interactive Message Builders (MessageBuilder v4.6), and full backwards compatibility for MikirBot & Kiu-style bots.</div>
4
4
 
5
5
  > [!IMPORTANT]
6
- > **This is a custom fork and patch of `@whiskeysockets/baileys` (`blurose/baileys`)**
6
+ > **This is a custom fork and patch of `@whiskeysockets/baileys` (`@blurose/baileys`)**
7
7
  >
8
8
  > Developed & Maintained by: **Xyraa Team** & **alfavz**.
9
9
  >
10
- > This version introduces stable and native support for sending media (audios, images, videos, and documents) to WhatsApp Channels / Newsletters, bypassing E2E encryption for public channel broadcasts, and properly formatting the output stanzas (`type="media"` and `mediatype` metadata) which is currently unsupported in the official WhiskeySockets repository.
11
- >
12
- > In addition, it integrates **MessageBuilder v4.6** directly into the library, allowing you to generate advanced UI components (Buttons, Carousels, Native Flows, and AI Rich Responses) natively and easily.
10
+ > `@blurose/baileys` keeps the current upstream Baileys RC internals while adding a rich compatibility layer for older Kiu/@z4phdev-style bots and MikirBot projects. The goal is to let existing plugins continue working without replacing newer Baileys features such as modern LID/PN, newsletter, community, and MEX handling.
13
11
 
14
12
  ---
15
13
 
16
- # Sponsor & Support
17
- If you'd like to support the original author and maintainer of Baileys (Rajeh), you can book a slot or pre-order [here](https://purpshell.dev/book).
14
+ ## Maintenance Status & Compatibility
18
15
 
19
- # Disclaimer
20
- This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or its affiliates.
21
- Use at your own discretion. Do not spam people with this. We discourage any stalkerware, bulk or automated messaging usage.
16
+ Active maintained release: **1.1.5**
22
17
 
23
- ---
18
+ ### Key Enhancements & Compatibility Provided
24
19
 
25
- ## Key Features
26
- - **No Selenium/Chromium**: Baileys does not require Selenium or any other browser to interface with WhatsApp Web, saving massive amounts of RAM.
27
- - **Multi-Device Support**: Interacts natively with the multi-device and web versions of WhatsApp.
20
+ - **Group Participant Safety (1.1.5)**: Safe try-catch parsing for `messageStubParameters` preventing crashes on raw participant events.
21
+ - **Link Preview Safety (1.1.5)**: Silent fallback handling on link preview thumbnail fetch failures.
28
22
  - **Newsletter Media Patch**: Automatically maps correct CDN upload endpoints and formats stanzas so media displays perfectly in WhatsApp Channels.
29
23
  - **MessageBuilder v4.6 (Built-in)**: Chainable API for creating Buttons, Carousels, Native Flow messages, and AI Rich Response payloads natively from the library.
24
+ - **Legacy Store Helpers**:
25
+ - `makeInMemoryStore()`
26
+ - `loadMessages()`
27
+ - `fetchImageUrl()`
28
+ - `fetchGroupMetadata()`
29
+ - `fetchMessageReceipts()`
30
+ - **Legacy Export Aliases**:
31
+ - `isJidUser`
32
+ - `isJidNewsLetter`
33
+ - `MessageType`
34
+ - `Presence`
35
+ - `Mimetype`
36
+ - `WAFlag`
37
+ - `WA_MESSAGE_STUB_TYPES`
38
+ - **Receive & Meta AI / Bot Compatibility**:
39
+ - Meta AI / `@bot` `msmsg` replies via message-secret HKDF/AES-GCM decrypt.
40
+ - Automatic `remoteJidAlt` and `participantAlt` LID ↔ PN resolution.
41
+ - **Socket / Send Compatibility**:
42
+ - `setLabelGroup()`
43
+ - `sendStatusMention()`
44
+ - Kiu-style album/status/raw proto send branches.
45
+ - Android browser simulation support (`UserAgent.Platform.ANDROID`).
30
46
 
31
- ## Install
47
+ ---
32
48
 
33
- To install this custom patched version into your project, use:
49
+ ## Install
34
50
 
35
51
  ```bash
36
52
  npm install @blurose/baileys
37
53
  ```
38
54
 
39
- Then import it in your code:
40
-
41
- ```ts
42
- import makeWASocket from 'baileys' // (or whichever alias is configured)
55
+ ```js
56
+ const {
57
+ default: makeWASocket,
58
+ makeInMemoryStore,
59
+ isJidUser,
60
+ isJidNewsLetter,
61
+ MessageType,
62
+ Mimetype,
63
+ Button,
64
+ ButtonV2,
65
+ Carousel,
66
+ AIRich
67
+ } = require('@blurose/baileys')
68
+
69
+ const store = makeInMemoryStore({})
43
70
  ```
44
71
 
45
72
  ---
@@ -54,27 +81,21 @@ import makeWASocket from 'baileys' // (or whichever alias is configured)
54
81
  - [Caching Group Metadata (Recommended)](#caching-group-metadata-recommended)
55
82
  - [Improve Retry System & Decrypt Poll Votes](#improve-retry-system--decrypt-poll-votes)
56
83
  - [Receive Notifications in Whatsapp App](#receive-notifications-in-whatsapp-app)
57
- - [Save Auth Info](#saving--restoring-sessions)
84
+ - [Saving & Restoring Sessions](#saving--restoring-sessions)
58
85
  - [Handling Events](#handling-events)
59
86
  - [Implementing a Data Store](#implementing-a-data-store)
60
87
  - [Whatsapp IDs Explain](#whatsapp-ids-explain)
61
88
  - [Utility Functions](#utility-functions)
62
89
  - [Sending Messages](#sending-messages)
90
+ - [Non-Media Messages](#non-media-messages)
91
+ - [Media Messages & Newsletter Sending](#media-messages--newsletter-sending)
63
92
  - [MessageBuilder Documentation (UI Components)](#messagebuilder-documentation-ui-components)
64
93
  - [1. Button Builder (Button V1)](#1-button-builder-button-v1)
65
94
  - [2. ButtonV2 Builder (Native Flow)](#2-buttonv2-builder-native-flow)
66
95
  - [3. Carousel Builder](#3-carousel-builder)
67
96
  - [4. AIRich Builder (AI Rich Response)](#4-airich-builder-ai-rich-response)
68
- - [Modify Messages](#modify-messages)
69
- - [Manipulating Media Messages](#manipulating-media-messages)
70
- - [Reject Call](#reject-call)
71
- - [Send States in Chat](#send-states-in-chat)
72
- - [Modifying Chats](#modifying-chats)
73
- - [User Querys](#user-querys)
74
- - [Groups](#groups)
75
- - [Privacy](#privacy)
76
- - [Broadcast Lists & Stories](#broadcast-lists--stories)
77
- - [Writing Custom Functionality](#writing-custom-functionality)
97
+ - [Credits & Acknowledgements](#credits--acknowledgements)
98
+ - [License](#license)
78
99
 
79
100
  ---
80
101
 
@@ -85,10 +106,10 @@ WhatsApp provides a multi-device API that allows Baileys to be authenticated as
85
106
  ### Starting socket with **QR-CODE**
86
107
 
87
108
  ```ts
88
- import makeWASocket from 'baileys'
109
+ import makeWASocket from '@blurose/baileys'
89
110
 
90
111
  const sock = makeWASocket({
91
- browser: Browsers.ubuntu('My App'),
112
+ browser: ['Ubuntu', 'Chrome', '20.0.0'],
92
113
  printQRInTerminal: true
93
114
  })
94
115
  ```
@@ -98,26 +119,59 @@ If the connection is successful, you will see a QR code printed on your terminal
98
119
  ### Starting socket with **Pairing Code**
99
120
 
100
121
  ```ts
101
- import makeWASocket from 'baileys'
122
+ import makeWASocket from '@blurose/baileys'
102
123
 
103
124
  const sock = makeWASocket({
104
125
  printQRInTerminal: false
105
126
  })
106
127
 
107
128
  if (!sock.authState.creds.registered) {
108
- const number = 'XXXXXXXXXXX' // Country code + phone number without + or spacing
129
+ const number = '628XXXXXXXXX' // Country code + phone number without + or spacing
109
130
  const code = await sock.requestPairingCode(number)
110
131
  console.log(code)
111
132
  }
112
133
  ```
113
134
 
135
+ ### Receive Full History
136
+
137
+ ```ts
138
+ const sock = makeWASocket({
139
+ syncFullHistory: true
140
+ })
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Important Notes About Socket Config
146
+
147
+ ### Caching Group Metadata (Recommended)
148
+ - If you use Baileys for groups, we recommend setting `cachedGroupMetadata` in socket config:
149
+
150
+ ```ts
151
+ const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
152
+
153
+ const sock = makeWASocket({
154
+ cachedGroupMetadata: async (jid) => groupCache.get(jid)
155
+ })
156
+
157
+ sock.ev.on('groups.update', async ([event]) => {
158
+ const metadata = await sock.groupMetadata(event.id)
159
+ groupCache.set(event.id, metadata)
160
+ })
161
+
162
+ sock.ev.on('group-participants.update', async (event) => {
163
+ const metadata = await sock.groupMetadata(event.id)
164
+ groupCache.set(event.id, metadata)
165
+ })
166
+ ```
167
+
114
168
  ---
115
169
 
116
170
  ## Saving & Restoring Sessions
117
171
 
118
172
  Save credentials to log back in without scanning a QR code:
119
173
  ```ts
120
- import makeWASocket, { useMultiFileAuthState } from 'baileys'
174
+ import makeWASocket, { useMultiFileAuthState } from '@blurose/baileys'
121
175
 
122
176
  const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
123
177
 
@@ -127,6 +181,55 @@ sock.ev.on('creds.update', saveCreds)
127
181
 
128
182
  ---
129
183
 
184
+ ## Handling Events
185
+
186
+ ```ts
187
+ sock.ev.on('messages.upsert', ({ messages }) => {
188
+ console.log('got messages', messages)
189
+ })
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Implementing a Data Store
195
+
196
+ This custom fork restores `makeInMemoryStore` out of the box:
197
+
198
+ ```ts
199
+ import makeWASocket, { makeInMemoryStore } from '@blurose/baileys'
200
+
201
+ const store = makeInMemoryStore({})
202
+ store.readFromFile('./baileys_store.json')
203
+ setInterval(() => {
204
+ store.writeToFile('./baileys_store.json')
205
+ }, 10_000)
206
+
207
+ const sock = makeWASocket({})
208
+ store.bind(sock.ev)
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Whatsapp IDs Explain
214
+
215
+ - `jid` format:
216
+ - User: `[country code][phone number]@s.whatsapp.net` (e.g. `628123456789@s.whatsapp.net`)
217
+ - LID User: `[id]@lid`
218
+ - Group: `[timestamp]@g.us`
219
+ - Channel / Newsletter: `[id]@newsletter`
220
+ - Stories: `status@broadcast`
221
+
222
+ ---
223
+
224
+ ## Utility Functions
225
+
226
+ - `isJidUser(jid)`: Checks if JID is a phone number user.
227
+ - `isJidNewsletter(jid)` / `isJidNewsLetter(jid)`: Checks if JID is a WhatsApp Channel.
228
+ - `getContentType(message)`: Returns message content type.
229
+ - `downloadContentFromMessage(message, type)`: Downloads media content buffer.
230
+
231
+ ---
232
+
130
233
  ## Sending Messages
131
234
 
132
235
  ### Non-Media Messages
@@ -168,7 +271,7 @@ You can import the builders directly from the library:
168
271
  ```javascript
169
272
  const { Button, ButtonV2, Carousel, AIRich } = require('@blurose/baileys');
170
273
  // or when using ESM:
171
- // import { Button, ButtonV2, Carousel, AIRich } from 'baileys';
274
+ // import { Button, ButtonV2, Carousel, AIRich } from '@blurose/baileys';
172
275
  ```
173
276
 
174
277
  ### 1. Button Builder (Button V1)
@@ -280,10 +383,14 @@ Ini auto citation:
280
383
 
281
384
  ---
282
385
 
386
+ # Disclaimer
387
+ This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or its affiliates.
388
+ Use at your own discretion. Do not spam people with this. We discourage any stalkerware, bulk or automated messaging usage.
389
+
283
390
  # Credits & Acknowledgements
284
391
  - Forked from the official [WhiskeySockets/Baileys](https://github.com/WhiskeySockets/Baileys) project by **Rajeh Taher** and contributors.
285
- - Patch ideas and concepts incorporated from **wileys** package.
286
- - Patched, customized, and maintained by **Xyraa Team** & **alfavz**.
392
+ - Compatibility ideas and shims inspired by **KonaimaV2/baileys** (Arraffi) and **wileys**.
393
+ - Maintained & Developed by **Xyraa Team** & **alfavz**.
287
394
 
288
395
  # License
289
396
  Copyright (c) 2025 Rajeh Taher/WhiskeySockets & Xyraa Team. Licensed under the MIT License.
@@ -1393,6 +1393,20 @@ export const makeMessagesRecvSocket = (config) => {
1393
1393
  if (messageRetryManager && msg.key.id) {
1394
1394
  messageRetryManager.cancelPendingPhoneRequest(msg.key.id);
1395
1395
  }
1396
+ if (isLidUser(msg.key.participant) && msg.key.participantAlt) {
1397
+ msg.key.participant = msg.key.participantAlt;
1398
+ }
1399
+ if (!isJidGroup(msg.key.remoteJid) && isLidUser(msg.key.remoteJid) && msg.key.remoteJidAlt) {
1400
+ msg.key.remoteJid = msg.key.remoteJidAlt;
1401
+ }
1402
+ const quotedCtx = msg.message?.extendedTextMessage?.contextInfo;
1403
+ if (isJidGroup(msg.key.remoteJid) && isLidUser(quotedCtx?.participant)) {
1404
+ try {
1405
+ const metadata = await groupMetadata(msg.key.remoteJid);
1406
+ const found = metadata?.participants?.find(p => p.id === quotedCtx.participant || p.lid === quotedCtx.participant);
1407
+ quotedCtx.participant = found?.jid || found?.pn || quotedCtx.participant;
1408
+ } catch { }
1409
+ }
1396
1410
  const isNewsletter = isJidNewsletter(msg.key.remoteJid);
1397
1411
  if (!isNewsletter) {
1398
1412
  // no type in the receipt => message delivered
@@ -0,0 +1,19 @@
1
+ export type LegacyInMemoryStore = {
2
+ chats: Record<string, any>
3
+ contacts: Record<string, any>
4
+ messages: Record<string, any[] & { upsert?: (msg: any, mode?: string) => any, get?: (id: string) => any }>
5
+ groupMetadata: Record<string, any>
6
+ presences: Record<string, any>
7
+ state: Record<string, any>
8
+ bind: (ev: { on?: (event: string, listener: (...args: any[]) => void) => any }) => LegacyInMemoryStore
9
+ insertMessage: (msg: any, mode?: string) => any
10
+ loadMessage: (jid: string, id: string) => any
11
+ mostRecentMessage: (jid: string) => any
12
+ readFromFile: (path: string) => void
13
+ writeToFile: (path: string) => void
14
+ toJSON: () => any
15
+ }
16
+ export declare const makeInMemoryStore: (opts?: { logger?: any }) => LegacyInMemoryStore
17
+ export default makeInMemoryStore
18
+
19
+ export declare const makeCacheManagerAuthState: () => Promise<never>;
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Legacy makeInMemoryStore compatibility helper.
3
+ *
4
+ * Baileys v7 no longer ships the old Store folder used by many CJS bots.
5
+ * This lightweight store keeps the old surface MikirBot needs: chats, contacts,
6
+ * messages, bind(ev), readFromFile(), writeToFile(), loadMessage().
7
+ */
8
+ import { writeFileSync, readFileSync, existsSync } from 'fs'
9
+
10
+ const jidKey = (jid = '') => String(jid)
11
+ const messageId = (msg = {}) => msg?.key?.id || msg?.id || ''
12
+ const chatIdFromMessage = (msg = {}) => msg?.key?.remoteJid || msg?.chat || ''
13
+
14
+ const makeMessageBucket = () => {
15
+ const arr = []
16
+ arr.upsert = (msg, mode = 'append') => {
17
+ const id = messageId(msg)
18
+ const idx = id ? arr.findIndex((x) => messageId(x) === id) : -1
19
+ if (idx >= 0) arr[idx] = { ...arr[idx], ...msg }
20
+ else if (mode === 'prepend') arr.unshift(msg)
21
+ else arr.push(msg)
22
+ return msg
23
+ }
24
+ arr.get = (id) => arr.find((x) => messageId(x) === id)
25
+ arr.toJSON = () => Array.from(arr)
26
+ return arr
27
+ }
28
+
29
+ export const makeInMemoryStore = ({ logger } = {}) => {
30
+ const store = {
31
+ chats: {},
32
+ contacts: {},
33
+ messages: {},
34
+ groupMetadata: {},
35
+ presences: {},
36
+ labels: {},
37
+ labelAssociations: {},
38
+ state: {},
39
+ logger,
40
+
41
+ bind(ev) {
42
+ if (!ev?.on) return this
43
+
44
+ ev.on('messaging-history.set', ({ chats = [], contacts = [], messages = [], isLatest } = {}) => {
45
+ for (const chat of chats) if (chat?.id) this.chats[jidKey(chat.id)] = { ...(this.chats[jidKey(chat.id)] || {}), ...chat }
46
+ for (const contact of contacts) if (contact?.id) this.contacts[jidKey(contact.id)] = { ...(this.contacts[jidKey(contact.id)] || {}), ...contact }
47
+ for (const msg of messages) this.insertMessage(msg)
48
+ this.state.isLatest = isLatest
49
+ })
50
+
51
+ ev.on('chats.set', ({ chats = [] } = {}) => {
52
+ this.chats = {}
53
+ for (const chat of chats) if (chat?.id) this.chats[jidKey(chat.id)] = chat
54
+ })
55
+
56
+ ev.on('contacts.set', ({ contacts = [] } = {}) => {
57
+ this.contacts = {}
58
+ for (const contact of contacts) if (contact?.id) this.contacts[jidKey(contact.id)] = contact
59
+ })
60
+
61
+ ev.on('messages.set', ({ messages = [] } = {}) => {
62
+ this.messages = {}
63
+ for (const msg of messages) this.insertMessage(msg)
64
+ })
65
+
66
+ ev.on('chats.upsert', (chats = []) => {
67
+ for (const chat of chats) if (chat?.id) this.chats[jidKey(chat.id)] = { ...(this.chats[jidKey(chat.id)] || {}), ...chat }
68
+ })
69
+
70
+ ev.on('chats.update', (updates = []) => {
71
+ for (const update of updates) if (update?.id) this.chats[jidKey(update.id)] = { ...(this.chats[jidKey(update.id)] || {}), ...update }
72
+ })
73
+
74
+ ev.on('contacts.upsert', (contacts = []) => {
75
+ for (const contact of contacts) if (contact?.id) this.contacts[jidKey(contact.id)] = { ...(this.contacts[jidKey(contact.id)] || {}), ...contact }
76
+ })
77
+
78
+ ev.on('contacts.update', (updates = []) => {
79
+ for (const update of updates) if (update?.id) this.contacts[jidKey(update.id)] = { ...(this.contacts[jidKey(update.id)] || {}), ...update }
80
+ })
81
+
82
+ ev.on('messages.upsert', ({ messages = [], type } = {}) => {
83
+ const mode = type === 'prepend' ? 'prepend' : 'append'
84
+ for (const msg of messages) this.insertMessage(msg, mode)
85
+ })
86
+
87
+ ev.on('messages.update', (updates = []) => {
88
+ for (const update of updates) {
89
+ const jid = jidKey(update?.key?.remoteJid)
90
+ const id = update?.key?.id
91
+ if (!jid || !id || !this.messages[jid]) continue
92
+ const msg = this.messages[jid].get(id)
93
+ if (msg) Object.assign(msg, update.update || update)
94
+ }
95
+ })
96
+
97
+ ev.on('groups.update', (updates = []) => {
98
+ for (const update of updates) if (update?.id) this.groupMetadata[jidKey(update.id)] = { ...(this.groupMetadata[jidKey(update.id)] || {}), ...update }
99
+ })
100
+
101
+ ev.on('group-participants.update', ({ id, participants = [], action } = {}) => {
102
+ if (!id) return
103
+ const meta = this.groupMetadata[jidKey(id)] || { id, participants: [] }
104
+ const existing = new Map((meta.participants || []).map((p) => [p.id, p]))
105
+ if (action === 'remove') for (const jid of participants) existing.delete(jid)
106
+ else for (const jid of participants) if (!existing.has(jid)) existing.set(jid, { id: jid })
107
+ meta.participants = Array.from(existing.values())
108
+ this.groupMetadata[jidKey(id)] = meta
109
+ })
110
+
111
+ ev.on('presence.update', ({ id, presences } = {}) => {
112
+ if (id) this.presences[jidKey(id)] = presences || {}
113
+ })
114
+
115
+ return this
116
+ },
117
+
118
+ insertMessage(msg, mode = 'append') {
119
+ const jid = jidKey(chatIdFromMessage(msg))
120
+ if (!jid) return msg
121
+ if (!this.messages[jid]) this.messages[jid] = makeMessageBucket()
122
+ return this.messages[jid].upsert(msg, mode)
123
+ },
124
+
125
+ loadMessage(jid, id) {
126
+ return this.messages?.[jidKey(jid)]?.get?.(id)
127
+ },
128
+
129
+ loadMessages(jid, count = 25) {
130
+ const bucket = this.messages?.[jidKey(jid)] || []
131
+ return Array.from(bucket).slice(-count)
132
+ },
133
+
134
+ fetchImageUrl(jid) {
135
+ return this.contacts?.[jidKey(jid)]?.imgUrl || this.chats?.[jidKey(jid)]?.imgUrl
136
+ },
137
+
138
+ fetchGroupMetadata(jid) {
139
+ return this.groupMetadata?.[jidKey(jid)]
140
+ },
141
+
142
+ fetchMessageReceipts() {
143
+ return []
144
+ },
145
+
146
+ getLabels() { return this.labels || [] },
147
+ getChatLabels(jid) { return this.labelAssociations?.[jidKey(jid)] || [] },
148
+ getMessageLabels(jid, id) { return this.labelAssociations?.[`${jidKey(jid)}|${id}`] || [] },
149
+
150
+ mostRecentMessage(jid) {
151
+ const bucket = this.messages?.[jidKey(jid)] || []
152
+ return bucket[bucket.length - 1]
153
+ },
154
+
155
+ readFromFile(path) {
156
+ if (!existsSync(path)) return
157
+ const data = JSON.parse(readFileSync(path, 'utf8'))
158
+ this.chats = data.chats || {}
159
+ this.contacts = data.contacts || {}
160
+ this.groupMetadata = data.groupMetadata || {}
161
+ this.presences = data.presences || {}
162
+ this.labels = data.labels || {}
163
+ this.labelAssociations = data.labelAssociations || {}
164
+ this.state = data.state || {}
165
+ this.messages = {}
166
+ for (const [jid, messages] of Object.entries(data.messages || {})) {
167
+ const bucket = makeMessageBucket()
168
+ for (const msg of messages || []) bucket.upsert(msg)
169
+ this.messages[jid] = bucket
170
+ }
171
+ },
172
+
173
+ writeToFile(path) {
174
+ const messages = {}
175
+ for (const [jid, bucket] of Object.entries(this.messages || {})) messages[jid] = Array.from(bucket || [])
176
+ writeFileSync(path, JSON.stringify({
177
+ chats: this.chats,
178
+ contacts: this.contacts,
179
+ messages,
180
+ groupMetadata: this.groupMetadata,
181
+ presences: this.presences,
182
+ labels: this.labels,
183
+ labelAssociations: this.labelAssociations,
184
+ state: this.state
185
+ }, null, 2))
186
+ },
187
+
188
+ toJSON() {
189
+ const messages = {}
190
+ for (const [jid, bucket] of Object.entries(this.messages || {})) messages[jid] = Array.from(bucket || [])
191
+ return {
192
+ chats: this.chats,
193
+ contacts: this.contacts,
194
+ messages,
195
+ groupMetadata: this.groupMetadata,
196
+ presences: this.presences,
197
+ labels: this.labels,
198
+ labelAssociations: this.labelAssociations,
199
+ state: this.state
200
+ }
201
+ }
202
+ }
203
+
204
+ return store
205
+ }
206
+
207
+ export default makeInMemoryStore
208
+
209
+
210
+ /**
211
+ * Kiu/@z4phdev legacy export placeholder.
212
+ * The modern auth path should use useMultiFileAuthState(), but exposing this
213
+ * name prevents old imports from crashing. It intentionally fails loudly if
214
+ * someone tries to use the unimplemented cache-manager auth backend.
215
+ */
216
+ export const makeCacheManagerAuthState = async () => {
217
+ throw new Error('makeCacheManagerAuthState is not implemented in @konaa/baileys; use useMultiFileAuthState instead')
218
+ }
@@ -486,32 +486,68 @@ export const generateWAMessageContent = async (message, options) => {
486
486
  };
487
487
  }
488
488
  else if (hasNonNullishProperty(message, 'buttons')) {
489
- const buttonsMessage = {
490
- contentText: message.text || message.caption || '',
491
- footerText: message.footer || '',
492
- buttons: message.buttons,
493
- headerType: 1
494
- };
489
+ let header = {};
495
490
  if (hasNonNullishProperty(message, 'image')) {
496
491
  const { imageMessage } = await prepareWAMessageMedia({ image: message.image }, options);
497
- buttonsMessage.imageMessage = imageMessage;
498
- buttonsMessage.headerType = 4;
492
+ header = {
493
+ title: message.title || '',
494
+ hasMediaAttachment: true,
495
+ imageMessage
496
+ };
499
497
  }
500
498
  else if (hasNonNullishProperty(message, 'video')) {
501
499
  const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options);
502
- buttonsMessage.videoMessage = videoMessage;
503
- buttonsMessage.headerType = 5;
500
+ header = {
501
+ title: message.title || '',
502
+ hasMediaAttachment: true,
503
+ videoMessage
504
+ };
504
505
  }
505
506
  else if (hasNonNullishProperty(message, 'document')) {
506
507
  const { documentMessage } = await prepareWAMessageMedia({ document: message.document }, options);
507
- buttonsMessage.documentMessage = documentMessage;
508
- buttonsMessage.headerType = 3;
508
+ header = {
509
+ title: message.title || '',
510
+ hasMediaAttachment: true,
511
+ documentMessage
512
+ };
509
513
  }
510
514
  else if (hasNonNullishProperty(message, 'location')) {
511
- buttonsMessage.locationMessage = message.location;
512
- buttonsMessage.headerType = 6;
515
+ header = {
516
+ title: message.title || '',
517
+ hasMediaAttachment: true,
518
+ locationMessage: message.location
519
+ };
513
520
  }
514
- m.buttonsMessage = buttonsMessage;
521
+ else if (message.title) {
522
+ header = {
523
+ title: message.title,
524
+ hasMediaAttachment: false
525
+ };
526
+ }
527
+
528
+ m.interactiveMessage = {
529
+ header: Object.keys(header).length ? header : undefined,
530
+ body: {
531
+ text: message.text || message.caption || ''
532
+ },
533
+ footer: message.footer ? {
534
+ text: message.footer
535
+ } : undefined,
536
+ nativeFlowMessage: {
537
+ buttons: message.buttons.map(btn => {
538
+ if (btn.buttonText?.displayText) {
539
+ return {
540
+ name: 'quick_reply',
541
+ buttonParamsJson: JSON.stringify({
542
+ display_text: btn.buttonText.displayText,
543
+ id: btn.buttonId || ''
544
+ })
545
+ };
546
+ }
547
+ return btn;
548
+ })
549
+ }
550
+ };
515
551
  }
516
552
  else {
517
553
  m = await prepareWAMessageMedia(message, options);
@@ -507,12 +507,26 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
507
507
  const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid.phoneNumber)); // ADD SUPPORT FOR LID
508
508
  switch (message.messageStubType) {
509
509
  case WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
510
- participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
510
+ participants = message.messageStubParameters.map((a) => {
511
+ try {
512
+ return JSON.parse(a);
513
+ }
514
+ catch (_a) {
515
+ return a;
516
+ }
517
+ }) || [];
511
518
  emitParticipantsUpdate('modify');
512
519
  break;
513
520
  case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
514
521
  case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
515
- participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
522
+ participants = message.messageStubParameters.map((a) => {
523
+ try {
524
+ return JSON.parse(a);
525
+ }
526
+ catch (_a) {
527
+ return a;
528
+ }
529
+ }) || [];
516
530
  emitParticipantsUpdate('remove');
517
531
  // mark the chat read only if you left the group
518
532
  if (participantsIncludesMe()) {
@@ -522,18 +536,39 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
522
536
  case WAMessageStubType.GROUP_PARTICIPANT_ADD:
523
537
  case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
524
538
  case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
525
- participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
539
+ participants = message.messageStubParameters.map((a) => {
540
+ try {
541
+ return JSON.parse(a);
542
+ }
543
+ catch (_a) {
544
+ return a;
545
+ }
546
+ }) || [];
526
547
  if (participantsIncludesMe()) {
527
548
  chat.readOnly = false;
528
549
  }
529
550
  emitParticipantsUpdate('add');
530
551
  break;
531
552
  case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
532
- participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
553
+ participants = message.messageStubParameters.map((a) => {
554
+ try {
555
+ return JSON.parse(a);
556
+ }
557
+ catch (_a) {
558
+ return a;
559
+ }
560
+ }) || [];
533
561
  emitParticipantsUpdate('demote');
534
562
  break;
535
563
  case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
536
- participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
564
+ participants = message.messageStubParameters.map((a) => {
565
+ try {
566
+ return JSON.parse(a);
567
+ }
568
+ catch (_a) {
569
+ return a;
570
+ }
571
+ }) || [];
537
572
  emitParticipantsUpdate('promote');
538
573
  break;
539
574
  case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
@@ -43,7 +43,9 @@ const getClientPayload = (config) => {
43
43
  connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
44
44
  userAgent: getUserAgent(config)
45
45
  };
46
- payload.webInfo = getWebInfo(config);
46
+ if (!config.browser[1].toLocaleLowerCase().includes('android')) {
47
+ payload.webInfo = getWebInfo(config);
48
+ }
47
49
  if (config.pushName) {
48
50
  payload.pushName = config.pushName;
49
51
  }
@@ -64,6 +66,9 @@ export const generateLoginNode = (userJid, config) => {
64
66
  };
65
67
  const getPlatformType = (platform) => {
66
68
  const platformType = platform.toUpperCase();
69
+ if (platformType === 'ANDROID') {
70
+ return proto.DeviceProps.PlatformType.ANDROID_PHONE;
71
+ }
67
72
  return (proto.DeviceProps.PlatformType[platformType] ||
68
73
  proto.DeviceProps.PlatformType.CHROME);
69
74
  };
@@ -63,6 +63,8 @@ export const areJidsSameUser = (jid1, jid2) => jidDecode(jid1)?.user === jidDeco
63
63
  export const isJidMetaAI = (jid) => jid?.endsWith('@bot');
64
64
  /** is the jid a PN user */
65
65
  export const isPnUser = (jid) => jid?.endsWith('@s.whatsapp.net');
66
+ // Kiu/@z4phdev legacy alias
67
+ export const isJidUser = isPnUser;
66
68
  /** is the jid a LID */
67
69
  export const isLidUser = (jid) => jid?.endsWith('@lid');
68
70
  /** is the jid a broadcast */
@@ -73,6 +75,8 @@ export const isJidGroup = (jid) => jid?.endsWith('@g.us');
73
75
  export const isJidStatusBroadcast = (jid) => jid === 'status@broadcast';
74
76
  /** is the jid a newsletter */
75
77
  export const isJidNewsletter = (jid) => jid?.endsWith('@newsletter');
78
+ // Kiu/@z4phdev legacy typo-cased alias
79
+ export const isJidNewsLetter = isJidNewsletter;
76
80
  /** is the jid a hosted PN */
77
81
  export const isHostedPnUser = (jid) => jid?.endsWith('@hosted');
78
82
  /** is the jid a hosted LID */
@@ -87,6 +91,73 @@ export const jidNormalizedUser = (jid) => {
87
91
  const { user, server } = result;
88
92
  return jidEncode(user, server === 'c.us' ? 's.whatsapp.net' : server);
89
93
  };
94
+
95
+ // Compatibility helper inspired by Elaina Baileys.
96
+ // This is a suffix-level fallback only; it is not a real LID↔PN resolver.
97
+ export const lidToJid = (jid) => jid && jid.endsWith('@lid') ? jid.replace('@lid', '@s.whatsapp.net') : jid;
98
+
99
+ // Meta bot id compatibility map inspired by Elaina Baileys.
100
+ const BOT_JID_MAP = new Map([
101
+ ['867051314767696', '13135550002'],
102
+ ['1061492271844689', '13135550005'],
103
+ ['245886058483988', '13135550009'],
104
+ ['3509905702656130', '13135550012'],
105
+ ['1059680132034576', '13135550013'],
106
+ ['715681030623646', '13135550014'],
107
+ ['1644971366323052', '13135550015'],
108
+ ['582497970646566', '13135550019'],
109
+ ['645459357769306', '13135550022'],
110
+ ['294997126699143', '13135550023'],
111
+ ['1522631578502677', '13135550027'],
112
+ ['719421926276396', '13135550030'],
113
+ ['1788488635002167', '13135550031'],
114
+ ['24232338603080193', '13135550033'],
115
+ ['689289903143209', '13135550035'],
116
+ ['871626054177096', '13135550039'],
117
+ ['362351902849370', '13135550042'],
118
+ ['1744617646041527', '13135550043'],
119
+ ['893887762270570', '13135550046'],
120
+ ['1155032702135830', '13135550047'],
121
+ ['333931965993883', '13135550048'],
122
+ ['853748013058752', '13135550049'],
123
+ ['1559068611564819', '13135550053'],
124
+ ['890487432705716', '13135550054'],
125
+ ['240254602395494', '13135550055'],
126
+ ['1578420349663261', '13135550062'],
127
+ ['322908887140421', '13135550065'],
128
+ ['3713961535514771', '13135550067'],
129
+ ['997884654811738', '13135550070'],
130
+ ['403157239387035', '13135550081'],
131
+ ['535242369074963', '13135550082'],
132
+ ['946293427247659', '13135550083'],
133
+ ['3664707673802291', '13135550084'],
134
+ ['1821827464894892', '13135550085'],
135
+ ['1760312477828757', '13135550086'],
136
+ ['439480398712216', '13135550087'],
137
+ ['1876735582800984', '13135550088'],
138
+ ['984025089825661', '13135550089'],
139
+ ['1001336351558186', '13135550090'],
140
+ ['3739346336347061', '13135550091'],
141
+ ['3632749426974980', '13135550092'],
142
+ ['427864203481615', '13135550093'],
143
+ ['1434734570493055', '13135550094'],
144
+ ['992873449225921', '13135550095'],
145
+ ['813087747426445', '13135550096'],
146
+ ['806369104931434', '13135550098'],
147
+ ['1220982902403148', '13135550099'],
148
+ ['1365893374104393', '13135550100'],
149
+ ['491811473512352', '13165550064'],
150
+ ]);
151
+
152
+ export const getBotJid = (jid) => {
153
+ const sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1;
154
+ if (sepIdx < 0) return jid;
155
+ const server = jid.slice(sepIdx + 1);
156
+ if (server !== 'bot') return jid;
157
+ const user = jid.slice(0, sepIdx);
158
+ const mappedNumber = BOT_JID_MAP.get(user);
159
+ return mappedNumber ? `${mappedNumber}@s.whatsapp.net` : jid;
160
+ };
90
161
  export const transferDevice = (fromJid, toJid) => {
91
162
  const fromDecoded = jidDecode(fromJid);
92
163
  const deviceId = fromDecoded?.device || 0;
package/lib/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import makeWASocket from './Socket/index.js';
2
+ import { proto } from '../WAProto/index.js';
2
3
  export * from '../WAProto/index.js';
3
4
  export * from './Utils/index.js';
4
5
  export * from './Types/index.js';
@@ -6,6 +7,57 @@ export * from './Defaults/index.js';
6
7
  export * from './WABinary/index.js';
7
8
  export * from './WAM/index.js';
8
9
  export * from './WAUSync/index.js';
10
+ export * from './Store/index.js';
11
+ // Kiu/@z4phdev legacy root exports.
12
+ export const MessageType = {
13
+ text: 'conversation',
14
+ extendedText: 'extendedTextMessage',
15
+ image: 'imageMessage',
16
+ video: 'videoMessage',
17
+ audio: 'audioMessage',
18
+ sticker: 'stickerMessage',
19
+ document: 'documentMessage',
20
+ contact: 'contactMessage',
21
+ contactsArray: 'contactsArrayMessage',
22
+ location: 'locationMessage',
23
+ liveLocation: 'liveLocationMessage',
24
+ buttons: 'buttonsMessage',
25
+ template: 'templateMessage',
26
+ list: 'listMessage',
27
+ reaction: 'reactionMessage',
28
+ pollCreation: 'pollCreationMessage',
29
+ pollUpdate: 'pollUpdateMessage'
30
+ };
31
+ export const Presence = {
32
+ available: 'available',
33
+ unavailable: 'unavailable',
34
+ composing: 'composing',
35
+ recording: 'recording',
36
+ paused: 'paused'
37
+ };
38
+ export const Mimetype = {
39
+ jpeg: 'image/jpeg',
40
+ jpg: 'image/jpeg',
41
+ png: 'image/png',
42
+ gif: 'image/gif',
43
+ webp: 'image/webp',
44
+ mp4: 'video/mp4',
45
+ mp3: 'audio/mpeg',
46
+ ogg: 'audio/ogg; codecs=opus',
47
+ opus: 'audio/ogg; codecs=opus',
48
+ pdf: 'application/pdf',
49
+ doc: 'application/msword',
50
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
51
+ xls: 'application/vnd.ms-excel',
52
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
53
+ ppt: 'application/vnd.ms-powerpoint',
54
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
55
+ json: 'application/json',
56
+ zip: 'application/zip',
57
+ txt: 'text/plain'
58
+ };
59
+ export const WAFlag = { ignore: 'ignore', ack: 'ack', unavailable: 'unavailable' };
60
+ export const WA_MESSAGE_STUB_TYPES = proto.WebMessageInfo?.StubType || {};
9
61
  export { makeWASocket };
10
62
  export default makeWASocket;
11
63
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blurose/baileys",
3
3
  "type": "module",
4
- "version": "1.1.3",
4
+ "version": "1.1.5",
5
5
  "description": "A WebSockets library for interacting with WhatsApp Web",
6
6
  "keywords": [
7
7
  "whatsapp",