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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.13.4",
3
+ "version": "0.13.5",
4
4
  "releaseNotes": [
5
5
  "1. react router implemented",
6
6
  "2. new workspace design",
@@ -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. Install it with:
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 reconnecting = false;
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
- await this.connect();
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
- // Dynamic import — fails gracefully if baileys is not installed
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: true,
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
- if (qr && this.onQR) {
53
- this.onQR(qr);
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 shouldReconnect = statusCode !== DisconnectReason.loggedOut;
59
-
60
- log.warn(`[whatsapp] Connection closed: ${statusCode}. Reconnect: ${shouldReconnect}`);
61
-
62
- if (shouldReconnect && !this.reconnecting) {
63
- this.reconnecting = true;
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;