@oxidezap/baileyrs 0.0.7
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/LICENSE +21 -0
- package/README.md +490 -0
- package/WAProto/index.d.ts +13875 -0
- package/WAProto/index.js +175 -0
- package/lib/Defaults/index.d.ts +9 -0
- package/lib/Defaults/index.d.ts.map +1 -0
- package/lib/Defaults/index.js +32 -0
- package/lib/Defaults/index.js.map +1 -0
- package/lib/Socket/blocking.d.ts +6 -0
- package/lib/Socket/blocking.d.ts.map +1 -0
- package/lib/Socket/blocking.js +9 -0
- package/lib/Socket/blocking.js.map +1 -0
- package/lib/Socket/chat-actions.d.ts +32 -0
- package/lib/Socket/chat-actions.d.ts.map +1 -0
- package/lib/Socket/chat-actions.js +78 -0
- package/lib/Socket/chat-actions.js.map +1 -0
- package/lib/Socket/contacts.d.ts +10 -0
- package/lib/Socket/contacts.d.ts.map +1 -0
- package/lib/Socket/contacts.js +21 -0
- package/lib/Socket/contacts.js.map +1 -0
- package/lib/Socket/events.d.ts +10 -0
- package/lib/Socket/events.d.ts.map +1 -0
- package/lib/Socket/events.js +293 -0
- package/lib/Socket/events.js.map +1 -0
- package/lib/Socket/groups.d.ts +28 -0
- package/lib/Socket/groups.d.ts.map +1 -0
- package/lib/Socket/groups.js +90 -0
- package/lib/Socket/groups.js.map +1 -0
- package/lib/Socket/index.d.ts +202 -0
- package/lib/Socket/index.d.ts.map +1 -0
- package/lib/Socket/index.js +378 -0
- package/lib/Socket/index.js.map +1 -0
- package/lib/Socket/messages.d.ts +42 -0
- package/lib/Socket/messages.d.ts.map +1 -0
- package/lib/Socket/messages.js +172 -0
- package/lib/Socket/messages.js.map +1 -0
- package/lib/Socket/newsletter.d.ts +9 -0
- package/lib/Socket/newsletter.d.ts.map +1 -0
- package/lib/Socket/newsletter.js +18 -0
- package/lib/Socket/newsletter.js.map +1 -0
- package/lib/Socket/presence.d.ts +7 -0
- package/lib/Socket/presence.d.ts.map +1 -0
- package/lib/Socket/presence.js +12 -0
- package/lib/Socket/presence.js.map +1 -0
- package/lib/Socket/profile.d.ts +14 -0
- package/lib/Socket/profile.d.ts.map +1 -0
- package/lib/Socket/profile.js +36 -0
- package/lib/Socket/profile.js.map +1 -0
- package/lib/Socket/transport.d.ts +12 -0
- package/lib/Socket/transport.d.ts.map +1 -0
- package/lib/Socket/transport.js +90 -0
- package/lib/Socket/transport.js.map +1 -0
- package/lib/Socket/types.d.ts +30 -0
- package/lib/Socket/types.d.ts.map +1 -0
- package/lib/Socket/types.js +3 -0
- package/lib/Socket/types.js.map +1 -0
- package/lib/Types/Auth.d.ts +144 -0
- package/lib/Types/Auth.d.ts.map +1 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Auth.js.map +1 -0
- package/lib/Types/BinaryNode.d.ts +15 -0
- package/lib/Types/BinaryNode.d.ts.map +1 -0
- package/lib/Types/BinaryNode.js +2 -0
- package/lib/Types/BinaryNode.js.map +1 -0
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.d.ts.map +1 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Bussines.js.map +1 -0
- package/lib/Types/Call.d.ts +15 -0
- package/lib/Types/Call.d.ts.map +1 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Call.js.map +1 -0
- package/lib/Types/Chat.d.ts +123 -0
- package/lib/Types/Chat.d.ts.map +1 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Chat.js.map +1 -0
- package/lib/Types/Contact.d.ts +24 -0
- package/lib/Types/Contact.d.ts.map +1 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Contact.js.map +1 -0
- package/lib/Types/Events.d.ts +238 -0
- package/lib/Types/Events.d.ts.map +1 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/Events.js.map +1 -0
- package/lib/Types/GroupMetadata.d.ts +67 -0
- package/lib/Types/GroupMetadata.d.ts.map +1 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/GroupMetadata.js.map +1 -0
- package/lib/Types/Label.d.ts +47 -0
- package/lib/Types/Label.d.ts.map +1 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/Label.js.map +1 -0
- package/lib/Types/LabelAssociation.d.ts +30 -0
- package/lib/Types/LabelAssociation.d.ts.map +1 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/LabelAssociation.js.map +1 -0
- package/lib/Types/Message.d.ts +298 -0
- package/lib/Types/Message.d.ts.map +1 -0
- package/lib/Types/Message.js +12 -0
- package/lib/Types/Message.js.map +1 -0
- package/lib/Types/Newsletter.d.ts +98 -0
- package/lib/Types/Newsletter.d.ts.map +1 -0
- package/lib/Types/Newsletter.js +31 -0
- package/lib/Types/Newsletter.js.map +1 -0
- package/lib/Types/Socket.d.ts +54 -0
- package/lib/Types/Socket.d.ts.map +1 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/Socket.js.map +1 -0
- package/lib/Types/State.d.ts +29 -0
- package/lib/Types/State.d.ts.map +1 -0
- package/lib/Types/State.js +2 -0
- package/lib/Types/State.js.map +1 -0
- package/lib/Types/index.d.ts +60 -0
- package/lib/Types/index.d.ts.map +1 -0
- package/lib/Types/index.js +25 -0
- package/lib/Types/index.js.map +1 -0
- package/lib/Utils/browser-utils.d.ts +3 -0
- package/lib/Utils/browser-utils.d.ts.map +1 -0
- package/lib/Utils/browser-utils.js +22 -0
- package/lib/Utils/browser-utils.js.map +1 -0
- package/lib/Utils/event-buffer.d.ts +7 -0
- package/lib/Utils/event-buffer.d.ts.map +1 -0
- package/lib/Utils/event-buffer.js +42 -0
- package/lib/Utils/event-buffer.js.map +1 -0
- package/lib/Utils/generics.d.ts +13 -0
- package/lib/Utils/generics.d.ts.map +1 -0
- package/lib/Utils/generics.js +40 -0
- package/lib/Utils/generics.js.map +1 -0
- package/lib/Utils/index.d.ts +10 -0
- package/lib/Utils/index.d.ts.map +1 -0
- package/lib/Utils/index.js +10 -0
- package/lib/Utils/index.js.map +1 -0
- package/lib/Utils/logger.d.ts +13 -0
- package/lib/Utils/logger.d.ts.map +1 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/logger.js.map +1 -0
- package/lib/Utils/messages-media.d.ts +51 -0
- package/lib/Utils/messages-media.d.ts.map +1 -0
- package/lib/Utils/messages-media.js +223 -0
- package/lib/Utils/messages-media.js.map +1 -0
- package/lib/Utils/messages.d.ts +88 -0
- package/lib/Utils/messages.d.ts.map +1 -0
- package/lib/Utils/messages.js +730 -0
- package/lib/Utils/messages.js.map +1 -0
- package/lib/Utils/use-bridge-store.d.ts +13 -0
- package/lib/Utils/use-bridge-store.d.ts.map +1 -0
- package/lib/Utils/use-bridge-store.js +124 -0
- package/lib/Utils/use-bridge-store.js.map +1 -0
- package/lib/Utils/use-memory-store.d.ts +9 -0
- package/lib/Utils/use-memory-store.d.ts.map +1 -0
- package/lib/Utils/use-memory-store.js +23 -0
- package/lib/Utils/use-memory-store.js.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +26 -0
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
- package/lib/Utils/wrap-legacy-store.d.ts +36 -0
- package/lib/Utils/wrap-legacy-store.d.ts.map +1 -0
- package/lib/Utils/wrap-legacy-store.js +708 -0
- package/lib/Utils/wrap-legacy-store.js.map +1 -0
- package/lib/WABinary/index.d.ts +2 -0
- package/lib/WABinary/index.d.ts.map +1 -0
- package/lib/WABinary/index.js +2 -0
- package/lib/WABinary/index.js.map +1 -0
- package/lib/WABinary/jid-utils.d.ts +20 -0
- package/lib/WABinary/jid-utils.d.ts.map +1 -0
- package/lib/WABinary/jid-utils.js +51 -0
- package/lib/WABinary/jid-utils.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/package.json +98 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 João Lucas (jlucaso1) and oxidezap contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# baileyrs
|
|
2
|
+
|
|
3
|
+
A Rust-powered WhatsApp Web library for JavaScript, with a Baileys-compatible API.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
baileyrs is a thin JavaScript wrapper over [whatsapp-rust](https://github.com/oxidezap/whatsapp-rust)
|
|
8
|
+
compiled to WebAssembly. The heavy lifting — Signal protocol, Noise handshake, media
|
|
9
|
+
encryption, binary-node (de)serialization, protobuf codec — runs in Rust/WASM via the
|
|
10
|
+
[whatsapp-rust-bridge](https://www.npmjs.com/package/whatsapp-rust-bridge) package.
|
|
11
|
+
|
|
12
|
+
The public surface intentionally mirrors [Baileys](https://github.com/WhiskeySockets/Baileys)
|
|
13
|
+
so existing integrations can migrate with minimal changes. See
|
|
14
|
+
[ATTRIBUTION.md](ATTRIBUTION.md) for details.
|
|
15
|
+
|
|
16
|
+
### vs. Baileys
|
|
17
|
+
|
|
18
|
+
| Area | Original Baileys | baileyrs |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Signal Protocol | JS (libsignal) | Rust/WASM |
|
|
21
|
+
| Media encrypt/decrypt | Node.js crypto | Rust AES-256-CBC + HMAC |
|
|
22
|
+
| Media upload/download | JS fetch + temp files | Rust with CDN failover, auth refresh, resumable upload |
|
|
23
|
+
| Key management | JS auth state | Rust `PersistenceManager` |
|
|
24
|
+
| Auto-reconnect | Manual `startSock()` loop | Built-in with fibonacci backoff |
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install @oxidezap/baileyrs
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then import:
|
|
33
|
+
```ts
|
|
34
|
+
import makeWASocket from '@oxidezap/baileyrs'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@oxidezap/baileyrs'
|
|
41
|
+
import { Boom } from '@hapi/boom'
|
|
42
|
+
|
|
43
|
+
const { state } = await useMultiFileAuthState('auth_info')
|
|
44
|
+
const sock = makeWASocket({ auth: state })
|
|
45
|
+
|
|
46
|
+
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
|
|
47
|
+
if (connection === 'close') {
|
|
48
|
+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
49
|
+
if (statusCode === DisconnectReason.loggedOut) {
|
|
50
|
+
console.log('Logged out')
|
|
51
|
+
}
|
|
52
|
+
// Auto-reconnect is handled by the Rust engine — no need to call makeWASocket again
|
|
53
|
+
}
|
|
54
|
+
if (connection === 'open') {
|
|
55
|
+
console.log('Connected')
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
sock.ev.on('messages.upsert', ({ messages }) => {
|
|
60
|
+
for (const msg of messages) {
|
|
61
|
+
console.log('received message', msg.key.id)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Connecting
|
|
67
|
+
|
|
68
|
+
### QR Code
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const sock = makeWASocket({
|
|
72
|
+
auth: state,
|
|
73
|
+
browser: Browsers.ubuntu('My App')
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A QR code will be emitted via `connection.update` events. Scan it with your phone.
|
|
78
|
+
|
|
79
|
+
### Pairing Code
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const sock = makeWASocket({ auth: state })
|
|
83
|
+
|
|
84
|
+
if (!sock.isLoggedIn) {
|
|
85
|
+
const code = await sock.requestPairingCode('5511999999999')
|
|
86
|
+
console.log('Pairing code:', code)
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Auth State
|
|
91
|
+
|
|
92
|
+
All state — crypto keys, Signal sessions, device identity, and push name — is managed and persisted by the Rust bridge. No `creds.json`, no `saveCreds` callback.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { useMultiFileAuthState } from '@oxidezap/baileyrs'
|
|
96
|
+
|
|
97
|
+
const { state } = await useMultiFileAuthState('auth_folder')
|
|
98
|
+
const sock = makeWASocket({ auth: state })
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Files created in `auth_folder/`:
|
|
102
|
+
- `device-*.bin` — Rust device state (noise keys, identity, push name, etc.)
|
|
103
|
+
- `session-*.bin` — Signal sessions
|
|
104
|
+
- `identity-*.bin` — Signal identity keys
|
|
105
|
+
- `pre-key-*.bin` — Signal pre-keys
|
|
106
|
+
- `sender-key-*.bin` — Group sender keys
|
|
107
|
+
|
|
108
|
+
### Custom Store (Native)
|
|
109
|
+
|
|
110
|
+
For new deployments, implement `JsStoreCallbacks` directly — a flat binary key-value store. The Rust bridge handles all serialization internally.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import makeWASocket from '@oxidezap/baileyrs'
|
|
114
|
+
|
|
115
|
+
const store = {
|
|
116
|
+
async get(store: string, key: string): Promise<Uint8Array | null> {
|
|
117
|
+
// read from your DB: SELECT value FROM wa_store WHERE store=? AND key=?
|
|
118
|
+
},
|
|
119
|
+
async set(store: string, key: string, value: Uint8Array): Promise<void> {
|
|
120
|
+
// upsert to your DB: INSERT ... ON DUPLICATE KEY UPDATE
|
|
121
|
+
},
|
|
122
|
+
async delete(store: string, key: string): Promise<void> {
|
|
123
|
+
// delete from your DB: DELETE FROM wa_store WHERE store=? AND key=?
|
|
124
|
+
},
|
|
125
|
+
async flush(): Promise<void> { /* flush pending writes if you batch */ }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const sock = makeWASocket({ auth: { store } })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
No creds management, no type routing — just `(store, key) → bytes`. Works with any backend (MySQL, Redis, S3, etc.).
|
|
132
|
+
|
|
133
|
+
### Migrating from Upstream Baileys
|
|
134
|
+
|
|
135
|
+
`wrapLegacyStore` imports an existing session from [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys) (or any custom store built on it, like [mysql-baileys](https://github.com/bobslavtriev/mysql-baileys)) without requiring a new QR scan.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import makeWASocket, { useLegacyMultiFileAuthState, wrapLegacyStore } from '@oxidezap/baileyrs'
|
|
139
|
+
|
|
140
|
+
// Works with any upstream auth state: useMultiFileAuthState, useMySQLAuthState, etc.
|
|
141
|
+
const { state, saveCreds } = await useLegacyMultiFileAuthState('/path/to/baileys_auth_info')
|
|
142
|
+
const store = await wrapLegacyStore(state, saveCreds)
|
|
143
|
+
const sock = makeWASocket({ auth: { store } })
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Sending Messages
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// Text
|
|
150
|
+
await sock.sendMessage(jid, { text: 'Hello!' })
|
|
151
|
+
|
|
152
|
+
// Quote
|
|
153
|
+
await sock.sendMessage(jid, { text: 'Reply' }, { quoted: msg })
|
|
154
|
+
|
|
155
|
+
// Mention
|
|
156
|
+
await sock.sendMessage(jid, {
|
|
157
|
+
text: '@12345678901',
|
|
158
|
+
mentions: ['12345678901@s.whatsapp.net']
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
// Forward
|
|
162
|
+
await sock.sendMessage(jid, { forward: msg })
|
|
163
|
+
|
|
164
|
+
// Location
|
|
165
|
+
await sock.sendMessage(jid, {
|
|
166
|
+
location: { degreesLatitude: 24.12, degreesLongitude: 55.11 }
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// Contact
|
|
170
|
+
await sock.sendMessage(jid, {
|
|
171
|
+
contacts: {
|
|
172
|
+
displayName: 'Jeff',
|
|
173
|
+
contacts: [{ vcard: 'BEGIN:VCARD\nVERSION:3.0\nFN:Jeff\nEND:VCARD' }]
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// Reaction
|
|
178
|
+
await sock.sendMessage(jid, { react: { text: '💖', key: msg.key } })
|
|
179
|
+
|
|
180
|
+
// Poll
|
|
181
|
+
await sock.sendMessage(jid, {
|
|
182
|
+
poll: { name: 'My Poll', values: ['Yes', 'No'], selectableCount: 1 }
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
// Delete (for everyone)
|
|
186
|
+
await sock.sendMessage(jid, { delete: msg.key })
|
|
187
|
+
|
|
188
|
+
// Edit
|
|
189
|
+
await sock.sendMessage(jid, { text: 'updated text', edit: msg.key })
|
|
190
|
+
|
|
191
|
+
// Disappearing messages
|
|
192
|
+
await sock.sendMessage(jid, { disappearingMessagesInChat: 604800 }) // 7 days
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Media Messages
|
|
196
|
+
|
|
197
|
+
Media encryption, upload, and CDN failover are handled entirely by the Rust bridge.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
// Image
|
|
201
|
+
await sock.sendMessage(jid, { image: readFileSync('photo.jpg'), caption: 'Hello' })
|
|
202
|
+
|
|
203
|
+
// Video
|
|
204
|
+
await sock.sendMessage(jid, { video: { url: './clip.mp4' }, caption: 'Watch this' })
|
|
205
|
+
|
|
206
|
+
// Audio
|
|
207
|
+
await sock.sendMessage(jid, { audio: { url: './audio.ogg' }, mimetype: 'audio/ogg; codecs=opus' })
|
|
208
|
+
|
|
209
|
+
// Document
|
|
210
|
+
await sock.sendMessage(jid, {
|
|
211
|
+
document: { url: './file.pdf' },
|
|
212
|
+
mimetype: 'application/pdf',
|
|
213
|
+
fileName: 'report.pdf'
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
// View once
|
|
217
|
+
await sock.sendMessage(jid, { image: { url: './photo.jpg' }, viewOnce: true })
|
|
218
|
+
|
|
219
|
+
// GIF (mp4 with gifPlayback)
|
|
220
|
+
await sock.sendMessage(jid, { video: readFileSync('anim.mp4'), gifPlayback: true })
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
> Thumbnails are auto-generated for images (requires `jimp` or `sharp`). Video thumbnails need `ffmpeg` on your system, or provide `jpegThumbnail` directly.
|
|
224
|
+
|
|
225
|
+
#### Streaming Upload (Large Files)
|
|
226
|
+
|
|
227
|
+
For files that are too large to buffer in memory, pass a `processMedia` hook to `sendMessage`:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
await sock.sendMessage(jid, { video: readFileSync('large-video.mp4') }, {
|
|
231
|
+
processMedia: async (buffer, mediaType, waClient) => {
|
|
232
|
+
const { Writable } = await import('node:stream')
|
|
233
|
+
const fs = await import('node:fs')
|
|
234
|
+
const os = await import('node:os')
|
|
235
|
+
const path = await import('node:path')
|
|
236
|
+
|
|
237
|
+
const tmpEnc = path.join(os.tmpdir(), `enc-${Date.now()}`)
|
|
238
|
+
|
|
239
|
+
// Streaming encrypt → temp file (constant ~40KB memory)
|
|
240
|
+
const input = new Blob([new Uint8Array(buffer)]).stream()
|
|
241
|
+
const output = Writable.toWeb(fs.createWriteStream(tmpEnc))
|
|
242
|
+
const enc = await waClient.encryptMediaStream(input, output, mediaType)
|
|
243
|
+
|
|
244
|
+
// Upload from temp file
|
|
245
|
+
const encData = await fs.promises.readFile(tmpEnc)
|
|
246
|
+
await fs.promises.unlink(tmpEnc)
|
|
247
|
+
|
|
248
|
+
const upload = await waClient.uploadEncryptedMediaStream(
|
|
249
|
+
() => new Blob([new Uint8Array(encData)]).stream(),
|
|
250
|
+
enc.mediaKey, enc.fileSha256, enc.fileEncSha256, enc.fileLength, mediaType
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return { upload: { ...upload, ...enc } }
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Downloading Media
|
|
259
|
+
|
|
260
|
+
The recommended way to download media is via the socket method — it handles CDN failover, auth refresh, HMAC verification, and media re-upload automatically:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
// Buffer (recommended)
|
|
264
|
+
const buffer = await sock.downloadMedia(msg, 'buffer')
|
|
265
|
+
await writeFile('photo.jpg', buffer)
|
|
266
|
+
|
|
267
|
+
// Stream
|
|
268
|
+
const stream = await sock.downloadMedia(msg, 'stream')
|
|
269
|
+
for await (const chunk of stream) {
|
|
270
|
+
// process chunk — only ~64KB in memory at a time
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
<details>
|
|
275
|
+
<summary>Advanced: standalone utility (for use without a socket)</summary>
|
|
276
|
+
|
|
277
|
+
If you need to download media outside of a socket context (e.g., custom logger or reupload logic), use the standalone `downloadMediaMessage` utility:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { downloadMediaMessage } from '@oxidezap/baileyrs'
|
|
281
|
+
|
|
282
|
+
const buffer = await downloadMediaMessage(msg, 'buffer', {}, {
|
|
283
|
+
logger: sock.logger,
|
|
284
|
+
reuploadRequest: m => sock.updateMediaMessage(m),
|
|
285
|
+
waClient: sock.waClient!
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
### Re-upload Expired Media
|
|
292
|
+
```ts
|
|
293
|
+
await sock.updateMediaMessage(msg)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Read Receipts
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
await sock.readMessages([{ remoteJid: msg.key.remoteJid!, id: msg.key.id! }])
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Presence
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
// Online/offline
|
|
306
|
+
await sock.sendPresenceUpdate('available')
|
|
307
|
+
await sock.sendPresenceUpdate('unavailable')
|
|
308
|
+
|
|
309
|
+
// Subscribe to a contact's presence
|
|
310
|
+
await sock.presenceSubscribe(jid)
|
|
311
|
+
|
|
312
|
+
// Typing indicator
|
|
313
|
+
await sock.sendChatState(jid, 'composing')
|
|
314
|
+
await sock.sendChatState(jid, 'paused')
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Chat Actions
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
await sock.pinChat(jid, true)
|
|
321
|
+
await sock.muteChat(jid, 8 * 60 * 60 * 1000) // mute 8h
|
|
322
|
+
await sock.muteChat(jid, null) // unmute
|
|
323
|
+
await sock.archiveChat(jid, true)
|
|
324
|
+
await sock.starMessage(jid, msgId, true)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Reject Calls
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
await sock.rejectCall(callId, callFrom)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## User Queries
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
// Check if on WhatsApp
|
|
337
|
+
const [result] = await sock.onWhatsApp('+1234567890')
|
|
338
|
+
if (result.exists) console.log('JID:', result.jid)
|
|
339
|
+
|
|
340
|
+
// Fetch status
|
|
341
|
+
const status = await sock.fetchStatus(jid)
|
|
342
|
+
|
|
343
|
+
// Profile picture
|
|
344
|
+
const url = await sock.profilePictureUrl(jid, 'image')
|
|
345
|
+
|
|
346
|
+
// Business profile
|
|
347
|
+
const profile = await sock.getBusinessProfile(jid)
|
|
348
|
+
|
|
349
|
+
// On-demand history (messages arrive via messaging-history.set event)
|
|
350
|
+
await sock.fetchMessageHistory(50, oldestMsg.key, oldestMsg.messageTimestamp)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Profile
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
await sock.setPushName('My Name')
|
|
357
|
+
await sock.updateProfileStatus('Hello World!')
|
|
358
|
+
await sock.updateProfilePicture(jid, imageBytes)
|
|
359
|
+
await sock.removeProfilePicture()
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Groups
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
// Create
|
|
366
|
+
const group = await sock.groupCreate('Group Name', ['1234@s.whatsapp.net'])
|
|
367
|
+
|
|
368
|
+
// Participants
|
|
369
|
+
await sock.groupParticipantsUpdate(jid, ['1234@s.whatsapp.net'], 'add') // or 'remove', 'promote', 'demote'
|
|
370
|
+
|
|
371
|
+
// Metadata
|
|
372
|
+
const metadata = await sock.groupMetadata(jid)
|
|
373
|
+
const all = await sock.groupFetchAllParticipating()
|
|
374
|
+
|
|
375
|
+
// Settings
|
|
376
|
+
await sock.groupUpdateSubject(jid, 'New Name')
|
|
377
|
+
await sock.groupUpdateDescription(jid, 'New Description')
|
|
378
|
+
await sock.groupSettingUpdate(jid, 'announce', true) // only admins send
|
|
379
|
+
await sock.groupSettingUpdate(jid, 'locked', true) // only admins edit settings
|
|
380
|
+
await sock.groupToggleEphemeral(jid, 604800) // 7 days
|
|
381
|
+
await sock.groupMemberAddMode(jid, 'admin_add') // or 'all_member_add'
|
|
382
|
+
|
|
383
|
+
// Invite
|
|
384
|
+
const code = await sock.groupInviteCode(jid)
|
|
385
|
+
const newCode = await sock.groupRevokeInvite(jid)
|
|
386
|
+
const response = await sock.groupAcceptInvite(code)
|
|
387
|
+
const info = await sock.groupGetInviteInfo(code)
|
|
388
|
+
|
|
389
|
+
// Join requests
|
|
390
|
+
const requests = await sock.groupRequestParticipantsList(jid)
|
|
391
|
+
await sock.groupRequestParticipantsUpdate(jid, ['1234@s.whatsapp.net'], 'approve')
|
|
392
|
+
|
|
393
|
+
// Leave
|
|
394
|
+
await sock.groupLeave(jid)
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Privacy
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
// Block/unblock
|
|
401
|
+
await sock.updateBlockStatus(jid, 'block')
|
|
402
|
+
await sock.updateBlockStatus(jid, 'unblock')
|
|
403
|
+
|
|
404
|
+
// Fetch
|
|
405
|
+
const settings = await sock.fetchPrivacySettings()
|
|
406
|
+
const blocklist = await sock.fetchBlocklist()
|
|
407
|
+
|
|
408
|
+
// Update privacy settings
|
|
409
|
+
await sock.updateLastSeenPrivacy('contacts') // 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
410
|
+
await sock.updateOnlinePrivacy('all') // 'all' | 'match_last_seen'
|
|
411
|
+
await sock.updateProfilePicturePrivacy('contacts')
|
|
412
|
+
await sock.updateStatusPrivacy('contacts')
|
|
413
|
+
await sock.updateReadReceiptsPrivacy('all') // 'all' | 'none'
|
|
414
|
+
await sock.updateGroupsAddPrivacy('contacts')
|
|
415
|
+
await sock.updateDefaultDisappearingMode(604800) // seconds, 0 to disable
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## Newsletters (Channels)
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
const channel = await sock.newsletterCreate('My Channel', 'Description')
|
|
422
|
+
const meta = await sock.newsletterMetadata(jid)
|
|
423
|
+
await sock.newsletterSubscribe(jid)
|
|
424
|
+
await sock.newsletterUnsubscribe(jid)
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Memory Monitoring
|
|
428
|
+
|
|
429
|
+
```ts
|
|
430
|
+
import { getWasmMemoryBytes } from 'whatsapp-rust-bridge'
|
|
431
|
+
|
|
432
|
+
// WASM linear memory (total reserved)
|
|
433
|
+
const wasmBytes = getWasmMemoryBytes()
|
|
434
|
+
console.log(`WASM memory: ${(wasmBytes / 1024 / 1024).toFixed(1)} MB`)
|
|
435
|
+
|
|
436
|
+
// Detailed cache/collection diagnostics from the Rust engine
|
|
437
|
+
const diag = await sock.waClient!.getMemoryDiagnostics()
|
|
438
|
+
console.log(diag) // { signalCacheSessions, groupCache, deviceCache, ... }
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Socket Config
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
const sock = makeWASocket({
|
|
445
|
+
// Required
|
|
446
|
+
auth: state,
|
|
447
|
+
|
|
448
|
+
// Connection
|
|
449
|
+
waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
|
|
450
|
+
connectTimeoutMs: 20_000,
|
|
451
|
+
keepAliveIntervalMs: 30_000,
|
|
452
|
+
|
|
453
|
+
// Identity
|
|
454
|
+
version: [2, 3000, 1035194821],
|
|
455
|
+
browser: Browsers.macOS('Chrome'),
|
|
456
|
+
|
|
457
|
+
// Events
|
|
458
|
+
emitOwnEvents: true,
|
|
459
|
+
shouldIgnoreJid: jid => false,
|
|
460
|
+
|
|
461
|
+
// Proxy (for fetch/HTTP requests — uses undici dispatcher)
|
|
462
|
+
options: { dispatcher: undiciAgent },
|
|
463
|
+
|
|
464
|
+
// Cache (Rust-side, see CacheConfig type)
|
|
465
|
+
cache: { group: { ttlSecs: 7200 } }
|
|
466
|
+
})
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## Relationship to Baileys
|
|
470
|
+
|
|
471
|
+
baileyrs began as a fork of [WhiskeySockets/Baileys](https://github.com/WhiskeySockets/Baileys)
|
|
472
|
+
but the internals have been rewritten from the ground up on top of
|
|
473
|
+
[whatsapp-rust](https://github.com/oxidezap/whatsapp-rust). Only the public API shape
|
|
474
|
+
is preserved, to make migration from Baileys straightforward.
|
|
475
|
+
|
|
476
|
+
See [ATTRIBUTION.md](ATTRIBUTION.md) for the full attribution notice.
|
|
477
|
+
|
|
478
|
+
## Disclaimer
|
|
479
|
+
|
|
480
|
+
This project is not affiliated with, endorsed by, or in any way officially connected to
|
|
481
|
+
WhatsApp LLC or Meta Platforms, Inc. "WhatsApp" is a trademark of its respective owners.
|
|
482
|
+
baileyrs is an unofficial, community-driven library provided for educational and
|
|
483
|
+
interoperability purposes.
|
|
484
|
+
|
|
485
|
+
Use at your own risk. The authors are not responsible for any misuse, account bans, or
|
|
486
|
+
violations of WhatsApp's Terms of Service that may result from the use of this software.
|
|
487
|
+
|
|
488
|
+
## License
|
|
489
|
+
|
|
490
|
+
MIT — see [LICENSE](LICENSE).
|