n4lyx 3.0.4 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.MD CHANGED
@@ -3,8 +3,8 @@
3
3
  ```
4
4
  ███╗ ██╗ ██╗ ██╗ ██╗ ██╗ ██╗ ██╗ ██╗
5
5
  ████╗ ██║ ██║ ██║ ██║ ╚██╗ ██╔╝ ╚██╗██╔╝
6
- ██╔██╗ ██║ ███████║ ██║ ╚████╔╝ ╚███╔╝
7
- ██║╚██╗██║ ╚════██║ ██║ ╚██╔╝ ██╔██╗
6
+ ██╔██╗ ██║ ███████║ ██║ ╚████╔╝ ╚███╔╝
7
+ ██║╚██╗██║ ╚════██║ ██║ ╚██╔╝ ██╔██╗
8
8
  ██║ ╚████║ ██║ ███████╗ ██║ ██╔╝ ██╗
9
9
  ╚═╝ ╚═══╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝
10
10
  ```
@@ -28,46 +28,35 @@ Dirancang untuk **production-ready**: minim crash, tahan edge-case, dan tetap ri
28
28
 
29
29
  ---
30
30
 
31
- ## ✨ **Fitur Utama**
31
+ ## ✨ Fitur Utama
32
32
 
33
- - ⚡ **Tag All System** — mention semua / admin / non-admin otomatis
34
- - 📸 **Group Status V2** — kirim story langsung ke group
35
- - 🎯 **Shorthand Methods** — kirim pesan tanpa ribet object manual
36
- - 🔄 **Auto-safe Handling** — banyak method sudah null-safe & anti crash
37
- - 🧠 **Smart Internal Handling** — cache, retry, dan sync lebih stabil
33
+ - ⚡ **Tag All System** — mention semua / admin / non-admin otomatis
34
+ - 📸 **Group Status V2** — kirim story langsung ke group
35
+ - 🎯 **Shorthand Methods** — kirim pesan tanpa ribet object manual
36
+ - 🔄 **Auto-safe Handling** — banyak method sudah null-safe & anti crash
37
+ - 🧠 **Smart Internal Handling** — cache, retry, dan sync lebih stabil
38
+ - 📡 **Channel Tracker** — cek semua channel & group yang diikuti
39
+ - 👥 **Contact Fetcher** — ambil semua kontak tersimpan
40
+ - 🖼️ **Media Converter** — resize, compress, dan convert ke sticker otomatis
41
+ - 📦 **Sticker Pack Batch** — kirim sticker pack sekaligus (bukan 1-by-1)
42
+ - 📄 **Document Pack** — kirim banyak dokumen sekaligus dengan delay & parallel mode
38
43
 
39
44
  ---
40
45
 
41
- ## ⚠️ **Stability & Fixes (Latest Update)**
42
-
43
- Versi terbaru membawa peningkatan besar pada stabilitas sistem:
44
-
45
- - ✅ **Profile Picture Safe Fetch**
46
- Tidak crash jika error (404, *not-authorized*, dll). Akan mengembalikan `null`.
47
-
48
- - ✅ **Message Handling Stabil**
49
- Dedup cache dan proses *upsert* sudah dibungkus `try/catch` untuk mencegah crash.
50
-
51
- - ✅ **Sync State Lebih Robust**
52
- Transisi state lebih aman dengan handling timeout yang tetap berjalan normal.
53
-
54
- - ✅ **Group Metadata Safe Guard**
55
- Tidak menyebabkan error jika data kosong atau tidak valid.
56
-
57
- - ✅ **Newsletter Parsing Aman**
58
- Semua proses parsing dilindungi, tidak akan crash jika terjadi kegagalan.
59
-
60
- - ✅ **Interactive & Button Normalization**
61
- Mendukung berbagai format tombol (`buttonId`, `id`, `text`, dll).
62
-
63
- - ✅ **WhatsApp Check Konsisten**
64
- Method seperti `isOnWhatsApp`, `onWhatsApp`, dll selalu mengembalikan array (tidak `undefined`).
65
-
66
- - ✅ **Dependency Optional**
67
- Dependency seperti `chalk` bersifat opsional dan memiliki fallback otomatis.
68
-
69
- - ✅ **Broadcast & Group Handling Fix**
70
- Menggunakan method internal yang lebih akurat dan stabil untuk pengiriman massal dan pengelolaan group.
46
+ ## ⚠️ Stability & Fixes (Latest)
47
+
48
+ - **Profile Picture Safe Fetch** tidak crash jika 404 / not-authorized, return `null`
49
+ - ✅ **Message Handling Stabil** — dedup cache dibungkus try/catch
50
+ - ✅ **Sync State Robust** — transisi state lebih aman, timeout tetap berjalan
51
+ - **Group Metadata Safe Guard** tidak error jika data kosong
52
+ - ✅ **Newsletter Parsing Aman** — selalu dilindungi, tidak crash
53
+ - ✅ **Interactive & Button Normalization** — support berbagai format tombol
54
+ - **isOnWhatsApp Konsisten** selalu return object (tidak undefined)
55
+ - ✅ **chalk Optional** — fallback otomatis jika tidak terinstall
56
+ - ✅ **Broadcast & Group Fix** — method internal lebih akurat
57
+ - **sendDocument Auto Mime** deteksi mimetype otomatis dari extension
58
+ - ✅ **sendStickerPack Batch** — kirim paralel per batch, bukan 1-by-1
59
+ - ✅ **Auto Join Channel** — client otomatis join channel saat connect
71
60
 
72
61
  ---
73
62
 
@@ -81,49 +70,44 @@ Versi terbaru membawa peningkatan besar pada stabilitas sistem:
81
70
  npm i n4lyx
82
71
  ```
83
72
 
84
- ```js
85
- // CommonJS
86
- const { default: makeWASocket } = require('n4lyx')
73
+ ```bash
74
+ # Optional tapi direkomendasikan untuk fitur convert/sticker
75
+ npm i sharp # lebih cepat (recommended)
76
+ npm i jimp # fallback jika sharp tidak bisa
77
+ npm i link-preview-js
78
+ npm i qrcode-terminal
79
+ ```
87
80
 
88
- // ESM
89
- import makeWASocket from 'n4lyx'
81
+ ```js
82
+ const { default: makeWASocket } = require("n4lyx")
90
83
  ```
91
84
 
92
85
  ---
93
86
 
94
87
  ## Quick Start
95
88
 
96
- Ini contoh bot paling minimal yang bisa jalan — terima pesan, balas "pong", auto-reconnect kalau putus.
97
-
98
89
  ```js
99
- const { default: makeWASocket, DisconnectReason, useMultiFileAuthState } = require('n4lyx')
100
- const { Boom } = require('@hapi/boom')
90
+ const { default: makeWASocket, DisconnectReason, useMultiFileAuthState } = require("n4lyx")
91
+ const { Boom } = require("@hapi/boom")
101
92
 
102
93
  async function start() {
103
- const { state, saveCreds } = await useMultiFileAuthState('auth')
94
+ const { state, saveCreds } = await useMultiFileAuthState("auth")
104
95
 
105
- const sock = makeWASocket({
106
- auth: state,
107
- printQRInTerminal: true
108
- })
96
+ const sock = makeWASocket({ auth: state, printQRInTerminal: true })
109
97
 
110
- // Handle koneksi
111
- sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
112
- if (connection === 'close') {
113
- const shouldReconnect =
114
- new Boom(lastDisconnect?.error)?.output?.statusCode !== DisconnectReason.loggedOut
98
+ sock.ev.on("connection.update", ({ connection, lastDisconnect }) => {
99
+ if (connection === "close") {
100
+ const shouldReconnect = new Boom(lastDisconnect?.error)?.output?.statusCode !== DisconnectReason.loggedOut
115
101
  if (shouldReconnect) start()
116
102
  }
117
103
  })
118
104
 
119
- // Simpan credentials
120
- sock.ev.on('creds.update', saveCreds)
105
+ sock.ev.on("creds.update", saveCreds)
121
106
 
122
- // Terima pesan
123
- sock.ev.on('messages.upsert', async ({ messages }) => {
107
+ sock.ev.on("messages.upsert", async ({ messages }) => {
124
108
  const msg = messages[0]
125
109
  if (!msg.message) return
126
- await sock.sendMessage(msg.key.remoteJid, { text: 'pong' })
110
+ await sock.sendMessage(msg.key.remoteJid, { text: "pong" })
127
111
  })
128
112
  }
129
113
 
@@ -135,458 +119,358 @@ start()
135
119
  ## Login
136
120
 
137
121
  ### QR Code
138
-
139
- Scan QR dari terminal — paling cepat untuk testing.
140
-
141
122
  ```js
142
123
  const sock = makeWASocket({ printQRInTerminal: true })
143
124
  ```
144
125
 
145
126
  ### Pairing Code
146
-
147
- Cocok kalau nggak bisa scan QR (server headless, dll).
148
-
149
127
  ```js
