@raevon/n8n-nodes-whatsapp 1.0.6 → 1.0.8
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.
|
@@ -48,6 +48,7 @@ const baileys_1 = __importStar(require("@whiskeysockets/baileys"));
|
|
|
48
48
|
const p_queue_1 = __importDefault(require("p-queue"));
|
|
49
49
|
const node_path_1 = __importDefault(require("node:path"));
|
|
50
50
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
51
|
+
const qrcode_1 = __importDefault(require("qrcode"));
|
|
51
52
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
52
53
|
const randBetween = (min, max) => max > min ? min + Math.floor(Math.random() * (max - min + 1)) : min;
|
|
53
54
|
// Silent logger — Baileys expects pino-compatible logger with these methods
|
|
@@ -122,8 +123,16 @@ async function scheduleReconnect(cfg) {
|
|
|
122
123
|
}, delay);
|
|
123
124
|
}
|
|
124
125
|
async function initSocket(cfg, authPath) {
|
|
125
|
-
if
|
|
126
|
-
|
|
126
|
+
// Always create fresh socket if current one is dead
|
|
127
|
+
if (socketInstance && socketStatus === 'connected') {
|
|
128
|
+
try {
|
|
129
|
+
if (socketInstance.user)
|
|
130
|
+
return socketInstance;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Socket dead, create new one
|
|
134
|
+
}
|
|
135
|
+
}
|
|
127
136
|
const gen = ++generation; // #10: Snapshot generation for this connection attempt
|
|
128
137
|
const resolvedPath = expandHome(authPath);
|
|
129
138
|
if (!node_fs_1.default.existsSync(resolvedPath)) {
|
|
@@ -156,7 +165,7 @@ async function initSocket(cfg, authPath) {
|
|
|
156
165
|
console.error('[WhatsApp] Failed to save credentials:', err.message);
|
|
157
166
|
});
|
|
158
167
|
});
|
|
159
|
-
sock.ev.on('connection.update', (update) => {
|
|
168
|
+
sock.ev.on('connection.update', async (update) => {
|
|
160
169
|
var _a, _b;
|
|
161
170
|
if (gen !== generation)
|
|
162
171
|
return; // #10: Ignore stale connection events
|
|
@@ -164,10 +173,10 @@ async function initSocket(cfg, authPath) {
|
|
|
164
173
|
if (qr) {
|
|
165
174
|
latestQr = qr;
|
|
166
175
|
socketStatus = 'qr_ready';
|
|
167
|
-
//
|
|
176
|
+
// Generate QR locally using qrcode package — no external service
|
|
168
177
|
if (qrResolve) {
|
|
169
|
-
const
|
|
170
|
-
qrResolve({ qr, qrUrl });
|
|
178
|
+
const qrDataUrl = await qrcode_1.default.toDataURL(qr, { width: 300, margin: 2 });
|
|
179
|
+
qrResolve({ qr, qrUrl: qrDataUrl });
|
|
171
180
|
qrResolve = null;
|
|
172
181
|
}
|
|
173
182
|
}
|
|
@@ -209,8 +218,17 @@ async function getWhatsAppCredentials(credentials) {
|
|
|
209
218
|
};
|
|
210
219
|
}
|
|
211
220
|
async function ensureConnected(cfg) {
|
|
212
|
-
|
|
213
|
-
|
|
221
|
+
// Always try to use existing socket first, but verify it's actually alive
|
|
222
|
+
if (socketInstance && socketStatus === 'connected') {
|
|
223
|
+
try {
|
|
224
|
+
// Quick check — if socket user is set, it's alive
|
|
225
|
+
if (socketInstance.user)
|
|
226
|
+
return socketInstance;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
// Socket is dead, reconnect below
|
|
230
|
+
}
|
|
231
|
+
}
|
|
214
232
|
const antiBanCfg = {
|
|
215
233
|
messageDelayMinMs: cfg.messageDelayMinMs,
|
|
216
234
|
messageDelayMaxMs: cfg.messageDelayMaxMs,
|
|
@@ -227,42 +245,29 @@ async function ensureConnected(cfg) {
|
|
|
227
245
|
if (!queue) {
|
|
228
246
|
queue = new p_queue_1.default({ concurrency: 1 });
|
|
229
247
|
}
|
|
230
|
-
// Check if session already exists
|
|
248
|
+
// Check if session already exists on disk
|
|
231
249
|
const resolvedPath = expandHome(cfg.sessionPath);
|
|
232
250
|
const hasSession = node_fs_1.default.existsSync(resolvedPath) && node_fs_1.default.readdirSync(resolvedPath).length > 0;
|
|
233
|
-
const sock = await initSocket(antiBanCfg, cfg.sessionPath);
|
|
234
|
-
// If no session, wait for QR with a reasonable timeout
|
|
235
251
|
if (!hasSession) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// 90 second timeout — QR codes expire quickly, user needs to act fast
|
|
239
|
-
setTimeout(() => {
|
|
240
|
-
if (qrResolve) {
|
|
241
|
-
qrResolve(null);
|
|
242
|
-
qrResolve = null;
|
|
243
|
-
}
|
|
244
|
-
}, 90000);
|
|
252
|
+
throw new n8n_workflow_1.NodeApiError({}, {
|
|
253
|
+
message: 'No WhatsApp session found. Run the WhatsApp Connect node first to scan QR code.',
|
|
245
254
|
});
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
clearInterval(checkInterval);
|
|
263
|
-
reject(new Error('Connection failed after QR scan'));
|
|
264
|
-
}
|
|
265
|
-
}, 1000);
|
|
255
|
+
}
|
|
256
|
+
// Session exists — connect using saved credentials (no QR needed)
|
|
257
|
+
const sock = await initSocket(antiBanCfg, cfg.sessionPath);
|
|
258
|
+
// Wait for connection to open (up to 15s)
|
|
259
|
+
await new Promise((resolve) => {
|
|
260
|
+
const check = setInterval(() => {
|
|
261
|
+
if (socketStatus === 'connected' || socketStatus === 'error' || socketStatus === 'logged_out') {
|
|
262
|
+
clearInterval(check);
|
|
263
|
+
resolve();
|
|
264
|
+
}
|
|
265
|
+
}, 500);
|
|
266
|
+
setTimeout(() => { clearInterval(check); resolve(); }, 15000);
|
|
267
|
+
});
|
|
268
|
+
if (socketStatus !== 'connected') {
|
|
269
|
+
throw new n8n_workflow_1.NodeApiError({}, {
|
|
270
|
+
message: `WhatsApp connection failed (status: ${socketStatus}). Try running Connect node again.`,
|
|
266
271
|
});
|
|
267
272
|
}
|
|
268
273
|
return sock;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raevon/n8n-nodes-whatsapp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "n8n community node for WhatsApp — send and receive messages with anti-ban protection via the Baileys library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package",
|
|
@@ -36,10 +36,12 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@whiskeysockets/baileys": "^7.0.0-rc13",
|
|
39
|
-
"p-queue": "^8.0.1"
|
|
39
|
+
"p-queue": "^8.0.1",
|
|
40
|
+
"qrcode": "^1.5.4"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/node": "^20.19.39",
|
|
44
|
+
"@types/qrcode": "^1.5.6",
|
|
43
45
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
44
46
|
"@typescript-eslint/parser": "^6.21.0",
|
|
45
47
|
"eslint": "^8.57.1",
|