@n4tzz/n4lyx 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.MD +690 -0
- package/WAProto/GenerateStatics.sh +15 -0
- package/WAProto/WAProto.proto +2995 -0
- package/WAProto/index.d.ts +44070 -0
- package/WAProto/index.js +127017 -0
- package/WAProto/p.html +1 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +120 -0
- package/lib/Defaults/n4lyx-version.json +3 -0
- package/lib/Signal/Group/ciphertext-message.js +15 -0
- package/lib/Signal/Group/group-session-builder.js +64 -0
- package/lib/Signal/Group/group_cipher.js +96 -0
- package/lib/Signal/Group/index.js +57 -0
- package/lib/Signal/Group/keyhelper.js +55 -0
- package/lib/Signal/Group/queue-job.js +57 -0
- package/lib/Signal/Group/sender-chain-key.js +34 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
- package/lib/Signal/Group/sender-key-message.js +69 -0
- package/lib/Signal/Group/sender-key-name.js +51 -0
- package/lib/Signal/Group/sender-key-record.js +53 -0
- package/lib/Signal/Group/sender-key-state.js +99 -0
- package/lib/Signal/Group/sender-message-key.js +29 -0
- package/lib/Signal/libsignal.js +174 -0
- package/lib/Socket/Client/index.js +18 -0
- package/lib/Socket/Client/types.js +13 -0
- package/lib/Socket/Client/websocket.js +72 -0
- package/lib/Socket/business.js +260 -0
- package/lib/Socket/chats.js +972 -0
- package/lib/Socket/groups.js +387 -0
- package/lib/Socket/index.js +10 -0
- package/lib/Socket/messages-recv.js +1104 -0
- package/lib/Socket/messages-send.js +889 -0
- package/lib/Socket/newsletter.js +250 -0
- package/lib/Socket/socket.js +646 -0
- package/lib/Socket/usync.js +70 -0
- package/lib/Store/index.js +8 -0
- package/lib/Store/make-in-memory-store.js +439 -0
- package/lib/Store/make-ordered-dictionary.js +81 -0
- package/lib/Store/object-repository.js +27 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +4 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +27 -0
- package/lib/Types/LabelAssociation.js +9 -0
- package/lib/Types/Message.js +7 -0
- package/lib/Types/Newsletter.js +18 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/State.js +2 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +42 -0
- package/lib/Utils/auth-utils.js +199 -0
- package/lib/Utils/browser-utils.js +35 -0
- package/lib/Utils/business.js +234 -0
- package/lib/Utils/chat-utils.js +730 -0
- package/lib/Utils/crypto.js +193 -0
- package/lib/Utils/decode-wa-message.js +207 -0
- package/lib/Utils/event-buffer.js +518 -0
- package/lib/Utils/generics.js +467 -0
- package/lib/Utils/history.js +94 -0
- package/lib/Utils/index.js +35 -0
- package/lib/Utils/link-preview.js +126 -0
- package/lib/Utils/logger.js +7 -0
- package/lib/Utils/lt-hash.js +51 -0
- package/lib/Utils/make-mutex.js +43 -0
- package/lib/Utils/message-retry-manager.js +128 -0
- package/lib/Utils/messages-media.js +879 -0
- package/lib/Utils/messages.js +1071 -0
- package/lib/Utils/n4lyx-event-stream.js +63 -0
- package/lib/Utils/noise-handler.js +150 -0
- package/lib/Utils/process-message.js +404 -0
- package/lib/Utils/signal.js +153 -0
- package/lib/Utils/use-multi-file-auth-state.js +125 -0
- package/lib/Utils/validate-connection.js +229 -0
- package/lib/WABinary/constants.js +1303 -0
- package/lib/WABinary/decode.js +265 -0
- package/lib/WABinary/encode.js +250 -0
- package/lib/WABinary/generic-utils.js +110 -0
- package/lib/WABinary/index.js +21 -0
- package/lib/WABinary/jid-utils.js +85 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +13 -0
- package/lib/WAM/constants.js +15350 -0
- package/lib/WAM/encode.js +155 -0
- package/lib/WAM/index.js +19 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +53 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
- package/lib/WAUSync/Protocols/index.js +20 -0
- package/lib/WAUSync/USyncQuery.js +89 -0
- package/lib/WAUSync/USyncUser.js +26 -0
- package/lib/WAUSync/index.js +19 -0
- package/lib/index.js +102 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 wileys
|
|
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,690 @@
|
|
|
1
|
+
# n4lyx
|
|
2
|
+
|
|
3
|
+
> WhatsApp Web API — multi-device, TypeScript-first, built different.
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/n4lyx)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://npmjs.com/package/n4lyx)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
**n4lyx** is a WhatsApp Web API library built for real projects. Proper `@lid → @pn` resolution, full multi-device support, clean TypeScript API. Fast, minimal, no bloat.
|
|
12
|
+
|
|
13
|
+
> Not affiliated with WhatsApp Inc. Don't spam. Don't abuse. You're responsible for how you use this.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i n4lyx
|
|
21
|
+
# or latest build
|
|
22
|
+
npm i n4lyx@latest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
const { default: makeWASocket } = require('n4lyx')
|
|
27
|
+
// ESM
|
|
28
|
+
import makeWASocket from 'n4lyx'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
const { default: makeWASocket, DisconnectReason, useMultiFileAuthState } = require('n4lyx')
|
|
37
|
+
const { Boom } = require('@hapi/boom')
|
|
38
|
+
|
|
39
|
+
async function connect() {
|
|
40
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth')
|
|
41
|
+
|
|
42
|
+
const sock = makeWASocket({
|
|
43
|
+
auth: state,
|
|
44
|
+
printQRInTerminal: true,
|
|
45
|
+
browser: ['n4lyx', 'Desktop', '1.0.0']
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
|
|
49
|
+
if (connection === 'close') {
|
|
50
|
+
const code = (lastDisconnect?.error as Boom)?.output?.statusCode
|
|
51
|
+
if (code !== DisconnectReason.loggedOut) connect()
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
56
|
+
for (const msg of messages) {
|
|
57
|
+
if (!msg.message) continue
|
|
58
|
+
await sock.sendMessage(msg.key.remoteJid!, { text: 'pong' })
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
sock.ev.on('creds.update', saveCreds)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
connect()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Authentication
|
|
71
|
+
|
|
72
|
+
### QR Code
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
const { default: makeWASocket, Browsers } = require('n4lyx')
|
|
76
|
+
|
|
77
|
+
const sock = makeWASocket({
|
|
78
|
+
browser: Browsers.ubuntu('n4lyx'),
|
|
79
|
+
printQRInTerminal: true
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Pairing Code
|
|
84
|
+
|
|
85
|
+
Phone number must include country code — no spaces, no symbols.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
const sock = makeWASocket({ printQRInTerminal: false })
|
|
89
|
+
|
|
90
|
+
if (!sock.authState.creds.registered) {
|
|
91
|
+
const code = await sock.requestPairingCode('628XXXXXXXXX')
|
|
92
|
+
console.log('Pairing code:', code)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Custom pairing code (exactly 8 chars)
|
|
96
|
+
if (!sock.authState.creds.registered) {
|
|
97
|
+
const code = await sock.requestPairingCode('628XXXXXXXXX', 'N4LYX001')
|
|
98
|
+
console.log('Pairing code:', code)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Persist Auth
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
const { useMultiFileAuthState } = require('n4lyx')
|
|
106
|
+
|
|
107
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth')
|
|
108
|
+
const sock = makeWASocket({ auth: state })
|
|
109
|
+
sock.ev.on('creds.update', saveCreds)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> For production, store credentials in a real database (PostgreSQL, MongoDB, Redis) — not on disk.
|
|
113
|
+
|
|
114
|
+
### Full History Sync
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
const sock = makeWASocket({
|
|
118
|
+
browser: Browsers.macOS('Desktop'),
|
|
119
|
+
syncFullHistory: true
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Configuration
|
|
126
|
+
|
|
127
|
+
### Group Metadata Cache
|
|
128
|
+
|
|
129
|
+
Required for group-heavy bots. Cuts down repeated API calls significantly.
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
const NodeCache = require('node-cache')
|
|
133
|
+
|
|
134
|
+
const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })
|
|
135
|
+
|
|
136
|
+
const sock = makeWASocket({
|
|
137
|
+
cachedGroupMetadata: async (jid) => groupCache.get(jid)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
sock.ev.on('groups.update', async ([event]) => {
|
|
141
|
+
groupCache.set(event.id, await sock.groupMetadata(event.id))
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
sock.ev.on('group-participants.update', async (event) => {
|
|
145
|
+
groupCache.set(event.id, await sock.groupMetadata(event.id))
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Message Store
|
|
150
|
+
|
|
151
|
+
Needed for message retry and poll vote decryption.
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
const sock = makeWASocket({
|
|
155
|
+
getMessage: async (key) => await getMessageFromStore(key)
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Background Mode
|
|
160
|
+
|
|
161
|
+
Disable online status to receive push notifications while "offline".
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
const sock = makeWASocket({ markOnlineOnConnect: false })
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## In-Memory Store
|
|
170
|
+
|
|
171
|
+
n4lyx doesn't ship a default persistent store. A basic in-memory store is available for local dev and testing — not recommended for production.
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
const { makeInMemoryStore } = require('n4lyx')
|
|
175
|
+
|
|
176
|
+
const store = makeInMemoryStore({})
|
|
177
|
+
store.readFromFile('./store.json')
|
|
178
|
+
setInterval(() => store.writeToFile('./store.json'), 10_000)
|
|
179
|
+
|
|
180
|
+
const sock = makeWASocket({})
|
|
181
|
+
store.bind(sock.ev)
|
|
182
|
+
|
|
183
|
+
sock.ev.on('chats.upsert', () => console.log(store.chats.all()))
|
|
184
|
+
sock.ev.on('contacts.upsert', () => console.log(Object.values(store.contacts)))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
> Build your own store backed by a proper DB for anything in production.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Sending Messages
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
await sock.sendMessage(jid, content, options?)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Text
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
await sock.sendMessage(jid, { text: 'hello' })
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Reply / Quote
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
await sock.sendMessage(jid, { text: 'hello' }, { quoted: message })
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Mention
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
await sock.sendMessage(jid, {
|
|
213
|
+
text: '@628XXXXXXXXX',
|
|
214
|
+
mentions: ['628XXXXXXXXX@s.whatsapp.net']
|
|
215
|
+
})
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Forward
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
await sock.sendMessage(jid, { forward: msg })
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Location
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
await sock.sendMessage(jid, {
|
|
228
|
+
location: { degreesLatitude: -6.2, degreesLongitude: 106.8 }
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Contact
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
const vcard = [
|
|
236
|
+
'BEGIN:VCARD',
|
|
237
|
+
'VERSION:3.0',
|
|
238
|
+
'FN:John Doe',
|
|
239
|
+
'TEL;type=CELL;waid=628XXXXXXXXX:+62 8XX-XXXX-XXXX',
|
|
240
|
+
'END:VCARD'
|
|
241
|
+
].join('\n')
|
|
242
|
+
|
|
243
|
+
await sock.sendMessage(jid, {
|
|
244
|
+
contacts: { displayName: 'John', contacts: [{ vcard }] }
|
|
245
|
+
})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Reaction
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
await sock.sendMessage(jid, {
|
|
252
|
+
react: { text: '🔥', key: message.key }
|
|
253
|
+
})
|
|
254
|
+
// Remove: text: ''
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Poll
|
|
258
|
+
|
|
259
|
+
```js
|
|
260
|
+
await sock.sendMessage(jid, {
|
|
261
|
+
poll: {
|
|
262
|
+
name: 'Pick one',
|
|
263
|
+
values: ['Option A', 'Option B'],
|
|
264
|
+
selectableCount: 1
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Pin Message
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
await sock.sendMessage(jid, {
|
|
273
|
+
pin: {
|
|
274
|
+
type: 1, // 0 = unpin
|
|
275
|
+
time: 86400, // 86400 = 24h | 604800 = 7d | 2592000 = 30d
|
|
276
|
+
key: message.key
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Media
|
|
282
|
+
|
|
283
|
+
All media supports `Buffer`, `{ url: '...' }`, or `{ stream: Stream }`.
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
// Image
|
|
287
|
+
await sock.sendMessage(jid, {
|
|
288
|
+
image: { url: './photo.png' },
|
|
289
|
+
caption: 'caption'
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Video
|
|
293
|
+
await sock.sendMessage(jid, {
|
|
294
|
+
video: { url: './video.mp4' },
|
|
295
|
+
caption: 'caption',
|
|
296
|
+
ptv: false // true = video note (circle)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
// Audio
|
|
300
|
+
// Convert: ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
|
|
301
|
+
await sock.sendMessage(jid, {
|
|
302
|
+
audio: { url: './audio.ogg' },
|
|
303
|
+
mimetype: 'audio/mp4'
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
// GIF (must be MP4 + gifPlayback flag)
|
|
307
|
+
await sock.sendMessage(jid, {
|
|
308
|
+
video: fs.readFileSync('./animation.mp4'),
|
|
309
|
+
gifPlayback: true
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
// View once (works on image, video, audio)
|
|
313
|
+
await sock.sendMessage(jid, {
|
|
314
|
+
image: { url: './photo.png' },
|
|
315
|
+
viewOnce: true
|
|
316
|
+
})
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Link Preview
|
|
320
|
+
|
|
321
|
+
Requires `link-preview-js`:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
npm i link-preview-js
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
```js
|
|
328
|
+
await sock.sendMessage(jid, {
|
|
329
|
+
text: 'check this out: https://npmjs.com/package/n4lyx'
|
|
330
|
+
})
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Edit & Delete
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
// Delete for everyone
|
|
339
|
+
const sent = await sock.sendMessage(jid, { text: 'oops' })
|
|
340
|
+
await sock.sendMessage(jid, { delete: sent.key })
|
|
341
|
+
|
|
342
|
+
// Edit message
|
|
343
|
+
await sock.sendMessage(jid, {
|
|
344
|
+
text: 'corrected text',
|
|
345
|
+
edit: sent.key
|
|
346
|
+
})
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Downloading Media
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
import { downloadMediaMessage, getContentType } from 'n4lyx'
|
|
355
|
+
import { createWriteStream } from 'fs'
|
|
356
|
+
|
|
357
|
+
sock.ev.on('messages.upsert', async ({ messages: [m] }) => {
|
|
358
|
+
if (!m.message) return
|
|
359
|
+
if (getContentType(m) !== 'imageMessage') return
|
|
360
|
+
|
|
361
|
+
const stream = await downloadMediaMessage(m, 'stream', {}, {
|
|
362
|
+
logger,
|
|
363
|
+
reuploadRequest: sock.updateMediaMessage
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
stream.pipe(createWriteStream('./download.jpeg'))
|
|
367
|
+
})
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Re-upload expired media:
|
|
371
|
+
|
|
372
|
+
```js
|
|
373
|
+
await sock.updateMediaMessage(msg)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Chat Modifications
|
|
379
|
+
|
|
380
|
+
> Wrong updates can log you out of all devices. Handle with care.
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
const last = await getLastMessage(jid) // your implementation
|
|
384
|
+
|
|
385
|
+
// Archive
|
|
386
|
+
await sock.chatModify({ archive: true, lastMessages: [last] }, jid)
|
|
387
|
+
|
|
388
|
+
// Mute (ms) / unmute
|
|
389
|
+
await sock.chatModify({ mute: 8 * 60 * 60 * 1000 }, jid) // 8h
|
|
390
|
+
await sock.chatModify({ mute: null }, jid)
|
|
391
|
+
|
|
392
|
+
// Mark unread
|
|
393
|
+
await sock.chatModify({ markRead: false, lastMessages: [last] }, jid)
|
|
394
|
+
|
|
395
|
+
// Pin / unpin
|
|
396
|
+
await sock.chatModify({ pin: true }, jid)
|
|
397
|
+
await sock.chatModify({ pin: false }, jid)
|
|
398
|
+
|
|
399
|
+
// Delete chat
|
|
400
|
+
await sock.chatModify({
|
|
401
|
+
delete: true,
|
|
402
|
+
lastMessages: [{ key: last.key, messageTimestamp: last.messageTimestamp }]
|
|
403
|
+
}, jid)
|
|
404
|
+
|
|
405
|
+
// Delete message (self only)
|
|
406
|
+
await sock.chatModify({
|
|
407
|
+
clear: { messages: [{ id: 'MESSAGE_ID', fromMe: true, timestamp: '...' }] }
|
|
408
|
+
}, jid)
|
|
409
|
+
|
|
410
|
+
// Star / unstar
|
|
411
|
+
await sock.chatModify({
|
|
412
|
+
star: {
|
|
413
|
+
messages: [{ id: 'MESSAGE_ID', fromMe: true }],
|
|
414
|
+
star: true // false = unstar
|
|
415
|
+
}
|
|
416
|
+
}, jid)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Disappearing Messages
|
|
420
|
+
|
|
421
|
+
```js
|
|
422
|
+
// Enable (86400 = 24h | 604800 = 7d | 7776000 = 90d)
|
|
423
|
+
await sock.sendMessage(jid, { disappearingMessagesInChat: WA_DEFAULT_EPHEMERAL })
|
|
424
|
+
|
|
425
|
+
// Send as ephemeral
|
|
426
|
+
await sock.sendMessage(jid, { text: 'poof' }, { ephemeralExpiration: WA_DEFAULT_EPHEMERAL })
|
|
427
|
+
|
|
428
|
+
// Disable
|
|
429
|
+
await sock.sendMessage(jid, { disappearingMessagesInChat: false })
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Groups
|
|
435
|
+
|
|
436
|
+
```js
|
|
437
|
+
// Create
|
|
438
|
+
const group = await sock.groupCreate('Group Name', ['jid@s.whatsapp.net'])
|
|
439
|
+
console.log('Created:', group.gid)
|
|
440
|
+
|
|
441
|
+
// Add / remove / promote / demote
|
|
442
|
+
await sock.groupParticipantsUpdate(jid, ['jid@s.whatsapp.net'], 'add')
|
|
443
|
+
// 'add' | 'remove' | 'promote' | 'demote'
|
|
444
|
+
|
|
445
|
+
// Update name
|
|
446
|
+
await sock.groupUpdateSubject(jid, 'New Name')
|
|
447
|
+
|
|
448
|
+
// Update description
|
|
449
|
+
await sock.groupUpdateDescription(jid, 'New description')
|
|
450
|
+
|
|
451
|
+
// Settings
|
|
452
|
+
await sock.groupSettingUpdate(jid, 'announcement') // admin-only send
|
|
453
|
+
await sock.groupSettingUpdate(jid, 'not_announcement') // everyone can send
|
|
454
|
+
await sock.groupSettingUpdate(jid, 'locked') // admin-only settings
|
|
455
|
+
await sock.groupSettingUpdate(jid, 'unlocked') // everyone can edit
|
|
456
|
+
|
|
457
|
+
// Leave
|
|
458
|
+
await sock.groupLeave(jid)
|
|
459
|
+
|
|
460
|
+
// Invite link
|
|
461
|
+
const code = await sock.groupInviteCode(jid)
|
|
462
|
+
// link: https://chat.whatsapp.com/${code}
|
|
463
|
+
|
|
464
|
+
// Revoke invite
|
|
465
|
+
await sock.groupRevokeInvite(jid)
|
|
466
|
+
|
|
467
|
+
// Join via code (without https://chat.whatsapp.com/)
|
|
468
|
+
await sock.groupAcceptInvite(code)
|
|
469
|
+
|
|
470
|
+
// Metadata (participants, name, desc...)
|
|
471
|
+
const meta = await sock.groupMetadata(jid)
|
|
472
|
+
|
|
473
|
+
// Ephemeral
|
|
474
|
+
await sock.groupToggleEphemeral(jid, 86400)
|
|
475
|
+
|
|
476
|
+
// Add mode
|
|
477
|
+
await sock.groupMemberAddMode(jid, 'all_member_add') // or 'admin_add'
|
|
478
|
+
|
|
479
|
+
// Join requests
|
|
480
|
+
const requests = await sock.groupRequestParticipantsList(jid)
|
|
481
|
+
await sock.groupRequestParticipantsUpdate(jid, ['jid@s.whatsapp.net'], 'approve') // or 'reject'
|
|
482
|
+
|
|
483
|
+
// All joined group metadata
|
|
484
|
+
const all = await sock.groupFetchAllParticipating()
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## Presence
|
|
490
|
+
|
|
491
|
+
```js
|
|
492
|
+
// Mark messages as read
|
|
493
|
+
await sock.readMessages([key])
|
|
494
|
+
|
|
495
|
+
// Send presence
|
|
496
|
+
// 'available' | 'unavailable' | 'composing' | 'recording' | 'paused'
|
|
497
|
+
await sock.sendPresenceUpdate('composing', jid)
|
|
498
|
+
|
|
499
|
+
// Subscribe to contact presence
|
|
500
|
+
sock.ev.on('presence.update', console.log)
|
|
501
|
+
await sock.presenceSubscribe(jid)
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Querying
|
|
507
|
+
|
|
508
|
+
```js
|
|
509
|
+
// Check if number is on WhatsApp
|
|
510
|
+
const [result] = await sock.onWhatsApp(jid)
|
|
511
|
+
if (result.exists) console.log(result.jid)
|
|
512
|
+
|
|
513
|
+
// Status text
|
|
514
|
+
const status = await sock.fetchStatus(jid)
|
|
515
|
+
|
|
516
|
+
// Profile picture
|
|
517
|
+
const url = await sock.profilePictureUrl(jid) // low res
|
|
518
|
+
const urlHD = await sock.profilePictureUrl(jid, 'image') // high res
|
|
519
|
+
|
|
520
|
+
// Business profile
|
|
521
|
+
const biz = await sock.getBusinessProfile(jid)
|
|
522
|
+
console.log(biz.description, biz.category)
|
|
523
|
+
|
|
524
|
+
// Message history (max 50 per call)
|
|
525
|
+
const oldest = await getOldestMessage(jid) // your implementation
|
|
526
|
+
await sock.fetchMessageHistory(50, oldest.key, oldest.messageTimestamp)
|
|
527
|
+
// messages arrive via messaging.history-set
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Privacy
|
|
533
|
+
|
|
534
|
+
```js
|
|
535
|
+
// Block / unblock
|
|
536
|
+
await sock.updateBlockStatus(jid, 'block')
|
|
537
|
+
await sock.updateBlockStatus(jid, 'unblock')
|
|
538
|
+
|
|
539
|
+
// Get settings
|
|
540
|
+
await sock.fetchPrivacySettings(true)
|
|
541
|
+
|
|
542
|
+
// Get blocklist
|
|
543
|
+
await sock.fetchBlocklist()
|
|
544
|
+
|
|
545
|
+
// Update settings
|
|
546
|
+
// 'all' | 'contacts' | 'contact_blacklist' | 'none'
|
|
547
|
+
await sock.updateLastSeenPrivacy('contacts')
|
|
548
|
+
await sock.updateProfilePicturePrivacy('contacts')
|
|
549
|
+
await sock.updateStatusPrivacy('contacts')
|
|
550
|
+
await sock.updateReadReceiptsPrivacy('all')
|
|
551
|
+
await sock.updateGroupsAddPrivacy('contacts')
|
|
552
|
+
await sock.updateOnlinePrivacy('all') // or 'match_last_seen'
|
|
553
|
+
|
|
554
|
+
// Default disappearing mode
|
|
555
|
+
await sock.updateDefaultDisappearingMode(86400)
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Profile
|
|
561
|
+
|
|
562
|
+
```js
|
|
563
|
+
await sock.updateProfileStatus('available')
|
|
564
|
+
await sock.updateProfileName('My Name')
|
|
565
|
+
await sock.updateProfilePicture(jid, { url: './avatar.jpeg' })
|
|
566
|
+
await sock.removeProfilePicture(jid)
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Broadcast & Stories
|
|
572
|
+
|
|
573
|
+
```js
|
|
574
|
+
// Send to story / broadcast list
|
|
575
|
+
await sock.sendMessage(
|
|
576
|
+
'status@broadcast',
|
|
577
|
+
{ image: { url: url }, caption: 'caption' },
|
|
578
|
+
{
|
|
579
|
+
backgroundColor: '#000',
|
|
580
|
+
font: 0,
|
|
581
|
+
statusJidList: ['jid@s.whatsapp.net'],
|
|
582
|
+
broadcast: true
|
|
583
|
+
}
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
// Broadcast list info
|
|
587
|
+
const info = await sock.getBroadcastListInfo('1234@broadcast')
|
|
588
|
+
console.log(info.name, info.recipients)
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## Calls
|
|
594
|
+
|
|
595
|
+
```js
|
|
596
|
+
sock.ev.on('call', async ([call]) => {
|
|
597
|
+
await sock.rejectCall(call.id, call.from)
|
|
598
|
+
})
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## Poll Decryption
|
|
604
|
+
|
|
605
|
+
Polls are encrypted by default. Decryption happens in `messages.update`.
|
|
606
|
+
|
|
607
|
+
```js
|
|
608
|
+
sock.ev.on('messages.update', async (events) => {
|
|
609
|
+
for (const { key, update } of events) {
|
|
610
|
+
if (!update.pollUpdates) continue
|
|
611
|
+
|
|
612
|
+
const creation = await getMessage(key) // your implementation
|
|
613
|
+
if (!creation) continue
|
|
614
|
+
|
|
615
|
+
console.log(
|
|
616
|
+
getAggregateVotesInPollMessage({
|
|
617
|
+
message: creation,
|
|
618
|
+
pollUpdates: update.pollUpdates
|
|
619
|
+
})
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
})
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## Low-Level: WebSocket Callbacks
|
|
628
|
+
|
|
629
|
+
```js
|
|
630
|
+
// Intercept raw WA frames
|
|
631
|
+
sock.ws.on('CB:edge_routing', (node) => { })
|
|
632
|
+
sock.ws.on('CB:edge_routing,id:abcd', (node) => { })
|
|
633
|
+
sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node) => { })
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Debug mode — logs every WA protocol frame:
|
|
637
|
+
|
|
638
|
+
```js
|
|
639
|
+
const sock = makeWASocket({ logger: P({ level: 'debug' }) })
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## JID Format
|
|
645
|
+
|
|
646
|
+
| Type | Format |
|
|
647
|
+
|-----------|-------------------------------|
|
|
648
|
+
| User | `628XXXXXXXXX@s.whatsapp.net` |
|
|
649
|
+
| Group | `123456789-123456@g.us` |
|
|
650
|
+
| Broadcast | `[timestamp]@broadcast` |
|
|
651
|
+
| Story | `status@broadcast` |
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## Utilities
|
|
656
|
+
|
|
657
|
+
| Function | Description |
|
|
658
|
+
|-------------------------------|--------------------------------------|
|
|
659
|
+
| `getContentType(msg)` | Returns content type of a message |
|
|
660
|
+
| `getDevice(msg)` | Returns sender's device info |
|
|
661
|
+
| `makeCacheableSignalKeyStore` | Speeds up auth key store operations |
|
|
662
|
+
| `downloadContentFromMessage` | Downloads raw content from a message |
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## Optional Dependencies
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
npm i jimp # or sharp — thumbnail generation
|
|
670
|
+
npm i link-preview-js # link previews in text messages
|
|
671
|
+
npm i qrcode-terminal # QR rendering in terminal
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Video thumbnails require `ffmpeg` on your system.
|
|
675
|
+
|
|
676
|
+
Audio conversion:
|
|
677
|
+
|
|
678
|
+
```bash
|
|
679
|
+
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## License
|
|
685
|
+
|
|
686
|
+
MIT — see [LICENSE](LICENSE).
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
<sub>n4lyx — built by N4tzz.</sub>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# n4lyx - WAProto static generation script
|
|
3
|
+
# Regenerates index.js and index.d.ts from WAProto.proto
|
|
4
|
+
|
|
5
|
+
echo "Generating WAProto statics from WAProto.proto..."
|
|
6
|
+
|
|
7
|
+
yarn pbjs -t static-module -w commonjs -o ./WAProto/index.js ./WAProto/WAProto.proto
|
|
8
|
+
yarn pbts -o ./WAProto/index.d.ts ./WAProto/index.js
|
|
9
|
+
|
|
10
|
+
echo "Done. WAProto/index.js and WAProto/index.d.ts regenerated."
|
|
11
|
+
|
|
12
|
+
# Alternative (if using protoc):
|
|
13
|
+
# protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto \
|
|
14
|
+
# --ts_proto_opt=env=node,useOptionals=true,forceLong=long \
|
|
15
|
+
# --ts_proto_out=. ./WAProto/WAProto.proto
|