@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,499 @@
1
+ /**
2
+ * REST API Gateway Example - HTTP endpoint untuk kirim pesan WhatsApp
3
+ *
4
+ * Features:
5
+ * - POST /send-text - Send text message
6
+ * - POST /send-media - Send image/video/audio
7
+ * - GET /status - Get connection status
8
+ * - GET /health - Health check
9
+ * - POST /webhook - Set webhook untuk incoming messages
10
+ * - GET /groups - List groups
11
+ * - POST /groups/create - Create new group
12
+ * - GET /contacts - List known contacts
13
+ *
14
+ * Setup:
15
+ * 1. npm install
16
+ * 2. npm start
17
+ * 3. Scan QR yang muncul
18
+ * 4. Setelah connected, test dengan curl:
19
+ *
20
+ * curl -X POST http://localhost:3000/send-text \
21
+ * -H "Content-Type: application/json" \
22
+ * -d '{"to":"6281234567890","message":"Hello from API!"}'
23
+ *
24
+ * Security:
25
+ * - Set API_KEY environment variable untuk auth (Bearer token)
26
+ * - Set ALLOWED_IPS untuk IP whitelist
27
+ */
28
+
29
+ import express, { Request, Response, NextFunction } from 'express';
30
+ import {
31
+ makeWASocket,
32
+ useFileAuthState,
33
+ isGroupJid,
34
+ jidToString,
35
+ type WAMessage,
36
+ type JIDLike
37
+ } from 'waliwa';
38
+
39
+ // ============== Config ==============
40
+
41
+ const CONFIG = {
42
+ port: parseInt(process.env.PORT ?? '3000', 10),
43
+ apiKey: process.env.API_KEY,
44
+ allowedIps: process.env.ALLOWED_IPS?.split(',').map(ip => ip.trim()) ?? [],
45
+ webhookUrl: process.env.WEBHOOK_URL,
46
+ rateLimitPerMinute: parseInt(process.env.RATE_LIMIT ?? '60', 10),
47
+ bodyLimit: '10mb'
48
+ };
49
+
50
+ // ============== App State ==============
51
+
52
+ const app = express();
53
+ app.use(express.json({ limit: CONFIG.bodyLimit }));
54
+ app.use(express.urlencoded({ extended: true, limit: CONFIG.bodyLimit }));
55
+
56
+ let sock: ReturnType<typeof makeWASocket> | null = null;
57
+ let isReady = false;
58
+
59
+ // Rate limiter per IP
60
+ const rateLimiter = new Map<string, { count: number; resetAt: number }>();
61
+
62
+ // Webhook subscribers
63
+ const webhooks = new Set<string>();
64
+
65
+ // ============== Auth Middleware ==============
66
+
67
+ function authMiddleware(req: Request, res: Response, next: NextFunction): void {
68
+ // Check IP whitelist
69
+ if (CONFIG.allowedIps.length > 0) {
70
+ const clientIp = req.ip ?? req.socket.remoteAddress ?? '';
71
+ const cleanIp = clientIp.replace('::ffff:', '');
72
+ if (!CONFIG.allowedIps.includes(cleanIp)) {
73
+ res.status(403).json({ error: 'IP not allowed' });
74
+ return;
75
+ }
76
+ }
77
+
78
+ // Check API key
79
+ if (CONFIG.apiKey) {
80
+ const auth = req.headers.authorization;
81
+ if (auth !== `Bearer ${CONFIG.apiKey}`) {
82
+ res.status(401).json({ error: 'Unauthorized' });
83
+ return;
84
+ }
85
+ }
86
+
87
+ // Rate limit
88
+ const clientKey = req.ip ?? 'unknown';
89
+ const now = Date.now();
90
+ let entry = rateLimiter.get(clientKey);
91
+ if (!entry || now > entry.resetAt) {
92
+ entry = { count: 0, resetAt: now + 60000 };
93
+ rateLimiter.set(clientKey, entry);
94
+ }
95
+ if (entry.count >= CONFIG.rateLimitPerMinute) {
96
+ res.status(429).json({ error: 'Rate limit exceeded' });
97
+ return;
98
+ }
99
+ entry.count++;
100
+
101
+ next();
102
+ }
103
+
104
+ // ============== WhatsApp Connection ==============
105
+
106
+ async function startWhatsApp() {
107
+ console.log('Starting WhatsApp connection...');
108
+ const { state } = await useFileAuthState('./auth');
109
+
110
+ sock = makeWASocket({
111
+ authState: state,
112
+ printQRInTerminal: true,
113
+ ramOptimizationLevel: 2,
114
+ maxReconnectAttempts: 10
115
+ });
116
+
117
+ sock.ev.on('connection.update', (update) => {
118
+ const { connection, qr } = update;
119
+ if (qr) console.log('Scan QR dengan WhatsApp mobile...');
120
+ if (connection === 'open') {
121
+ console.log('✓ WhatsApp connected as', sock!.user?.id);
122
+ isReady = true;
123
+ }
124
+ if (connection === 'close') {
125
+ console.log('Connection closed, reconnecting...');
126
+ isReady = false;
127
+ }
128
+ });
129
+
130
+ // Forward incoming messages ke webhook subscribers
131
+ sock.ev.on('message.upsert', async ({ messages }) => {
132
+ for (const message of messages) {
133
+ await forwardToWebhooks(message);
134
+ }
135
+ });
136
+
137
+ // Forward call events
138
+ sock.ev.on('calls', async (callEvent) => {
139
+ await forwardToWebhooks(callEvent, 'call');
140
+ });
141
+ }
142
+
143
+ // ============== Webhook Forwarding ==============
144
+
145
+ async function forwardToWebhooks(payload: any, type: string = 'message'): Promise<void> {
146
+ if (webhooks.size === 0) return;
147
+
148
+ const body = JSON.stringify({
149
+ type,
150
+ timestamp: Date.now(),
151
+ data: payload
152
+ });
153
+
154
+ for (const url of webhooks) {
155
+ try {
156
+ await fetch(url, {
157
+ method: 'POST',
158
+ headers: { 'Content-Type': 'application/json' },
159
+ body
160
+ });
161
+ } catch (err: any) {
162
+ console.error(`Webhook ${url} failed:`, err.message);
163
+ }
164
+ }
165
+ }
166
+
167
+ // ============== API Routes ==============
168
+
169
+ // Health check
170
+ app.get('/health', (req: Request, res: Response) => {
171
+ res.json({ status: 'ok', timestamp: Date.now() });
172
+ });
173
+
174
+ // Connection status
175
+ app.get('/status', authMiddleware, (req: Request, res: Response) => {
176
+ res.json({
177
+ connected: isReady,
178
+ user: sock?.user,
179
+ timestamp: Date.now()
180
+ });
181
+ });
182
+
183
+ // Send text message
184
+ app.post('/send-text', authMiddleware, async (req: Request, res: Response) => {
185
+ if (!isReady || !sock) {
186
+ res.status(503).json({ error: 'WhatsApp not connected' });
187
+ return;
188
+ }
189
+
190
+ const { to, message, mentions, quotedId } = req.body;
191
+
192
+ if (!to || !message) {
193
+ res.status(400).json({ error: 'Missing required fields: to, message' });
194
+ return;
195
+ }
196
+
197
+ try {
198
+ const jid = normalizeJid(to);
199
+ const content: any = { text: message };
200
+
201
+ if (mentions && Array.isArray(mentions)) {
202
+ content.mentions = mentions.map((m: string) => normalizeJid(m));
203
+ }
204
+
205
+ const result = await sock.sendMessage(jid, content);
206
+ res.json({
207
+ success: true,
208
+ messageId: result.key.id,
209
+ status: result.status,
210
+ timestamp: result.messageTimestamp
211
+ });
212
+ } catch (err: any) {
213
+ res.status(500).json({ error: err.message });
214
+ }
215
+ });
216
+
217
+ // Send media (image, video, audio, document)
218
+ app.post('/send-media', authMiddleware, async (req: Request, res: Response) => {
219
+ if (!isReady || !sock) {
220
+ res.status(503).json({ error: 'WhatsApp not connected' });
221
+ return;
222
+ }
223
+
224
+ const { to, type, base64, mimetype, caption, fileName } = req.body;
225
+
226
+ if (!to || !type || !base64 || !mimetype) {
227
+ res.status(400).json({ error: 'Missing required fields: to, type, base64, mimetype' });
228
+ return;
229
+ }
230
+
231
+ try {
232
+ const jid = normalizeJid(to);
233
+ const buffer = Buffer.from(base64, 'base64');
234
+
235
+ // First upload ke WhatsApp CDN
236
+ const uploadResult = await sock.uploadMedia(buffer, type, mimetype, fileName);
237
+
238
+ // Then send message dengan media reference
239
+ let content: any;
240
+ switch (type) {
241
+ case 'image':
242
+ content = {
243
+ image: { stream: buffer as any, mimetype },
244
+ caption
245
+ };
246
+ break;
247
+ case 'video':
248
+ content = {
249
+ video: { stream: buffer as any, mimetype },
250
+ caption
251
+ };
252
+ break;
253
+ case 'audio':
254
+ content = {
255
+ audio: { stream: buffer as any, mimetype }
256
+ };
257
+ break;
258
+ case 'document':
259
+ content = {
260
+ document: { stream: buffer as any, mimetype, fileName }
261
+ };
262
+ break;
263
+ default:
264
+ res.status(400).json({ error: `Unknown media type: ${type}` });
265
+ return;
266
+ }
267
+
268
+ const result = await sock.sendMessage(jid, content);
269
+ res.json({
270
+ success: true,
271
+ messageId: result.key.id,
272
+ status: result.status,
273
+ mediaUrl: uploadResult.url,
274
+ timestamp: result.messageTimestamp
275
+ });
276
+ } catch (err: any) {
277
+ res.status(500).json({ error: err.message });
278
+ }
279
+ });
280
+
281
+ // Send reaction
282
+ app.post('/send-reaction', authMiddleware, async (req: Request, res: Response) => {
283
+ if (!isReady || !sock) {
284
+ res.status(503).json({ error: 'WhatsApp not connected' });
285
+ return;
286
+ }
287
+
288
+ const { to, messageId, emoji } = req.body;
289
+ if (!to || !messageId || !emoji) {
290
+ res.status(400).json({ error: 'Missing required fields: to, messageId, emoji' });
291
+ return;
292
+ }
293
+
294
+ try {
295
+ const result = await sock.reactToMessage(
296
+ normalizeJid(to),
297
+ { remoteJid: normalizeJid(to), fromMe: false, id: messageId },
298
+ emoji
299
+ );
300
+ res.json({ success: true, status: result.status });
301
+ } catch (err: any) {
302
+ res.status(500).json({ error: err.message });
303
+ }
304
+ });
305
+
306
+ // Delete message
307
+ app.delete('/message', authMiddleware, async (req: Request, res: Response) => {
308
+ if (!isReady || !sock) {
309
+ res.status(503).json({ error: 'WhatsApp not connected' });
310
+ return;
311
+ }
312
+
313
+ const { to, messageId, revokeEveryone } = req.body;
314
+ if (!to || !messageId) {
315
+ res.status(400).json({ error: 'Missing required fields: to, messageId' });
316
+ return;
317
+ }
318
+
319
+ try {
320
+ const result = await sock.deleteMessage(
321
+ normalizeJid(to),
322
+ { remoteJid: normalizeJid(to), fromMe: true, id: messageId },
323
+ { revokeEveryone: revokeEveryone ?? false }
324
+ );
325
+ res.json({ success: true, status: result.status });
326
+ } catch (err: any) {
327
+ res.status(500).json({ error: err.message });
328
+ }
329
+ });
330
+
331
+ // List groups
332
+ app.get('/groups', authMiddleware, async (req: Request, res: Response) => {
333
+ if (!isReady || !sock) {
334
+ res.status(503).json({ error: 'WhatsApp not connected' });
335
+ return;
336
+ }
337
+
338
+ // Note: Real implementation perlu query groups dari sync
339
+ // Simplified untuk example
340
+ res.json({
341
+ success: true,
342
+ groups: [],
343
+ note: 'Use specific group ID via /groups/:id for metadata'
344
+ });
345
+ });
346
+
347
+ // Get group metadata
348
+ app.get('/groups/:jid', authMiddleware, async (req: Request, res: Response) => {
349
+ if (!isReady || !sock) {
350
+ res.status(503).json({ error: 'WhatsApp not connected' });
351
+ return;
352
+ }
353
+
354
+ try {
355
+ const metadata = await sock.groupMetadata(req.params.jid);
356
+ res.json({ success: true, metadata });
357
+ } catch (err: any) {
358
+ res.status(500).json({ error: err.message });
359
+ }
360
+ });
361
+
362
+ // Create group
363
+ app.post('/groups/create', authMiddleware, async (req: Request, res: Response) => {
364
+ if (!isReady || !sock) {
365
+ res.status(503).json({ error: 'WhatsApp not connected' });
366
+ return;
367
+ }
368
+
369
+ const { subject, participants, description } = req.body;
370
+ if (!subject || !participants || !Array.isArray(participants)) {
371
+ res.status(400).json({ error: 'Missing required: subject, participants[]' });
372
+ return;
373
+ }
374
+
375
+ try {
376
+ const metadata = await sock.groupCreate({
377
+ subject,
378
+ participants: participants.map((p: string) => normalizeJid(p)),
379
+ desc: description
380
+ });
381
+ res.json({ success: true, groupId: metadata.id, subject: metadata.subject });
382
+ } catch (err: any) {
383
+ res.status(500).json({ error: err.message });
384
+ }
385
+ });
386
+
387
+ // Group participants management
388
+ app.post('/groups/:jid/participants', authMiddleware, async (req: Request, res: Response) => {
389
+ if (!isReady || !sock) {
390
+ res.status(503).json({ error: 'WhatsApp not connected' });
391
+ return;
392
+ }
393
+
394
+ const { participants, action } = req.body;
395
+ if (!participants || !action) {
396
+ res.status(400).json({ error: 'Missing required: participants[], action' });
397
+ return;
398
+ }
399
+
400
+ if (!['add', 'remove', 'promote', 'demote'].includes(action)) {
401
+ res.status(400).json({ error: 'Invalid action' });
402
+ return;
403
+ }
404
+
405
+ try {
406
+ await sock.groupParticipantsUpdate(
407
+ req.params.jid,
408
+ participants.map((p: string) => normalizeJid(p)),
409
+ action
410
+ );
411
+ res.json({ success: true });
412
+ } catch (err: any) {
413
+ res.status(500).json({ error: err.message });
414
+ }
415
+ });
416
+
417
+ // Get invite code
418
+ app.get('/groups/:jid/invite', authMiddleware, async (req: Request, res: Response) => {
419
+ if (!isReady || !sock) {
420
+ res.status(503).json({ error: 'WhatsApp not connected' });
421
+ return;
422
+ }
423
+ try {
424
+ const code = await sock.groupInviteCode(req.params.jid);
425
+ res.json({ success: true, code, url: `https://chat.whatsapp.com/${code}` });
426
+ } catch (err: any) {
427
+ res.status(500).json({ error: err.message });
428
+ }
429
+ });
430
+
431
+ // Webhook management
432
+ app.post('/webhook', authMiddleware, (req: Request, res: Response) => {
433
+ const { url, action } = req.body;
434
+ if (!url) {
435
+ res.status(400).json({ error: 'Missing required: url' });
436
+ return;
437
+ }
438
+ if (action === 'remove') {
439
+ webhooks.delete(url);
440
+ } else {
441
+ webhooks.add(url);
442
+ }
443
+ res.json({ success: true, webhooks: Array.from(webhooks) });
444
+ });
445
+
446
+ app.get('/webhooks', authMiddleware, (req: Request, res: Response) => {
447
+ res.json({ webhooks: Array.from(webhooks) });
448
+ });
449
+
450
+ // ============== Helpers ==============
451
+
452
+ function normalizeJid(input: string): string {
453
+ // Remove non-digit chars dari phone number
454
+ const clean = input.replace(/[^0-9]/g, '');
455
+ // Jika sudah ada @, pakai apa adanya
456
+ if (input.includes('@')) return input;
457
+ // Jika 628... format, default ke s.whatsapp.net
458
+ return `${clean}@s.whatsapp.net`;
459
+ }
460
+
461
+ // ============== Error Handler ==============
462
+
463
+ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
464
+ console.error('Unhandled error:', err.message);
465
+ res.status(500).json({ error: 'Internal server error', message: err.message });
466
+ });
467
+
468
+ // ============== Start Server ==============
469
+
470
+ async function main() {
471
+ await startWhatsApp();
472
+
473
+ app.listen(CONFIG.port, () => {
474
+ console.log(`\n=== Waliwa REST API Gateway ===`);
475
+ console.log(`Listening on http://localhost:${CONFIG.port}`);
476
+ console.log(`Auth: ${CONFIG.apiKey ? 'API Key required' : 'No auth (set API_KEY env var)'}`);
477
+ console.log(`IP whitelist: ${CONFIG.allowedIps.length > 0 ? CONFIG.allowedIps.join(', ') : 'disabled'}`);
478
+ console.log(`Rate limit: ${CONFIG.rateLimitPerMinute}/min per IP`);
479
+ console.log(`\nEndpoints:`);
480
+ console.log(` GET /health`);
481
+ console.log(` GET /status`);
482
+ console.log(` POST /send-text`);
483
+ console.log(` POST /send-media`);
484
+ console.log(` POST /send-reaction`);
485
+ console.log(` DELETE /message`);
486
+ console.log(` GET /groups`);
487
+ console.log(` GET /groups/:jid`);
488
+ console.log(` POST /groups/create`);
489
+ console.log(` POST /groups/:jid/participants`);
490
+ console.log(` GET /groups/:jid/invite`);
491
+ console.log(` POST /webhook`);
492
+ console.log(` GET /webhooks\n`);
493
+ });
494
+ }
495
+
496
+ main().catch(err => {
497
+ console.error('Fatal error:', err);
498
+ process.exit(1);
499
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "waliwa-rest-gateway",
3
+ "version": "1.0.0",
4
+ "description": "HTTP REST API gateway untuk kirim pesan WhatsApp via REST endpoints",
5
+ "main": "index.ts",
6
+ "scripts": {
7
+ "start": "ts-node index.ts"
8
+ },
9
+ "dependencies": {
10
+ "waliwa": "file:../../",
11
+ "express": "^4.18.2"
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "^20.11.0",
15
+ "@types/express": "^4.17.21",
16
+ "typescript": "^5.3.3",
17
+ "ts-node": "^10.9.2"
18
+ }
19
+ }
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@kangwifi-pro/waliwa",
3
+ "version": "1.0.0",
4
+ "description": "Lightweight, RAM-efficient WhatsApp library with hybrid protocol (WhatsApp Web MD + Mobile API), Multi-Branch SKDM Recovery system, and 9+ Baileys issue fixes. More complete than Baileys, lighter than ZapoJS.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.cjs"
11
+ },
12
+ "./types": {
13
+ "import": "./dist/types/index.js",
14
+ "require": "./dist/types/index.cjs"
15
+ }
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "dev": "ts-node examples/echo-bot/index.ts",
23
+ "lint": "eslint src --ext .ts",
24
+ "test": "jest",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "whatsapp",
29
+ "bot",
30
+ "wa-web",
31
+ "multi-device",
32
+ "reverse-engineering",
33
+ "baileys",
34
+ "zapojs",
35
+ "lightweight",
36
+ "ram-efficient",
37
+ "noise-protocol",
38
+ "protobuf",
39
+ "pairing-code",
40
+ "qr-code"
41
+ ],
42
+ "author": "waliwa contributors",
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">=16.0.0"
46
+ },
47
+ "dependencies": {
48
+ "@noble/curves": "^1.4.0",
49
+ "@noble/hashes": "^1.4.0",
50
+ "@noble/ciphers": "^0.5.1",
51
+ "protobufjs": "^7.3.0",
52
+ "ws": "^8.16.0",
53
+ "qrcode-terminal": "^0.12.0",
54
+ "axios": "^1.6.7"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^20.11.20",
58
+ "@types/ws": "^8.5.10",
59
+ "@types/qrcode-terminal": "^0.12.2",
60
+ "typescript": "^5.3.3",
61
+ "ts-node": "^10.9.2",
62
+ "eslint": "^8.56.0",
63
+ "@typescript-eslint/eslint-plugin": "^7.0.2",
64
+ "jest": "^29.7.0",
65
+ "ts-jest": "^29.1.2"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "openai": {
69
+ "optional": true
70
+ },
71
+ "express": {
72
+ "optional": true
73
+ }
74
+ }
75
+ }