waengine 1.7.5 → 1.7.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.
@@ -1,4 +1,5 @@
1
1
  import { ConsoleLogger } from "./console-logger.js";
2
+ import { ERROR_CODES, getErrorDescription, createError, getErrorCategory } from "./error-codes.js";
2
3
 
3
4
  export class ErrorHandler {
4
5
  constructor(options = {}) {
@@ -15,48 +16,124 @@ export class ErrorHandler {
15
16
  this.logger = new ConsoleLogger({ silent: false });
16
17
  this.errorCount = 0;
17
18
  this.lastError = null;
19
+ this.errorStats = new Map(); // Track error frequency by code
18
20
  }
19
21
 
20
22
  /**
21
- * Handle any error with support information
23
+ * Handle any error with support information and error codes
22
24
  */
23
25
  handleError(error, context = {}) {
24
26
  this.errorCount++;
27
+
28
+ // Extract or assign error code
29
+ const errorCode = error.code || context.errorCode || this.detectErrorCode(error, context);
30
+ const errorDescription = getErrorDescription(errorCode);
31
+ const errorCategory = getErrorCategory(errorCode);
32
+
33
+ // Track error statistics
34
+ if (!this.errorStats.has(errorCode)) {
35
+ this.errorStats.set(errorCode, { count: 0, firstSeen: new Date(), lastSeen: null });
36
+ }
37
+ const stats = this.errorStats.get(errorCode);
38
+ stats.count++;
39
+ stats.lastSeen = new Date();
40
+
25
41
  this.lastError = {
26
42
  error: error,
43
+ errorCode: errorCode,
44
+ errorDescription: errorDescription,
45
+ errorCategory: errorCategory,
27
46
  context: context,
28
47
  timestamp: new Date(),
29
- count: this.errorCount
48
+ count: this.errorCount,
49
+ occurrences: stats.count
30
50
  };
31
51
 
32
- // Log error details
52
+ // Log error details with error code
33
53
  if (this.options.logErrors) {
34
54
  console.error(`\n❌ WAEngine Error #${this.errorCount}:`);
55
+ console.error(` Error Code: ${errorCode}`);
56
+ console.error(` Category: ${errorCategory}`);
57
+ console.error(` Description: ${errorDescription}`);
35
58
  console.error(` Context: ${context.action || 'Unknown'}`);
36
59
  console.error(` Message: ${error.message}`);
37
60
  if (context.details) {
38
61
  console.error(` Details: ${context.details}`);
39
62
  }
40
63
  console.error(` Time: ${new Date().toLocaleString()}`);
64
+ if (stats.count > 1) {
65
+ console.error(` Occurrences: ${stats.count} (First: ${stats.firstSeen.toLocaleString()})`);
66
+ }
41
67
  }
42
68
 
43
69
  // Show support information
44
70
  if (this.options.showSupportInfo) {
45
- this.showSupportInfo(error, context);
71
+ this.showSupportInfo(error, context, errorCode);
46
72
  }
47
73
 
48
74
  // Send error report (if enabled)
49
75
  if (this.options.sendErrorReports) {
50
- this.sendErrorReport(error, context);
76
+ this.sendErrorReport(error, context, errorCode);
51
77
  }
52
78
 
53
79
  return this.lastError;
54
80
  }
55
81
 
56
82
  /**
57
- * Show support contact information
83
+ * Detect error code from error message and context
58
84
  */
59
- showSupportInfo(error, context) {
85
+ detectErrorCode(error, context) {
86
+ const message = error.message?.toLowerCase() || '';
87
+ const action = context.action?.toLowerCase() || '';
88
+
89
+ // Connection errors - check timeout BEFORE general connection
90
+ if (message.includes('timeout')) {
91
+ return ERROR_CODES.CONNECTION.TIMEOUT;
92
+ }
93
+ if (message.includes('connection') || message.includes('socket') || message.includes('econnrefused')) {
94
+ return ERROR_CODES.CONNECTION.FAILED;
95
+ }
96
+ if (message.includes('disconnected') || message.includes('closed')) {
97
+ return ERROR_CODES.CONNECTION.LOST;
98
+ }
99
+
100
+ // Auth errors
101
+ if (message.includes('auth') || message.includes('creds') || message.includes('credentials')) {
102
+ return ERROR_CODES.AUTH.FAILED;
103
+ }
104
+ if (message.includes('qr') || action.includes('qr')) {
105
+ return ERROR_CODES.QR.GENERATION_FAILED;
106
+ }
107
+ if (message.includes('session') || message.includes('corrupted')) {
108
+ return ERROR_CODES.AUTH.SESSION_CORRUPTED;
109
+ }
110
+
111
+ // File errors
112
+ if (message.includes('enoent') || message.includes('file not found')) {
113
+ return ERROR_CODES.FILE.NOT_FOUND;
114
+ }
115
+ if (message.includes('eperm') || message.includes('permission')) {
116
+ return ERROR_CODES.FILE.PERMISSION_DENIED;
117
+ }
118
+
119
+ // Message errors
120
+ if (action.includes('message') || action.includes('send')) {
121
+ return ERROR_CODES.MESSAGE.SEND_FAILED;
122
+ }
123
+
124
+ // Plugin errors
125
+ if (action.includes('plugin')) {
126
+ return ERROR_CODES.PLUGIN.LOAD_FAILED;
127
+ }
128
+
129
+ // Default unknown error
130
+ return ERROR_CODES.SYSTEM.UNKNOWN_ERROR;
131
+ }
132
+
133
+ /**
134
+ * Show support contact information with error code
135
+ */
136
+ showSupportInfo(error, context, errorCode) {
60
137
  console.log("\n" + "=".repeat(50));
61
138
  console.log("❌ FEHLER AUFGETRETEN!");
62
139
  console.log("=".repeat(50));
@@ -69,54 +146,131 @@ export class ErrorHandler {
69
146
  }
70
147
 
71
148
  console.log(`\n🔍 Fehler-Details:`);
149
+ console.log(` • Error Code: ${errorCode}`);
150
+ console.log(` • Beschreibung: ${getErrorDescription(errorCode)}`);
151
+ console.log(` • Kategorie: ${getErrorCategory(errorCode)}`);
72
152
  console.log(` • Fehler: ${error.message}`);
73
153
  console.log(` • WAEngine Version: ${this.getWAEngineVersion()}`);
74
- console.log(` • Error ID: WAE-${Date.now()}-${this.errorCount}`);
75
154
 
76
155
  // Kurze, hilfreiche Lösungsvorschläge
77
156
  console.log(`\n💡 Schnelle Lösung:`);
78
- this.showQuickFixes(error, context);
157
+ this.showQuickFixes(error, context, errorCode);
79
158
 
159
+ console.log(`\n📖 Mehr Infos: Siehe ERROR-CODES.md für Details zu ${errorCode}`);
80
160
  console.log("=".repeat(50) + "\n");
81
161
  }
82
162
 
83
163
  /**
84
- * Show quick fixes for common errors
164
+ * Show quick fixes for common errors based on error code
85
165
  */
86
- showQuickFixes(error, context) {
87
- const message = error.message.toLowerCase();
166
+ showQuickFixes(error, context, errorCode) {
167
+ const fixes = this.getQuickFixForErrorCode(errorCode);
88
168
 
89
- if (message.includes('qr') || message.includes('auth')) {
90
- console.log("Lösche 'auth' Ordner und scanne QR neu");
91
- }
92
- else if (message.includes('connection') || message.includes('socket')) {
93
- console.log(" → Prüfe Internetverbindung und starte Bot neu");
94
- }
95
- else if (message.includes('sharp') || message.includes('sticker')) {
96
- console.log(" → Installiere Sharp: npm install sharp");
97
- }
98
- else if (message.includes('plugin')) {
99
- console.log(" → Installiere Dependencies: npm install --force");
100
- }
101
- else if (message.includes('permission') || message.includes('admin')) {
102
- console.log(" → Bot braucht Admin-Rechte in der Gruppe");
103
- }
104
- else {
105
- console.log(" → Starte Bot neu oder kontaktiere Support");
169
+ if (fixes.length > 0) {
170
+ fixes.forEach(fix => console.log(`${fix}`));
171
+ } else {
172
+ // Fallback to message-based detection
173
+ const message = error.message.toLowerCase();
174
+
175
+ if (message.includes('qr') || message.includes('auth')) {
176
+ console.log(" → Lösche 'auth' Ordner und scanne QR neu");
177
+ }
178
+ else if (message.includes('connection') || message.includes('socket')) {
179
+ console.log(" → Prüfe Internetverbindung und starte Bot neu");
180
+ }
181
+ else if (message.includes('sharp') || message.includes('sticker')) {
182
+ console.log(" → Installiere Sharp: npm install sharp");
183
+ }
184
+ else if (message.includes('plugin')) {
185
+ console.log(" → Installiere Dependencies: npm install --force");
186
+ }
187
+ else if (message.includes('permission') || message.includes('admin')) {
188
+ console.log(" → Bot braucht Admin-Rechte in der Gruppe");
189
+ }
190
+ else {
191
+ console.log(" → Starte Bot neu oder kontaktiere Support");
192
+ }
106
193
  }
107
194
  }
108
195
 
109
196
  /**
110
- * Send error report to support (if enabled)
197
+ * Get quick fixes for specific error codes
111
198
  */
112
- async sendErrorReport(error, context) {
199
+ getQuickFixForErrorCode(errorCode) {
200
+ const fixes = {
201
+ [ERROR_CODES.CONNECTION.FAILED]: [
202
+ "Prüfe deine Internetverbindung",
203
+ "Starte den Bot neu",
204
+ "Prüfe ob WhatsApp Server erreichbar sind"
205
+ ],
206
+ [ERROR_CODES.CONNECTION.TIMEOUT]: [
207
+ "Erhöhe das Connection Timeout in den Optionen",
208
+ "Prüfe deine Netzwerkgeschwindigkeit",
209
+ "Versuche es später erneut"
210
+ ],
211
+ [ERROR_CODES.AUTH.FAILED]: [
212
+ "Lösche den 'auth' Ordner",
213
+ "Scanne den QR-Code erneut",
214
+ "Stelle sicher dass WhatsApp auf dem Handy aktiv ist"
215
+ ],
216
+ [ERROR_CODES.AUTH.SESSION_CORRUPTED]: [
217
+ "Lösche den 'auth' Ordner komplett",
218
+ "Starte den Bot neu und scanne QR-Code",
219
+ "Prüfe ob genug Speicherplatz vorhanden ist"
220
+ ],
221
+ [ERROR_CODES.QR.GENERATION_FAILED]: [
222
+ "Installiere qrcode-terminal: npm install qrcode-terminal",
223
+ "Vergrößere dein Terminal-Fenster",
224
+ "Verwende Browser-QR statt Terminal-QR"
225
+ ],
226
+ [ERROR_CODES.FILE.NOT_FOUND]: [
227
+ "Prüfe ob die Datei existiert",
228
+ "Prüfe den Dateipfad",
229
+ "Stelle sicher dass die Datei nicht verschoben wurde"
230
+ ],
231
+ [ERROR_CODES.FILE.PERMISSION_DENIED]: [
232
+ "Führe den Bot mit Administrator-Rechten aus",
233
+ "Prüfe Datei-Berechtigungen",
234
+ "Schließe andere Programme die die Datei verwenden"
235
+ ],
236
+ [ERROR_CODES.MESSAGE.SEND_FAILED]: [
237
+ "Prüfe ob die Verbindung aktiv ist",
238
+ "Prüfe ob die Nummer/Gruppe existiert",
239
+ "Versuche es erneut"
240
+ ],
241
+ [ERROR_CODES.PLUGIN.LOAD_FAILED]: [
242
+ "Installiere Plugin-Dependencies: npm install",
243
+ "Prüfe Plugin-Konfiguration",
244
+ "Prüfe Plugin-Kompatibilität mit WAEngine Version"
245
+ ],
246
+ [ERROR_CODES.MOBILE.DETECTION_FAILED]: [
247
+ "Aktualisiere @whiskeysockets/baileys",
248
+ "Prüfe Mobile-Support Konfiguration",
249
+ "Verwende Desktop-Modus als Fallback"
250
+ ]
251
+ };
252
+
253
+ return fixes[errorCode] || [];
254
+ }
255
+
256
+ /**
257
+ * Send error report to support (if enabled) with error code
258
+ */
259
+ async sendErrorReport(error, context, errorCode) {
113
260
  try {
261
+ const stats = this.errorStats.get(errorCode);
262
+
114
263
  const report = {
115
- errorId: `WAE-${Date.now()}-${this.errorCount}`,
264
+ errorCode: errorCode,
265
+ errorDescription: getErrorDescription(errorCode),
266
+ errorCategory: getErrorCategory(errorCode),
116
267
  message: error.message,
117
268
  stack: error.stack,
118
269
  context: context,
119
- version: this.getWAEngineVersion(),
270
+ occurrences: stats?.count || 1,
271
+ firstSeen: stats?.firstSeen?.toISOString(),
272
+ lastSeen: stats?.lastSeen?.toISOString(),
273
+ version: await this.getWAEngineVersion(),
120
274
  nodeVersion: process.version,
121
275
  platform: process.platform,
122
276
  timestamp: new Date().toISOString()
@@ -129,7 +283,7 @@ export class ErrorHandler {
129
283
  // body: JSON.stringify(report)
130
284
  // });
131
285
 
132
- console.log("📤 Fehlerbericht automatisch gesendet (Error ID: " + report.errorId + ")");
286
+ console.log(`📤 Fehlerbericht automatisch gesendet (Error Code: ${errorCode})`);
133
287
  } catch (reportError) {
134
288
  console.log("⚠️ Fehlerbericht konnte nicht gesendet werden");
135
289
  }
@@ -154,8 +308,17 @@ export class ErrorHandler {
154
308
  * Handle connection errors specifically
155
309
  */
156
310
  handleConnectionError(error, reconnectAttempt = 0) {
311
+ // Assign specific error code based on error type
312
+ let errorCode = ERROR_CODES.CONNECTION.FAILED;
313
+ if (error.message?.includes('timeout')) {
314
+ errorCode = ERROR_CODES.CONNECTION.TIMEOUT;
315
+ } else if (error.message?.includes('lost') || error.message?.includes('closed')) {
316
+ errorCode = ERROR_CODES.CONNECTION.LOST;
317
+ }
318
+
157
319
  return this.handleError(error, {
158
320
  action: 'connection',
321
+ errorCode: errorCode,
159
322
  reconnectAttempt: reconnectAttempt,
160
323
  details: `Wiederverbindungsversuch ${reconnectAttempt}`
161
324
  });
@@ -165,8 +328,16 @@ export class ErrorHandler {
165
328
  * Handle plugin errors specifically
166
329
  */
167
330
  handlePluginError(error, pluginName) {
331
+ let errorCode = ERROR_CODES.PLUGIN.LOAD_FAILED;
332
+ if (error.message?.includes('not found')) {
333
+ errorCode = ERROR_CODES.PLUGIN.NOT_FOUND;
334
+ } else if (error.message?.includes('config')) {
335
+ errorCode = ERROR_CODES.PLUGIN.INVALID_CONFIG;
336
+ }
337
+
168
338
  return this.handleError(error, {
169
339
  action: 'plugin',
340
+ errorCode: errorCode,
170
341
  plugin: pluginName,
171
342
  details: `Plugin '${pluginName}' Fehler`
172
343
  });
@@ -178,6 +349,7 @@ export class ErrorHandler {
178
349
  handleCommandError(error, command, userId) {
179
350
  return this.handleError(error, {
180
351
  action: 'command',
352
+ errorCode: ERROR_CODES.COMMAND.EXECUTION_FAILED,
181
353
  command: command,
182
354
  user: userId,
183
355
  details: `Command '${command}' Fehler`
@@ -188,20 +360,41 @@ export class ErrorHandler {
188
360
  * Handle message errors specifically
189
361
  */
190
362
  handleMessageError(error, messageType) {
363
+ let errorCode = ERROR_CODES.MESSAGE.SEND_FAILED;
364
+ if (error.message?.includes('media')) {
365
+ errorCode = ERROR_CODES.MESSAGE.MEDIA_UPLOAD_FAILED;
366
+ } else if (error.message?.includes('format')) {
367
+ errorCode = ERROR_CODES.MESSAGE.INVALID_FORMAT;
368
+ }
369
+
191
370
  return this.handleError(error, {
192
371
  action: 'message',
372
+ errorCode: errorCode,
193
373
  messageType: messageType,
194
374
  details: `${messageType} Nachricht Fehler`
195
375
  });
196
376
  }
197
377
 
198
378
  /**
199
- * Get error statistics
379
+ * Get error statistics with error code breakdown
200
380
  */
201
381
  getErrorStats() {
382
+ const errorsByCode = {};
383
+ this.errorStats.forEach((stats, code) => {
384
+ errorsByCode[code] = {
385
+ count: stats.count,
386
+ description: getErrorDescription(code),
387
+ category: getErrorCategory(code),
388
+ firstSeen: stats.firstSeen,
389
+ lastSeen: stats.lastSeen
390
+ };
391
+ });
392
+
202
393
  return {
203
394
  totalErrors: this.errorCount,
204
395
  lastError: this.lastError,
396
+ errorsByCode: errorsByCode,
397
+ mostCommonError: this.getMostCommonError(),
205
398
  supportContacts: {
206
399
  email: this.options.supportEmail,
207
400
  discord: this.options.supportDiscord,
@@ -210,6 +403,27 @@ export class ErrorHandler {
210
403
  };
211
404
  }
212
405
 
406
+ /**
407
+ * Get most common error code
408
+ */
409
+ getMostCommonError() {
410
+ let maxCount = 0;
411
+ let mostCommon = null;
412
+
413
+ this.errorStats.forEach((stats, code) => {
414
+ if (stats.count > maxCount) {
415
+ maxCount = stats.count;
416
+ mostCommon = {
417
+ code: code,
418
+ count: stats.count,
419
+ description: getErrorDescription(code)
420
+ };
421
+ }
422
+ });
423
+
424
+ return mostCommon;
425
+ }
426
+
213
427
  /**
214
428
  * Reset error count
215
429
  */
package/src/message.js CHANGED
@@ -569,6 +569,88 @@ export class Message {
569
569
  });
570
570
  }
571
571
 
572
+ async deleteFromReply() {
573
+ // Prüfe ob die Message eine Reply ist
574
+ const contextInfo = this.raw.message?.extendedTextMessage?.contextInfo;
575
+ const quotedMessage = contextInfo?.quotedMessage;
576
+ const quotedKey = contextInfo?.stanzaId;
577
+ const quotedParticipant = contextInfo?.participant;
578
+
579
+ if (!quotedMessage || !quotedKey) {
580
+ console.log('❌ Keine Reply-Message gefunden zum Löschen');
581
+ return { success: false, reason: 'no_reply' };
582
+ }
583
+
584
+ try {
585
+ // Bot JID ermitteln
586
+ const botJid = this.client.socket.user?.id;
587
+ const botNumber = botJid?.split('@')[0]?.split(':')[0];
588
+ const quotedNumber = quotedParticipant?.split('@')[0]?.split(':')[0];
589
+
590
+ // Prüfe ob Message vom Bot ist
591
+ const isFromBot = botNumber === quotedNumber;
592
+
593
+ console.log('🔍 Debug Info:');
594
+ console.log(' Bot Number:', botNumber);
595
+ console.log(' Quoted Number:', quotedNumber);
596
+ console.log(' Is Group:', this.isGroup);
597
+ console.log(' Is from Bot:', isFromBot);
598
+
599
+ // Erstelle den Key für die quoted Message
600
+ const messageKey = {
601
+ remoteJid: this.from,
602
+ id: quotedKey,
603
+ fromMe: isFromBot // true wenn vom Bot, false wenn von anderem User
604
+ };
605
+
606
+ // In Gruppen: participant hinzufügen
607
+ if (this.isGroup && quotedParticipant) {
608
+ messageKey.participant = quotedParticipant;
609
+ }
610
+
611
+ console.log('🗑️ Versuche Message zu löschen:', JSON.stringify(messageKey, null, 2));
612
+
613
+ // Lösche die quoted Message
614
+ const result = await this.client.socket.sendMessage(this.from, {
615
+ delete: messageKey
616
+ });
617
+
618
+ console.log('✅ Lösch-Request gesendet:', result);
619
+ return {
620
+ success: true,
621
+ messageId: quotedKey,
622
+ wasFromBot: isFromBot,
623
+ result: result
624
+ };
625
+
626
+ } catch (error) {
627
+ console.error('❌ Fehler beim Löschen:', error.message);
628
+
629
+ // Spezifische Fehlerbehandlung
630
+ if (error.message?.includes('not-found') || error.message?.includes('404')) {
631
+ return {
632
+ success: false,
633
+ reason: 'message_not_found',
634
+ error: 'Message zu alt oder bereits gelöscht'
635
+ };
636
+ }
637
+
638
+ if (error.message?.includes('forbidden') || error.message?.includes('403')) {
639
+ return {
640
+ success: false,
641
+ reason: 'no_permission',
642
+ error: 'WhatsApp erlaubt nur das Löschen eigener Messages!'
643
+ };
644
+ }
645
+
646
+ return {
647
+ success: false,
648
+ reason: 'unknown_error',
649
+ error: error.message
650
+ };
651
+ }
652
+ }
653
+
572
654
  // ===== MENTION HELPERS =====
573
655
 
574
656
  getMentions() {