150
128
  const sock = makeWASocket({ printQRInTerminal: false })
151
-
152
129
  if (!sock.authState.creds.registered) {
153
- const code = await sock.requestPairingCode('628XXXXXXXXX')
154
- console.log('Kode pairing:', code) // → misalnya: N4LX-1234
130
+ const code = await sock.requestPairingCode("628XXXXXXXXX")
131
+ console.log("Kode pairing:", code)
155
132
  }
156
133
  ```
157
134
 
158
- Custom kode (tepat 8 karakter):
159
-
160
- ```js
161
- const code = await sock.requestPairingCode('628XXXXXXXXX', 'N4LYX001')
162
- ```
163
-
164
135
  ### Simpan Session
165
-
166
- Session disimpan ke folder `auth/`. Kalau file-nya ada, next run langsung connect tanpa QR lagi.
167
-
168
136
  ```js
169
- const { state, saveCreds } = await useMultiFileAuthState('auth')
137
+ const { state, saveCreds } = await useMultiFileAuthState("auth")
170
138
  const sock = makeWASocket({ auth: state })
171
- sock.ev.on('creds.update', saveCreds)
139
+ sock.ev.on("creds.update", saveCreds)
172
140
  ```
173
141
 
174
- > **Untuk production:** simpan credentials ke database (PostgreSQL / MongoDB / Redis), bukan ke disk. Disk bisa corrupt, database tidak.
175
-
176
142
  ---
177
143
 
178
144
  ## Config Penting
179
145
 
180
146
  ### Cache Group Metadata
181
-
182
- Wajib kalau bot kamu aktif di banyak group. Ini ngurangin request ke WA API secara signifikan.
183
-
184
147
  ```js
185
- const NodeCache = require('node-cache')
148
+ const NodeCache = require("node-cache")
186
149
  const groupCache = new NodeCache({ stdTTL: 300, useClones: false })
187
150
 
188
151
  const sock = makeWASocket({
189
152
  cachedGroupMetadata: async (jid) => groupCache.get(jid)
190
153
  })
191
154
 
192
- // Update cache kalau ada perubahan di group
193
- sock.ev.on('groups.update', async ([e]) => {
194
- groupCache.set(e.id, await sock.groupMetadata(e.id))
195
- })
196
- sock.ev.on('group-participants.update', async (e) => {
197
- groupCache.set(e.id, await sock.groupMetadata(e.id))
198
- })
155
+ sock.ev.on("groups.update", async ([e]) => { groupCache.set(e.id, await sock.groupMetadata(e.id)) })
156
+ sock.ev.on("group-participants.update", async (e) => { groupCache.set(e.id, await sock.groupMetadata(e.id)) })
199
157
  ```
200
158
 
201
159
  ### Background Mode
202
-
203
- Bot nggak kelihatan online tapi tetap terima pesan.
204
-
205
160
  ```js
206
161
  const sock = makeWASocket({ markOnlineOnConnect: false })
207
162
  ```
208
163
 
209
- ### Message Store (untuk Poll & Retry)
164
+ ---
210
165
 
211
- Diperlukan untuk dekripsi poll vote dan message retry.
166
+ ## NEW: Channel, Group & Contact Tracker
212
167
 
168
+ ### Cek Semua Channel yang Diikuti
213
169
  ```js
214
- const sock = makeWASocket({
215
- getMessage: async (key) => await getMessageFromDB(key)
216
- // implementasi getMessageFromDB sesuai DB kamu
217
- })
218
- ```
170
+ const channels = await sock.getFollowedChannels()
171
+ // [{ jid, name, description, subscribers, role, state, invite }, ...]
219
172
 
220
- ---
221
-
222
- ## Kirim Pesan
173
+ for (const ch of channels) {
174
+ console.log(`📡 ${ch.name} — ${ch.subscribers} subscribers`)
175
+ }
176
+ ```
223
177
 
224
- Semua pengiriman pesan lewat satu method: `sock.sendMessage(jid, content, options?)`.
178
+ ### Cek Semua Group yang Diikuti
179
+ ```js
180
+ // Cepat (tanpa profile pic)
181
+ const groups = await sock.getJoinedGroups()
182
+ // → [{ id, subject, participants, ... }, ...]
225
183
 
226
- ### Teks biasa
184
+ // Lengkap dengan foto profil
185
+ const groupsFull = await sock.getJoinedGroups(true)
186
+ // → [{ id, subject, participants, profilePic, ... }, ...]
227
187
 
228
- ```js
229
- await sock.sendMessage(jid, { text: 'Halo!' })
188
+ for (const g of groups) {
189
+ console.log(`👥 ${g.subject} ${g.participants?.length} member`)
190
+ }
230
191
  ```
231
192
 
232
- ### Reply / Quote
233
-
193
+ ### Cek Semua Kontak
234
194
  ```js
235
- await sock.sendMessage(jid, { text: 'Oke siap' }, { quoted: message })
195
+ const contacts = await sock.getAllContacts()
196
+ // → [{ jid, lid, exists, name }, ...]
197
+
198
+ const saved = contacts.filter(c => c.exists)
199
+ console.log(`📒 Total kontak tersimpan: ${saved.length}`)
236
200
  ```
237
201
 
238
- ### Mention user
202
+ ---
203
+
204
+ ## NEW: Convert, Resize & Compress ⚡
239
205
 
206
+ ### Convert Image → Sticker WebP
240
207
  ```js
