@kangwifi-pro/waliwa 3.0.0 → 3.0.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/README.md CHANGED
@@ -1,600 +1,467 @@
1
1
  # Waliwa
2
2
 
3
- > **Lightweight WhatsApp library with hybrid protocol (WA Web MD + Mobile API)**
3
+ > WhatsApp library based on Baileys 7 + zaileys + baileys-mbuilder
4
4
  >
5
- > Lebih lengkap dari Baileys, lebih ringan dari ZapoJS, lebih hemat RAM.
5
+ > Super ringan, fluent API, dengan MessageBuilder, CommandSystem, Automation, dan Plugin system.
6
6
 
7
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
8
- [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D16-green.svg)](https://nodejs.org/)
7
+ [![npm version](https://img.shields.io/npm/v/@kangwifi-pro/waliwa.svg)](https://www.npmjs.com/package/@kangwifi-pro/waliwa)
9
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
9
 
11
- ## ✨ Fitur Utama
12
-
13
- ### Hybrid Protocol (Lebih Lengkap dari Baileys)
14
- - **WhatsApp Web Multi-Device** - QR code login via WebSocket + Noise Protocol
15
- - **Mobile API Pairing** - Login via phone number + 8-character code (tanpa scan QR)
16
- - **Auto-Fallback** - Switch otomatis antara WA Web dan Mobile API jika gagal
17
-
18
- ### SKDM (Store Key Data Manager) - Baru!
19
- - **Auto-regenerate pre-keys** saat hampir habis (fix Baileys pre-key exhaustion)
20
- - **LRU cache** untuk sessions (RAM efficient, fix memory leak)
21
- - **Atomic file writes** (fix session corruption on disconnect)
22
- - **Identity change detection** (security alerts)
23
- - **Background key rotation** otomatis
24
-
25
- ### RAM-Efficient (Lebih Ringan dari ZapoJS)
26
- - **Buffer Pooling** - Reuse buffer untuk hindari GC pressure
27
- - **Lazy Loading** - Hanya load sessions/keys saat dibutuhkan
28
- - **Debounced Writes** - Batch disk writes untuk hemat IO
29
- - **3 Level Optimasi** - Balanced, Aggressive, Ultra (untuk low-end devices)
30
-
31
- ### Fix Baileys Issues (9+ fixes)
32
- 1. ✅ Pre-key exhaustion → auto-regeneration
33
- 2. ✅ Race condition → per-recipient message queue
34
- 3. ✅ Memory leak → WeakEventEmitter dengan FinalizationRegistry
35
- 4. ✅ Connection hang → heartbeat dengan dead detection
36
- 5. ✅ Decryption failure → retry queue + session prefetch
37
- 6. ✅ Duplicate messages → idempotency cache dengan TTL
38
- 7. ✅ Group events missing → event coalescing
39
- 8. ✅ Media upload timeout → chunked upload dengan resume
40
- 9. ✅ History sync incomplete → resume manager
41
-
42
- ### Fitur Baru
43
- - ✅ **Multi-Branch SKDM Recovery** - 8 disconnect reasons dengan recovery branches masing-masing
44
- - ✅ **Health Monitor** - real-time health score 0-100 dengan auto-recovery
45
- - ✅ **Multi-account Manager** - manage multiple WhatsApp accounts
46
- - ✅ **Webhook System** - reliable delivery dengan HMAC signature + retry + DLQ
47
- - ✅ **Circuit Breaker** - prevent retry storms untuk failed recipients
48
- - ✅ **Rate Limit Tracker** - per-recipient rate limiting
49
- - ✅ **Message Persistence** - survive restarts dengan pending message recovery
50
-
51
- ### Fitur Lengkap WhatsApp
52
- - ✅ **Auth & Session** - QR pairing, phone code pairing, persistent session
53
- - ✅ **Messages** - Text, media, reply, forward, reactions, polls
54
- - ✅ **Group Management** - Create, invite, promote, demote, settings, anti-link, anti-spam
55
- - ✅ **Advanced** - Newsletter, Status/Stories, Business Profile, Catalog, Labels
56
- - ✅ **Call Handling** - Incoming call notification, auto-reject, voice transcription hook
57
- - ✅ **Media** - Upload/download dengan AES-256-CBC + HMAC-SHA256 encryption
58
-
59
- ### Original Implementation
60
- - Clean-room implementation dari Noise Protocol XX handshake
61
- - Manual binary encoder/decoder untuk WA Web binary format
62
- - Hybrid approach: lib untuk primitives (Noble Curves), manual untuk WA-specific encoding
63
-
64
- ## 📦 Instalasi
10
+ ## Instalasi
65
11
 
66
12
  ```bash
67
- npm install waliwa
68
- # atau
69
- yarn add waliwa
70
- # atau
71
- pnpm add waliwa
13
+ npm install @kangwifi-pro/waliwa
72
14
  ```
73
15
 
74
- ## 🚀 Quick Start
75
-
76
- ### Basic Bot dengan QR Code
77
-
78
- ```typescript
79
- import { makeWASocket, useFileAuthState } from 'waliwa';
80
-
81
- async function main() {
82
- // Initialize file-based auth state
83
- const { state } = await useFileAuthState('./auth');
84
-
85
- // Create socket
86
- const sock = makeWASocket({
87
- authState: state,
88
- printQRInTerminal: true,
89
- ramOptimizationLevel: 2 // 1=balanced, 2=aggressive, 3=ultra
90
- });
91
-
92
- // Connection events
93
- sock.ev.on('connection.update', ({ connection, qr }) => {
94
- if (qr) console.log('Scan QR dengan WhatsApp mobile');
95
- if (connection === 'open') console.log('✓ Connected!');
96
- });
97
-
98
- // Handle messages
99
- sock.ev.on('message.upsert', async ({ messages, type }) => {
100
- if (type !== 'notify') return;
101
- for (const msg of messages) {
102
- if (!msg.key.fromMe && msg.message?.text) {
103
- await sock.sendMessage(msg.key.remoteJid, {
104
- text: `Echo: ${msg.message.text}`
105
- });
106
- }
107
- }
108
- });
109
- }
110
-
111
- main();
112
- ```
113
-
114
- ### Mobile API Mode (Pairing Code)
16
+ ## Quick Start (3 baris)
115
17
 
116
18
  ```typescript
117
- import { makeWASocket, useFileAuthState } from 'waliwa';
118
-
119
- const { state } = await useFileAuthState('./auth');
19
+ import { quickStart, MessageHelper } from '@kangwifi-pro/waliwa';
120
20
 
121
- const sock = makeWASocket({
122
- authState: state,
123
- mobile: true, // Enable Mobile API mode
124
- phoneNumber: '6281234567890', // Target phone number
125
- ramOptimizationLevel: 3
126
- });
127
-
128
- sock.ev.on('pairing-code.update', ({ code }) => {
129
- console.log(`\nPairing code: ${code}`);
130
- console.log('Input code ini di WhatsApp mobile app > Settings > Linked Devices\n');
131
- });
21
+ const sock = await quickStart({ authFolder: './auth' });
132
22
 
133
- sock.ev.on('connection.update', ({ connection }) => {
134
- if (connection === 'open') console.log('✓ Paired & connected!');
23
+ sock.ev.on('messages.upsert', async ({ messages }) => {
24
+ for (const msg of messages) {
25
+ if (MessageHelper.isFromMe(msg)) continue;
26
+ const text = MessageHelper.getText(msg);
27
+ if (text === '!ping') await MessageHelper.reply(sock, msg, 'pong! 🏓');
28
+ }
135
29
  });
136
30
  ```
137
31
 
138
- ### Multi-Branch SKDM Recovery
32
+ QR otomatis muncul di terminal. Scan dengan WhatsApp → Settings → Linked Devices.
139
33
 
140
- ```typescript
141
- import { makeWASocket, useFileAuthState } from 'waliwa';
142
-
143
- const { state } = await useFileAuthState('./auth');
144
-
145
- const sock = makeWASocket({
146
- authState: state,
147
- printQRInTerminal: true,
148
-
149
- // Multi-Branch Recovery config
150
- recovery: {
151
- enabled: true,
152
- maxAttemptsPerBranch: 3, // Max attempts per branch
153
- maxTotalAttempts: 20, // Total max attempts
154
- initialDelayMs: 1000, // Initial backoff delay
155
- maxDelayMs: 60000, // Max backoff delay
156
- rateLimitedDelayMs: 300000 // 5 min cooldown for rate limit
157
- }
158
- });
34
+ Auto-reconnect, auto-save credentials, auto-keepalive — semua sudah aktif default.
159
35
 
160
- // Monitor recovery events
161
- sock.recoveryManager.on('recovery:start', ({ reason, code }) => {
162
- console.warn(`Recovery started: ${reason} (code ${code})`);
163
- });
36
+ ## Fitur Utama
164
37
 
165
- sock.recoveryManager.on('recovery:success', ({ reason, totalAttempts, duration }) => {
166
- console.log(`Recovery succeeded: ${reason} in ${duration}ms (${totalAttempts} attempts)`);
167
- });
168
-
169
- sock.recoveryManager.on('recovery:failed', ({ reason, fatal }) => {
170
- console.error(`Recovery failed: ${reason} (fatal: ${fatal})`);
171
- if (fatal) {
172
- // Manual QR re-scan required
173
- notifyAdmin(`Bot logged out! Reason: ${reason}. Re-auth required.`);
174
- }
175
- });
176
-
177
- // Branches:
178
- // Connection lost Immediate retry Stream reconnect Backoff →
179
- // Key refresh Pre-key fetch Full re-auth QR
180
- // Rate limited Wait cooldown 5min Backoff retry
181
- // Logged out Key refresh No recovery (fatal)
182
- // Multi-device mismatch Key refresh Full re-auth QR
183
- // Connection replaced Key refresh Full re-auth QR
184
- // ... dan lainnya
185
- ```
38
+ | Modul | Asal | Deskripsi |
39
+ |-------|------|-----------|
40
+ | Core | Baileys 7 | Koneksi WA Web multi-device, Noise XX, protobuf |
41
+ | `quickStart()` | Waliwa | One-liner setup dengan auto QR, reconnect, save creds |
42
+ | `MessageBuilder` | zaileys | Fluent chaining: `.to().text().image().reply().send()` |
43
+ | `ButtonBuilder` | baileys-mbuilder | Button interactive messages |
44
+ | `CarouselBuilder` | baileys-mbuilder | Carousel card messages |
45
+ | `AIRichBuilder` | baileys-mbuilder | AI rich response (hyperlink, citation, LaTeX) |
46
+ | `CommandSystem` | zaileys | Command registry + middleware + guards (cooldown, adminOnly) |
47
+ | `AutoRejectCall` | zaileys | Auto-reject incoming calls |
48
+ | `AutoRead` | zaileys | Auto-mark messages as read |
49
+ | `AutoPresence` | zaileys | Auto typing indicator |
50
+ | `Broadcast` | zaileys | Send to multiple recipients dengan delay |
51
+ | `Scheduler` | zaileys | Schedule messages untuk future delivery |
52
+ | `RateLimiter` | zaileys | Per-recipient rate limiting |
53
+ | `PluginRegistry` | zaileys | Modular plugin system dengan `definePlugin()` |
54
+ | `MediaHelper` | Waliwa | Download, convert, resize (sharp) |
55
+ | `StickerHelper` | Waliwa | Create stickers dari image/video/text (sharp + ffmpeg) |
56
+ | `MessageHelper` | Waliwa | Parse, format, reply utilities |
186
57
 
187
- ## 📖 API Reference
58
+ ## API
188
59
 
189
- ### Events (Baileys-style)
60
+ ### quickStart()
190
61
 
191
62
  ```typescript
192
- sock.ev.on('connection.update', (update) => {});
193
- sock.ev.on('creds.update', (creds) => {});
194
- sock.ev.on('qr.update', (qr) => {});
195
- sock.ev.on('pairing-code.update', (code) => {});
196
- sock.ev.on('message.upsert', ({ messages, type }) => {});
197
- sock.ev.on('message.update', ({ messages, keys }) => {});
198
- sock.ev.on('message.reaction', ({ key, reaction, sender }) => {});
199
- sock.ev.on('presence.update', (presence) => {});
200
- sock.ev.on('chats.upsert', (chats) => {});
201
- sock.ev.on('groups.upsert', (groups) => {});
202
- sock.ev.on('groups.update', (groups) => {});
203
- sock.ev.on('group-participants.update', (update) => {});
204
- sock.ev.on('calls', (callEvent) => {});
205
- sock.ev.on('contacts.upsert', (contacts) => {});
63
+ const sock = await quickStart({
64
+ authFolder: './auth',
65
+ browser: ['Waliwa Bot', 'Chrome', '1.0.0'],
66
+ printQRInTerminal: true, // default: true
67
+ autoReconnect: true, // default: true
68
+ reconnectDelayMs: 5000, // default: 5000
69
+ markOnlineOnConnect: true,
70
+ syncFullHistory: false
71
+ });
206
72
  ```
207
73
 
208
- ### Send Messages
74
+ ### MessageBuilder
209
75
 
210
76
  ```typescript
211
- // Text
212
- await sock.sendMessage(jid, { text: 'Hello!' });
77
+ import { MessageBuilder } from '@kangwifi-pro/waliwa';
213
78
 
214
- // Reply
215
- await sock.sendMessage(jid, {
216
- text: 'Reply!',
217
- quoted: originalMessage
218
- });
79
+ const builder = new MessageBuilder(sock);
219
80
 
220
- // Mention
221
- await sock.sendMessage(jid, {
222
- text: 'Hi @user!',
223
- mentions: ['6281234567890@s.whatsapp.net']
224
- });
81
+ // Text + reply + mentions
82
+ await builder.to(jid).text('Hello!').reply(message).mentions(['user@s.whatsapp.net']).send();
225
83
 
226
84
  // Image
227
- import { readFileSync } from 'fs';
228
- await sock.sendMessage(jid, {
229
- image: { stream: readFileSync('photo.jpg'), mimetype: 'image/jpeg' },
230
- caption: 'Photo caption'
231
- });
85
+ await builder.to(jid).image(buffer, { caption: 'Check this!' }).send();
86
+
87
+ // Audio (voice note)
88
+ await builder.to(jid).audio(buffer, { ptt: true }).send();
232
89
 
233
90
  // Document
234
- await sock.sendMessage(jid, {
235
- document: {
236
- stream: readFileSync('doc.pdf'),
237
- mimetype: 'application/pdf',
238
- fileName: 'document.pdf'
239
- }
240
- });
91
+ await builder.to(jid).document(buffer, { fileName: 'report.pdf' }).send();
92
+
93
+ // Sticker
94
+ await builder.to(jid).sticker(webpBuffer).send();
241
95
 
242
96
  // Location
243
- await sock.sendMessage(jid, {
244
- location: {
245
- degreesLatitude: -6.2088,
246
- degreesLongitude: 106.8456,
247
- name: 'Jakarta'
248
- }
249
- });
97
+ await builder.to(jid).location(-6.2088, 106.8456, { name: 'Jakarta' }).send();
250
98
 
251
99
  // Contact
252
- await sock.sendMessage(jid, {
253
- contact: {
254
- displayName: 'John Doe',
255
- vcard: 'BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+6281234567890\nEND:VCARD'
256
- }
257
- });
100
+ await builder.to(jid).contact(vcardString, 'John Doe').send();
258
101
 
259
102
  // Poll
260
- await sock.sendMessage(jid, {
261
- poll: {
262
- name: 'Pilih makan siang',
263
- values: ['Nasi Goreng', 'Mie Ayam', 'Sate'],
264
- selectableCounts: [1]
265
- }
266
- });
267
-
268
- // Reaction
269
- await sock.reactToMessage(jid, message.key, '👍');
270
- ```
103
+ await builder.to(jid).poll('Pilih makan?', ['Nasi', 'Mie', 'Sate']).send();
271
104
 
272
- ### Group Management
273
-
274
- ```typescript
275
- // Create group
276
- const group = await sock.groupCreate({
277
- subject: 'My Group',
278
- participants: ['6281234567890@s.whatsapp.net'],
279
- desc: 'Group description'
280
- });
105
+ // Buttons
106
+ await builder.to(jid).text('Choose:').buttons([
107
+ { label: 'Yes', id: 'yes' },
108
+ { label: 'No', id: 'no' }
109
+ ]).send();
281
110
 
282
- // Get metadata
283
- const metadata = await sock.groupMetadata(group.id);
111
+ // Carousel
112
+ await builder.to(jid).carousel([
113
+ { title: 'Product A', text: '$10', buttons: [{ label: 'Buy', id: 'buy_a' }] },
114
+ { title: 'Product B', text: '$20', buttons: [{ label: 'Buy', id: 'buy_b' }] }
115
+ ]).send();
284
116
 
285
- // Update subject
286
- await sock.groupUpdateSubject(group.id, 'New Name');
117
+ // Broadcast ke multiple recipients
118
+ await builder.to('dummy').text('Announcement!').broadcast([jid1, jid2, jid3], 2000);
287
119
 
288
- // Add/remove/promote/demote
289
- await sock.groupParticipantsUpdate(group.id, ['user@s.whatsapp.net'], 'add');
290
- await sock.groupParticipantsUpdate(group.id, ['user@s.whatsapp.net'], 'remove');
291
- await sock.groupParticipantsUpdate(group.id, ['user@s.whatsapp.net'], 'promote');
292
- await sock.groupParticipantsUpdate(group.id, ['user@s.whatsapp.net'], 'demote');
120
+ // View once
121
+ await builder.to(jid).image(buffer).viewOnce().send();
122
+ ```
293
123
 
294
- // Invite link
295
- const code = await sock.groupInviteCode(group.id);
296
- await sock.groupRevokeInvite(group.id);
124
+ ### ButtonBuilder
297
125
 
298
- // Join via code
299
- const joinedGroupJid = await sock.groupJoinViaCode('inviteCode');
126
+ ```typescript
127
+ import { ButtonBuilder } from '@kangwifi-pro/waliwa';
300
128
 
301
- // Leave group
302
- await sock.groupLeave(group.id);
129
+ const msg = new ButtonBuilder()
130
+ .text('Choose an option:')
131
+ .button('Yes', 'yes_id')
132
+ .button('No', 'no_id')
133
+ .footer('Powered by Waliwa')
134
+ .build();
303
135
 
304
- // Settings
305
- await sock.groupSettingUpdate(group.id, 'restrict', true); // Only admins can send
306
- await sock.groupSettingUpdate(group.id, 'announce', true); // Only admins can edit info
136
+ await sock.sendMessage(jid, msg);
307
137
  ```
308
138
 
309
- ### Call Handling
139
+ ### CarouselBuilder
310
140
 
311
141
  ```typescript
312
- sock.ev.on('calls', async (callEvent) => {
313
- console.log(`Incoming ${callEvent.isVideo ? 'video' : 'voice'} call from ${callEvent.from}`);
314
-
315
- // Auto-reject
316
- await sock.rejectCall(callEvent.id, callEvent.from);
317
- });
318
- ```
142
+ import { CarouselBuilder } from '@kangwifi-pro/waliwa';
319
143
 
320
- ### Media Upload/Download
144
+ const msg = new CarouselBuilder()
145
+ .card(c => c.title('Product A').text('$10').button('Buy', 'buy_a'))
146
+ .card(c => c.title('Product B').text('$20').button('Buy', 'buy_b'))
147
+ .build();
321
148
 
322
- ```typescript
323
- import { readFileSync, writeFileSync } from 'fs';
324
-
325
- // Upload
326
- const buffer = readFileSync('photo.jpg');
327
- const uploadResult = await sock.uploadMedia(buffer, 'image', 'image/jpeg', 'photo.jpg');
328
- console.log('Uploaded:', uploadResult.url);
329
-
330
- // Download (from message)
331
- if (msg.message?.image) {
332
- const downloadResult = await sock.downloadMedia(
333
- msg.message.image.url,
334
- msg.message.image.mediaKey,
335
- 'image',
336
- msg.message.image.mimetype
337
- );
338
- writeFileSync('downloaded.jpg', downloadResult.buffer);
339
- }
149
+ await sock.sendMessage(jid, msg);
340
150
  ```
341
151
 
342
- ### Presence & Typing Indicator
152
+ ### AIRichBuilder
343
153
 
344
154
  ```typescript
345
- // Subscribe to user presence
346
- await sock.presenceSubscribe(['6281234567890@s.whatsapp.net']);
347
-
348
- // Listen to presence updates
349
- sock.ev.on('presence.update', ({ jid, presence }) => {
350
- console.log(`${jid} is ${presence}`);
351
- });
155
+ import { AIRichBuilder } from '@kangwifi-pro/waliwa';
352
156
 
353
- // Send typing indicator
354
- await sock.sendPresenceUpdate(jid, 'composing'); // typing
355
- await sock.sendPresenceUpdate(jid, 'recording'); // recording voice
356
- await sock.sendPresenceUpdate(jid, 'paused'); // stopped
157
+ const msg = new AIRichBuilder()
158
+ .text('Visit [Google](https://google.com) for details')
159
+ .build();
357
160
 
358
- // Update own presence
359
- await sock.updatePresence('available');
360
- await sock.updatePresence('unavailable');
161
+ await sock.sendMessage(jid, msg);
361
162
  ```
362
163
 
363
- ### Advanced Features
164
+ ### CommandSystem
364
165
 
365
166
  ```typescript
366
- // Newsletter
367
- const newsletter = await sock.newsletterManager.create('My Channel', 'Description');
368
- await sock.newsletterManager.subscribe(newsletter.id);
167
+ import { CommandSystem } from '@kangwifi-pro/waliwa';
369
168
 
370
- // Status/Stories
371
- await sock.statusManager.sendTextStatus('Hello world!', {
372
- backgroundColor: '#FF0000'
169
+ const cmd = new CommandSystem(sock, {
170
+ prefix: '!',
171
+ ownerIds: ['6281234567890@s.whatsapp.net']
373
172
  });
374
173
 
375
- // Business Profile
376
- await sock.businessProfileManager.update({
377
- description: 'My Business',
378
- email: 'contact@business.com',
379
- address: 'Jakarta, Indonesia'
174
+ // Simple command
175
+ cmd.command('ping', async (ctx) => {
176
+ await ctx.reply('pong! 🏓');
380
177
  });
381
178
 
382
- // Catalog
383
- await sock.catalogManager.addProduct({
384
- name: 'Product 1',
385
- description: 'Description',
386
- price: 100000,
387
- currency: 'IDR'
179
+ // With guards
180
+ cmd.command('kick', {
181
+ adminOnly: true,
182
+ cooldown: 5000,
183
+ description: 'Kick member dari grup',
184
+ aliases: ['remove']
185
+ }, async (ctx) => {
186
+ // ctx.sender, ctx.jid, ctx.args, ctx.isGroup, ctx.isOwner, ctx.quoted
187
+ const target = ctx.mentions[0] || ctx.quoted?.participant;
188
+ if (!target) return ctx.reply('Tag atau reply user yang mau di-kick');
189
+ await sock.groupParticipantsUpdate(ctx.jid, [target], 'remove');
190
+ await ctx.reply(`✅ Kicked ${target}`);
388
191
  });
389
- ```
390
192
 
391
- ## 🏗️ Arsitektur
193
+ // Middleware
194
+ cmd.use(async (ctx, next) => {
195
+ console.log(`[${ctx.senderName}] ${ctx.fullText}`);
196
+ await next();
197
+ });
392
198
 
393
- ```
394
- ┌──────────────────────────────────────────────────────────────────┐
395
- │ Your Application │
396
- └──────────────────────────────────────────────────────────────────┘
397
-
398
-
399
- ┌──────────────────────────────────────────────────────────────────┐
400
- │ WASocket (Public API) │
401
- │ Event Emitter, sendMessage, groupCreate, etc. │
402
- └──────────────────────────────────────────────────────────────────┘
403
-
404
- ┌─────────────────────────┼─────────────────────────┐
405
- ▼ ▼ ▼
406
- ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
407
- │ Messages │ │ Groups │ │ Calls │
408
- │ Send/Receive │ │ Management │ │ Handler │
409
- │ Media │ │ Participants│ │ Reject │
410
- └──────────────┘ └──────────────┘ └──────────────┘
411
-
412
-
413
- ┌──────────────────────────────────────────────────────────────────┐
414
- │ Hybrid Socket Manager │
415
- │ Auto-fallback antara WA Web MD dan Mobile API │
416
- └──────────────────────────────────────────────────────────────────┘
417
-
418
- ┌─────────────────────────┼─────────────────────────┐
419
- ▼ ▼ ▼
420
- ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
421
- │ WA Web MD │ │ Mobile API │ │ Auth State │
422
- │ WebSocket │ │ Pairing │ │ File JSON │
423
- └──────────────┘ └──────────────┘ └──────────────┘
424
- │ │
425
- ▼ ▼
426
- ┌──────────────────────────────────────────────────────────────────┐
427
- │ Noise Protocol XX Handshake │
428
- │ + AES-256-GCM Traffic Cipher + WA Binary Protocol │
429
- └──────────────────────────────────────────────────────────────────┘
430
-
431
-
432
- ┌──────────────────────────────────────────────────────────────────┐
433
- │ Crypto Primitives (@noble/curves + @noble/hashes) │
434
- │ Curve25519, Ed25519, SHA-256, HMAC, HKDF, AES-GCM/CBC │
435
- └──────────────────────────────────────────────────────────────────┘
199
+ cmd.attach();
436
200
  ```
437
201
 
438
- ## 🔒 Reverse Engineering Approach
202
+ #### CommandContext Properties
203
+
204
+ | Property | Type | Description |
205
+ |----------|------|-------------|
206
+ | `sock` | any | Socket instance |
207
+ | `message` | any | Raw WA message |
208
+ | `jid` | string | Chat JID |
209
+ | `sender` | string | Sender JID |
210
+ | `text` | string | Full message text |
211
+ | `command` | string | Command name (tanpa prefix) |
212
+ | `args` | string[] | Arguments |
213
+ | `isGroup` | boolean | Apakah dari grup |
214
+ | `isFromMe` | boolean | Apakah dari bot sendiri |
215
+ | `isOwner` | boolean | Apakah sender adalah owner |
216
+ | `senderName` | string | Nama sender (pushName) |
217
+ | `quoted` | any | Quoted message context |
218
+ | `mentions` | string[] | Mentioned JIDs |
219
+
220
+ #### CommandContext Methods
221
+
222
+ | Method | Description |
223
+ |--------|-------------|
224
+ | `reply(text)` | Reply ke message |
225
+ | `replyWithMedia(buffer)` | Reply dengan image |
226
+ | `react(emoji)` | React ke message |
227
+ | `sendTyping()` | Kirim typing indicator |
228
+ | `sendRecording()` | Kirim recording indicator |
229
+ | `stopTyping()` | Stop typing indicator |
230
+
231
+ #### CommandOptions
232
+
233
+ | Option | Type | Description |
234
+ |--------|------|-------------|
235
+ | `adminOnly` | boolean | Hanya admin grup |
236
+ | `ownerOnly` | boolean | Hanya owner bot |
237
+ | `groupOnly` | boolean | Hanya bisa di grup |
238
+ | `privateOnly` | boolean | Hanya bisa di DM |
239
+ | `cooldown` | number | Cooldown dalam ms |
240
+ | `rateLimit` | { max, windowMs } | Rate limit per user |
241
+ | `aliases` | string[] | Command aliases |
242
+ | `description` | string | Deskripsi untuk help |
243
+
244
+ ### Automation
439
245
 
440
- Waliwa adalah clean-room implementation berdasarkan publicly documented WhatsApp protocol:
246
+ ```typescript
247
+ import { AutoRejectCall, AutoRead, AutoPresence, Broadcast, Scheduler, RateLimiter } from '@kangwifi-pro/waliwa';
248
+
249
+ // Auto-reject incoming calls
250
+ const autoReject = new AutoRejectCall(sock);
251
+ autoReject.start();
252
+ // Allow specific users
253
+ autoReject.allow('6281234567890@s.whatsapp.net');
254
+
255
+ // Auto-read messages (exclude groups)
256
+ const autoRead = new AutoRead(sock, { excludeGroups: true });
257
+ autoRead.start();
258
+
259
+ // Auto typing indicator
260
+ const autoPresence = new AutoPresence(sock);
261
+ autoPresence.start();
262
+
263
+ // Broadcast
264
+ const broadcast = new Broadcast(sock, 2000); // 2s delay
265
+ await broadcast.sendText([jid1, jid2, jid3], 'Announcement!');
266
+
267
+ // Scheduler
268
+ const scheduler = new Scheduler(sock);
269
+ scheduler.schedule('reminder1', jid, { text: 'Waktunya meeting!' }, 60 * 60 * 1000); // 1 hour
270
+ scheduler.cancel('reminder1');
271
+ scheduler.list(); // [{ id, jid }]
272
+
273
+ // Rate limiter
274
+ const limiter = new RateLimiter();
275
+ limiter.setLimit(jid, 10, 60000); // 10 messages per minute
276
+ if (limiter.canSend(jid)) {
277
+ await sock.sendMessage(jid, { text: 'Hi!' });
278
+ }
279
+ ```
441
280
 
442
- 1. **Noise Protocol Framework** - Public spec dari [noiseprotocol.org](https://noiseprotocol.org/)
443
- - Pattern: `Noise_XX_25519_AESGCM_SHA256`
444
- - Manual implementation di `src/core/noise.ts`
281
+ ### Plugin System
445
282
 
446
- 2. **WhatsApp Binary Format** - Custom binary protocol untuk encoding
447
- - Tags: list, dictionary, packed nibble/hex, binary 8/20/32
448
- - Manual encoder/decoder di `src/core/binary.ts`
283
+ ```typescript
284
+ import { definePlugin, PluginLoader } from '@kangwifi-pro/waliwa';
285
+
286
+ // plugins/echo.ts
287
+ export default definePlugin({
288
+ name: 'echo',
289
+ version: '1.0.0',
290
+ description: 'Echo plugin',
291
+ onLoad: (ctx) => console.log('Echo plugin loaded!'),
292
+ onMessage: async (msg, ctx) => {
293
+ const text = msg.message?.conversation || '';
294
+ if (text === '!echo') {
295
+ await ctx.sock.sendMessage(msg.key.remoteJid, { text: 'Echo!' });
296
+ }
297
+ }
298
+ });
449
299
 
450
- 3. **Multi-Device Protocol** - WebSocket with encrypted frames
451
- - Frame: `[WA header][version][length][encrypted payload]`
452
- - AES-256-GCM dengan counter-based nonce
300
+ // Load plugins
301
+ const loader = new PluginLoader(sock);
302
+ await loader.loadFromDir('./plugins');
303
+ loader.getRegistry().list(); // [{ name, version, description }]
304
+ ```
453
305
 
454
- 4. **Mobile API Pairing** - Companion device registration
455
- - Pairing code: 8 alphanumeric chars derived via HKDF
456
- - Format: `AB12-CD34` (dash separator)
306
+ ### MediaHelper
457
307
 
458
- 5. **Media Encryption** - AES-256-CBC + HMAC-SHA256
459
- - 112-byte derived key (iv + cipherKey + macKey + refKey)
460
- - 10-byte MAC truncation sesuai WA spec
308
+ ```typescript
309
+ import { MediaHelper } from '@kangwifi-pro/waliwa';
461
310
 
462
- ## 📊 RAM Usage Comparison
311
+ // Download dari message
312
+ const buffer = await MediaHelper.downloadFromMessage(sock, msg);
463
313
 
464
- | Library | Idle RAM | Active RAM | Notes |
465
- |---------------|----------|------------|--------------------------------------|
466
- | Baileys | ~80 MB | ~150 MB | Pino logger, full buffer |
467
- | ZapoJS | ~60 MB | ~120 MB | Heavy dependencies |
468
- | **Waliwa** | **~35 MB** | **~70 MB** | Buffer pool, lazy load, debounced IO |
314
+ // Download dari URL
315
+ const buffer = await MediaHelper.downloadFromUrl('https://...');
469
316
 
470
- *Benchmarks pada Node.js 20, single account, moderate message rate*
317
+ // Resize (untuk profile picture 640x640)
318
+ const resized = await MediaHelper.resizeImage(buffer, 640, 640);
471
319
 
472
- ## 📚 Examples
320
+ // Convert format
321
+ const webp = await MediaHelper.toWebP(buffer);
322
+ const jpeg = await MediaHelper.toJPEG(buffer, 80);
473
323
 
474
- 4 contoh bot siap pakai tersedia di `examples/`:
324
+ // Compress
325
+ const compressed = await MediaHelper.compress(buffer, 60);
475
326
 
476
- 1. **echo-bot** - Basic echo bot untuk testing
477
- ```bash
478
- cd examples/echo-bot && npm install && npm start
479
- ```
327
+ // Thumbnail
328
+ const thumb = await MediaHelper.createThumbnail(buffer, 200);
480
329
 
481
- 2. **group-bot** - Group management dengan admin commands
482
- ```bash
483
- cd examples/group-bot && npm install && npm start
484
- ```
330
+ // Watermark
331
+ const watermarked = await MediaHelper.addWatermark(buffer, '© Waliwa');
485
332
 
486
- 3. **ai-bot** - AI chatbot dengan OpenAI GPT integration
487
- ```bash
488
- cd examples/ai-bot
489
- echo "OPENAI_API_KEY=your_key" > .env
490
- npm install && npm start
491
- ```
333
+ // Grayscale / blur
334
+ const gray = await MediaHelper.grayscale(buffer);
335
+ const blurred = await MediaHelper.blur(buffer, 5);
336
+ ```
492
337
 
493
- 4. **rest-gateway** - HTTP REST API untuk send/receive
494
- ```bash
495
- cd examples/rest-gateway && npm install && npm start
496
- curl -X POST http://localhost:3000/send-text \
497
- -H "Content-Type: application/json" \
498
- -d '{"to":"6281234567890","message":"Hello!"}'
499
- ```
338
+ ### StickerHelper
500
339
 
501
- ## 📖 Documentation
340
+ ```typescript
341
+ import { StickerHelper } from '@kangwifi-pro/waliwa';
502
342
 
503
- - [**Multi-Branch SKDM Recovery**](docs/RECOVERY.md) - Recovery branches per disconnect reason
504
- - [**SKDM (Store Key Data Manager)**](docs/SKDM.md) - Key management subsystem
505
- - [**Baileys Fixes**](docs/BAILEYS_FIXES.md) - Detail 9+ fix untuk issue Baileys
506
- - [**New Features**](docs/FEATURES.md) - Health monitor, multi-account, webhooks, dll
507
- - [**Architecture**](docs/ARCHITECTURE.md) - Internal design dan module dependencies
508
- - [**Protocol**](docs/PROTOCOL.md) - WhatsApp protocol reverse engineering details
509
- - [**API Reference**](docs/API.md) - Complete API documentation
343
+ // Dari image
344
+ const sticker = await StickerHelper.fromImage(imageBuffer, {
345
+ pack: 'My Pack',
346
+ author: 'Me',
347
+ categories: ['😀']
348
+ });
510
349
 
511
- ## 🔧 Production Monitoring
350
+ // Dari video (animated)
351
+ const animated = await StickerHelper.fromVideo(videoBuffer);
512
352
 
513
- ```typescript
514
- const sock = makeWASocket({ authState: state });
515
-
516
- // Get comprehensive system stats
517
- const stats = sock.getSystemStats();
518
- console.log(JSON.stringify(stats, null, 2));
519
- // {
520
- // messageQueue: { totalQueues: 5, totalPending: 0, ... },
521
- // circuitBreakers: [],
522
- // rateLimits: { trackedRecipients: 12, ... },
523
- // webhooks: { sent: 145, failed: 3, ... },
524
- // messagePersistence: { total: 89, pending: 0, failed: 1 },
525
- // idempotency: { size: 89, hitRate: 0.95 },
526
- // health: { status: 'healthy', score: 95, ... }
527
- // }
528
-
529
- // Health monitoring
530
- sock.healthMonitor.on('health:recovery', (status) => {
531
- console.warn('Auto-recovery triggered:', status.issues);
353
+ // Dari text
354
+ const textSticker = await StickerHelper.fromText('Hello!', {
355
+ color: '#ffffff',
356
+ backgroundColor: '#000000'
532
357
  });
533
358
 
534
- // Register webhook untuk external monitoring
535
- sock.registerWebhook({
536
- url: 'https://yourapp.com/webhook',
537
- events: ['message.sent', 'message.failed', 'auth.success'],
538
- secret: process.env.WEBHOOK_SECRET,
539
- enabled: true,
540
- retryCount: 5,
541
- retryDelayMs: 1000,
542
- timeoutMs: 10000
543
- });
544
- ```
359
+ // Dari URL
360
+ const urlSticker = await StickerHelper.fromUrl('https://...');
545
361
 
546
- ## ⚙️ Configuration
362
+ // Dari file
363
+ const fileSticker = await StickerHelper.fromFile('./image.jpg');
547
364
 
548
- ### WaliwaConfig Options
365
+ // Send
366
+ await sock.sendMessage(jid, { sticker });
367
+ ```
549
368
 
550
- | Option | Type | Default | Description |
551
- |-------------------------|-----------|--------------------------------------|--------------------------------------|
552
- | authState | AuthState | **required** | Auth state (file, memory, custom) |
553
- | printQRInTerminal | boolean | false | Print QR ke terminal |
554
- | mobile | boolean | false | Use Mobile API mode |
555
- | phoneNumber | string | - | Phone number untuk Mobile API mode |
556
- | browser | [3 string]| ['Waliwa', 'WA', '1.0.0'] | Browser identification |
557
- | wsURL | string | wss://web.whatsapp.com/ws/chat | Custom WebSocket URL |
558
- | connectTimeoutMs | number | 20000 | Connect timeout ms |
559
- | keepAliveIntervalMs | number | 20000 | Keep-alive ping interval |
560
- | maxReconnectAttempts | number | 10 | Max auto-reconnect attempts |
561
- | reconnectInterval | number | 2000 | Initial reconnect delay ms |
562
- | ramOptimizationLevel | 1/2/3 | 2 | 1=balanced, 2=aggressive, 3=ultra |
563
- | syncFullHistory | boolean | false | Sync full message history on connect |
564
- | markOnlineOnConnect | boolean | true | Mark bot online saat connect |
369
+ ### MessageHelper
565
370
 
566
- ### RAM Optimization Levels
371
+ ```typescript
372
+ import { MessageHelper } from '@kangwifi-pro/waliwa';
373
+
374
+ // Extract text
375
+ const text = MessageHelper.getText(msg);
376
+
377
+ // Info
378
+ MessageHelper.isFromMe(msg);
379
+ MessageHelper.isGroupMessage(msg);
380
+ MessageHelper.getSender(msg);
381
+ MessageHelper.getChat(msg);
382
+ MessageHelper.hasMedia(msg);
383
+ MessageHelper.getMediaType(msg);
384
+ MessageHelper.getMentions(msg);
385
+ MessageHelper.getQuoted(msg);
386
+
387
+ // Parse command
388
+ const cmd = MessageHelper.parseCommand(msg, '!');
389
+ // { command: 'ping', args: [], fullText: '!ping' }
390
+
391
+ // Actions
392
+ await MessageHelper.reply(sock, msg, 'Hello!');
393
+ await MessageHelper.sendText(sock, jid, 'Hi!', { mentions: [...] });
394
+ await MessageHelper.mentionAll(sock, groupJid);
395
+ await MessageHelper.react(sock, msg, '👍');
396
+ await MessageHelper.markAsRead(sock, msg.key);
397
+ await MessageHelper.sendTyping(sock, jid);
398
+ await MessageHelper.stopTyping(sock, jid);
399
+ await MessageHelper.delete(sock, msg);
400
+ await MessageHelper.forward(sock, toJid, msg);
401
+ ```
567
402
 
568
- | Level | Buffer Pool | Lazy Load | Debounce | Use Case |
569
- |-----------|-------------|-----------|----------|-----------------------------------|
570
- | 1 Balanced| 8 buffers | Off | 100ms | Development, high-throughput |
571
- | 2 Aggressive| 16 buffers| On | 50ms | Production default |
572
- | 3 Ultra | 32 buffers | On | 25ms | Low-end VPS, multi-account |
403
+ ## Events
573
404
 
574
- ## 🛠️ Development
405
+ ```typescript
406
+ sock.ev.on('connection.update', (update) => {
407
+ // update.connection: 'connecting' | 'open' | 'close'
408
+ // update.qr: string (QR code)
409
+ // update.lastDisconnect: { error, output }
410
+ });
575
411
 
576
- ```bash
577
- # Install dependencies
578
- npm install
412
+ sock.ev.on('messages.upsert', ({ messages, type }) => {
413
+ // type: 'notify' (new) | 'append' (history)
414
+ });
415
+
416
+ sock.ev.on('messages.update', (updates) => {
417
+ // Status updates: sent, delivered, read
418
+ });
579
419
 
580
- # Build library
581
- npm run build
420
+ sock.ev.on('message-receipt.update', (updates) => {
421
+ // Delivery/read receipts
422
+ });
582
423
 
583
- # Run tests
584
- npm test
424
+ sock.ev.on('presence.update', ({ id, presences }) => {
425
+ // Presence: available, unavailable, composing, recording
426
+ });
585
427
 
586
- # Run example
587
- cd examples/echo-bot && npm start
428
+ sock.ev.on('chats.upsert', (chats) => {});
429
+ sock.ev.on('chats.update', (chats) => {});
430
+ sock.ev.on('contacts.upsert', (contacts) => {});
431
+ sock.ev.on('groups.upsert', (groups) => {});
432
+ sock.ev.on('groups.update', (groups) => {});
433
+ sock.ev.on('group-participants.update', (update) => {
434
+ // update.action: 'add' | 'remove' | 'promote' | 'demote'
435
+ });
436
+ sock.ev.on('call', (calls) => {});
437
+ sock.ev.on('creds.update', () => saveCreds());
588
438
  ```
589
439
 
590
- ## ⚠️ Disclaimer
440
+ ## Reconnect Behavior
441
+
442
+ | Status Code | Reason | Reconnect? |
443
+ |-------------|--------|------------|
444
+ | 515 | Restart required | ✅ Ya |
445
+ | 428 | Connection closed | ✅ Ya |
446
+ | 440 | Connection replaced | ✅ Ya |
447
+ | 500 | Server error | ✅ Ya |
448
+ | 401 | Logged out | ❌ Tidak (clear auth folder) |
591
449
 
592
- This library is for educational purposes. WhatsApp is a trademark of WhatsApp Inc., and this project is not affiliated with or endorsed by WhatsApp Inc. Use at your own risk and comply with WhatsApp's Terms of Service.
450
+ Auto-reconnect default aktif dengan delay 5 detik.
593
451
 
594
- ## 📄 License
452
+ ## Dependencies
595
453
 
596
- MIT - See [LICENSE](LICENSE) file for details.
454
+ | Package | Purpose |
455
+ |---------|---------|
456
+ | `@whiskeysockets/baileys` | Core WA protocol |
457
+ | `@hapi/boom` | Error handling |
458
+ | `pino` + `pino-pretty` | Logging |
459
+ | `qrcode-terminal` | QR display |
460
+ | `axios` | HTTP requests |
461
+ | `mime-types` | MIME detection |
462
+ | `sharp` | Image processing |
463
+ | `fluent-ffmpeg` + `@ffmpeg-installer/ffmpeg` | Video/sticker processing |
597
464
 
598
- ## 🤝 Contributing
465
+ ## License
599
466
 
600
- Contributions welcome! Please read contributing guidelines dan ensure all tests pass sebelum submit PR.
467
+ MIT