@kangwifi-pro/waliwa 1.0.0

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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +600 -0
  3. package/dist/advanced/features.d.ts +211 -0
  4. package/dist/advanced/features.d.ts.map +1 -0
  5. package/dist/advanced/features.js +671 -0
  6. package/dist/advanced/features.js.map +1 -0
  7. package/dist/auth/auth-state.d.ts +89 -0
  8. package/dist/auth/auth-state.d.ts.map +1 -0
  9. package/dist/auth/auth-state.js +330 -0
  10. package/dist/auth/auth-state.js.map +1 -0
  11. package/dist/auth/pairing-code.d.ts +78 -0
  12. package/dist/auth/pairing-code.d.ts.map +1 -0
  13. package/dist/auth/pairing-code.js +191 -0
  14. package/dist/auth/pairing-code.js.map +1 -0
  15. package/dist/auth/qr-code.d.ts +60 -0
  16. package/dist/auth/qr-code.d.ts.map +1 -0
  17. package/dist/auth/qr-code.js +151 -0
  18. package/dist/auth/qr-code.js.map +1 -0
  19. package/dist/calls/handler.d.ts +61 -0
  20. package/dist/calls/handler.d.ts.map +1 -0
  21. package/dist/calls/handler.js +117 -0
  22. package/dist/calls/handler.js.map +1 -0
  23. package/dist/core/binary.d.ts +74 -0
  24. package/dist/core/binary.d.ts.map +1 -0
  25. package/dist/core/binary.js +448 -0
  26. package/dist/core/binary.js.map +1 -0
  27. package/dist/core/crypto.d.ts +60 -0
  28. package/dist/core/crypto.d.ts.map +1 -0
  29. package/dist/core/crypto.js +170 -0
  30. package/dist/core/crypto.js.map +1 -0
  31. package/dist/core/noise.d.ts +106 -0
  32. package/dist/core/noise.d.ts.map +1 -0
  33. package/dist/core/noise.js +307 -0
  34. package/dist/core/noise.js.map +1 -0
  35. package/dist/events/emitter.d.ts +44 -0
  36. package/dist/events/emitter.d.ts.map +1 -0
  37. package/dist/events/emitter.js +79 -0
  38. package/dist/events/emitter.js.map +1 -0
  39. package/dist/features/index.d.ts +342 -0
  40. package/dist/features/index.d.ts.map +1 -0
  41. package/dist/features/index.js +755 -0
  42. package/dist/features/index.js.map +1 -0
  43. package/dist/fixes/index.d.ts +333 -0
  44. package/dist/fixes/index.d.ts.map +1 -0
  45. package/dist/fixes/index.js +762 -0
  46. package/dist/fixes/index.js.map +1 -0
  47. package/dist/groups/management.d.ts +86 -0
  48. package/dist/groups/management.d.ts.map +1 -0
  49. package/dist/groups/management.js +443 -0
  50. package/dist/groups/management.js.map +1 -0
  51. package/dist/index.d.ts +65 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +236 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/messages/media.d.ts +93 -0
  56. package/dist/messages/media.d.ts.map +1 -0
  57. package/dist/messages/media.js +252 -0
  58. package/dist/messages/media.js.map +1 -0
  59. package/dist/messages/message-encoder.d.ts +70 -0
  60. package/dist/messages/message-encoder.d.ts.map +1 -0
  61. package/dist/messages/message-encoder.js +453 -0
  62. package/dist/messages/message-encoder.js.map +1 -0
  63. package/dist/messages/send.d.ts +101 -0
  64. package/dist/messages/send.d.ts.map +1 -0
  65. package/dist/messages/send.js +409 -0
  66. package/dist/messages/send.js.map +1 -0
  67. package/dist/recovery/index.d.ts +125 -0
  68. package/dist/recovery/index.d.ts.map +1 -0
  69. package/dist/recovery/index.js +584 -0
  70. package/dist/recovery/index.js.map +1 -0
  71. package/dist/skdm/index.d.ts +220 -0
  72. package/dist/skdm/index.d.ts.map +1 -0
  73. package/dist/skdm/index.js +600 -0
  74. package/dist/skdm/index.js.map +1 -0
  75. package/dist/socket/hybrid.d.ts +118 -0
  76. package/dist/socket/hybrid.d.ts.map +1 -0
  77. package/dist/socket/hybrid.js +352 -0
  78. package/dist/socket/hybrid.js.map +1 -0
  79. package/dist/socket/wa-socket.d.ts +300 -0
  80. package/dist/socket/wa-socket.d.ts.map +1 -0
  81. package/dist/socket/wa-socket.js +1094 -0
  82. package/dist/socket/wa-socket.js.map +1 -0
  83. package/dist/socket/ws-socket.d.ts +96 -0
  84. package/dist/socket/ws-socket.d.ts.map +1 -0
  85. package/dist/socket/ws-socket.js +302 -0
  86. package/dist/socket/ws-socket.js.map +1 -0
  87. package/dist/types/index.d.ts +444 -0
  88. package/dist/types/index.d.ts.map +1 -0
  89. package/dist/types/index.js +7 -0
  90. package/dist/types/index.js.map +1 -0
  91. package/dist/utils/jid.d.ts +46 -0
  92. package/dist/utils/jid.d.ts.map +1 -0
  93. package/dist/utils/jid.js +152 -0
  94. package/dist/utils/jid.js.map +1 -0
  95. package/dist/utils/logger.d.ts +45 -0
  96. package/dist/utils/logger.d.ts.map +1 -0
  97. package/dist/utils/logger.js +79 -0
  98. package/dist/utils/logger.js.map +1 -0
  99. package/dist/utils/retry.d.ts +43 -0
  100. package/dist/utils/retry.d.ts.map +1 -0
  101. package/dist/utils/retry.js +175 -0
  102. package/dist/utils/retry.js.map +1 -0
  103. package/docs/API.md +745 -0
  104. package/docs/ARCHITECTURE.md +307 -0
  105. package/docs/BAILEYS_FIXES.md +360 -0
  106. package/docs/FEATURES.md +532 -0
  107. package/docs/PROTOCOL.md +489 -0
  108. package/docs/RECOVERY.md +409 -0
  109. package/docs/SKDM.md +233 -0
  110. package/examples/ai-bot/index.ts +479 -0
  111. package/examples/ai-bot/package.json +17 -0
  112. package/examples/echo-bot/index.ts +171 -0
  113. package/examples/echo-bot/package.json +18 -0
  114. package/examples/group-bot/index.ts +557 -0
  115. package/examples/group-bot/package.json +17 -0
  116. package/examples/rest-gateway/index.ts +499 -0
  117. package/examples/rest-gateway/package.json +19 -0
  118. package/package.json +75 -0
  119. package/src/advanced/features.ts +817 -0
  120. package/src/auth/auth-state.ts +342 -0
  121. package/src/auth/pairing-code.ts +246 -0
  122. package/src/auth/qr-code.ts +191 -0
  123. package/src/calls/handler.ts +153 -0
  124. package/src/core/binary.ts +464 -0
  125. package/src/core/crypto.ts +189 -0
  126. package/src/core/noise.ts +406 -0
  127. package/src/events/emitter.ts +88 -0
  128. package/src/features/index.ts +921 -0
  129. package/src/fixes/index.ts +882 -0
  130. package/src/groups/management.ts +497 -0
  131. package/src/index.ts +274 -0
  132. package/src/messages/media.ts +372 -0
  133. package/src/messages/message-encoder.ts +520 -0
  134. package/src/messages/send.ts +521 -0
  135. package/src/recovery/index.ts +704 -0
  136. package/src/skdm/index.ts +693 -0
  137. package/src/socket/hybrid.ts +414 -0
  138. package/src/socket/wa-socket.ts +1347 -0
  139. package/src/socket/ws-socket.ts +355 -0
  140. package/src/types/index.ts +457 -0
  141. package/src/utils/jid.ts +156 -0
  142. package/src/utils/logger.ts +84 -0
  143. package/src/utils/retry.ts +205 -0
  144. package/tsconfig.json +30 -0
