fluxy-bot 0.13.4 → 0.13.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/package.json
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Session persisted in ~/.fluxy/whatsapp-session/.
|
|
5
5
|
*
|
|
6
6
|
* Baileys is imported dynamically so the supervisor starts even if
|
|
7
|
-
* @whiskeysockets/baileys is not installed.
|
|
8
|
-
* npm install @whiskeysockets/baileys
|
|
7
|
+
* @whiskeysockets/baileys is not installed.
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
import path from 'path';
|
|
@@ -14,13 +13,17 @@ import { log } from '../../shared/logger.js';
|
|
|
14
13
|
import type { Channel, ChannelRouter, OutgoingMessage } from './types.js';
|
|
15
14
|
|
|
16
15
|
const SESSION_DIR = path.join(DATA_DIR, 'whatsapp-session');
|
|
16
|
+
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
17
|
+
const RECONNECT_BASE_DELAY = 5_000; // 5s, doubles each retry
|
|
17
18
|
|
|
18
19
|
export class WhatsAppChannel implements Channel {
|
|
19
20
|
readonly type = 'whatsapp' as const;
|
|
20
21
|
private sock: any = null;
|
|
21
22
|
private router: ChannelRouter | null = null;
|
|
22
23
|
private onQR?: (qr: string) => void;
|
|
23
|
-
private
|
|
24
|
+
private reconnectAttempts = 0;
|
|
25
|
+
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
26
|
+
private shuttingDown = false;
|
|
24
27
|
|
|
25
28
|
constructor(onQR?: (qr: string) => void) {
|
|
26
29
|
this.onQR = onQR;
|
|
@@ -28,11 +31,18 @@ export class WhatsAppChannel implements Channel {
|
|
|
28
31
|
|
|
29
32
|
async initialize(router: ChannelRouter): Promise<void> {
|
|
30
33
|
this.router = router;
|
|
31
|
-
|
|
34
|
+
try {
|
|
35
|
+
await this.connect();
|
|
36
|
+
} catch (err: any) {
|
|
37
|
+
// Don't let baileys crash the supervisor — log and move on
|
|
38
|
+
log.warn(`[whatsapp] Initial connection failed: ${err.message}`);
|
|
39
|
+
log.warn('[whatsapp] WhatsApp will remain inactive. Restart Fluxy after scanning QR to retry.');
|
|
40
|
+
}
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
private async connect(): Promise<void> {
|
|
35
|
-
|
|
44
|
+
if (this.shuttingDown) return;
|
|
45
|
+
|
|
36
46
|
const baileys = await import('@whiskeysockets/baileys');
|
|
37
47
|
const makeWASocket = baileys.default;
|
|
38
48
|
const { useMultiFileAuthState, DisconnectReason } = baileys;
|
|
@@ -41,7 +51,7 @@ export class WhatsAppChannel implements Channel {
|
|
|
41
51
|
|
|
42
52
|
this.sock = makeWASocket({
|
|
43
53
|
auth: state,
|
|
44
|
-
printQRInTerminal
|
|
54
|
+
// printQRInTerminal is deprecated in baileys v7 — we handle QR via connection.update
|
|
45
55
|
});
|
|
46
56
|
|
|
47
57
|
this.sock.ev.on('creds.update', saveCreds);
|
|
@@ -49,31 +59,46 @@ export class WhatsAppChannel implements Channel {
|
|
|
49
59
|
this.sock.ev.on('connection.update', (update: any) => {
|
|
50
60
|
const { connection, lastDisconnect, qr } = update;
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
// Handle QR code — surface it to chat UI
|
|
63
|
+
if (qr) {
|
|
64
|
+
log.info('[whatsapp] QR code received — scan with your phone to link');
|
|
65
|
+
if (this.onQR) this.onQR(qr);
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
if (connection === 'close') {
|
|
57
69
|
const statusCode = (lastDisconnect?.error as any)?.output?.statusCode;
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
setTimeout(() => {
|
|
65
|
-
this.reconnecting = false;
|
|
66
|
-
this.connect().catch((err) => {
|
|
67
|
-
log.warn(`[whatsapp] Reconnect failed: ${err.message}`);
|
|
68
|
-
});
|
|
69
|
-
}, 5000);
|
|
70
|
-
} else if (!shouldReconnect) {
|
|
71
|
-
log.warn('[whatsapp] Logged out — scan QR again to reconnect');
|
|
70
|
+
const isLoggedOut = statusCode === DisconnectReason.loggedOut;
|
|
71
|
+
|
|
72
|
+
if (isLoggedOut) {
|
|
73
|
+
log.warn('[whatsapp] Logged out. Scan QR again to reconnect.');
|
|
74
|
+
this.sock = null;
|
|
75
|
+
return;
|
|
72
76
|
}
|
|
77
|
+
|
|
78
|
+
this.reconnectAttempts++;
|
|
79
|
+
|
|
80
|
+
if (this.reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
|
|
81
|
+
log.warn(`[whatsapp] Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached. Giving up.`);
|
|
82
|
+
log.warn('[whatsapp] WhatsApp will remain inactive. Restart Fluxy to retry.');
|
|
83
|
+
this.sock = null;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Exponential backoff: 5s, 10s, 20s, 40s, 80s
|
|
88
|
+
const delay = RECONNECT_BASE_DELAY * Math.pow(2, this.reconnectAttempts - 1);
|
|
89
|
+
log.warn(`[whatsapp] Connection closed (${statusCode}). Reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
|
|
90
|
+
|
|
91
|
+
this.reconnectTimer = setTimeout(() => {
|
|
92
|
+
this.reconnectTimer = null;
|
|
93
|
+
this.connect().catch((err) => {
|
|
94
|
+
log.warn(`[whatsapp] Reconnect failed: ${err.message}`);
|
|
95
|
+
});
|
|
96
|
+
}, delay);
|
|
73
97
|
}
|
|
74
98
|
|
|
75
99
|
if (connection === 'open') {
|
|
76
100
|
log.ok('[whatsapp] Connected to WhatsApp');
|
|
101
|
+
this.reconnectAttempts = 0; // Reset on successful connection
|
|
77
102
|
}
|
|
78
103
|
});
|
|
79
104
|
|
|
@@ -133,6 +158,11 @@ export class WhatsAppChannel implements Channel {
|
|
|
133
158
|
}
|
|
134
159
|
|
|
135
160
|
async shutdown(): Promise<void> {
|
|
161
|
+
this.shuttingDown = true;
|
|
162
|
+
if (this.reconnectTimer) {
|
|
163
|
+
clearTimeout(this.reconnectTimer);
|
|
164
|
+
this.reconnectTimer = null;
|
|
165
|
+
}
|
|
136
166
|
if (this.sock) {
|
|
137
167
|
this.sock.end(undefined);
|
|
138
168
|
this.sock = null;
|