@vielhuber/wahelper 1.7.7 → 1.7.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/package.json +6 -2
- package/wahelper-daemon.js +85 -12
- package/wahelper.js +49 -48
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielhuber/wahelper",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "Lightweight whatsapp integration layer.",
|
|
5
5
|
"main": "wahelper.js",
|
|
6
6
|
"files": [
|
|
@@ -27,9 +27,13 @@
|
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@prettier/plugin-php": "^0.25.0",
|
|
30
|
-
"prettier": "^3.9.
|
|
30
|
+
"prettier": "^3.9.6"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"allowScripts": {
|
|
36
|
+
"baileys": true,
|
|
37
|
+
"protobufjs": true
|
|
34
38
|
}
|
|
35
39
|
}
|
package/wahelper-daemon.js
CHANGED
|
@@ -39,6 +39,8 @@ export default class wahelperDaemon {
|
|
|
39
39
|
this.isFirstRun = false;
|
|
40
40
|
this.reconnectDelay = 1000;
|
|
41
41
|
this.consecutiveFailures = 0;
|
|
42
|
+
this.connectionAttempt = null;
|
|
43
|
+
this.connectionTimeout = null;
|
|
42
44
|
this.httpServer = null;
|
|
43
45
|
|
|
44
46
|
if (this.args.device) {
|
|
@@ -627,23 +629,68 @@ export default class wahelperDaemon {
|
|
|
627
629
|
return;
|
|
628
630
|
}
|
|
629
631
|
this.connecting = true;
|
|
632
|
+
let connectionAttempt = Symbol('connection');
|
|
633
|
+
let socket = null;
|
|
634
|
+
let staleSocket = null;
|
|
635
|
+
let connectionTimeoutError = new Error('connection attempt timed out');
|
|
636
|
+
this.connectionAttempt = connectionAttempt;
|
|
637
|
+
clearTimeout(this.connectionTimeout);
|
|
638
|
+
this.connectionTimeout = setTimeout(() => {
|
|
639
|
+
if (this.connectionAttempt !== connectionAttempt || this.connected) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
this.connectionTimeout = null;
|
|
643
|
+
this.connected = false;
|
|
644
|
+
this.connecting = false;
|
|
645
|
+
this.lastError = { source: 'connect', message: connectionTimeoutError.message, at: Date.now() };
|
|
646
|
+
this.log('⛔ Connect error: ' + connectionTimeoutError.message);
|
|
647
|
+
console.log('⛔ Connect error: ' + connectionTimeoutError.message);
|
|
648
|
+
let socketToClose = socket || staleSocket || this.sock;
|
|
649
|
+
if (socketToClose) {
|
|
650
|
+
void socketToClose.end(connectionTimeoutError);
|
|
651
|
+
}
|
|
652
|
+
setTimeout(() => {
|
|
653
|
+
if (
|
|
654
|
+
this.connectionAttempt !== connectionAttempt ||
|
|
655
|
+
this.connected ||
|
|
656
|
+
this.connecting
|
|
657
|
+
) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (this.sock === socketToClose) {
|
|
661
|
+
this.sock = null;
|
|
662
|
+
}
|
|
663
|
+
this.connect();
|
|
664
|
+
}, this.reconnectDelay);
|
|
665
|
+
}, 60000);
|
|
630
666
|
this.log('Connecting...');
|
|
631
667
|
console.log('Connecting...');
|
|
632
668
|
|
|
633
669
|
useMultiFileAuthState(this.dirname + '/' + this.authFolder)
|
|
634
670
|
.then(async ({ state, saveCreds }) => {
|
|
671
|
+
if (this.connectionAttempt !== connectionAttempt) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
635
674
|
let { version } = await fetchLatestBaileysVersion();
|
|
675
|
+
if (this.connectionAttempt !== connectionAttempt) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
636
678
|
console.log('Baileys version: ' + version.join('.'));
|
|
637
679
|
|
|
638
680
|
// close stale socket if present
|
|
639
|
-
|
|
681
|
+
staleSocket = this.sock;
|
|
682
|
+
this.sock = null;
|
|
683
|
+
if (staleSocket) {
|
|
640
684
|
try {
|
|
641
|
-
|
|
685
|
+
await staleSocket.end();
|
|
642
686
|
} catch (_) {}
|
|
643
687
|
}
|
|
688
|
+
if (this.connectionAttempt !== connectionAttempt) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
644
691
|
|
|
645
692
|
console.log('Creating WebSocket...');
|
|
646
|
-
|
|
693
|
+
socket = makeWASocket({
|
|
647
694
|
auth: state,
|
|
648
695
|
logger: P({ level: 'silent' }, P.destination(2)),
|
|
649
696
|
// sync full history only during initial pairing and its required reconnect
|
|
@@ -651,25 +698,27 @@ export default class wahelperDaemon {
|
|
|
651
698
|
version,
|
|
652
699
|
browser: Browsers.windows('Desktop')
|
|
653
700
|
});
|
|
701
|
+
this.sock = socket;
|
|
702
|
+
staleSocket = null;
|
|
654
703
|
|
|
655
|
-
|
|
704
|
+
socket.ev.on('messaging-history.set', async obj => {
|
|
656
705
|
this.log('messaging-history.set');
|
|
657
706
|
await this.storeDataToDatabase(obj);
|
|
658
707
|
// allow media downloads on all future syncs (reconnects)
|
|
659
708
|
this.isFirstRun = false;
|
|
660
709
|
});
|
|
661
710
|
|
|
662
|
-
|
|
711
|
+
socket.ev.on('messages.upsert', async obj => {
|
|
663
712
|
this.log('messages.upsert');
|
|
664
713
|
await this.storeDataToDatabase(obj);
|
|
665
714
|
});
|
|
666
715
|
|
|
667
|
-
|
|
716
|
+
socket.ev.on('chats.upsert', async obj => {
|
|
668
717
|
this.log('chats.upsert');
|
|
669
718
|
await this.storeDataToDatabase(obj);
|
|
670
719
|
});
|
|
671
720
|
|
|
672
|
-
|
|
721
|
+
socket.ev.on('messages.update', async updates => {
|
|
673
722
|
try {
|
|
674
723
|
await this.markMessagesRead(updates);
|
|
675
724
|
} catch (error) {
|
|
@@ -677,7 +726,7 @@ export default class wahelperDaemon {
|
|
|
677
726
|
}
|
|
678
727
|
});
|
|
679
728
|
|
|
680
|
-
|
|
729
|
+
socket.ev.on('chats.update', async updates => {
|
|
681
730
|
try {
|
|
682
731
|
await this.markChatsRead(updates);
|
|
683
732
|
} catch (error) {
|
|
@@ -685,9 +734,12 @@ export default class wahelperDaemon {
|
|
|
685
734
|
}
|
|
686
735
|
});
|
|
687
736
|
|
|
688
|
-
|
|
737
|
+
socket.ev.on('creds.update', saveCreds);
|
|
689
738
|
|
|
690
|
-
|
|
739
|
+
socket.ev.on('connection.update', async update => {
|
|
740
|
+
if (this.sock !== socket) {
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
691
743
|
let { connection, lastDisconnect, qr } = update;
|
|
692
744
|
let statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
693
745
|
this.log(connection);
|
|
@@ -698,7 +750,7 @@ export default class wahelperDaemon {
|
|
|
698
750
|
// request pairing code once per session
|
|
699
751
|
if (!this.pairingCodeRequested && this.device) {
|
|
700
752
|
this.pairingCodeRequested = true;
|
|
701
|
-
|
|
753
|
+
socket
|
|
702
754
|
.requestPairingCode(this.device)
|
|
703
755
|
.then(code => {
|
|
704
756
|
this.pairingCode = code;
|
|
@@ -719,6 +771,9 @@ export default class wahelperDaemon {
|
|
|
719
771
|
}
|
|
720
772
|
} else {
|
|
721
773
|
if (connection === 'close') {
|
|
774
|
+
clearTimeout(this.connectionTimeout);
|
|
775
|
+
this.connectionTimeout = null;
|
|
776
|
+
this.connectionAttempt = null;
|
|
722
777
|
this.connected = false;
|
|
723
778
|
this.connecting = false;
|
|
724
779
|
|
|
@@ -747,7 +802,13 @@ export default class wahelperDaemon {
|
|
|
747
802
|
// the symptom — keep the more specific upstream
|
|
748
803
|
// reason (e.g. "rate-overlimit") instead of burying
|
|
749
804
|
// it under a generic "connectionLost"
|
|
750
|
-
if (
|
|
805
|
+
if (lastDisconnect?.error === connectionTimeoutError) {
|
|
806
|
+
this.lastError = {
|
|
807
|
+
source: 'connect',
|
|
808
|
+
message: connectionTimeoutError.message,
|
|
809
|
+
at: Date.now()
|
|
810
|
+
};
|
|
811
|
+
} else if (this.lastError?.source !== 'pairing') {
|
|
751
812
|
let reason =
|
|
752
813
|
DisconnectReason && statusCode
|
|
753
814
|
? Object.keys(DisconnectReason).find(k => DisconnectReason[k] === statusCode)
|
|
@@ -775,6 +836,9 @@ export default class wahelperDaemon {
|
|
|
775
836
|
}
|
|
776
837
|
|
|
777
838
|
if (connection === 'open') {
|
|
839
|
+
clearTimeout(this.connectionTimeout);
|
|
840
|
+
this.connectionTimeout = null;
|
|
841
|
+
this.connectionAttempt = null;
|
|
778
842
|
this.connected = true;
|
|
779
843
|
this.connecting = false;
|
|
780
844
|
this.qr = null;
|
|
@@ -790,6 +854,12 @@ export default class wahelperDaemon {
|
|
|
790
854
|
});
|
|
791
855
|
})
|
|
792
856
|
.catch(error => {
|
|
857
|
+
if (this.connectionAttempt !== connectionAttempt) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
clearTimeout(this.connectionTimeout);
|
|
861
|
+
this.connectionTimeout = null;
|
|
862
|
+
this.connectionAttempt = null;
|
|
793
863
|
this.connecting = false;
|
|
794
864
|
this.lastError = { source: 'connect', message: error.message, at: Date.now() };
|
|
795
865
|
this.log('⛔ Connect error: ' + error.message);
|
|
@@ -920,6 +990,9 @@ export default class wahelperDaemon {
|
|
|
920
990
|
|
|
921
991
|
gracefulShutdown() {
|
|
922
992
|
this.connected = false;
|
|
993
|
+
clearTimeout(this.connectionTimeout);
|
|
994
|
+
this.connectionAttempt = null;
|
|
995
|
+
this.connectionTimeout = null;
|
|
923
996
|
if (this.sock) {
|
|
924
997
|
try {
|
|
925
998
|
this.sock.end();
|
package/wahelper.js
CHANGED
|
@@ -84,61 +84,62 @@ export default class wahelper {
|
|
|
84
84
|
this.resetFolder();
|
|
85
85
|
}
|
|
86
86
|
let response = null;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
if (daemonStatus.message === 'qr_required') {
|
|
99
|
-
console.log('\n⚠️ Pairing required. Scan the QR code with WhatsApp, then retry.\n');
|
|
100
|
-
console.log(daemonStatus.qrString);
|
|
101
|
-
}
|
|
102
|
-
if (daemonStatus.message === 'daemon_error' || daemonStatus.message === 'daemon_timeout') {
|
|
103
|
-
console.log('⛔ ' + (daemonStatus.public_message || daemonStatus.message));
|
|
87
|
+
if (this.args.action === 'fetch_messages') {
|
|
88
|
+
let filter = null;
|
|
89
|
+
if (typeof this.args.filter === 'string' && this.args.filter !== '') {
|
|
90
|
+
try {
|
|
91
|
+
filter = JSON.parse(this.args.filter);
|
|
92
|
+
} catch (_) {
|
|
93
|
+
filter = null;
|
|
94
|
+
}
|
|
95
|
+
} else if (this.args.filter && typeof this.args.filter === 'object') {
|
|
96
|
+
filter = this.args.filter;
|
|
104
97
|
}
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
true
|
|
98
|
+
response = await this.fetchMessages(
|
|
99
|
+
filter,
|
|
100
|
+
this.args.limit,
|
|
101
|
+
this.args.order,
|
|
102
|
+
this.args.exclude_body === true ||
|
|
103
|
+
this.args.exclude_body === 'true' ||
|
|
104
|
+
this.args.exclude_body === '1'
|
|
113
105
|
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
106
|
+
}
|
|
107
|
+
if (this.args.action === 'view_message') {
|
|
108
|
+
response = await this.viewMessage(this.args.id);
|
|
109
|
+
}
|
|
110
|
+
if (this.args.action === 'send_user' || this.args.action === 'send_group') {
|
|
111
|
+
let daemonStatus = await this.ensureDaemon();
|
|
112
|
+
if (!daemonStatus.connected) {
|
|
113
|
+
if (daemonStatus.message === 'daemon_not_running') {
|
|
114
|
+
console.log(
|
|
115
|
+
'⛔ Daemon not running. Start it with: npx wahelper-daemon --device ' + this.args.device
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (daemonStatus.message === 'pairing_required') {
|
|
119
|
+
console.log('\n⚠️ Pairing required. Enter this code in WhatsApp (Linked Devices), then retry.\n');
|
|
120
|
+
console.log('Pairing code: ' + daemonStatus.pairingCode);
|
|
125
121
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
if (daemonStatus.message === 'qr_required') {
|
|
123
|
+
console.log('\n⚠️ Pairing required. Scan the QR code with WhatsApp, then retry.\n');
|
|
124
|
+
console.log(daemonStatus.qrString);
|
|
125
|
+
}
|
|
126
|
+
if (daemonStatus.message === 'daemon_error' || daemonStatus.message === 'daemon_timeout') {
|
|
127
|
+
console.log('⛔ ' + (daemonStatus.public_message || daemonStatus.message));
|
|
128
|
+
}
|
|
129
|
+
this.write(
|
|
130
|
+
{
|
|
131
|
+
success: false,
|
|
132
|
+
message: daemonStatus.message,
|
|
133
|
+
public_message: daemonStatus.public_message || null,
|
|
134
|
+
data: daemonStatus.data || daemonStatus.pairingCode || daemonStatus.qrString || null
|
|
135
|
+
},
|
|
136
|
+
true
|
|
133
137
|
);
|
|
134
138
|
}
|
|
135
|
-
if (this.args.action === '
|
|
136
|
-
response = await this.viewMessage(this.args.id);
|
|
137
|
-
}
|
|
138
|
-
if (this.args.action === 'send_user') {
|
|
139
|
+
if (daemonStatus.connected && this.args.action === 'send_user') {
|
|
139
140
|
response = await this.sendMessageToUser(this.args.number, this.args.message, this.args.attachments);
|
|
140
141
|
}
|
|
141
|
-
if (this.args.action === 'send_group') {
|
|
142
|
+
if (daemonStatus.connected && this.args.action === 'send_group') {
|
|
142
143
|
response = await this.sendMessageToGroup(this.args.name, this.args.message, this.args.attachments);
|
|
143
144
|
}
|
|
144
145
|
}
|