@@ -0,0 +1,409 @@
1
+ # Multi-Branch SKDM Recovery System
2
+
3
+ Unlike basic reconnect yang hanya mencoba satu jalur, Waliwa mengimplementasikan sistem pemulihan Multi-Branch Session Key & Device Management (SKDM) yang lengkap. Saat pemutusan koneksi (disconnect) terjadi, sistem akan mencoba berbagai strategi pemulihan secara berurutan.
4
+
5
+ ## Tabel Cabang Pemulihan
6
+
7
+ | Disconnect Reason | Recovery Branches (in order) | Fatal? |
8
+ |-------------------|------------------------------|--------|
9
+ | **Connection lost** (1006/1001) | Immediate retry → Stream reconnect → Backoff → Key refresh → Pre-key fetch → Full re-auth | ❌ |
10
+ | **Rate limited** (429) | Wait cooldown (5min) → Backoff retry | ❌ |
11
+ | **Restart required** (428) | Update app version → Key refresh → Full re-auth QR | ❌ |
12
+ | **Logged out** (401/403) | Key refresh → No recovery | ✅ Fatal |
13
+ | **Forbidden** (511) | Immediate retry → Key refresh → No recovery | ❌ |
14
+ | **Multi-device mismatch** (409) | Key refresh → Full re-auth QR → No recovery | ❌ |
15
+ | **Bad session** | Key refresh → Pre-key fetch → Full re-auth QR | ❌ |
16
+ | **Connection replaced** (440) | Key refresh → Full re-auth QR | ❌ |
17
+ | **Unknown** | Backoff retry → Key refresh → Full re-auth QR | ❌ |
18
+
19
+ Setiap cabang memiliki batas percobaan (retry limit) tersendiri (default 3). Total percobaan di semua cabang dibatasi (default 20).
20
+
21
+ ## Konfigurasi
22
+
23
+ ```typescript
24
+ import { makeWASocket, useFileAuthState } from 'waliwa';
25
+
26
+ const { state } = await useFileAuthState('./auth');
27
+
28
+ const sock = makeWASocket({
29
+ authState: state,
30
+ printQRInTerminal: true,
31
+
32
+ // Multi-Branch SKDM Recovery configuration
33
+ recovery: {
34
+ enabled: true, // Enable recovery system (default: true)
35
+ maxAttemptsPerBranch: 3, // Max attempts per branch (default: 3)
36
+ maxTotalAttempts: 20, // Total max attempts across all branches (default: 20)
37
+ initialDelayMs: 1000, // Initial delay for backoff (default: 1000ms)
38
+ maxDelayMs: 60000, // Max delay for backoff (default: 60000ms)
39
+ rateLimitedDelayMs: 300000 // Cooldown for rate limited (default: 5min)
40
+ }
41
+ });
42
+ ```
43
+
44
+ ## Pemulihan Per Disconnect Reason
45
+
46
+ ### 1. Connection Lost (codes 1006, 1001, 0, undefined)
47
+
48
+ Branch paling lengkap - 6 strategi pemulihan berurutan.
49
+
50
+ **Flow:**
51
+ ```
52
+ Connection lost detected
53
+
54
+ 1. Immediate retry (0ms delay)
55
+ ↓ fail
56
+ 2. Stream reconnect (500ms delay) - resume stream state
57
+ ↓ fail
58
+ 3. Backoff retry (1s, 2s, 4s exponential)
59
+ ↓ fail x 3
60
+ 4. Key refresh (SKDM regenerate pre-keys)
61
+ ↓ fail
62
+ 5. Pre-key fetch (force new pre-keys from server)
63
+ ↓ fail
64
+ 6. Full re-auth QR (clear creds, new QR scan)
65
+ ```
66
+
67
+ ### 2. Rate Limited (code 429)
68
+
69
+ Wait untuk cooldown lalu coba lagi.
70
+
71
+ **Flow:**
72
+ ```
73
+ Rate limited detected (429)
74
+
75
+ 1. Wait cooldown 5 minutes
76
+
77
+ 2. Backoff retry
78
+ ```
79
+
80
+ ### 3. Restart Required (code 428)
81
+
82
+ Server butuh update version. Update browser identification.
83
+
84
+ **Flow:**
85
+ ```
86
+ Restart required (428)
87
+
88
+ 1. Update app version (bump browser version)
89
+
90
+ 2. Key refresh
91
+
92
+ 3. Full re-auth QR
93
+ ```
94
+
95
+ ### 4. Logged Out (codes 401, 403) - FATAL
96
+
97
+ Tidak ada pemulihan yang possible. Clear creds dan emit fatal event.
98
+
99
+ **Flow:**
100
+ ```
101
+ Logged out (401/403)
102
+
103
+ 1. Key refresh (last attempt)
104
+
105
+ ❌ No recovery - emit 'recovery:failed' dengan fatal=true
106
+ ```
107
+
108
+ ### 5. Forbidden (code 511)
109
+
110
+ Coba sekali lagi, lalu refresh keys.
111
+
112
+ **Flow:**
113
+ ```
114
+ Forbidden (511)
115
+
116
+ 1. Immediate retry
117
+ ↓ fail
118
+ 2. Key refresh
119
+ ↓ fail
120
+ ❌ No recovery
121
+ ```
122
+
123
+ ### 6. Multi-device Mismatch (code 409)
124
+
125
+ Multi-device state tidak sinkron dengan server.
126
+
127
+ **Flow:**
128
+ ```
129
+ Multi-device mismatch (409)
130
+
131
+ 1. Key refresh
132
+ ↓ fail
133
+ 2. Full re-auth QR
134
+ ↓ fail
135
+ ❌ No recovery
136
+ ```
137
+
138
+ ### 7. Bad Session (generic)
139
+
140
+ Session tidak valid, butuh refresh dan re-fetch pre-keys.
141
+
142
+ **Flow:**
143
+ ```
144
+ Bad session detected
145
+
146
+ 1. Key refresh
147
+ ↓ fail
148
+ 2. Pre-key fetch
149
+ ↓ fail
150
+ 3. Full re-auth QR
151
+ ```
152
+
153
+ ### 8. Connection Replaced (code 440)
154
+
155
+ Koneksi diganti dengan device lain. Coba re-auth.
156
+
157
+ **Flow:**
158
+ ```
159
+ Connection replaced (440)
160
+
161
+ 1. Key refresh
162
+ ↓ fail
163
+ 2. Full re-auth QR
164
+ ```
165
+
166
+ ## Aksi Pemulihan (Recovery Actions)
167
+
168
+ | Action | Deskripsi | Default Delay |
169
+ |--------|-----------|---------------|
170
+ | `immediate_retry` | Coba reconnect langsung tanpa delay | 0ms |
171
+ | `stream_reconnect` | Resume koneksi dari stream state yang tersimpan | 500ms |
172
+ | `backoff_retry` | Reconnect dengan exponential backoff | 1s, 2s, 4s... |
173
+ | `wait_cooldown` | Tunggu cooldown 5 menit (untuk rate limit) | 300000ms |
174
+ | `update_app_version` | Update identifikasi browser/app version | 1s |
175
+ | `key_refresh` | Refresh Signal keys via SKDM | 1s |
176
+ | `prekey_fetch` | Fetch pre-keys baru dari server | 1s |
177
+ | `full_reauth_qr` | Full re-authentication dengan QR code baru | 1s |
178
+ | `no_recovery` | Tidak ada pemulihan yang possible (fatal) | - |
179
+
180
+ ## Event
181
+
182
+ RecoveryManager mengeluarkan beberapa event untuk monitoring:
183
+
184
+ ```typescript
185
+ sock.recoveryManager.on('recovery:start', (info) => {
186
+ console.log(`Recovery started: ${info.reason} (code: ${info.code})`);
187
+ });
188
+
189
+ sock.recoveryManager.on('recovery:branch:start', (info) => {
190
+ console.log(`Branch started: ${info.reason}`);
191
+ console.log(`Actions: ${info.actions.join(' → ')}`);
192
+ });
193
+
194
+ sock.recoveryManager.on('recovery:action:start', (info) => {
195
+ console.log(`Action: ${info.action} (attempt ${info.attempt})`);
196
+ });
197
+
198
+ sock.recoveryManager.on('recovery:action:success', (info) => {
199
+ console.log(`✓ ${info.action} succeeded in ${info.duration}ms`);
200
+ });
201
+
202
+ sock.recoveryManager.on('recovery:action:failed', (info) => {
203
+ console.log(`✗ ${info.action} failed: ${info.error}`);
204
+ });
205
+
206
+ sock.recoveryManager.on('recovery:success', (info) => {
207
+ console.log(`✓ Recovery succeeded after ${info.totalAttempts} attempts in ${info.duration}ms`);
208
+ });
209
+
210
+ sock.recoveryManager.on('recovery:failed', (info) => {
211
+ console.log(`✗ Recovery failed (fatal: ${info.fatal})`);
212
+ if (info.fatal) {
213
+ console.log('Manual intervention required (re-scan QR)');
214
+ }
215
+ });
216
+
217
+ sock.recoveryManager.on('recovery:progress', (info) => {
218
+ console.log(`Progress: ${info.progress.toFixed(1)}% (${info.totalAttempts}/${info.maxTotalAttempts})`);
219
+ });
220
+ ```
221
+
222
+ ## API
223
+
224
+ ### Get Recovery Stats
225
+
226
+ ```typescript
227
+ const stats = sock.getRecoveryStats();
228
+ console.log(stats);
229
+ // {
230
+ // totalRecoveries: 5,
231
+ // successfulRecoveries: 4,
232
+ // failedRecoveries: 1,
233
+ // successRate: 0.8,
234
+ // byReason: {
235
+ // connection_lost: { success: 3, failure: 0 },
236
+ // rate_limited: { success: 1, failure: 0 },
237
+ // logged_out: { success: 0, failure: 1 }
238
+ // }
239
+ // }
240
+ ```
241
+
242
+ ### Check Recovery Status
243
+
244
+ ```typescript
245
+ if (sock.isRecovering()) {
246
+ const ctx = sock.getCurrentRecovery();
247
+ console.log(`Recovering from: ${ctx.reason}`);
248
+ console.log(`Current action: ${ctx.history[ctx.history.length - 1]?.action}`);
249
+ console.log(`Progress: ${ctx.totalAttempts}/${20} total attempts`);
250
+ }
251
+ ```
252
+
253
+ ### Manual Trigger (untuk testing)
254
+
255
+ ```typescript
256
+ import { mapCodeToReason } from 'waliwa';
257
+
258
+ // Simulate disconnect
259
+ const reason = mapCodeToReason(429);
260
+ const success = await sock.triggerRecovery(reason, 429, 'rate limit exceeded');
261
+ console.log(`Recovery ${success ? 'succeeded' : 'failed'}`);
262
+ ```
263
+
264
+ ### Cancel Ongoing Recovery
265
+
266
+ ```typescript
267
+ // Cancel recovery manually
268
+ sock.recoveryManager.cancel();
269
+ ```
270
+
271
+ ## Custom Branches
272
+
273
+ Anda dapat mengganti (override) cabang default dengan yang custom:
274
+
275
+ ```typescript
276
+ import { makeWASocket, RecoveryManager, type RecoveryBranch } from 'waliwa';
277
+
278
+ const customBranches: RecoveryBranch[] = [
279
+ {
280
+ reason: 'connection_lost',
281
+ actions: ['immediate_retry', 'backoff_retry'], // Simplified
282
+ maxAttempts: 5
283
+ },
284
+ {
285
+ reason: 'rate_limited',
286
+ actions: ['wait_cooldown', 'immediate_retry'],
287
+ maxAttempts: 2
288
+ }
289
+ // ... (other branches pakai default)
290
+ ];
291
+
292
+ // Pass via config (atau instantiate manual)
293
+ const recoveryManager = new RecoveryManager({
294
+ branches: customBranches,
295
+ maxAttemptsPerBranch: 5,
296
+ maxTotalAttempts: 30
297
+ });
298
+ ```
299
+
300
+ ## Custom Action Handlers
301
+
302
+ Override handler default untuk action tertentu:
303
+
304
+ ```typescript
305
+ import { makeWASocket, type RecoveryAction } from 'waliwa';
306
+
307
+ const sock = makeWASocket({
308
+ authState: state,
309
+ recovery: {
310
+ enabled: true,
311
+ actionHandlers: {
312
+ // Custom handler untuk key_refresh
313
+ key_refresh: async (ctx) => {
314
+ console.log(`Custom key refresh (attempt ${ctx.attempt})`);
315
+ // Custom logic: backup old keys sebelum refresh
316
+ await backupKeys();
317
+ // Lalu refresh
318
+ await sock.getSKDM()?.preKeyManager.regeneratePreKeys();
319
+ // Try reconnect
320
+ return await sock.recoveryManager.connect();
321
+ },
322
+
323
+ // Custom handler untuk full_reauth_qr
324
+ full_reauth_qr: async (ctx) => {
325
+ console.log('Custom full re-auth');
326
+ // Send notification ke admin
327
+ await notifyAdmin('Bot needs re-authentication!');
328
+ // Lalu start re-auth
329
+ await sock.recoveryManager.startFullReauth();
330
+ return true;
331
+ }
332
+ }
333
+ }
334
+ });
335
+ ```
336
+
337
+ ## Production Setup Example
338
+
339
+ ```typescript
340
+ import { makeWASocket, useFileAuthState } from 'waliwa';
341
+
342
+ async function main() {
343
+ const { state } = await useFileAuthState('./auth');
344
+
345
+ const sock = makeWASocket({
346
+ authState: state,
347
+ printQRInTerminal: true,
348
+ ramOptimizationLevel: 2,
349
+
350
+ // Multi-branch recovery
351
+ recovery: {
352
+ enabled: true,
353
+ maxAttemptsPerBranch: 3,
354
+ maxTotalAttempts: 20,
355
+ initialDelayMs: 1000,
356
+ maxDelayMs: 60000,
357
+ rateLimitedDelayMs: 300000 // 5 minutes
358
+ }
359
+ });
360
+
361
+ // Monitor recovery events
362
+ sock.recoveryManager.on('recovery:start', ({ reason, code }) => {
363
+ console.warn(`⚠️ Recovery started: ${reason} (code ${code})`);
364
+ });
365
+
366
+ sock.recoveryManager.on('recovery:success', ({ reason, totalAttempts, duration }) => {
367
+ console.log(`✅ Recovery succeeded: ${reason} in ${duration}ms (${totalAttempts} attempts)`);
368
+ });
369
+
370
+ sock.recoveryManager.on('recovery:failed', ({ reason, fatal }) => {
371
+ console.error(`❌ Recovery failed: ${reason} (fatal: ${fatal})`);
372
+ if (fatal) {
373
+ // Send alert ke admin - manual QR scan required
374
+ notifyAdmin(`Bot logged out! Reason: ${reason}. Manual re-auth required.`);
375
+ }
376
+ });
377
+
378
+ // Periodic stats logging
379
+ setInterval(() => {
380
+ const stats = sock.getRecoveryStats();
381
+ console.log('Recovery stats:', stats);
382
+ }, 60000);
383
+
384
+ // Graceful shutdown
385
+ process.on('SIGINT', async () => {
386
+ console.log('Shutting down...');
387
+ // Cancel ongoing recovery
388
+ sock.recoveryManager.cancel();
389
+ await sock.end();
390
+ process.exit(0);
391
+ });
392
+ }
393
+
394
+ main();
395
+ ```
396
+
397
+ ## Perbandingan dengan Baileys
398
+
399
+ | Aspek | Baileys | Waliwa |
400
+ |-------|---------|--------|
401
+ | Reconnect strategy | Single path (exponential backoff) | Multi-branch berdasarkan disconnect reason |
402
+ | Rate limit handling | Sama dengan disconnect biasa | Cooldown khusus 5 menit |
403
+ | Logged out | Coba reconnect sama | Fatal - clear creds, minta QR ulang |
404
+ | Connection replaced | Tetap coba reconnect | Key refresh + re-auth QR |
405
+ | Multi-device mismatch | Tidak ada handling khusus | Key refresh + re-auth QR |
406
+ | Max retry limit | Single global limit | Per-branch + total cap |
407
+ | Custom handlers | Tidak ada | Setiap action bisa di-override |
408
+ | Recovery events | Tidak ada | 7 event types untuk monitoring |
409
+ | Recovery stats | Tidak ada | Per-reason success/failure tracking |
package/docs/SKDM.md ADDED
@@ -0,0 +1,233 @@
1
+ # SKDM (Store Key Data Manager)
2
+
3
+ SKDM adalah subsystem cerdas untuk manage Signal protocol keys. Dibuat untuk mengatasi issue-issue Baileys yang sering dikeluhkan terkait key management.
4
+
5
+ ## Masalah Baileys yang Diatasi SKDM
6
+
7
+ | Baileys Issue | SKDM Solution |
8
+ |---------------|---------------|
9
+ | Pre-key exhaustion (pre-keys habis tanpa warning) | PreKeyManager dengan auto-regeneration |
10
+ | Session corruption on disconnect | AtomicFileWriter (write ke .tmp lalu rename) |
11
+ | Decryption failure untuk old messages | SessionManager.prefetchSessions() |
12
+ | Memory leak dari sessions lama | LRUCache dengan TTL eviction |
13
+ | App state keys bertumpuk tanpa cleanup | AppStateKeyManager.cleanup() |
14
+ | Identity changes gak tracked | IdentityKeyManager dengan change detection |
15
+
16
+ ## Quick Start
17
+
18
+ ```typescript
19
+ import { makeWASocket, useFileAuthState, SKDM } from 'waliwa';
20
+
21
+ const state = await useFileAuthState('./auth');
22
+
23
+ // SKDM otomatis initialized di dalam WASocket
24
+ const sock = makeWASocket({
25
+ authState: state,
26
+ printQRInTerminal: true
27
+ });
28
+
29
+ // Akses SKDM instance
30
+ const skdm = sock.getSKDM();
31
+
32
+ // Get stats
33
+ console.log(skdm?.getStats());
34
+ // Output:
35
+ // {
36
+ // preKeys: { total: 95, nextId: 105, lastRegenTime: 1234567890, needsRegen: false },
37
+ // sessions: { size: 12, hits: 45, misses: 3, hitRate: 0.937, totalSessions: 50, expiredSessions: 0 },
38
+ // identities: { total: 50, changed: 0 },
39
+ // appStateKeys: 15,
40
+ // pendingSaves: 0
41
+ // }
42
+ ```
43
+
44
+ ## Komponen SKDM
45
+
46
+ ### 1. PreKeyManager
47
+
48
+ Auto-regenerate pre-keys saat hampir habis. Mencegah Baileys issue di mana bot tiba-tiba tidak bisa menerima pesan baru karena pre-keys habis.
49
+
50
+ ```typescript
51
+ const skdm = sock.getSKDM();
52
+
53
+ // Manual trigger
54
+ await skdm.preKeyManager.regeneratePreKeys();
55
+
56
+ // Check stats
57
+ const stats = skdm.preKeyManager.getStats();
58
+ console.log(`Pre-keys: ${stats.total}/${stats.target}`);
59
+ console.log(`Needs regeneration: ${stats.needsRegen}`);
60
+
61
+ // Consume pre-key (otomatis saat receive message)
62
+ skdm.preKeyManager.consumePreKey(42);
63
+ // Auto-triggers regeneration if low
64
+ ```
65
+
66
+ **Konfigurasi:**
67
+
68
+ ```typescript
69
+ makeWASocket({
70
+ authState: state,
71
+ // SKDM config
72
+ minPreKeys: 5, // Regenerate jika < 5 pre-keys
73
+ maxPreKeysBatch: 50, // Max 50 pre-keys per regeneration
74
+ targetPreKeyCount: 100, // Maintain 100 pre-keys total
75
+ enableKeyRotation: true // Background rotation tiap 1 jam
76
+ });
77
+ ```
78
+
79
+ ### 2. SessionManager
80
+
81
+ LRU cache untuk sessions - mencegah memory leak.
82
+
83
+ ```typescript
84
+ const skdm = sock.getSKDM();
85
+
86
+ // Get session (auto-cache)
87
+ const session = skdm.sessionManager.getSession('6281@s.whatsapp.net');
88
+
89
+ // Prefetch sessions untuk multiple users
90
+ // Berguna sebelum bulk decrypt group messages
91
+ skdm.sessionManager.prefetchSessions([
92
+ 'user1@s.whatsapp.net',
93
+ 'user2@s.whatsapp.net',
94
+ 'user3@s.whatsapp.net'
95
+ ]);
96
+
97
+ // Cleanup expired sessions (otomatis tiap 6 jam)
98
+ const cleaned = skdm.sessionManager.cleanupExpiredSessions();
99
+ console.log(`Cleaned ${cleaned} sessions`);
100
+
101
+ // Get cache stats
102
+ const stats = skdm.sessionManager.getStats();
103
+ console.log(`Cache hit rate: ${(stats.hitRate * 100).toFixed(1)}%`);
104
+ ```
105
+
106
+ ### 3. IdentityKeyManager
107
+
108
+ Track identity changes untuk security.
109
+
110
+ ```typescript
111
+ const skdm = sock.getSKDM();
112
+
113
+ // Check identity changes (security alerts)
114
+ const changed = skdm.identityManager.getChangedIdentities();
115
+ if (changed.length > 0) {
116
+ console.warn('Identity changed untuk users:', changed);
117
+ // Verify dengan user, lalu acknowledge
118
+ for (const jid of changed) {
119
+ // After manual verification:
120
+ skdm.identityManager.acknowledge(jid);
121
+ }
122
+ }
123
+
124
+ // Trust identity (override safety)
125
+ skdm.identityManager.trust('6281@s.whatsapp.net');
126
+ ```
127
+
128
+ ### 4. AppStateKeyManager
129
+
130
+ Manage app state sync keys dengan cleanup otomatis.
131
+
132
+ ```typescript
133
+ const skdm = sock.getSKDM();
134
+
135
+ // Cleanup old app state keys (keep last 50)
136
+ const cleaned = skdm.appStateManager.cleanup(50);
137
+ console.log(`Cleaned ${cleaned} old app state keys`);
138
+ ```
139
+
140
+ ### 5. AtomicFileWriter
141
+
142
+ Atomic writes untuk prevent corruption saat disconnect/power failure.
143
+
144
+ ```typescript
145
+ import { AtomicFileWriter } from 'waliwa';
146
+
147
+ // Safe write - akan write ke .tmp lalu rename (atomic di POSIX)
148
+ await AtomicFileWriter.writeFile(
149
+ './auth/session.json',
150
+ JSON.stringify(sessionData),
151
+ 'utf-8'
152
+ );
153
+
154
+ // Even jika process crash saat write:
155
+ // - .tmp file mungkin tertinggal (safe to delete)
156
+ // - Original file tidak corrupt
157
+ ```
158
+
159
+ ## LRU Cache
160
+
161
+ SKDM menggunakan LRU cache custom untuk RAM efficiency.
162
+
163
+ ```typescript
164
+ import { LRUCache } from 'waliwa';
165
+
166
+ const cache = new LRUCache<string, any>(500); // Max 500 entries
167
+
168
+ cache.set('key1', { data: 'value' });
169
+ const value = cache.get('key1');
170
+
171
+ const stats = cache.getStats();
172
+ console.log(stats);
173
+ // { size: 1, hits: 1, misses: 0, hitRate: 1 }
174
+ ```
175
+
176
+ ## Monitoring
177
+
178
+ SKDM exposes stats untuk monitoring:
179
+
180
+ ```typescript
181
+ // Comprehensive stats
182
+ const stats = sock.getSKDMStats();
183
+ console.log(JSON.stringify(stats, null, 2));
184
+
185
+ // System stats (includes SKDM + other components)
186
+ const systemStats = sock.getSystemStats();
187
+ console.log(JSON.stringify(systemStats, null, 2));
188
+ ```
189
+
190
+ ## Background Jobs
191
+
192
+ SKDM menjalankan beberapa background jobs otomatis:
193
+
194
+ | Job | Interval | Purpose |
195
+ |-----|----------|---------|
196
+ | Pre-key rotation check | 1 hour | Regenerate pre-keys jika low |
197
+ | Session cleanup | 6 hours | Hapus expired sessions (>30 days) |
198
+ | AppState key cleanup | 24 hours | Hapus unused app state keys |
199
+
200
+ Jobs otomatis di-stop saat `sock.end()` dipanggil.
201
+
202
+ ## Configuration
203
+
204
+ Semua konfigurasi SKDM via WaliwaConfig:
205
+
206
+ ```typescript
207
+ makeWASocket({
208
+ authState: state,
209
+
210
+ // PreKey config
211
+ minPreKeys: 5,
212
+ maxPreKeysBatch: 50,
213
+ targetPreKeyCount: 100,
214
+ enableKeyRotation: true,
215
+
216
+ // Session cache config
217
+ maxSessionCacheSize: 500,
218
+ sessionExpiryMs: 30 * 24 * 60 * 60 * 1000, // 30 days
219
+ enableSessionPrefetch: true,
220
+
221
+ // Storage
222
+ storageFolder: './auth',
223
+ prefix: 'waliwa-session'
224
+ });
225
+ ```
226
+
227
+ ## Best Practices
228
+
229
+ 1. **Always call `sock.end()`** saat shutdown untuk flush pending saves
230
+ 2. **Monitor `getSKDMStats()`** secara periodik untuk detect issues
231
+ 3. **Handle identity changes** sebagai security alert
232
+ 4. **Don't manually edit** session files - use SKDM API
233
+ 5. **Backup auth folder** sebelum updates besar