241
- await sock.sendMessage(jid, {
242
- text: 'Hei @628XXXXXXXXX, cek ini',
243
- mentions: ['628XXXXXXXXX@s.whatsapp.net']
208
+ // Dari buffer gambar biasa
209
+ const { buffer, metadata } = await sock.convertToSticker(imageBuffer, {
210
+ packName: "Pack Gue",
211
+ packPublisher: "N4tzz",
212
+ quality: 80, // 1-100
213
+ maxSize: 512, // max px (default 512)
244
214
  })
245
- ```
215
+ await sock.sendMessage(jid, { sticker: buffer, ...metadata })
246
216
 
247
- ### Tag All
248
-
249
- Fitur eksklusif n4lyx. Auto-fetch participant list lalu mention semua sekaligus.
217
+ // Atau langsung kirim setelah convert
218
+ const result = await sock.convertToSticker(imageBuffer, { packName: "Sticker", packPublisher: "Bot" })
219
+ await sock.sendStickerWithMetadata(jid, result.buffer, result.metadata)
220
+ ```
250
221
 
222
+ ### Resize & Compress Image
251
223
  ```js
252
- // Tag semua member
253
- await sock.sendMessage(jid, {
254
- text: '📢 Pengumuman penting buat semua!',
255
- tagAll: true
224
+ // Resize ke max 800px, format JPEG, quality 75%
225
+ const compressed = await sock.convertMedia(imageBuffer, {
226
+ maxSize: 800,
227
+ format: "jpeg",
228
+ quality: 75,
256
229
  })
257
-
258
- // Tag admin aja
259
- await sock.sendMessage(jid, {
260
- text: '🔔 Info untuk para admin',
261
- tagAll: true,
262
- tagAllScope: 'admins'
230
+ await sock.sendImage(jid, compressed, "Foto sudah dikompress")
231
+
232
+ // Resize ke dimensi spesifik
233
+ const resized = await sock.convertMedia(imageBuffer, {
234
+ width: 1280,
235
+ height: 720,
236
+ format: "webp",
237
+ quality: 85,
263
238
  })
264
239
 
265
- // Tag non-admin aja
266
- await sock.sendMessage(jid, {
267
- text: '👋 Hei member!',
268
- tagAll: true,
269
- tagAllScope: 'non_admins'
270
- })
240
+ // Convert ke PNG
241
+ const png = await sock.convertMedia(imageBuffer, { format: "png", quality: 90 })
271
242
  ```
272
243
 
273
- Atau ambil list JID-nya dulu kalau mau diproses manual:
274
-
275
- ```js
276
- const jids = await sock.groupTagAll(groupJid, 'all')
277
- // → ['628xxx@s.whatsapp.net', '628yyy@s.whatsapp.net', ...]
278
- ```
244
+ > **Catatan:** Butuh `sharp` (recommended) atau `jimp` terinstall.
245
+ > ```bash
246
+ > npm i sharp # atau: npm i jimp
247
+ > ```
279
248
 
280
- ### Media
249
+ ---
281
250
 
282
- Semua media support: `Buffer`, `{ url: '...' }`, atau `{ stream: Stream }`.
251
+ ## NEW: Sticker Pack Batch
283
252
 
253
+ ### Kirim Sticker Pack Sekaligus (Batch Parallel)
284
254
  ```js
285
- // Gambar
286
- await sock.sendMessage(jid, {
287
- image: { url: './foto.jpg' },
288
- caption: 'Caption foto'
255
+ // sendStickerPack — sekarang batch paralel per 5, bukan 1-by-1
256
+ await sock.sendStickerPack(jid, [buf1, buf2, buf3, buf4, buf5], "Pack Gue", "N4tzz", {
257
+ batchSize: 5, // kirim 5 sekaligus per batch
258
+ delayBatch: 500, // delay 500ms antar batch
289
259
  })
290
260
 
291
- // Video
292
- await sock.sendMessage(jid, {
293
- video: { url: './video.mp4' },
294
- caption: 'Caption video'
261
+ // sendStickerPackAlbum — batch lebih besar (max 10 per batch)
262
+ const results = await sock.sendStickerPackAlbum(jid, [buf1, buf2, buf3], "Pack Gue", "N4tzz", {
263
+ batchSize: 10,
264
+ delayBatch: 800,
295
265
  })
266
+ console.log(results) // [{ success, msg? }, ...]
267
+ ```
296
268
 
297
- // Audio biasa
298
- await sock.sendMessage(jid, {
299
- audio: { url: './audio.mp3' },
300
- mimetype: 'audio/mp4'
301
- })
269
+ ---
302
270
 
303
- // Voice note (PTT)
304
- await sock.sendMessage(jid, {
305
- audio: fs.readFileSync('./voice.ogg'),
306
- mimetype: 'audio/ogg; codecs=opus',
307
- ptt: true
308
- })
271
+ ## NEW: Document Pack ⚡
309
272
 
310
- // Sticker
311
- await sock.sendMessage(jid, {
312
- sticker: fs.readFileSync('./sticker.webp')
273
+ ### Kirim Banyak Dokumen Sekaligus
274
+ ```js
275
+ // Sequential dengan delay (default)
276
+ const results = await sock.sendDocumentPack(jid, [
277
+ { buffer: pdfBuffer, fileName: "laporan.pdf", caption: "Ini laporannya" },
278
+ { buffer: excelBuf, fileName: "data.xlsx", caption: "Data excel" },
279
+ { url: "https://...", fileName: "manual.pdf" },
280
+ ], {
281
+ delayMs: 600, // delay 600ms antar dokumen
313
282
  })
314
283
 
315
- // Dokumen
316
- await sock.sendMessage(jid, {
317
- document: { url: './laporan.pdf' },
318
- mimetype: 'application/pdf',
319
- fileName: 'laporan.pdf'
320
- })
284
+ // Kirim semua sekaligus (paralel)
285
+ const results = await sock.sendDocumentPack(jid, documents, { parallel: true })
286
+
287
+ console.log(results) // [{ success, msg? }, ...]
321
288
  ```
322
289
 
323
- ### Link Preview
290
+ > **Auto Mime Detection** — tidak perlu set `mimetype` manual. Deteksi otomatis dari extension:
291
+ > `.pdf` → `application/pdf`, `.xlsx` → spreadsheet, `.apk` → android package, dll.
324
292
 
325
- Install `link-preview-js` dulu, lalu kirim teks dengan URL biasa — preview auto-generate.
293
+ ---
326
294
 
327
- ```bash
328
- npm i link-preview-js
295
+ ## Kirim Pesan
296
+
297
+ ### Teks biasa
298
+ ```js
299
+ await sock.sendMessage(jid, { text: "Halo!" })
300
+ ```
301
+
302
+ ### Reply / Quote
303
+ ```js
304
+ await sock.sendMessage(jid, { text: "Oke siap" }, { quoted: message })
329
305
  ```
330
306
 
307
+ ### Mention user
331
308
  ```js
332
309
  await sock.sendMessage(jid, {
333
- text: 'Cek library ini: https://npmjs.com/package/n4lyx'
310
+ text: "Hei @628XXXXXXXXX, cek ini",
311
+ mentions: ["628XXXXXXXXX@s.whatsapp.net"]
334
312
  })
335
313
  ```
336
314
 
315
+ ### Tag All ⚡
316
+ ```js
317
+ // Tag semua member
318
+ await sock.sendMessage(jid, { text: "📢 Pengumuman!", tagAll: true })
319
+ // Tag admin saja
320
+ await sock.sendMessage(jid, { text: "🔔 Info admin", tagAll: true, tagAllScope: "admins" })
321
+ // Tag non-admin saja
322
+ await sock.sendMessage(jid, { text: "👋 Hei member!", tagAll: true, tagAllScope: "non_admins" })
323
+
324
+ // Ambil list JID manual
325
+ const jids = await sock.groupTagAll(groupJid, "all")
326
+ ```
327
+
337
328
  ---
338
329
 
339
330
  ## Shorthand Methods ⚡
340
331
 
341
- Biar nggak perlu susun object setiap kali, n4lyx punya shorthand methods langsung di `sock`.
342
-
343
332
  ### Gambar & Video
344
-
345
333
  ```js
346
- // Gambar
347
- await sock.sendImage(jid, buffer, 'Caption opsional')
348
- await sock.sendImage(jid, { url: './foto.jpg' })
349
-
350
- // Video
351
- await sock.sendVideo(jid, buffer, 'Caption opsional')
334
+ await sock.sendImage(jid, buffer, "Caption opsional")
335
+ await sock.sendImage(jid, { url: "./foto.jpg" })
336
+ await sock.sendVideo(jid, buffer, "Caption opsional")
352
337
  ```
353
338
 
354
339
  ### Audio
355
-
356
340
  ```js
357
- await sock.sendAudio(jid, buffer) // audio biasa
358
- await sock.sendAudio(jid, buffer, true) // voice note / PTT
359
- await sock.sendAudioPTT(jid, buffer) // alias PTT
360
- await sock.sendVoiceNote(jid, buffer) // alias voice note
341
+ await sock.sendAudio(jid, buffer) // audio biasa
342
+ await sock.sendAudio(jid, buffer, true) // voice note / PTT
343
+ await sock.sendAudioPTT(jid, buffer) // alias PTT
344
+ await sock.sendVoiceNote(jid, buffer) // alias voice note
361
345
  ```
362
346
 
363
- ### Dokumen
364
-
347
+ ### Dokumen (Auto Mime Detection)
365
348
  ```js
366
- await sock.sendDocument(jid, buffer, 'laporan.pdf', 'application/pdf', 'Ini file-nya')
349
+ // Mimetype auto-detect dari extension tidak perlu set manual
350
+ await sock.sendDocument(jid, buffer, "laporan.pdf", null, "Ini file-nya")
351
+ await sock.sendDocument(jid, buffer, "data.xlsx")
352
+ await sock.sendDocument(jid, buffer, "app.apk", null, "Update terbaru")
353
+
354
+ // Atau set manual jika perlu
355
+ await sock.sendDocument(jid, buffer, "file.bin", "application/octet-stream")
367
356
  ```
368
357
 
369
358
  ### GIF & Video Note
370
-
371
359
  ```js
372
- // GIF animasi
373
- await sock.sendGIF(jid, gifBuffer, 'wkwk')
374
-
375
- // Circular video note (kayak voice note tapi video)
360
+ await sock.sendGIF(jid, gifBuffer, "wkwk")
376
361
  await sock.sendPTV(jid, videoBuffer)
377
- await sock.sendPTV(jid, videoBuffer, { quoted: m }) // dengan quote
362
+ await sock.sendPTV(jid, videoBuffer, { quoted: m })
378
363
  ```
379
364
 
380
365
  ### View Once
381
-
382
- Media otomatis hilang setelah dilihat sekali.
383
-
384
366
  ```js
385
367
  await sock.sendViewOnce(jid, { image: buffer })
386
368
  await sock.sendViewOnce(jid, { video: buffer }, { quoted: m })
387
- await sock.sendViewOnce(jid, { audio: buffer, mimetype: 'audio/mp4' })
369
+ await sock.sendViewOnce(jid, { audio: buffer, mimetype: "audio/mp4" })
388
370
  ```
389
371
 
390
372
  ### Sticker
391
-
392
373
  ```js
393
- // Dari Buffer
394
374
  await sock.sendStickerFromBuffer(jid, buffer)
395
-
396
- // Dari URL langsung
397
- await sock.sendStickerFromUrl(jid, 'https://example.com/sticker.webp')
398
-
399
- // Dengan metadata pack
375
+ await sock.sendStickerFromUrl(jid, "https://example.com/sticker.webp")
400
376
  await sock.sendStickerWithMetadata(jid, buffer, {
401
- packName: 'Pack Gue',
402
- packPublisher: 'N4tzz',
403
- categories: ['😂']
377
+ packName: "Pack Gue", packPublisher: "N4tzz", categories: ["😂"]
404
378
  })
405
-
406
- // Kirim banyak sticker sekaligus (max 30, ada auto-delay)
407
- await sock.sendStickerPack(jid, [buf1, buf2, buf3], 'Pack Gue', 'N4tzz')
379
+ // Kirim banyak sticker (batch paralel, bukan 1-by-1)
380
+ await sock.sendStickerPack(jid, [buf1, buf2, buf3], "Pack Gue", "N4tzz")
408
381
  ```
409
382
 
410
383
  ### Album
411
-
412
- Kumpulan foto/video yang bisa di-swipe (max 10 item, bisa mix image + video).
413
-
414
384
  ```js
415
385
  await sock.sendAlbum(jid, [
416
- { image: buf1, caption: 'Foto 1' },
417
- { image: buf2, caption: 'Foto 2' },
418
- { video: buf3, caption: 'Video' }
386
+ { image: buf1, caption: "Foto 1" },
387
+ { image: buf2, caption: "Foto 2" },
388
+ { video: buf3, caption: "Video" }
419
389
  ])
420
390
  ```
421
391
 
422
392
  ### Poll
423
-
424
393
  ```js
425
- // Pilih lebih dari satu
426
- await sock.sendPoll(jid, 'Bahasa favorit?', ['JavaScript', 'Python', 'Go'])
427
-
428
- // Pilih satu saja
429
- await sock.sendPoll(jid, 'Setuju?', ['Ya', 'Tidak'], { selectableCount: 1 })
394
+ await sock.sendPoll(jid, "Bahasa favorit?", ["JavaScript", "Python", "Go"])
395
+ await sock.sendPoll(jid, "Setuju?", ["Ya", "Tidak"], { selectableCount: 1 })
430
396
  ```
431
397
 
432
398
  ### Lokasi
433
-
434
399
  ```js
435
- // Lokasi statis
436
- await sock.sendLocation(jid, -7.797068, 110.370529, 'Yogyakarta')
437
-
438
- // Live location
400
+ await sock.sendLocation(jid, -7.797068, 110.370529, "Yogyakarta")
439
401
  await sock.sendLiveLocation(jid, -7.79, 110.37, 10, 300)
440
- // parameter: lat, lng, accuracy (meter), duration (detik)
441
402
  ```
442
403
 
443
404
  ### Kontak
444
-
445
405
  ```js
446
- // Single
447
- await sock.sendContact(jid, {
448
- fullName: 'Budi Santoso',
449
- phoneNumber: '+62812xxxxxxx',
450
- org: 'Acme Corp' // opsional
451
- })
452
-
453
- // Multiple sekaligus
406
+ await sock.sendContact(jid, { fullName: "Budi Santoso", phoneNumber: "+62812xxxxxxx", org: "Acme" })
454
407
  await sock.sendContact(jid, [
455
- { fullName: 'Budi', phoneNumber: '+62812xxxxxxx' },
456
- { fullName: 'Sari', phoneNumber: '+62813xxxxxxx' }
408
+ { fullName: "Budi", phoneNumber: "+62812xxxxxxx" },
409
+ { fullName: "Sari", phoneNumber: "+62813xxxxxxx" }
457
410
  ])
458
411
  ```
459
412
 
460
413
  ### Event & Jadwal Call
461
-
462
414
  ```js
463
- // WhatsApp Event
464
415
  await sock.sendEvent(jid, {
465
- name: 'Rapat Mingguan',
466
- description: 'Sync tim setiap Senin',
467
- startTime: Date.now() + 3_600_000, // 1 jam dari sekarang
468
- endTime: Date.now() + 7_200_000, // 2 jam dari sekarang
469
- location: 'Google Meet',
470
- joinLink: 'https://meet.google.com/xxx'
416
+ name: "Rapat Mingguan", description: "Sync tim",
417
+ startTime: Date.now() + 3_600_000, endTime: Date.now() + 7_200_000,
418
+ location: "Google Meet", joinLink: "https://meet.google.com/xxx"
471
419
  })
472
-
473
- // Jadwalkan panggilan
474
- await sock.sendScheduledCall(jid, 'Catch-up session', Date.now() + 86_400_000) // video call (default)
475
- await sock.sendScheduledCall(jid, 'Voice call', Date.now() + 3_600_000, 2) // voice call
420
+ await sock.sendScheduledCall(jid, "Catch-up", Date.now() + 86_400_000) // video
421
+ await sock.sendScheduledCall(jid, "Voice call", Date.now() + 3_600_000, 2) // voice
476
422
  ```
477
423
 
478
424
  ### Reply & Mention
479
-
480
425
  ```js
481
- // Reply cepat
482
- await sock.sendReply(jid, 'Oke siap!', m)
483
-
484
- // Reply dengan media
485
- await sock.sendMediaReply(jid, { image: buffer, caption: 'ini' }, m)
486
-
487
- // Reply + mention sekaligus
488
- await sock.sendQuotedText(jid, 'Hayo @kamu', m, ['628xxx@s.whatsapp.net'])
489
-
490
- // Teks + mention
491
- await sock.sendTextWithMentions(jid, 'Halo @A dan @B', [jidA, jidB])
492
-
493
- // Tag all shorthand
494
- await sock.sendTagAll(jid, '📢 Pengumuman untuk semua')
495
- await sock.sendTagAll(jid, '🔔 Khusus admin', 'admins')
496
- await sock.sendTagAll(jid, '👋 Hei member', 'non_admins')
497
-
498
- // Tag all + mention
499
- await sock.sendMentionAll(jid, 'Hei semua!')
426
+ await sock.sendReply(jid, "Oke siap!", m)
427
+ await sock.sendMediaReply(jid, { image: buffer, caption: "ini" }, m)
428
+ await sock.sendQuotedText(jid, "Hayo @kamu", m, ["628xxx@s.whatsapp.net"])
429
+ await sock.sendTextWithMentions(jid, "Halo @A dan @B", [jidA, jidB])
430
+ await sock.sendTagAll(jid, "📢 Pengumuman untuk semua")
431
+ await sock.sendTagAll(jid, "🔔 Khusus admin", "admins")
432
+ await sock.sendMentionAll(jid, "Hei semua!")
500
433
  ```
501
434
 
502
435
  ### Invite Group
503
-
504
- Kirim invite sebagai card (bukan plain link).
505
-
506
436
  ```js
507
- await sock.sendGroupInvite(jid, '120363xxx@g.us')
437
+ await sock.sendGroupInvite(jid, "120363xxx@g.us")
508
438
  ```
509
439
 
510
440
  ### Typing Indicator
511
-
512
441
  ```js
513
- // Typing 3 detik lalu berhenti
514
- await sock.sendTyping(jid)
515
-
516
- // Recording 2 detik
517
- await sock.sendTyping(jid, 2000, 'recording')
518
-
519
- // Kirim pesan dengan typing dulu
520
- await sock.sendWithTyping(jid, { text: 'Halo!' })
521
- await sock.sendWithTyping(jid, { text: 'Halo!' }, {}, 2000) // typing 2 detik
442
+ await sock.sendTyping(jid) // typing 3 detik
443
+ await sock.sendTyping(jid, 2000, "recording") // recording 2 detik
444
+ await sock.sendWithTyping(jid, { text: "Halo!" })
445
+ await sock.sendWithTyping(jid, { text: "Halo!" }, {}, 2000)
522
446
  ```
523
447
 
524
448
  ### Broadcast & Multi-Message
525
-
526
449
  ```js
527
- // Kirim ke banyak JID (auto deduplicate, ada delay antar kirim)
528
450
  const results = await sock.broadcastMessage(
529
- ['628xxx@s.whatsapp.net', '628yyy@s.whatsapp.net'],
530
- { text: 'Pengumuman penting!' },
531
- { delayMs: 1000 }
451
+ ["628xxx@s.whatsapp.net", "628yyy@s.whatsapp.net"],
452
+ { text: "Pengumuman penting!" }, { delayMs: 1000 }
532
453
  )
533
- // results: [{ jid, success, msg? }, ...]
534
-
535
- // Broadcast ke semua group yang diikuti
536
- await sock.broadcastToGroups([groupJid1, groupJid2], { text: 'Halo semua group!' })
537
-
538
- // Kirim array pesan berurutan ke satu JID
454
+ await sock.broadcastToGroups({ text: "Halo semua group!" })
539
455
  await sock.sendMultipleMessages(jid, [
540
- { text: 'Pesan 1' },
541
- { text: 'Pesan 2' },
542
- { image: buffer, caption: 'Foto' }
543
- ], 800) // delay 800ms antar pesan
456
+ { text: "Pesan 1" }, { text: "Pesan 2" }, { image: buffer, caption: "Foto" }
457
+ ], 800)
544
458
  ```
545
459
 
546
460
  ### Status / Story
547
-
548
461
  ```js
549
- // Status pribadi
550
- await sock.sendStatus({ text: 'Pagi semua! ☀️', backgroundColor: '#128C7E' })
551
- await sock.sendStatus({ image: buffer, caption: 'Foto hari ini' })
552
- await sock.sendStatus({ video: buffer })
553
-
554
- // Batasi siapa yang bisa lihat
555
- await sock.sendStatus({ text: 'Khusus kamu' }, ['628xxx@s.whatsapp.net'])
462
+ await sock.sendStatus({ text: "Pagi semua! ☀️", backgroundColor: "#128C7E" })
463
+ await sock.sendStatus({ image: buffer, caption: "Foto hari ini" })
464
+ await sock.sendStatus({ text: "Khusus kamu" }, ["628xxx@s.whatsapp.net"])
556
465
  ```
557
466
 
558
467
  ### Group Status V2 ⚡
559
-
560
- Post story langsung di dalam group — muncul kayak story WhatsApp tapi di group.
561
-
562
468
  ```js
563
- // Teks
564
- await sock.groupStatusV2('120363xxx@g.us', {
565
- text: 'GM semua! 🌅',
566
- backgroundColor: '#25D366'
567
- })
568
-
569
- // Teks dengan font custom
570
- await sock.groupStatusV2('120363xxx@g.us', {
571
- text: 'Selamat ulang tahun! 🎉',
572
- backgroundColor: '#FF6B6B',
573
- font: 1
574
- })
575
-
576
- // Gambar
577
- await sock.groupStatusV2('120363xxx@g.us', {
578
- image: buffer,
579
- caption: 'Foto kegiatan hari ini'
580
- })
581
-
582
- // Video
583
- await sock.groupStatusV2('120363xxx@g.us', {
584
- video: buffer,
585
- caption: 'Tonton ini!'
586
- })
587
-
588
- // Sticker
589
- await sock.groupStatusV2('120363xxx@g.us', { sticker: buffer })
469
+ await sock.groupStatusV2("120363xxx@g.us", { text: "GM semua! 🌅", backgroundColor: "#25D366" })
470
+ await sock.groupStatusV2("120363xxx@g.us", { text: "HBD! 🎉", backgroundColor: "#FF6B6B", font: 1 })
471
+ await sock.groupStatusV2("120363xxx@g.us", { image: buffer, caption: "Foto kegiatan" })
472
+ await sock.groupStatusV2("120363xxx@g.us", { video: buffer, caption: "Tonton!" })
473
+ await sock.groupStatusV2("120363xxx@g.us", { sticker: buffer })
590
474
  ```
591
475
 
592
476
  ---
@@ -594,34 +478,20 @@ await sock.groupStatusV2('120363xxx@g.us', { sticker: buffer })
594
478
  ## Edit, Delete, React
595
479
 
596
480
  ```js
597
- const sent = await sock.sendMessage(jid, { text: 'Ada typo nih' })
598
-
599
- // Edit pesan
600
- await sock.editMessage(jid, sent.key, 'Sudah diperbaiki')
601
-
602
- // Hapus untuk semua
481
+ const sent = await sock.sendMessage(jid, { text: "Ada typo" })
482
+ await sock.editMessage(jid, sent.key, "Sudah diperbaiki")
603
483
  await sock.deleteMessage(jid, sent.key)
604
-
605
- // Pin pesan
606
484
  await sock.pinMessage(jid, m.key) // 24 jam
607
485
  await sock.pinMessage(jid, m.key, 604800) // 7 hari
608
486
  await sock.pinMessage(jid, m.key, 0) // unpin
609
-
610
- // Bookmark / keep
611
- await sock.keepMessage(jid, m.key) // keep
612
- await sock.keepMessage(jid, m.key, false) // unkeep
613
-
614
- // Bintang / star
615
- await sock.starMessage(jid, m.key, true) // bintangin
616
- await sock.unstarMessage(jid, m.key) // hapus bintang
617
-
618
- // React
619
- await sock.reactMessage(jid, m.key, '❤️')
620
- await sock.reactMessage(jid, m.key, '') // hapus reaksi
621
-
622
- // Forward
487
+ await sock.keepMessage(jid, m.key)
488
+ await sock.keepMessage(jid, m.key, false)
489
+ await sock.starMessage(jid, m.key, true)
490
+ await sock.unstarMessage(jid, m.key)
491
+ await sock.reactMessage(jid, m.key, "❤️")
492
+ await sock.reactMessage(jid, m.key, "") // hapus reaksi
623
493
  await sock.forwardMessage(jid, m)
624
- await sock.forwardWithComment(jid, m, 'Check ini!') // forward + komentar
494
+ await sock.forwardWithComment(jid, m, "Check ini!")
625
495
  ```
626
496
 
627
497
  ---
@@ -629,32 +499,21 @@ await sock.forwardWithComment(jid, m, 'Check ini!') // forward + komentar
629
499
  ## Chat Management
630
500
 
631
501
  ```js
632
- // Archive / unarchive
633
502
  await sock.archiveChat(jid, lastMsg)
634
503
  await sock.unarchiveChat(jid, lastMsg)
635
-
636
- // Pin / unpin chat
637
504
  await sock.pinChat(jid)
638
505
  await sock.unpinChat(jid)
639
-
640
- // Mute / unmute
641
- await sock.muteJid(jid) // mute 8 jam
642
- await sock.muteJid(jid, 24 * 60 * 60 * 1000) // mute 24 jam
506
+ await sock.muteJid(jid)
507
+ await sock.muteJid(jid, 24 * 60 * 60 * 1000)
643
508
  await sock.unmuteJid(jid)
644
-
645
- // Tandai baca / belum baca
646
509
  await sock.markAsRead([m.key])
647
- await sock.sendSeen(jid) // alias markAsRead
510
+ await sock.sendSeen(jid)
648
511
  await sock.markAsUnread(jid, lastMsg)
649
-
650
- // Hapus & bersihkan
651
512
  await sock.deleteChat(jid)
652
513
  await sock.clearChat(jid)
653
-
654
- // Block / unblock
655
514
  await sock.blockUser(jid)
656
515
  await sock.unblockUser(jid)
657
- await sock.fetchBlocklist() // ambil daftar yang diblokir
516
+ await sock.fetchBlocklist()
658
517
  ```
659
518
 
660
519
  ---
@@ -662,15 +521,10 @@ await sock.fetchBlocklist() // ambil daftar yang diblokir
662
521
  ## Disappearing Messages
663
522
 
664
523
  ```js
665
- // Aktifkan di chat
666
- await sock.sendDisappearingToggle(jid, 86400) // 24 jam
667
- await sock.setGroupDisappearing(jid, 604800) // 7 hari di group
668
- await sock.setGroupDisappearing(jid, 0) // matikan
669
-
670
- // Kirim satu pesan sebagai ephemeral
671
- await sock.sendDisappearingMessage(jid, { text: 'Pesan ini akan hilang' }, 86400)
672
-
673
- // Set default disappearing mode
524
+ await sock.sendDisappearingToggle(jid, 86400)
525
+ await sock.setGroupDisappearing(jid, 604800)
526
+ await sock.setGroupDisappearing(jid, 0)
527
+ await sock.sendDisappearingMessage(jid, { text: "Pesan ini akan hilang" }, 86400)
674
528
  await sock.setDefaultDisappearing(86400)
675
529
  ```
676
530
 
@@ -679,61 +533,37 @@ await sock.setDefaultDisappearing(86400)
679
533
  ## Groups
680
534
 
681
535
  ```js
682
- // Buat group baru
683
- const group = await sock.groupCreate('Nama Group', ['628xxx@s.whatsapp.net'])
684
- console.log('Group ID:', group.gid)
685
-
686
- // Tambah / hapus / promote / demote member
687
- await sock.groupParticipantsUpdate(jid, ['628xxx@s.whatsapp.net'], 'add')
688
- await sock.groupParticipantsUpdate(jid, ['628xxx@s.whatsapp.net'], 'remove')
689
- await sock.groupParticipantsUpdate(jid, ['628xxx@s.whatsapp.net'], 'promote')
690
- await sock.groupParticipantsUpdate(jid, ['628xxx@s.whatsapp.net'], 'demote')
691
-
692
- // Bulk action (auto chunk per 5 + delay)
693
- await sock.bulkGroupAction(jid, [jid1, jid2, jid3], 'remove')
694
-
695
- // Update info group
696
- await sock.groupUpdateSubject(jid, 'Nama Group Baru')
697
- await sock.groupUpdateDescription(jid, 'Deskripsi baru')
698
- await sock.updateGroupName(jid, 'Nama Group Baru') // alias
699
- await sock.updateGroupDescription(jid, 'Deskripsi baru') // alias
700
- await sock.updateGroupProfilePicture(jid, buffer) // ganti foto group
701
-
702
- // Setting group
703
- await sock.groupSettingUpdate(jid, 'announcement') // hanya admin yang bisa kirim
704
- await sock.groupSettingUpdate(jid, 'not_announcement') // semua bisa kirim
705
- await sock.updateGroupSetting(jid, 'locked') // alias
706
- await sock.updateGroupSetting(jid, 'unlocked')
707
-
708
- // Invite link
536
+ const group = await sock.groupCreate("Nama Group", ["628xxx@s.whatsapp.net"])
537
+ await sock.groupParticipantsUpdate(jid, ["628xxx@s.whatsapp.net"], "add")
538
+ await sock.groupParticipantsUpdate(jid, ["628xxx@s.whatsapp.net"], "remove")
539
+ await sock.groupParticipantsUpdate(jid, ["628xxx@s.whatsapp.net"], "promote")
540
+ await sock.groupParticipantsUpdate(jid, ["628xxx@s.whatsapp.net"], "demote")
541
+ await sock.bulkGroupAction(jid, [jid1, jid2, jid3], "remove")
542
+ await sock.updateGroupName(jid, "Nama Baru")
543
+ await sock.updateGroupDescription(jid, "Deskripsi baru")
544
+ await sock.updateGroupProfilePicture(jid, buffer)
545
+ await sock.updateGroupSetting(jid, "announcement")
546
+ await sock.updateGroupSetting(jid, "not_announcement")
547
+ await sock.updateGroupSetting(jid, "locked")
548
+ await sock.updateGroupSetting(jid, "unlocked")
709
549
  const code = await sock.groupInviteCode(jid)
710
- const link = await sock.getGroupInviteLink(jid) // return URL lengkap
711
- await sock.groupRevokeInvite(jid) // atau: revokeGroupInvite(jid)
712
- await sock.groupAcceptInvite(code) // join (tanpa URL prefix)
713
- await sock.joinGroupViaLink('https://chat.whatsapp.com/...') // join via URL
714
-
715
- // Info & metadata
716
- const meta = await sock.groupMetadata(jid)
717
- const all = await sock.fetchAllGroups() // semua group yang diikuti
718
-
719
- // Admin utilities
550
+ const link = await sock.getGroupInviteLink(jid)
551
+ await sock.groupRevokeInvite(jid)
552
+ await sock.groupAcceptInvite(code)
553
+ await sock.joinGroupViaLink("https://chat.whatsapp.com/...")
554
+ const meta = await sock.groupMetadata(jid)
555
+ const all = await sock.fetchAllGroups()
720
556
  const admins = await sock.getGroupAdmins(jid)
721
- const isAdmin = await sock.isGroupAdmin(jid, '628xxx@s.whatsapp.net')
557
+ const isAdmin = await sock.isGroupAdmin(jid, "628xxx@s.whatsapp.net")
722
558
  const members = await sock.getGroupParticipants(jid)
723
- await sock.sendToAdminsOnly(jid, 'Pesan khusus admin')
724
- await sock.sendAdminInvite(jid, targetJid) // undang jadi admin
725
-
726
- // Join approval
727
- await sock.setGroupJoinApproval(jid, true) // nyalakan approval
559
+ await sock.sendToAdminsOnly(jid, "Pesan khusus admin")
560
+ await sock.sendAdminInvite(jid, targetJid)
561
+ await sock.setGroupJoinApproval(jid, true)
728
562
  const requests = await sock.getGroupJoinRequests(jid)
729
- await sock.approveGroupJoinRequest(jid, ['628xxx@s.whatsapp.net'])
730
- await sock.rejectGroupJoinRequest(jid, ['628xxx@s.whatsapp.net'])
731
-
732
- // Member add mode
733
- await sock.setGroupMemberAddMode(jid, 'all_member_add') // semua bisa add
734
- await sock.setGroupMemberAddMode(jid, 'admin_add') // hanya admin
735
-
736
- // Leave
563
+ await sock.approveGroupJoinRequest(jid, ["628xxx@s.whatsapp.net"])
564
+ await sock.rejectGroupJoinRequest(jid, ["628xxx@s.whatsapp.net"])
565
+ await sock.setGroupMemberAddMode(jid, "all_member_add")
566
+ await sock.setGroupMemberAddMode(jid, "admin_add")
737
567
  await sock.leaveGroup(jid)
738
568
  ```
739
569
 
@@ -742,57 +572,39 @@ await sock.leaveGroup(jid)
742
572
  ## Interaktif: Buttons, List, Template ⚡
743
573
 
744
574
  ```js
745
- // Pesan dengan tombol
746
- await sock.sendButtonsMessage(jid, {
747
- text: 'Pilih salah satu:',
748
- buttons: [
749
- { buttonId: 'id1', buttonText: { displayText: 'Opsi A' }, type: 1 },
750
- { buttonId: 'id2', buttonText: { displayText: 'Opsi B' }, type: 1 }
751
- ],
752
- headerType: 1
753
- })
575
+ await sock.sendButtonsMessage(jid, "Pilih salah satu:", [
576
+ { buttonId: "id1", buttonText: { displayText: "Opsi A" }, type: 1 },
577
+ { buttonId: "id2", buttonText: { displayText: "Opsi B" }, type: 1 }
578
+ ], "Footer")
754
579
 
755
- // Gambar + tombol
756
- await sock.sendImageWithButtons(jid, buffer, 'Caption', [
757
- { buttonId: 'confirm', buttonText: { displayText: '✅ Konfirmasi' }, type: 1 },
758
- { buttonId: 'cancel', buttonText: { displayText: '❌ Batal' }, type: 1 }
580
+ await sock.sendImageWithButtons(jid, buffer, "Caption", [
581
+ { buttonId: "confirm", buttonText: { displayText: "✅ Konfirmasi" }, type: 1 },
582
+ { buttonId: "cancel", buttonText: { displayText: "❌ Batal" }, type: 1 }
759
583
  ])
760
-
761
- // Video + tombol
762
- await sock.sendVideoWithButtons(jid, videoBuffer, 'Tonton dulu', [
763
- { buttonId: 'share', buttonText: { displayText: '📤 Share' }, type: 1 }
584
+ await sock.sendVideoWithButtons(jid, videoBuffer, "Tonton dulu", [
585
+ { buttonId: "share", buttonText: { displayText: "📤 Share" }, type: 1 }
764
586
  ])
765
-
766
- // Dokumen + tombol
767
- await sock.sendDocumentWithButtons(jid, pdfBuffer, 'laporan.pdf', 'application/pdf', 'Ini laporan nya', [
768
- { buttonId: 'download', buttonText: { displayText: '⬇️ Download' }, type: 1 }
587
+ await sock.sendDocumentWithButtons(jid, pdfBuffer, "laporan.pdf", "Laporan ini", [
588
+ { buttonId: "download", buttonText: { displayText: "⬇️ Download" }, type: 1 }
769
589
  ])
770
590
 
771
- // List / menu
772
591
  await sock.sendListMessage(jid, {
773
- text: 'Pilih menu:',
774
- footer: 'n4lyx bot',
775
- title: 'Main Menu',
776
- buttonText: 'Buka Menu',
777
- sections: [
778
- {
779
- title: 'Kategori 1',
780
- rows: [
781
- { title: 'Info', rowId: 'info', description: 'Lihat informasi' },
782
- { title: 'Help', rowId: 'help', description: 'Bantuan' }
783
- ]
784
- }
785
- ]
592
+ text: "Pilih menu:", footer: "n4lyx bot", title: "Main Menu", buttonText: "Buka Menu",
593
+ sections: [{
594
+ title: "Kategori 1",
595
+ rows: [
596
+ { title: "Info", rowId: "info", description: "Lihat informasi" },
597
+ { title: "Help", rowId: "help", description: "Bantuan" }
598
+ ]
599
+ }]
786
600
  })
787
601
 
788
- // Template message
789
602
  await sock.sendTemplateMessage(jid, {
790
- text: 'Hai! Ada yang bisa dibantu?',
791
- footer: 'n4lyx',
603
+ text: "Hai! Ada yang bisa dibantu?", footer: "n4lyx",
792
604
  templateButtons: [
793
- { index: 1, urlButton: { displayText: '🌐 Website', url: 'https://example.com' } },
794
- { index: 2, callButton: { displayText: '📞 Telepon', phoneNumber: '+62812xxxxxxx' } },
795
- { index: 3, quickReplyButton: { displayText: '💬 Chat', id: 'chat' } }
605
+ { index: 1, urlButton: { displayText: "🌐 Website", url: "https://example.com" } },
606
+ { index: 2, callButton: { displayText: "📞 Telepon", phoneNumber: "+62812xxxxxxx" } },
607
+ { index: 3, quickReplyButton: { displayText: "💬 Chat", id: "chat" } }
796
608
  ]
797
609
  })
798
610
  ```
@@ -802,15 +614,10 @@ await sock.sendTemplateMessage(jid, {
802
614
  ## Newsletter ⚡
803
615
 
804
616
  ```js
805
- // Info channel / newsletter
806
617
  const info = await sock.getNewsletterInfo(newsletterJid)
807
-
808
- // Kirim pesan ke newsletter
809
- await sock.sendNewsletterMessage(newsletterJid, { text: 'Update terbaru!' })
810
- await sock.sendNewsletterMessage(newsletterJid, { image: buffer, caption: 'Foto' })
811
-
812
- // Reaksi di newsletter
813
- await sock.sendNewsletterReaction(newsletterJid, messageId, '🔥')
618
+ await sock.sendNewsletterMessage(newsletterJid, { text: "Update terbaru!" })
619
+ await sock.sendNewsletterMessage(newsletterJid, { image: buffer, caption: "Foto" })
620
+ await sock.sendNewsletterReaction(newsletterJid, messageId, "🔥")
814
621
  ```
815
622
 
816
623
  ---
@@ -818,52 +625,35 @@ await sock.sendNewsletterReaction(newsletterJid, messageId, '🔥')
818
625
  ## Download Media
819
626
 
820
627
  ```js
821
- const { downloadMediaMessage, getContentType } = require('n4lyx')
822
- const { createWriteStream } = require('fs')
628
+ const { downloadMediaMessage, getContentType } = require("n4lyx")
629
+ const { createWriteStream } = require("fs")
823
630
 
824
- sock.ev.on('messages.upsert', async ({ messages: [m] }) => {
631
+ sock.ev.on("messages.upsert", async ({ messages: [m] }) => {
825
632
  if (!m.message) return
826
633
  const type = getContentType(m)
827
-
828
- if (type === 'imageMessage') {
829
- const stream = await downloadMediaMessage(m, 'stream', {}, {
830
- logger,
831
- reuploadRequest: sock.updateMediaMessage
634
+ if (type === "imageMessage") {
635
+ const stream = await downloadMediaMessage(m, "stream", {}, {
636
+ logger, reuploadRequest: sock.updateMediaMessage
832
637
  })
833
- stream.pipe(createWriteStream('./download.jpg'))
638
+ stream.pipe(createWriteStream("./download.jpg"))
834
639
  }
835
640
  })
836
641
  ```
837
642
 
838
- Re-upload media yang expired (link kedaluwarsa):
839
-
840
- ```js
841
- const refreshed = await sock.updateMediaMessage(msg)
842
- ```
843
-
844
643
  ---
845
644
 
846
645
  ## Poll — Dekripsi Vote
847
646
 
848
- Poll dienkripsi by default. Dekripsi harus dilakukan di event `messages.update`.
849
-
850
647
  ```js
851
- const { getAggregateVotesInPollMessage } = require('n4lyx')
648
+ const { getAggregateVotesInPollMessage } = require("n4lyx")
852
649
 
853
- sock.ev.on('messages.update', async (events) => {
650
+ sock.ev.on("messages.update", async (events) => {
854
651
  for (const { key, update } of events) {
855
652
  if (!update.pollUpdates) continue
856
-
857
- const creation = await getMessage(key) // ambil dari DB/store kamu
653
+ const creation = await getMessage(key)
858
654
  if (!creation) continue
859
-
860
- const result = getAggregateVotesInPollMessage({
861
- message: creation,
862
- pollUpdates: update.pollUpdates
863
- })
864
-
865
- console.log('Hasil vote:', result)
866
- // result: [{ name: 'JavaScript', voters: ['628xxx@s.whatsapp.net', ...] }, ...]
655
+ const result = getAggregateVotesInPollMessage({ message: creation, pollUpdates: update.pollUpdates })
656
+ console.log("Hasil vote:", result)
867
657
  }
868
658
  })
869
659
  ```
@@ -873,18 +663,13 @@ sock.ev.on('messages.update', async (events) => {
873
663
  ## Presence
874
664
 
875
665
  ```js
876
- // Kirim indikator presence
877
- await sock.sendPresenceUpdate('composing', jid) // lagi ngetik
878
- await sock.sendPresenceUpdate('recording', jid) // lagi rekam audio
879
- await sock.sendPresenceUpdate('paused', jid) // berhenti ngetik
880
- await sock.sendPresenceUpdate('available', jid) // online
881
- await sock.sendPresenceUpdate('unavailable', jid) // offline
882
-
883
- // Subscribe presence orang lain
666
+ await sock.sendPresenceUpdate("composing", jid)
667
+ await sock.sendPresenceUpdate("recording", jid)
668
+ await sock.sendPresenceUpdate("paused", jid)
669
+ await sock.sendPresenceUpdate("available", jid)
670
+ await sock.sendPresenceUpdate("unavailable", jid)
884
671
  await sock.presenceSubscribe(jid)
885
- sock.ev.on('presence.update', ({ id, presences }) => {
886
- console.log(id, presences) // lihat siapa yang lagi online
887
- })
672
+ sock.ev.on("presence.update", ({ id, presences }) => { console.log(id, presences) })
888
673
  ```
889
674
 
890
675
  ---
@@ -892,26 +677,13 @@ sock.ev.on('presence.update', ({ id, presences }) => {
892
677
  ## Query & Info
893
678
 
894
679
  ```js
895
- // Cek apakah nomor terdaftar di WA
896
- const info = await sock.isOnWhatsApp('628xxxxxxxxx')
897
- // → { exists: true, jid: '628xxx@s.whatsapp.net' }
898
-
899
- // Info lengkap kontak
680
+ const info = await sock.isOnWhatsApp("628xxxxxxxxx")
900
681
  const contact = await sock.getContactInfo(jid)
901
-
902
- // Status teks (safe — return null kalau gagal)
903
- const status = await sock.getUserStatus(jid)
904
-
905
- // Foto profil (safe — return null kalau gagal)
906
- const pic = await sock.getProfilePicture(jid) // low res
907
- const picHD = await sock.getProfilePicture(jid, true) // high res
908
-
909
- // Business profile
910
- const biz = await sock.getBusinessProfile(jid)
911
-
912
- // Riwayat pesan (max 50 per call)
682
+ const status = await sock.getUserStatus(jid)
683
+ const pic = await sock.getProfilePicture(jid)
684
+ const picHD = await sock.getProfilePicture(jid, true)
685
+ const biz = await sock.getBusinessProfile(jid)
913
686
  await sock.fetchMessageHistory(50, oldest.key, oldest.messageTimestamp)
914
- // masuk via event: messaging.history-set
915
687
  ```
916
688
 
917
689
  ---
@@ -919,16 +691,12 @@ await sock.fetchMessageHistory(50, oldest.key, oldest.messageTimestamp)
919
691
  ## Privacy
920
692
 
921
693
  ```js
922
- // Update semua privacy settings
923
- // nilai: 'all' | 'contacts' | 'contact_blacklist' | 'none'
924
- await sock.updateLastSeenPrivacy('contacts')
925
- await sock.updateProfilePicturePrivacy('contacts')
926
- await sock.updateStatusPrivacy('contacts')
927
- await sock.updateReadReceiptsPrivacy('all')
928
- await sock.updateGroupsAddPrivacy('contacts')
929
- await sock.updateOnlinePrivacy('all') // atau 'match_last_seen'
930
-
931
- // Default disappearing mode
694
+ await sock.updateLastSeenPrivacy("contacts")
695
+ await sock.updateProfilePicturePrivacy("contacts")
696
+ await sock.updateStatusPrivacy("contacts")
697
+ await sock.updateReadReceiptsPrivacy("all")
698
+ await sock.updateGroupsAddPrivacy("contacts")
699
+ await sock.updateOnlinePrivacy("all")
932
700
  await sock.updateDefaultDisappearingMode(86400)
933
701
  ```
934
702
 
@@ -937,9 +705,9 @@ await sock.updateDefaultDisappearingMode(86400)
937
705
  ## Profile
938
706
 
939
707
  ```js
940
- await sock.updateProfileStatus('Sedang coding...')
941
- await sock.updateProfileName('Nama Baru')
942
- await sock.updateProfilePicture(jid, { url: './foto.jpg' })
708
+ await sock.updateProfileStatus("Sedang coding...")
709
+ await sock.updateProfileName("Nama Baru")
710
+ await sock.updateProfilePicture(jid, { url: "./foto.jpg" })
943
711
  await sock.removeProfilePicture(jid)
944
712
  ```
945
713
 
@@ -948,12 +716,7 @@ await sock.removeProfilePicture(jid)
948
716
  ## Calls
949
717
 
950
718
  ```js
951
- // Tolak incoming call
952
- sock.ev.on('call', async ([call]) => {
953
- await sock.rejectCall(call.id, call.from)
954
- })
955
-
956
- // Auto-reject semua call (aktifkan sekali saat startup)
719
+ sock.ev.on("call", async ([call]) => { await sock.rejectCall(call.id, call.from) })
957
720
  sock.rejectAllCalls()
958
721
  ```
959
722
 
@@ -961,76 +724,35 @@ sock.rejectAllCalls()
961
724
 
962
725
  ## In-Memory Store
963
726
 
964
- Untuk development / testing. **Jangan dipakai di production.**
965
-
966
727
  ```js
967
- const { makeInMemoryStore } = require('n4lyx')
968
-
728
+ const { makeInMemoryStore } = require("n4lyx")
969
729
  const store = makeInMemoryStore({})
970
- store.readFromFile('./store.json')
971
- setInterval(() => store.writeToFile('./store.json'), 10_000)
972
-
973
- const sock = makeWASocket({})
730
+ store.readFromFile("./store.json")
731
+ setInterval(() => store.writeToFile("./store.json"), 10_000)
974
732
  store.bind(sock.ev)
975
733
  ```
976
734
 
977
735
  ---
978
736
 
979
- ## WebSocket Low-Level
980
-
981
- ```js
982
- // Listen ke protokol WA secara langsung
983
- sock.ws.on('CB:edge_routing', (node) => { })
984
- sock.ws.on('CB:edge_routing,id:abcd', (node) => { })
985
- ```
986
-
987
- Debug mode — log semua WA protocol frame:
988
-
989
- ```js
990
- const P = require('pino')
991
- const sock = makeWASocket({ logger: P({ level: 'debug' }) })
992
- ```
993
-
994
- ---
995
-
996
737
  ## JID Format
997
738
 
998
739
  | Tipe | Format |
999
740
  |---|---|
1000
741
  | User | `628XXXXXXXXX@s.whatsapp.net` |
1001
742
  | Group | `123456789-123456@g.us` |
743
+ | Newsletter/Channel | `xxxxxxxxxx@newsletter` |
1002
744
  | Broadcast list | `[timestamp]@broadcast` |
1003
745
  | Story / Status | `status@broadcast` |
1004
746
 
1005
747
  ---
1006
748
 
1007
- ## Utilities
1008
-
1009
- | Fungsi | Kegunaan |
1010
- |---|---|
1011
- | `getContentType(msg)` | Ambil tipe konten dari sebuah pesan |
1012
- | `getDevice(msg)` | Info device pengirim pesan |
1013
- | `makeCacheableSignalKeyStore` | Percepat operasi auth key store |
1014
- | `downloadContentFromMessage` | Download raw content dari pesan |
1015
- | `fetchLatestN4lyxVersion` | Ambil versi terbaru n4lyx dari npm |
1016
- | `fetchLatestWaWebVersion` | Ambil versi terbaru WA Web |
1017
-
1018
- ---
1019
-
1020
749
  ## Optional Dependencies
1021
750
 
1022
- Install sesuai kebutuhan — nggak wajib semua.
1023
-
1024
751
  ```bash
1025
- npm i jimp # thumbnail generator (bisa juga pakai sharp)
1026
- npm i link-preview-js # link preview otomatis di pesan teks
1027
- npm i qrcode-terminal # render QR code di terminal
1028
- ```
1029
-
1030
- Konversi audio ke format yang kompatibel (butuh `ffmpeg` di sistem):
1031
-
1032
- ```bash
1033
- ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
752
+ npm i sharp # resize, compress, convert (RECOMMENDED)
753
+ npm i jimp # fallback resize/convert jika sharp tidak bisa
754
+ npm i link-preview-js # link preview otomatis
755
+ npm i qrcode-terminal # QR di terminal
1034
756
  ```
1035
757
 
1036
758
  ---
@@ -1040,6 +762,18 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1040
762
  <details>
1041
763
  <summary><strong>Lihat semua method (klik untuk expand)</strong></summary>
1042
764
 
765
+ ### NEW ⚡
766
+
767
+ | Method | Keterangan |
768
+ |---|---|
769
+ | `getFollowedChannels()` | Semua channel/newsletter yang diikuti |
770
+ | `getJoinedGroups(withMeta?)` | Semua group yang diikuti, optional dengan foto profil |
771
+ | `getAllContacts()` | Semua kontak tersimpan |
772
+ | `convertToSticker(buf, opts)` | Convert image → WebP sticker (resize+compress) |
773
+ | `convertMedia(buf, opts)` | Resize + compress image (JPEG/PNG/WebP) |
774
+ | `sendStickerPackAlbum(jid, stickers, pack, pub, opts)` | Kirim sticker pack batch besar paralel |
775
+ | `sendDocumentPack(jid, docs, opts)` | Kirim banyak dokumen sekaligus |
776
+
1043
777
  ### Pesan
1044
778
 
1045
779
  | Method | Keterangan |
@@ -1049,15 +783,17 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1049
783
  | `sendAudio` | Kirim audio / PTT |
1050
784
  | `sendAudioPTT` | Alias PTT |
1051
785
  | `sendVoiceNote` | Alias voice note |
1052
- | `sendDocument` | Kirim dokumen |
786
+ | `sendDocument` | Kirim dokumen (auto mime detection) |
1053
787
  | `sendGIF` | Kirim GIF animasi |
1054
788
  | `sendPTV` | Circular video note |
1055
789
  | `sendViewOnce` | View-once media |
1056
- | `sendSticker` / `sendStickerMessage` | Kirim sticker |
790
+ | `sendStickerMessage` | Kirim sticker |
1057
791
  | `sendStickerFromBuffer` | Sticker dari Buffer |
1058
792
  | `sendStickerFromUrl` | Sticker dari URL |
1059
793
  | `sendStickerWithMetadata` | Sticker + pack info |
1060
- | `sendStickerPack` | Kirim banyak sticker |
794
+ | `sendStickerPack` | Kirim banyak sticker (batch paralel) |
795
+ | `sendStickerPackAlbum` | Kirim sticker pack album mode |
796
+ | `sendDocumentPack` | Kirim banyak dokumen sekaligus |
1061
797
  | `sendAlbum` | Album swipeable |
1062
798
  | `sendPoll` | Buat poll |
1063
799
  | `sendEvent` | WhatsApp Event |
@@ -1082,7 +818,6 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1082
818
  | `sendWithQuotedFake` | Kirim dengan fake quote |
1083
819
  | `forwardWithComment` | Forward + komentar |
1084
820
  | `sendWithMentionAndReply` | Reply + mention sekaligus |
1085
- | `tagAll` di `sendMessage` | Auto-mention all/admin/non-admin |
1086
821
  | `groupTagAll` | Ambil list JID by scope |
1087
822
 
1088
823
  ### Interaktif
@@ -1098,10 +833,11 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1098
833
  | `sendVideoWithButtons` | Video + tombol |
1099
834
  | `sendDocumentWithButtons` | Dokumen + tombol |
1100
835
 
1101
- ### Newsletter
836
+ ### Newsletter / Channel
1102
837
 
1103
838
  | Method | Keterangan |
1104
839
  |---|---|
840
+ | `getFollowedChannels` | Semua channel yang diikuti |
1105
841
  | `sendNewsletterMessage` | Kirim ke newsletter |
1106
842
  | `sendNewsletterReaction` | Reaksi di newsletter |
1107
843
  | `getNewsletterInfo` | Info channel |
@@ -1150,16 +886,17 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1150
886
 
1151
887
  | Method | Keterangan |
1152
888
  |---|---|
889
+ | `getJoinedGroups` | Semua group yang diikuti |
1153
890
  | `groupCreate` | Buat group |
1154
891
  | `groupParticipantsUpdate` | add/remove/promote/demote |
1155
892
  | `bulkGroupAction` | Bulk action member |
1156
- | `groupUpdateSubject` / `updateGroupName` | Ganti nama |
1157
- | `groupUpdateDescription` / `updateGroupDescription` | Ganti deskripsi |
893
+ | `updateGroupName` | Ganti nama |
894
+ | `updateGroupDescription` | Ganti deskripsi |
1158
895
  | `updateGroupProfilePicture` | Ganti foto group |
1159
- | `updateGroupSetting` / `groupSettingUpdate` | Setting group |
1160
- | `getGroupInviteLink` / `groupInviteCode` | Invite link |
1161
- | `revokeGroupInvite` / `groupRevokeInvite` | Revoke link |
1162
- | `joinGroupViaLink` / `groupAcceptInvite` | Join group |
896
+ | `updateGroupSetting` | Setting group |
897
+ | `getGroupInviteLink` | Invite link URL |
898
+ | `revokeGroupInvite` | Revoke link |
899
+ | `joinGroupViaLink` | Join via URL |
1163
900
  | `groupMetadata` | Metadata group |
1164
901
  | `fetchAllGroups` | Semua group |
1165
902
  | `getGroupAdmins` | Daftar admin |
@@ -1172,7 +909,7 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1172
909
  | `approveGroupJoinRequest` | Approve request |
1173
910
  | `rejectGroupJoinRequest` | Reject request |
1174
911
  | `setGroupMemberAddMode` | Siapa yang bisa add member |
1175
- | `groupLeave` / `leaveGroup` | Leave group |
912
+ | `leaveGroup` | Leave group |
1176
913
  | `setGroupDisappearing` | Disappearing messages di group |
1177
914
 
1178
915
  ### Disappearing
@@ -1190,10 +927,18 @@ ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
1190
927
  | `sendStatus` | Post story pribadi |
1191
928
  | `groupStatusV2` | Post story di group ⚡ |
1192
929
 
930
+ ### Convert & Media Utils ⚡
931
+
932
+ | Method | Keterangan |
933
+ |---|---|
934
+ | `convertToSticker(buf, opts)` | Convert image → WebP sticker |
935
+ | `convertMedia(buf, opts)` | Resize + compress image |
936
+
1193
937
  ### Query & Info
1194
938
 
1195
939
  | Method | Keterangan |
1196
940
  |---|---|
941
+ | `getAllContacts` | Semua kontak tersimpan |
1197
942
  | `isOnWhatsApp` | Cek nomor (input fleksibel) |
1198
943
  | `getContactInfo` | Info kontak |
1199
944
  | `getUserStatus` | Status teks (safe) |