@vielhuber/wahelper 1.8.7 → 1.8.9
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/README.md +6 -0
- package/package.json +1 -1
- package/wahelper-daemon.js +45 -22
- package/wahelper.js +51 -20
package/README.md
CHANGED
|
@@ -53,6 +53,9 @@ npx wahelper \
|
|
|
53
53
|
--device "xxxxxxxxxxxx" \
|
|
54
54
|
...
|
|
55
55
|
|
|
56
|
+
# check the live connection
|
|
57
|
+
--action "get_status"
|
|
58
|
+
|
|
56
59
|
# fetch messages
|
|
57
60
|
--action "fetch_messages" \
|
|
58
61
|
--filter '{"from":"491234567890","to":"491234567890","message":"meeting","date_from":"2026-01-01","date_until":"2026-12-31"}' \
|
|
@@ -85,6 +88,9 @@ use vielhuber\wahelper\wahelper;
|
|
|
85
88
|
|
|
86
89
|
$wahelper = new wahelper();
|
|
87
90
|
|
|
91
|
+
// success is true only when connected
|
|
92
|
+
$status = $wahelper->getStatus(device: 'xxxxxxxxxxxx');
|
|
93
|
+
|
|
88
94
|
// fetch messages
|
|
89
95
|
$wahelper->fetchMessages(
|
|
90
96
|
device: 'xxxxxxxxxxxx',
|
package/package.json
CHANGED
package/wahelper-daemon.js
CHANGED
|
@@ -36,6 +36,7 @@ export default class wahelperDaemon {
|
|
|
36
36
|
this.dbLock = false;
|
|
37
37
|
this.connected = false;
|
|
38
38
|
this.connecting = false;
|
|
39
|
+
this.loggedOut = false;
|
|
39
40
|
this.qr = null;
|
|
40
41
|
this.pairingCode = null;
|
|
41
42
|
this.pairingCodeRequested = false;
|
|
@@ -698,8 +699,8 @@ export default class wahelperDaemon {
|
|
|
698
699
|
}
|
|
699
700
|
|
|
700
701
|
async sendMessageToUser(number = null, message = null, attachments = null) {
|
|
701
|
-
if (!this.connected
|
|
702
|
-
throw new Error('not_connected');
|
|
702
|
+
if (!this.getStatus().connected) {
|
|
703
|
+
throw new Error(this.loggedOut ? 'logged_out' : 'not_connected');
|
|
703
704
|
}
|
|
704
705
|
// validate all attachments exist before sending anything
|
|
705
706
|
if (attachments !== null && attachments.length > 0) {
|
|
@@ -724,8 +725,8 @@ export default class wahelperDaemon {
|
|
|
724
725
|
}
|
|
725
726
|
|
|
726
727
|
async sendMessageToGroup(name = null, message = null, attachments = null) {
|
|
727
|
-
if (!this.connected
|
|
728
|
-
throw new Error('not_connected');
|
|
728
|
+
if (!this.getStatus().connected) {
|
|
729
|
+
throw new Error(this.loggedOut ? 'logged_out' : 'not_connected');
|
|
729
730
|
}
|
|
730
731
|
// validate all attachments exist before sending anything
|
|
731
732
|
if (attachments !== null && attachments.length > 0) {
|
|
@@ -756,7 +757,7 @@ export default class wahelperDaemon {
|
|
|
756
757
|
}
|
|
757
758
|
|
|
758
759
|
connect() {
|
|
759
|
-
if (this.connecting) {
|
|
760
|
+
if (this.connecting || this.loggedOut) {
|
|
760
761
|
return;
|
|
761
762
|
}
|
|
762
763
|
this.connecting = true;
|
|
@@ -827,7 +828,8 @@ export default class wahelperDaemon {
|
|
|
827
828
|
// sync full history only during initial pairing and its required reconnect
|
|
828
829
|
syncFullHistory: !state.creds.registered || this.isFirstRun,
|
|
829
830
|
version,
|
|
830
|
-
|
|
831
|
+
// whatsapp rejects new logins as "Desktop" with full history sync (428 connectionClosed)
|
|
832
|
+
browser: Browsers.windows('Chrome')
|
|
831
833
|
});
|
|
832
834
|
this.sock = socket;
|
|
833
835
|
staleSocket = null;
|
|
@@ -885,10 +887,16 @@ export default class wahelperDaemon {
|
|
|
885
887
|
socket
|
|
886
888
|
.requestPairingCode(this.device)
|
|
887
889
|
.then(code => {
|
|
890
|
+
if (this.sock !== socket) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
888
893
|
this.pairingCode = code;
|
|
889
894
|
console.log('\nPairing code: ' + code);
|
|
890
895
|
})
|
|
891
896
|
.catch(err => {
|
|
897
|
+
if (this.sock !== socket) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
892
900
|
this.lastError = { source: 'pairing', message: err.message, at: Date.now() };
|
|
893
901
|
this.log('Pairing code request failed: ' + err.message);
|
|
894
902
|
});
|
|
@@ -917,16 +925,19 @@ export default class wahelperDaemon {
|
|
|
917
925
|
}
|
|
918
926
|
|
|
919
927
|
if (statusCode === DisconnectReason.loggedOut) {
|
|
920
|
-
|
|
928
|
+
this.loggedOut = true;
|
|
929
|
+
this.sock = null;
|
|
921
930
|
this.qr = null;
|
|
922
931
|
this.pairingCode = null;
|
|
923
932
|
this.pairingCodeRequested = false;
|
|
924
|
-
this.
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
933
|
+
this.lastError = {
|
|
934
|
+
source: 'disconnect',
|
|
935
|
+
message: 'Logged out. Automatic reconnect stopped; manual device linking required.',
|
|
936
|
+
statusCode,
|
|
937
|
+
at: Date.now()
|
|
938
|
+
};
|
|
939
|
+
this.log(this.lastError);
|
|
940
|
+
console.error(this.lastError.message);
|
|
930
941
|
return;
|
|
931
942
|
}
|
|
932
943
|
|
|
@@ -949,10 +960,16 @@ export default class wahelperDaemon {
|
|
|
949
960
|
source: 'disconnect',
|
|
950
961
|
message:
|
|
951
962
|
'connection closed' +
|
|
952
|
-
(reason
|
|
963
|
+
(reason
|
|
964
|
+
? ' (' + reason + ')'
|
|
965
|
+
: statusCode
|
|
966
|
+
? ' (statusCode=' + statusCode + ')'
|
|
967
|
+
: ''),
|
|
968
|
+
statusCode,
|
|
953
969
|
at: Date.now()
|
|
954
970
|
};
|
|
955
971
|
}
|
|
972
|
+
this.log(this.lastError);
|
|
956
973
|
this.consecutiveFailures++;
|
|
957
974
|
// first 3 attempts recover network blips fast (1s/2s/4s),
|
|
958
975
|
// after that back off to 15min so a persistent failure
|
|
@@ -1000,6 +1017,19 @@ export default class wahelperDaemon {
|
|
|
1000
1017
|
});
|
|
1001
1018
|
}
|
|
1002
1019
|
|
|
1020
|
+
getStatus() {
|
|
1021
|
+
return {
|
|
1022
|
+
success: true,
|
|
1023
|
+
connected: this.connected && this.sock?.ws?.isOpen === true,
|
|
1024
|
+
connecting: this.connecting,
|
|
1025
|
+
loggedOut: this.loggedOut,
|
|
1026
|
+
device: this.device,
|
|
1027
|
+
qr: this.qr,
|
|
1028
|
+
pairingCode: this.pairingCode,
|
|
1029
|
+
lastError: this.lastError
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1003
1033
|
startHttpServer() {
|
|
1004
1034
|
this.httpServer = http.createServer(async (req, res) => {
|
|
1005
1035
|
// bound to 127.0.0.1 below — every request additionally has to
|
|
@@ -1025,14 +1055,7 @@ export default class wahelperDaemon {
|
|
|
1025
1055
|
this.sendJsonResponse(res, 403, { success: false, message: 'forbidden' });
|
|
1026
1056
|
return;
|
|
1027
1057
|
}
|
|
1028
|
-
this.sendJsonResponse(res, 200,
|
|
1029
|
-
success: true,
|
|
1030
|
-
connected: this.connected,
|
|
1031
|
-
device: this.device,
|
|
1032
|
-
qr: this.qr,
|
|
1033
|
-
pairingCode: this.pairingCode,
|
|
1034
|
-
lastError: this.lastError
|
|
1035
|
-
});
|
|
1058
|
+
this.sendJsonResponse(res, 200, this.getStatus());
|
|
1036
1059
|
return;
|
|
1037
1060
|
}
|
|
1038
1061
|
|
package/wahelper.js
CHANGED
|
@@ -53,6 +53,28 @@ export default class wahelper {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async init() {
|
|
56
|
+
if (this.args.action === 'get_status') {
|
|
57
|
+
let status = this.args.device
|
|
58
|
+
? await this.callDaemon('GET', '/status')
|
|
59
|
+
: { success: false, message: 'missing_device' };
|
|
60
|
+
let connected = status.connected === true;
|
|
61
|
+
let response = {
|
|
62
|
+
success: connected,
|
|
63
|
+
message: connected ? 'connected' : status.loggedOut ? 'logged_out' : status.message || 'not_connected',
|
|
64
|
+
public_message: status.lastError?.message ?? null,
|
|
65
|
+
data: {
|
|
66
|
+
connected,
|
|
67
|
+
connecting: status.connecting === true,
|
|
68
|
+
loggedOut: status.loggedOut === true,
|
|
69
|
+
pairingRequired: status.loggedOut === true || Boolean(status.pairingCode || status.qr),
|
|
70
|
+
lastError: status.lastError ?? null
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
this.write(response, false);
|
|
74
|
+
console.log(JSON.stringify(response));
|
|
75
|
+
process.exitCode = connected ? 0 : 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
56
78
|
await this.awaitLock('init', true);
|
|
57
79
|
this.setLock('init', true);
|
|
58
80
|
this.write({ success: false, message: 'loading_state', data: null }, false);
|
|
@@ -127,7 +149,11 @@ export default class wahelper {
|
|
|
127
149
|
console.log('\n⚠️ Pairing required. Scan the QR code with WhatsApp, then retry.\n');
|
|
128
150
|
console.log(daemonStatus.qrString);
|
|
129
151
|
}
|
|
130
|
-
if (
|
|
152
|
+
if (
|
|
153
|
+
daemonStatus.message === 'daemon_error' ||
|
|
154
|
+
daemonStatus.message === 'daemon_timeout' ||
|
|
155
|
+
daemonStatus.message === 'logged_out'
|
|
156
|
+
) {
|
|
131
157
|
console.log('⛔ ' + (daemonStatus.public_message || daemonStatus.message));
|
|
132
158
|
}
|
|
133
159
|
this.write(
|
|
@@ -316,26 +342,25 @@ export default class wahelper {
|
|
|
316
342
|
}
|
|
317
343
|
|
|
318
344
|
async ensureDaemon() {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if (status.connected) {
|
|
328
|
-
return status;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// poll up to 30s — return immediately when pairing code appears
|
|
332
|
-
console.log('Waiting for daemon to connect...');
|
|
333
|
-
for (let i = 0; i < 30; i++) {
|
|
334
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
335
|
-
status = await this.callDaemon('GET', '/status');
|
|
345
|
+
for (let i = 0; i <= 30; i++) {
|
|
346
|
+
let status = await this.callDaemon('GET', '/status');
|
|
347
|
+
if (status.success === false) {
|
|
348
|
+
return {
|
|
349
|
+
connected: false,
|
|
350
|
+
message: status.message === 'daemon_not_reachable' ? 'daemon_not_running' : status.message
|
|
351
|
+
};
|
|
352
|
+
}
|
|
336
353
|
if (status.connected) {
|
|
337
354
|
return status;
|
|
338
355
|
}
|
|
356
|
+
if (status.loggedOut) {
|
|
357
|
+
return {
|
|
358
|
+
connected: false,
|
|
359
|
+
message: 'logged_out',
|
|
360
|
+
public_message: status.lastError?.message,
|
|
361
|
+
data: status.lastError
|
|
362
|
+
};
|
|
363
|
+
}
|
|
339
364
|
if (status.pairingCode) {
|
|
340
365
|
return { connected: false, message: 'pairing_required', pairingCode: status.pairingCode };
|
|
341
366
|
}
|
|
@@ -353,6 +378,12 @@ export default class wahelper {
|
|
|
353
378
|
data: status.lastError
|
|
354
379
|
};
|
|
355
380
|
}
|
|
381
|
+
if (i === 0) {
|
|
382
|
+
console.log('Waiting for daemon to connect...');
|
|
383
|
+
}
|
|
384
|
+
if (i < 30) {
|
|
385
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
386
|
+
}
|
|
356
387
|
}
|
|
357
388
|
return { connected: false, message: 'daemon_timeout' };
|
|
358
389
|
}
|
|
@@ -400,7 +431,7 @@ export default class wahelper {
|
|
|
400
431
|
}
|
|
401
432
|
});
|
|
402
433
|
});
|
|
403
|
-
req.setTimeout(30000, () => {
|
|
434
|
+
req.setTimeout(path === '/status' ? 5000 : 30000, () => {
|
|
404
435
|
req.destroy();
|
|
405
436
|
this.log('⛔ Daemon request timeout');
|
|
406
437
|
resolve({ success: false, message: 'daemon_timeout' });
|
|
@@ -642,6 +673,6 @@ if (
|
|
|
642
673
|
) {
|
|
643
674
|
let wa = new wahelper();
|
|
644
675
|
wa.init()
|
|
645
|
-
.then(() => process.exit(0))
|
|
676
|
+
.then(() => process.exit(process.exitCode ?? 0))
|
|
646
677
|
.catch(() => process.exit(1));
|
|
647
678
|
}
|