@blurose/baileys 1.1.2 → 1.1.4
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 +145 -40
- package/lib/Socket/messages-recv.js +14 -0
- package/lib/Store/index.d.ts +19 -0
- package/lib/Store/index.js +218 -0
- package/lib/Utils/messages.js +51 -15
- package/lib/Utils/validate-connection.js +6 -1
- package/lib/WABinary/jid-utils.js +71 -0
- package/lib/index.js +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,45 +1,70 @@
|
|
|
1
|
-
<h1 align='center'><img alt="Baileys logo" src="https://veracloud.biz.id/
|
|
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
|
|
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` (
|
|
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
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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.4**
|
|
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.
|
|
28
20
|
- **Newsletter Media Patch**: Automatically maps correct CDN upload endpoints and formats stanzas so media displays perfectly in WhatsApp Channels.
|
|
29
21
|
- **MessageBuilder v4.6 (Built-in)**: Chainable API for creating Buttons, Carousels, Native Flow messages, and AI Rich Response payloads natively from the library.
|
|
22
|
+
- **Legacy Store Helpers**:
|
|
23
|
+
- `makeInMemoryStore()`
|
|
24
|
+
- `loadMessages()`
|
|
25
|
+
- `fetchImageUrl()`
|
|
26
|
+
- `fetchGroupMetadata()`
|
|
27
|
+
- `fetchMessageReceipts()`
|
|
28
|
+
- **Legacy Export Aliases**:
|
|
29
|
+
- `isJidUser`
|
|
30
|
+
- `isJidNewsLetter`
|
|
31
|
+
- `MessageType`
|
|
32
|
+
- `Presence`
|
|
33
|
+
- `Mimetype`
|
|
34
|
+
- `WAFlag`
|
|
35
|
+
- `WA_MESSAGE_STUB_TYPES`
|
|
36
|
+
- **Receive & Meta AI / Bot Compatibility**:
|
|
37
|
+
- Meta AI / `@bot` `msmsg` replies via message-secret HKDF/AES-GCM decrypt.
|
|
38
|
+
- Automatic `remoteJidAlt` and `participantAlt` LID ↔ PN resolution.
|
|
39
|
+
- **Socket / Send Compatibility**:
|
|
40
|
+
- `setLabelGroup()`
|
|
41
|
+
- `sendStatusMention()`
|
|
42
|
+
- Kiu-style album/status/raw proto send branches.
|
|
43
|
+
- Android browser simulation support (`UserAgent.Platform.ANDROID`).
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
---
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
## Install
|
|
34
48
|
|
|
35
49
|
```bash
|
|
36
50
|
npm install @blurose/baileys
|
|
37
51
|
```
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
```js
|
|
54
|
+
const {
|
|
55
|
+
default: makeWASocket,
|
|
56
|
+
makeInMemoryStore,
|
|
57
|
+
isJidUser,
|
|
58
|
+
isJidNewsLetter,
|
|
59
|
+
MessageType,
|
|
60
|
+
Mimetype,
|
|
61
|
+
Button,
|
|
62
|
+
ButtonV2,
|
|
63
|
+
Carousel,
|
|
64
|
+
AIRich
|
|
65
|
+
} = require('@blurose/baileys')
|
|
66
|
+
|
|
67
|
+
const store = makeInMemoryStore({})
|
|
43
68
|
```
|
|
44
69
|
|
|
45
70
|
---
|
|
@@ -54,27 +79,21 @@ import makeWASocket from 'baileys' // (or whichever alias is configured)
|
|
|
54
79
|
- [Caching Group Metadata (Recommended)](#caching-group-metadata-recommended)
|
|
55
80
|
- [Improve Retry System & Decrypt Poll Votes](#improve-retry-system--decrypt-poll-votes)
|
|
56
81
|
- [Receive Notifications in Whatsapp App](#receive-notifications-in-whatsapp-app)
|
|
57
|
-
- [
|
|
82
|
+
- [Saving & Restoring Sessions](#saving--restoring-sessions)
|
|
58
83
|
- [Handling Events](#handling-events)
|
|
59
84
|
- [Implementing a Data Store](#implementing-a-data-store)
|
|
60
85
|
- [Whatsapp IDs Explain](#whatsapp-ids-explain)
|
|
61
86
|
- [Utility Functions](#utility-functions)
|
|
62
87
|
- [Sending Messages](#sending-messages)
|
|
88
|
+
- [Non-Media Messages](#non-media-messages)
|
|
89
|
+
- [Media Messages & Newsletter Sending](#media-messages--newsletter-sending)
|
|
63
90
|
- [MessageBuilder Documentation (UI Components)](#messagebuilder-documentation-ui-components)
|
|
64
91
|
- [1. Button Builder (Button V1)](#1-button-builder-button-v1)
|
|
65
92
|
- [2. ButtonV2 Builder (Native Flow)](#2-buttonv2-builder-native-flow)
|
|
66
93
|
- [3. Carousel Builder](#3-carousel-builder)
|
|
67
94
|
- [4. AIRich Builder (AI Rich Response)](#4-airich-builder-ai-rich-response)
|
|
68
|
-
- [
|
|
69
|
-
- [
|
|
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)
|
|
95
|
+
- [Credits & Acknowledgements](#credits--acknowledgements)
|
|
96
|
+
- [License](#license)
|
|
78
97
|
|
|
79
98
|
---
|
|
80
99
|
|
|
@@ -85,10 +104,10 @@ WhatsApp provides a multi-device API that allows Baileys to be authenticated as
|
|
|
85
104
|
### Starting socket with **QR-CODE**
|
|
86
105
|
|
|
87
106
|
```ts
|
|
88
|
-
import makeWASocket from 'baileys'
|
|
107
|
+
import makeWASocket from '@blurose/baileys'
|
|
89
108
|
|
|
90
109
|
const sock = makeWASocket({
|
|
91
|
-
browser:
|
|
110
|
+
browser: ['Ubuntu', 'Chrome', '20.0.0'],
|
|
92
111
|
printQRInTerminal: true
|
|
93
112
|
})
|
|
94
113
|
```
|
|
@@ -98,26 +117,59 @@ If the connection is successful, you will see a QR code printed on your terminal
|
|
|
98
117
|
### Starting socket with **Pairing Code**
|
|
99
118
|
|
|
100
119
|
```ts
|
|
101
|
-
import makeWASocket from 'baileys'
|
|
120
|
+
import makeWASocket from '@blurose/baileys'
|
|
102
121
|
|
|
103
122
|
const sock = makeWASocket({
|
|
104
123
|
printQRInTerminal: false
|
|
105
124
|
})
|
|
106
125
|
|
|
107
126
|
if (!sock.authState.creds.registered) {
|
|
108
|
-
const number = '
|
|
127
|
+
const number = '628XXXXXXXXX' // Country code + phone number without + or spacing
|
|
109
128
|
const code = await sock.requestPairingCode(number)
|
|
110
129
|
console.log(code)
|
|
111
130
|
}
|
|
112
131
|
```
|
|
113
132
|
|
|
133
|
+
### Receive Full History
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const sock = makeWASocket({
|
|
137
|
+
syncFullHistory: true
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Important Notes About Socket Config
|
|
144
|
+
|
|
145
|
+
### Caching Group Metadata (Recommended)
|
|
146
|
+
- If you use Baileys for groups, we recommend setting `cachedGroupMetadata` in socket config:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
|
|
150
|
+
|
|
151
|
+
const sock = makeWASocket({
|
|
152
|
+
cachedGroupMetadata: async (jid) => groupCache.get(jid)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
sock.ev.on('groups.update', async ([event]) => {
|
|
156
|
+
const metadata = await sock.groupMetadata(event.id)
|
|
157
|
+
groupCache.set(event.id, metadata)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
sock.ev.on('group-participants.update', async (event) => {
|
|
161
|
+
const metadata = await sock.groupMetadata(event.id)
|
|
162
|
+
groupCache.set(event.id, metadata)
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
114
166
|
---
|
|
115
167
|
|
|
116
168
|
## Saving & Restoring Sessions
|
|
117
169
|
|
|
118
170
|
Save credentials to log back in without scanning a QR code:
|
|
119
171
|
```ts
|
|
120
|
-
import makeWASocket, { useMultiFileAuthState } from 'baileys'
|
|
172
|
+
import makeWASocket, { useMultiFileAuthState } from '@blurose/baileys'
|
|
121
173
|
|
|
122
174
|
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
|
|
123
175
|
|
|
@@ -127,6 +179,55 @@ sock.ev.on('creds.update', saveCreds)
|
|
|
127
179
|
|
|
128
180
|
---
|
|
129
181
|
|
|
182
|
+
## Handling Events
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
186
|
+
console.log('got messages', messages)
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Implementing a Data Store
|
|
193
|
+
|
|
194
|
+
This custom fork restores `makeInMemoryStore` out of the box:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import makeWASocket, { makeInMemoryStore } from '@blurose/baileys'
|
|
198
|
+
|
|
199
|
+
const store = makeInMemoryStore({})
|
|
200
|
+
store.readFromFile('./baileys_store.json')
|
|
201
|
+
setInterval(() => {
|
|
202
|
+
store.writeToFile('./baileys_store.json')
|
|
203
|
+
}, 10_000)
|
|
204
|
+
|
|
205
|
+
const sock = makeWASocket({})
|
|
206
|
+
store.bind(sock.ev)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Whatsapp IDs Explain
|
|
212
|
+
|
|
213
|
+
- `jid` format:
|
|
214
|
+
- User: `[country code][phone number]@s.whatsapp.net` (e.g. `628123456789@s.whatsapp.net`)
|
|
215
|
+
- LID User: `[id]@lid`
|
|
216
|
+
- Group: `[timestamp]@g.us`
|
|
217
|
+
- Channel / Newsletter: `[id]@newsletter`
|
|
218
|
+
- Stories: `status@broadcast`
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Utility Functions
|
|
223
|
+
|
|
224
|
+
- `isJidUser(jid)`: Checks if JID is a phone number user.
|
|
225
|
+
- `isJidNewsletter(jid)` / `isJidNewsLetter(jid)`: Checks if JID is a WhatsApp Channel.
|
|
226
|
+
- `getContentType(message)`: Returns message content type.
|
|
227
|
+
- `downloadContentFromMessage(message, type)`: Downloads media content buffer.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
130
231
|
## Sending Messages
|
|
131
232
|
|
|
132
233
|
### Non-Media Messages
|
|
@@ -168,7 +269,7 @@ You can import the builders directly from the library:
|
|
|
168
269
|
```javascript
|
|
169
270
|
const { Button, ButtonV2, Carousel, AIRich } = require('@blurose/baileys');
|
|
170
271
|
// or when using ESM:
|
|
171
|
-
// import { Button, ButtonV2, Carousel, AIRich } from 'baileys';
|
|
272
|
+
// import { Button, ButtonV2, Carousel, AIRich } from '@blurose/baileys';
|
|
172
273
|
```
|
|
173
274
|
|
|
174
275
|
### 1. Button Builder (Button V1)
|
|
@@ -280,10 +381,14 @@ Ini auto citation:
|
|
|
280
381
|
|
|
281
382
|
---
|
|
282
383
|
|
|
384
|
+
# Disclaimer
|
|
385
|
+
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.
|
|
386
|
+
Use at your own discretion. Do not spam people with this. We discourage any stalkerware, bulk or automated messaging usage.
|
|
387
|
+
|
|
283
388
|
# Credits & Acknowledgements
|
|
284
389
|
- Forked from the official [WhiskeySockets/Baileys](https://github.com/WhiskeySockets/Baileys) project by **Rajeh Taher** and contributors.
|
|
285
|
-
-
|
|
286
|
-
-
|
|
390
|
+
- Compatibility ideas and shims inspired by **KonaimaV2/baileys** (Arraffi) and **wileys**.
|
|
391
|
+
- Maintained & Developed by **Xyraa Team** & **alfavz**.
|
|
287
392
|
|
|
288
393
|
# License
|
|
289
394
|
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
|
+
}
|
package/lib/Utils/messages.js
CHANGED
|
@@ -486,32 +486,68 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
486
486
|
};
|
|
487
487
|
}
|
|
488
488
|
else if (hasNonNullishProperty(message, 'buttons')) {
|
|
489
|
-
|
|
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
|
-
|
|
498
|
-
|
|
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
|
-
|
|
503
|
-
|
|
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
|
-
|
|
508
|
-
|
|
508
|
+
header = {
|
|
509
|
+
title: message.title || '',
|
|
510
|
+
hasMediaAttachment: true,
|
|
511
|
+
documentMessage
|
|
512
|
+
};
|
|
509
513
|
}
|
|
510
514
|
else if (hasNonNullishProperty(message, 'location')) {
|
|
511
|
-
|
|
512
|
-
|
|
515
|
+
header = {
|
|
516
|
+
title: message.title || '',
|
|
517
|
+
hasMediaAttachment: true,
|
|
518
|
+
locationMessage: message.location
|
|
519
|
+
};
|
|
513
520
|
}
|
|
514
|
-
|
|
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);
|
|
@@ -43,7 +43,9 @@ const getClientPayload = (config) => {
|
|
|
43
43
|
connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
|
|
44
44
|
userAgent: getUserAgent(config)
|
|
45
45
|
};
|
|
46
|
-
|
|
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
|