waengine 1.0.1
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/LICENSE +21 -0
- package/README.md +911 -0
- package/examples/easy-bot-examples.js +186 -0
- package/examples/multi-device-example.js +253 -0
- package/examples/quick-start.js +10 -0
- package/examples/simple-multi-device.js +42 -0
- package/package.json +67 -0
- package/src/client.js +412 -0
- package/src/core.js +79 -0
- package/src/device-manager.js +404 -0
- package/src/easy-bot.js +744 -0
- package/src/groups.js +156 -0
- package/src/index.js +6 -0
- package/src/message.js +628 -0
- package/src/messages.js +80 -0
- package/src/multi-client.js +374 -0
- package/src/qr.js +65 -0
- package/src/utils.js +0 -0
package/src/client.js
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import makeWASocket, { useMultiFileAuthState, DisconnectReason } from "@whiskeysockets/baileys";
|
|
2
|
+
import pino from "pino";
|
|
3
|
+
import { generateQRCode, closeBrowser } from "./qr.js";
|
|
4
|
+
import { Message } from "./message.js";
|
|
5
|
+
|
|
6
|
+
export class WhatsAppClient {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = {
|
|
9
|
+
authDir: "./auth",
|
|
10
|
+
printQR: false,
|
|
11
|
+
browser: options.browser || ["MyLibrary", "1.0.0", ""],
|
|
12
|
+
logLevel: options.logLevel || "silent", // Sauber ohne Debug
|
|
13
|
+
...options
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
this.socket = null;
|
|
17
|
+
this.isConnected = false;
|
|
18
|
+
this.eventHandlers = new Map();
|
|
19
|
+
|
|
20
|
+
// Prefix System
|
|
21
|
+
this.prefix = null;
|
|
22
|
+
this.commands = new Map();
|
|
23
|
+
|
|
24
|
+
// Deine eigenen API-Objekte
|
|
25
|
+
this.get = new GetAPI(this);
|
|
26
|
+
this.add = new AddAPI(this);
|
|
27
|
+
this.kick = new KickAPI(this);
|
|
28
|
+
this.promote = new PromoteAPI(this);
|
|
29
|
+
this.demote = new DemoteAPI(this);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ===== CONNECTION METHODS =====
|
|
33
|
+
|
|
34
|
+
async connect() {
|
|
35
|
+
console.log("🔄 Starte Verbindung...");
|
|
36
|
+
|
|
37
|
+
if (this.socket && this.isConnected) {
|
|
38
|
+
console.log("✅ Bereits verbunden");
|
|
39
|
+
return this.socket;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { state, saveCreds } = await useMultiFileAuthState(this.options.authDir);
|
|
43
|
+
console.log("📁 Auth-Daten geladen");
|
|
44
|
+
|
|
45
|
+
// Prüfen ob bereits eingeloggt
|
|
46
|
+
const isLoggedIn = !!state.creds?.me?.id;
|
|
47
|
+
console.log(`🔐 Login-Status: ${isLoggedIn ? 'Eingeloggt' : 'Nicht eingeloggt'}`);
|
|
48
|
+
|
|
49
|
+
this.socket = makeWASocket({
|
|
50
|
+
auth: state,
|
|
51
|
+
printQRInTerminal: this.options.printQR,
|
|
52
|
+
logger: pino({ level: this.options.logLevel }),
|
|
53
|
+
browser: this.options.browser
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log("🔌 Socket erstellt");
|
|
57
|
+
|
|
58
|
+
// QR-Code Browser nur öffnen wenn nicht eingeloggt
|
|
59
|
+
if (!this.options.printQR && !isLoggedIn) {
|
|
60
|
+
console.log("🌐 Öffne Browser für QR-Code...");
|
|
61
|
+
await generateQRCode();
|
|
62
|
+
} else if (isLoggedIn) {
|
|
63
|
+
console.log("✅ Bereits authentifiziert, verbinde direkt...");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
this.socket.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
|
|
68
|
+
console.log(`🔄 Connection Status: ${connection}`);
|
|
69
|
+
|
|
70
|
+
if (qr && !this.options.printQR && !isLoggedIn) {
|
|
71
|
+
console.log("📱 QR Code empfangen, zeige im Browser...");
|
|
72
|
+
await generateQRCode(qr);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (connection === "connecting") {
|
|
76
|
+
console.log("🔄 Verbinde mit WhatsApp...");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (connection === "close") {
|
|
80
|
+
console.log("🔴 Verbindung geschlossen");
|
|
81
|
+
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
|
|
82
|
+
|
|
83
|
+
if (shouldReconnect) {
|
|
84
|
+
console.log("🔄 Wiederverbindung...");
|
|
85
|
+
this.isConnected = false;
|
|
86
|
+
this.socket = null;
|
|
87
|
+
setTimeout(() => this.connect().then(resolve).catch(reject), 3000);
|
|
88
|
+
} else {
|
|
89
|
+
console.log("👋 Ausgeloggt - QR-Code wird beim nächsten Start benötigt");
|
|
90
|
+
await closeBrowser();
|
|
91
|
+
this.emit('disconnected', { reason: 'logged_out' });
|
|
92
|
+
}
|
|
93
|
+
} else if (connection === "open") {
|
|
94
|
+
console.log("✅ WhatsApp erfolgreich verbunden!");
|
|
95
|
+
this.isConnected = true;
|
|
96
|
+
this.setupEventHandlers();
|
|
97
|
+
this.emit('connected');
|
|
98
|
+
resolve(this);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
this.socket.ev.on("creds.update", saveCreds);
|
|
103
|
+
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
if (!this.isConnected) {
|
|
106
|
+
console.log("⏰ Verbindungs-Timeout");
|
|
107
|
+
reject(new Error("Connection timeout"));
|
|
108
|
+
}
|
|
109
|
+
}, 60000);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async disconnect() {
|
|
114
|
+
if (this.socket) {
|
|
115
|
+
this.socket.end();
|
|
116
|
+
this.socket = null;
|
|
117
|
+
this.isConnected = false;
|
|
118
|
+
await closeBrowser();
|
|
119
|
+
this.emit('disconnected', { reason: 'manual' });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ===== EVENT SYSTEM =====
|
|
124
|
+
|
|
125
|
+
on(event, handler) {
|
|
126
|
+
if (!this.eventHandlers.has(event)) {
|
|
127
|
+
this.eventHandlers.set(event, []);
|
|
128
|
+
}
|
|
129
|
+
this.eventHandlers.get(event).push(handler);
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
off(event, handler) {
|
|
134
|
+
if (this.eventHandlers.has(event)) {
|
|
135
|
+
const handlers = this.eventHandlers.get(event);
|
|
136
|
+
const index = handlers.indexOf(handler);
|
|
137
|
+
if (index > -1) {
|
|
138
|
+
handlers.splice(index, 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
emit(event, data) {
|
|
145
|
+
if (this.eventHandlers.has(event)) {
|
|
146
|
+
this.eventHandlers.get(event).forEach(handler => {
|
|
147
|
+
try {
|
|
148
|
+
handler(data);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error(`❌ Error in event handler for '${event}':`, error);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
setupEventHandlers() {
|
|
157
|
+
// Messages - Sauber ohne Debug-Spam
|
|
158
|
+
this.socket.ev.on("messages.upsert", ({ messages, type }) => {
|
|
159
|
+
if (type !== "notify") return;
|
|
160
|
+
|
|
161
|
+
messages.forEach(msg => {
|
|
162
|
+
if (!msg.message || msg.key.fromMe) return;
|
|
163
|
+
|
|
164
|
+
const messageData = this.parseMessage(msg);
|
|
165
|
+
const messageObj = new Message(this, messageData);
|
|
166
|
+
|
|
167
|
+
// Prefix System - Command Check
|
|
168
|
+
if (this.prefix && messageData.text && messageData.text.startsWith(this.prefix)) {
|
|
169
|
+
const commandText = messageData.text.slice(this.prefix.length).trim();
|
|
170
|
+
const [command, ...args] = commandText.split(' ');
|
|
171
|
+
|
|
172
|
+
messageObj.isCommand = true;
|
|
173
|
+
messageObj.command = command.toLowerCase();
|
|
174
|
+
messageObj.args = args;
|
|
175
|
+
messageObj.commandText = commandText;
|
|
176
|
+
|
|
177
|
+
// Command Event emittieren
|
|
178
|
+
this.emit('command', messageObj);
|
|
179
|
+
|
|
180
|
+
// Spezifischen Command Handler aufrufen falls vorhanden
|
|
181
|
+
if (this.commands.has(command.toLowerCase())) {
|
|
182
|
+
const handler = this.commands.get(command.toLowerCase());
|
|
183
|
+
try {
|
|
184
|
+
handler(messageObj, args);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error(`❌ Fehler in Command '${command}':`, error);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
messageObj.isCommand = false;
|
|
191
|
+
messageObj.command = null;
|
|
192
|
+
messageObj.args = [];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.emit('message', messageObj);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Group updates
|
|
200
|
+
this.socket.ev.on("group-participants.update", (update) => {
|
|
201
|
+
this.emit('group.participants.update', update);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Presence updates
|
|
205
|
+
this.socket.ev.on("presence.update", (update) => {
|
|
206
|
+
this.emit('presence.update', update);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
parseMessage(msg) {
|
|
211
|
+
const text =
|
|
212
|
+
msg.message.conversation ||
|
|
213
|
+
msg.message.extendedTextMessage?.text ||
|
|
214
|
+
msg.message.imageMessage?.caption ||
|
|
215
|
+
msg.message.videoMessage?.caption ||
|
|
216
|
+
null;
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
id: msg.key.id,
|
|
220
|
+
from: msg.key.remoteJid,
|
|
221
|
+
fromMe: msg.key.fromMe,
|
|
222
|
+
text: text,
|
|
223
|
+
timestamp: msg.messageTimestamp,
|
|
224
|
+
type: this.getMessageType(msg.message),
|
|
225
|
+
isGroup: msg.key.remoteJid?.includes("@g.us"),
|
|
226
|
+
raw: msg
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
getMessageType(message) {
|
|
231
|
+
if (message.conversation) return 'text';
|
|
232
|
+
if (message.imageMessage) return 'image';
|
|
233
|
+
if (message.videoMessage) return 'video';
|
|
234
|
+
if (message.audioMessage) return 'audio';
|
|
235
|
+
if (message.documentMessage) return 'document';
|
|
236
|
+
if (message.stickerMessage) return 'sticker';
|
|
237
|
+
if (message.locationMessage) return 'location';
|
|
238
|
+
if (message.contactMessage) return 'contact';
|
|
239
|
+
return 'unknown';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
getConnectionState() {
|
|
243
|
+
return {
|
|
244
|
+
isConnected: this.isConnected,
|
|
245
|
+
socket: !!this.socket
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ===== PREFIX SYSTEM =====
|
|
250
|
+
|
|
251
|
+
setPrefix(prefix) {
|
|
252
|
+
this.prefix = prefix;
|
|
253
|
+
console.log(`🎯 Prefix gesetzt auf: "${prefix}"`);
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getPrefix() {
|
|
258
|
+
return this.prefix;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
addCommand(command, handler) {
|
|
262
|
+
this.commands.set(command.toLowerCase(), handler);
|
|
263
|
+
console.log(`⚡ Command registriert: ${this.prefix || ''}${command}`);
|
|
264
|
+
return this;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
removeCommand(command) {
|
|
268
|
+
const removed = this.commands.delete(command.toLowerCase());
|
|
269
|
+
if (removed) {
|
|
270
|
+
console.log(`🗑️ Command entfernt: ${command}`);
|
|
271
|
+
}
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
getCommands() {
|
|
276
|
+
return Array.from(this.commands.keys());
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ===== PRESENCE SYSTEM =====
|
|
280
|
+
|
|
281
|
+
async setPresence(presence, chatId = null) {
|
|
282
|
+
try {
|
|
283
|
+
await this.socket.sendPresenceUpdate(presence, chatId);
|
|
284
|
+
return true;
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error(`❌ Fehler beim Setzen der Presence '${presence}':`, error);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async setOnline() {
|
|
292
|
+
return await this.setPresence('available');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async setOffline() {
|
|
296
|
+
return await this.setPresence('unavailable');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async setTyping(chatId) {
|
|
300
|
+
return await this.setPresence('composing', chatId);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async setRecording(chatId) {
|
|
304
|
+
return await this.setPresence('recording', chatId);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async setPaused(chatId) {
|
|
308
|
+
return await this.setPresence('paused', chatId);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ===== DEINE API-KLASSEN =====
|
|
313
|
+
|
|
314
|
+
class GetAPI {
|
|
315
|
+
constructor(client) {
|
|
316
|
+
this.client = client;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async GroupMetadata(groupId) {
|
|
320
|
+
return await this.client.socket.groupMetadata(groupId);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async GroupParticipants(groupId) {
|
|
324
|
+
const metadata = await this.GroupMetadata(groupId);
|
|
325
|
+
return metadata.participants;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async GroupAdmins(groupId) {
|
|
329
|
+
const participants = await this.GroupParticipants(groupId);
|
|
330
|
+
return participants.filter(p => p.admin === 'admin' || p.admin === 'superadmin');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
class AddAPI {
|
|
335
|
+
constructor(client) {
|
|
336
|
+
this.client = client;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async user(groupId, users, mentions = []) {
|
|
340
|
+
const result = await this.client.socket.groupParticipantsUpdate(groupId, users, 'add');
|
|
341
|
+
|
|
342
|
+
if (mentions.length > 0) {
|
|
343
|
+
const welcomeText = `Willkommen! ${mentions.map(id => `@${id.split('@')[0]}`).join(' ')}`;
|
|
344
|
+
await this.client.socket.sendMessage(groupId, {
|
|
345
|
+
text: welcomeText,
|
|
346
|
+
mentions: mentions
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
class KickAPI {
|
|
355
|
+
constructor(client) {
|
|
356
|
+
this.client = client;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async user(groupId, users, mentions = []) {
|
|
360
|
+
const result = await this.client.socket.groupParticipantsUpdate(groupId, users, 'remove');
|
|
361
|
+
|
|
362
|
+
if (mentions.length > 0) {
|
|
363
|
+
const kickText = `${mentions.map(id => `@${id.split('@')[0]}`).join(' ')} wurde entfernt.`;
|
|
364
|
+
await this.client.socket.sendMessage(groupId, {
|
|
365
|
+
text: kickText,
|
|
366
|
+
mentions: mentions
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
class PromoteAPI {
|
|
375
|
+
constructor(client) {
|
|
376
|
+
this.client = client;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async user(groupId, users, mentions = []) {
|
|
380
|
+
const result = await this.client.socket.groupParticipantsUpdate(groupId, users, 'promote');
|
|
381
|
+
|
|
382
|
+
if (mentions.length > 0) {
|
|
383
|
+
const promoteText = `🎉 ${mentions.map(id => `@${id.split('@')[0]}`).join(' ')} ist jetzt Admin!`;
|
|
384
|
+
await this.client.socket.sendMessage(groupId, {
|
|
385
|
+
text: promoteText,
|
|
386
|
+
mentions: mentions
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
class DemoteAPI {
|
|
395
|
+
constructor(client) {
|
|
396
|
+
this.client = client;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async user(groupId, users, mentions = []) {
|
|
400
|
+
const result = await this.client.socket.groupParticipantsUpdate(groupId, users, 'demote');
|
|
401
|
+
|
|
402
|
+
if (mentions.length > 0) {
|
|
403
|
+
const demoteText = `${mentions.map(id => `@${id.split('@')[0]}`).join(' ')} ist nicht mehr Admin.`;
|
|
404
|
+
await this.client.socket.sendMessage(groupId, {
|
|
405
|
+
text: demoteText,
|
|
406
|
+
mentions: mentions
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
}
|
package/src/core.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import makeWASocket, { useMultiFileAuthState, DisconnectReason } from "@whiskeysockets/baileys";
|
|
2
|
+
import pino from "pino";
|
|
3
|
+
import { generateQRCode, closeBrowser } from "./qr.js";
|
|
4
|
+
|
|
5
|
+
let socket = null;
|
|
6
|
+
let isConnected = false;
|
|
7
|
+
|
|
8
|
+
export async function getSocket() {
|
|
9
|
+
if (socket && isConnected) return socket;
|
|
10
|
+
|
|
11
|
+
const { state, saveCreds } = await useMultiFileAuthState("./auth");
|
|
12
|
+
|
|
13
|
+
socket = makeWASocket({
|
|
14
|
+
auth: state,
|
|
15
|
+
printQRInTerminal: false,
|
|
16
|
+
logger: pino({ level: "debug" }), // Debug-Level für mehr Logs
|
|
17
|
+
browser: ["Chrome (Linux)", "", ""]
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Browser öffnen für QR-Code
|
|
21
|
+
await generateQRCode();
|
|
22
|
+
|
|
23
|
+
// Connection-Events abwarten
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
socket.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
|
|
26
|
+
console.log(`🔄 Connection Update: ${connection}`);
|
|
27
|
+
|
|
28
|
+
if (qr) {
|
|
29
|
+
console.log("📱 QR-Code generiert - wird im Edge Browser angezeigt!");
|
|
30
|
+
await generateQRCode(qr);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (connection === "close") {
|
|
34
|
+
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
|
|
35
|
+
console.log("🔴 Verbindung geschlossen:", lastDisconnect?.error);
|
|
36
|
+
|
|
37
|
+
if (shouldReconnect) {
|
|
38
|
+
console.log("🔄 Versuche Wiederverbindung...");
|
|
39
|
+
isConnected = false;
|
|
40
|
+
socket = null;
|
|
41
|
+
getSocket().then(resolve).catch(reject);
|
|
42
|
+
} else {
|
|
43
|
+
await closeBrowser();
|
|
44
|
+
}
|
|
45
|
+
} else if (connection === "open") {
|
|
46
|
+
console.log("✅ Erfolgreich mit WhatsApp verbunden!");
|
|
47
|
+
console.log("🎉 Du kannst jetzt den Browser schließen oder offen lassen");
|
|
48
|
+
isConnected = true;
|
|
49
|
+
|
|
50
|
+
// Test: Alle Event-Listener anzeigen
|
|
51
|
+
console.log("🎧 Registrierte Events:", Object.keys(socket.ev.listenerCount));
|
|
52
|
+
|
|
53
|
+
resolve(socket);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
socket.ev.on("creds.update", saveCreds);
|
|
58
|
+
|
|
59
|
+
// WICHTIG: Alle Events loggen für Debug
|
|
60
|
+
socket.ev.on("messages.upsert", (data) => {
|
|
61
|
+
console.log("🚨 RAW MESSAGE EVENT:", JSON.stringify(data, null, 2));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
socket.ev.on("chats.set", (data) => {
|
|
65
|
+
console.log("💬 Chats Set Event:", data.length, "chats");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
socket.ev.on("contacts.set", (data) => {
|
|
69
|
+
console.log("👥 Contacts Set Event:", data.length, "contacts");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Timeout nach 60 Sekunden
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
if (!isConnected) {
|
|
75
|
+
reject(new Error("Connection timeout - QR-Code im Browser nicht gescannt?"));
|
|
76
|
+
}
|
|
77
|
+
}, 60000);
|
|
78
|
+
});
|
|
79
|
+
}
|