waengine 1.0.5 → 1.0.7

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 CHANGED
@@ -496,20 +496,52 @@ const messageTypes = await msg.stats.getMessagesByType()
496
496
 
497
497
  ### **Prefix Setup**
498
498
  ```javascript
499
- // Set prefix
499
+ // Global Prefix (Fallback)
500
500
  const prefix = "!"
501
501
  client.setPrefix(prefix)
502
502
 
503
- // Register commands
503
+ // Chat-spezifische Prefixes (NEU in v1.0.7!)
504
+ client.setChatPrefix(chatId, "#") // Für spezifischen Chat
505
+ client.getChatPrefix(chatId) // Prefix abrufen
506
+ client.removeChatPrefix(chatId) // Prefix entfernen
507
+
508
+ // Commands registrieren
504
509
  client.addCommand('help', async (msg, args) => {
505
510
  await msg.reply('Help text')
506
511
  })
512
+ ```
507
513
 
508
- client.addCommand('ping', async (msg, args) => {
509
- await msg.reply('Pong! 🏓')
510
- })
514
+ ### **Chat-spezifische Prefixes (v1.0.7)**
515
+ Jeder Chat/Gruppe kann einen eigenen Prefix haben:
516
+
517
+ ```javascript
518
+ // Setprefix Command (Admin only)
519
+ client.addCommand('setprefix', async (msg, args) => {
520
+ if (msg.isGroup && !(await msg.isAdmin())) {
521
+ return msg.reply('❌ Nur Admins können den Prefix ändern!');
522
+ }
523
+
524
+ const newPrefix = args[0];
525
+ client.setChatPrefix(msg.from, newPrefix);
526
+ await msg.reply(`✅ Prefix geändert zu: "${newPrefix}"`);
527
+ });
528
+
529
+ // Prefix Info Command
530
+ client.addCommand('prefixinfo', async (msg) => {
531
+ const chatPrefix = client.getChatPrefix(msg.from);
532
+ const stats = client.getPrefixStats();
533
+
534
+ await msg.reply(`🎯 Aktueller Prefix: "${chatPrefix}"\n📊 Gesamt Chats: ${stats.totalChats}`);
535
+ });
511
536
  ```
512
537
 
538
+ **Features:**
539
+ - ✅ **Persistent Storage** - Prefixes werden automatisch gespeichert
540
+ - ✅ **Admin-only** - Nur Admins können Prefixes in Gruppen ändern
541
+ - ✅ **Validierung** - Max 5 Zeichen, keine Leerzeichen
542
+ - ✅ **Statistics** - Übersicht über alle verwendeten Prefixes
543
+ - ✅ **Fallback** - Global Prefix als Standard
544
+
513
545
  ### **Command Properties**
514
546
  ```javascript
515
547
  // In message events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waengine",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "🚀 WAEngine - The most powerful WhatsApp Bot Library with Multi-Device Support & EasyBot API",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -24,6 +24,9 @@
24
24
  "messaging",
25
25
  "multi-account",
26
26
  "load-balancing",
27
+ "prefix-system",
28
+ "chat-specific",
29
+ "group-management",
27
30
  "typescript",
28
31
  "javascript",
29
32
  "nodejs"
package/src/client.js CHANGED
@@ -2,6 +2,8 @@ import { makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaile
2
2
  import pino from "pino";
3
3
  import { generateQRCode, closeBrowser } from "./qr.js";
4
4
  import { Message } from "./message.js";
5
+ import { SessionManager } from "./session-manager.js";
6
+ import { PrefixManager } from "./prefix-manager.js";
5
7
 
6
8
  export class WhatsAppClient {
7
9
  constructor(options = {}) {
@@ -10,6 +12,7 @@ export class WhatsAppClient {
10
12
  printQR: false,
11
13
  browser: options.browser || ["Chrome", "121.0.0", ""], // Aktueller Chrome
12
14
  logLevel: options.logLevel || "silent", // Sauber ohne Debug
15
+ autoCleanup: options.autoCleanup !== false, // Auto-Cleanup bei Logout
13
16
  ...options
14
17
  };
15
18
 
@@ -19,8 +22,12 @@ export class WhatsAppClient {
19
22
  this.isConnected = false;
20
23
  this.eventHandlers = new Map();
21
24
 
22
- // Prefix System
23
- this.prefix = null;
25
+ // Session Manager
26
+ this.sessionManager = new SessionManager(this.options.authDir);
27
+
28
+ // Prefix System (erweitert für gruppen-spezifische Prefixes)
29
+ this.prefix = null; // Global fallback
30
+ this.prefixManager = new PrefixManager('./data');
24
31
  this.commands = new Map();
25
32
 
26
33
  // Deine eigenen API-Objekte
@@ -34,10 +41,27 @@ export class WhatsAppClient {
34
41
  // ===== CONNECTION METHODS =====
35
42
 
36
43
  async connect() {
44
+ console.log("🔌 WAEngine startet...");
45
+
37
46
  if (this.socket && this.isConnected) {
38
47
  return this.socket;
39
48
  }
40
49
 
50
+ // Session-Validierung und Auto-Repair
51
+ await this.sessionManager.ensureAuthDir();
52
+ const sessionValidation = await this.sessionManager.validateSession();
53
+
54
+ if (!sessionValidation.valid) {
55
+ console.log(`📋 Session-Status: ${sessionValidation.reason}`);
56
+
57
+ if (sessionValidation.reason === 'corrupted') {
58
+ console.log("🔧 Repariere korrupte Session...");
59
+ await this.sessionManager.repairSession();
60
+ }
61
+ } else {
62
+ console.log(`✅ Gültige Session gefunden (User: ${sessionValidation.userId})`);
63
+ }
64
+
41
65
  const { state, saveCreds } = await useMultiFileAuthState(this.options.authDir);
42
66
  const isLoggedIn = !!state.creds?.me?.id;
43
67
 
@@ -129,9 +153,18 @@ export class WhatsAppClient {
129
153
  this.socket = null;
130
154
  setTimeout(() => this.connect().then(resolve).catch(reject), 3000);
131
155
  } else {
132
- console.log("👋 Ausgeloggt");
156
+ console.log("👋 Ausgeloggt - bereinige Session...");
157
+ this.isConnected = false;
158
+ this.socket = null;
159
+
160
+ // Auto-Cleanup bei Logout
161
+ if (this.options.autoCleanup) {
162
+ await this.sessionManager.cleanupSession();
163
+ console.log("🧹 Session automatisch bereinigt");
164
+ }
165
+
133
166
  await closeBrowser();
134
- this.emit('disconnected', { reason: 'logged_out' });
167
+ this.emit('disconnected', { reason: 'logged_out', cleaned: this.options.autoCleanup });
135
168
  reject(new Error('Logged out'));
136
169
  }
137
170
  } else if (connection === "open") {
@@ -164,6 +197,50 @@ export class WhatsAppClient {
164
197
  }
165
198
  }
166
199
 
200
+ // ===== SESSION MANAGEMENT =====
201
+
202
+ async getSessionStatus() {
203
+ return await this.sessionManager.getSessionStatus();
204
+ }
205
+
206
+ async validateSession() {
207
+ return await this.sessionManager.validateSession();
208
+ }
209
+
210
+ async cleanupSession() {
211
+ console.log("🧹 Manuelle Session-Bereinigung...");
212
+ const success = await this.sessionManager.cleanupSession();
213
+ if (success) {
214
+ console.log("✅ Session erfolgreich bereinigt");
215
+ }
216
+ return success;
217
+ }
218
+
219
+ async repairSession() {
220
+ console.log("🔧 Session-Reparatur...");
221
+ return await this.sessionManager.repairSession();
222
+ }
223
+
224
+ async backupSession() {
225
+ return await this.sessionManager.backupSession();
226
+ }
227
+
228
+ // Logout mit automatischer Bereinigung
229
+ async logout() {
230
+ if (this.socket) {
231
+ console.log("👋 Logout wird durchgeführt...");
232
+ this.socket.logout();
233
+
234
+ // Warte kurz und bereinige dann
235
+ setTimeout(async () => {
236
+ if (this.options.autoCleanup) {
237
+ await this.sessionManager.cleanupSession();
238
+ console.log("🧹 Session nach Logout bereinigt");
239
+ }
240
+ }, 1000);
241
+ }
242
+ }
243
+
167
244
  // ===== EVENT SYSTEM =====
168
245
 
169
246
  on(event, handler) {
@@ -233,28 +310,32 @@ export class WhatsAppClient {
233
310
 
234
311
  const messageObj = new Message(this, messageData);
235
312
 
236
- // Prefix System - Command Check
237
- if (this.prefix && messageData.text && messageData.text.startsWith(this.prefix)) {
238
- const commandText = messageData.text.slice(this.prefix.length).trim();
239
- const [command, ...args] = commandText.split(' ');
240
-
241
- console.log(`⚡ Command: ${this.prefix}${command}`);
242
-
243
- messageObj.isCommand = true;
244
- messageObj.command = command.toLowerCase();
245
- messageObj.args = args;
246
- messageObj.commandText = commandText;
247
-
248
- // Command Event emittieren
249
- this.emit('command', messageObj);
313
+ // Prefix System - Command Check (erweitert für Chat-spezifische Prefixes)
314
+ const chatPrefix = this.prefixManager.getPrefix(messageData.from);
315
+
316
+ if (messageData.text && messageData.text.startsWith(chatPrefix)) {
317
+ const commandData = this.prefixManager.parseCommand(messageData.text, messageData.from);
250
318
 
251
- // Spezifischen Command Handler aufrufen falls vorhanden
252
- if (this.commands.has(command.toLowerCase())) {
253
- const handler = this.commands.get(command.toLowerCase());
254
- try {
255
- handler(messageObj, args);
256
- } catch (error) {
257
- console.error(`❌ Fehler in Command '${command}':`, error);
319
+ if (commandData) {
320
+ console.log(`⚡ Command in ${messageData.from}: ${commandData.prefix}${commandData.command}`);
321
+
322
+ messageObj.isCommand = true;
323
+ messageObj.command = commandData.command;
324
+ messageObj.args = commandData.args;
325
+ messageObj.commandText = commandData.commandText;
326
+ messageObj.prefix = commandData.prefix;
327
+
328
+ // Command Event emittieren
329
+ this.emit('command', messageObj);
330
+
331
+ // Spezifischen Command Handler aufrufen falls vorhanden
332
+ if (this.commands.has(commandData.command)) {
333
+ const handler = this.commands.get(commandData.command);
334
+ try {
335
+ handler(messageObj, commandData.args);
336
+ } catch (error) {
337
+ console.error(`❌ Fehler in Command '${commandData.command}':`, error);
338
+ }
258
339
  }
259
340
  }
260
341
  } else {
@@ -349,15 +430,43 @@ export class WhatsAppClient {
349
430
  };
350
431
  }
351
432
 
352
- // ===== PREFIX SYSTEM =====
433
+ // ===== PREFIX SYSTEM (ERWEITERT) =====
353
434
 
435
+ // Global Prefix (Fallback)
354
436
  setPrefix(prefix) {
355
437
  this.prefix = prefix;
438
+ this.prefixManager.defaultPrefix = prefix;
439
+ console.log(`🌐 Global Prefix gesetzt: "${prefix}"`);
356
440
  return this;
357
441
  }
358
442
 
359
- getPrefix() {
360
- return this.prefix;
443
+ getPrefix(chatId = null) {
444
+ if (chatId) {
445
+ return this.prefixManager.getPrefix(chatId);
446
+ }
447
+ return this.prefix || this.prefixManager.defaultPrefix;
448
+ }
449
+
450
+ // Chat-spezifische Prefixes
451
+ setChatPrefix(chatId, prefix) {
452
+ return this.prefixManager.setPrefix(chatId, prefix);
453
+ }
454
+
455
+ getChatPrefix(chatId) {
456
+ return this.prefixManager.getPrefix(chatId);
457
+ }
458
+
459
+ removeChatPrefix(chatId) {
460
+ return this.prefixManager.removePrefix(chatId);
461
+ }
462
+
463
+ // Prefix Statistics
464
+ getPrefixStats() {
465
+ return this.prefixManager.getStats();
466
+ }
467
+
468
+ getAllPrefixes() {
469
+ return this.prefixManager.getAllPrefixes();
361
470
  }
362
471
 
363
472
  addCommand(command, handler) {
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { WhatsAppClient } from "./client.js";
2
2
  export { MultiWhatsAppClient } from "./multi-client.js";
3
3
  export { DeviceManager } from "./device-manager.js";
4
+ export { PrefixManager } from "./prefix-manager.js";
4
5
  export { EasyBot, createBot, createMultiBot, quickBot, bot, multiBot } from "./easy-bot.js";
5
6
  export { generateQRCode } from "./qr.js";
6
7
  export { Message } from "./message.js";
@@ -0,0 +1,158 @@
1
+ // Prefix Manager für gruppen-spezifische Prefixes
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ export class PrefixManager {
6
+ constructor(dataDir = './data') {
7
+ this.dataDir = dataDir;
8
+ this.prefixFile = path.join(dataDir, 'prefixes.json');
9
+ this.defaultPrefix = '!';
10
+ this.prefixes = new Map();
11
+
12
+ this.ensureDataDir();
13
+ this.loadPrefixes();
14
+ }
15
+
16
+ // ===== SETUP =====
17
+
18
+ ensureDataDir() {
19
+ if (!fs.existsSync(this.dataDir)) {
20
+ fs.mkdirSync(this.dataDir, { recursive: true });
21
+ console.log(`📁 Prefix Data Directory erstellt: ${this.dataDir}`);
22
+ }
23
+ }
24
+
25
+ // ===== LOAD/SAVE =====
26
+
27
+ loadPrefixes() {
28
+ try {
29
+ if (fs.existsSync(this.prefixFile)) {
30
+ const data = JSON.parse(fs.readFileSync(this.prefixFile, 'utf8'));
31
+ this.prefixes = new Map(Object.entries(data));
32
+ console.log(`📋 ${this.prefixes.size} Prefixes geladen`);
33
+ }
34
+ } catch (error) {
35
+ console.error('❌ Fehler beim Laden der Prefixes:', error);
36
+ this.prefixes = new Map();
37
+ }
38
+ }
39
+
40
+ savePrefixes() {
41
+ try {
42
+ const data = Object.fromEntries(this.prefixes);
43
+ fs.writeFileSync(this.prefixFile, JSON.stringify(data, null, 2));
44
+ console.log(`💾 Prefixes gespeichert (${this.prefixes.size} Einträge)`);
45
+ return true;
46
+ } catch (error) {
47
+ console.error('❌ Fehler beim Speichern der Prefixes:', error);
48
+ return false;
49
+ }
50
+ }
51
+
52
+ // ===== PREFIX MANAGEMENT =====
53
+
54
+ setPrefix(chatId, prefix) {
55
+ if (!chatId) {
56
+ throw new Error('❌ Chat ID ist erforderlich!');
57
+ }
58
+
59
+ if (!prefix || prefix.length === 0) {
60
+ throw new Error('❌ Prefix darf nicht leer sein!');
61
+ }
62
+
63
+ // Validierung: Prefix sollte nicht zu lang sein
64
+ if (prefix.length > 5) {
65
+ throw new Error('❌ Prefix darf maximal 5 Zeichen lang sein!');
66
+ }
67
+
68
+ this.prefixes.set(chatId, prefix);
69
+ this.savePrefixes();
70
+
71
+ console.log(`🎯 Prefix für ${chatId} gesetzt: "${prefix}"`);
72
+ return true;
73
+ }
74
+
75
+ getPrefix(chatId) {
76
+ if (!chatId) return this.defaultPrefix;
77
+
78
+ return this.prefixes.get(chatId) || this.defaultPrefix;
79
+ }
80
+
81
+ removePrefix(chatId) {
82
+ if (!chatId) return false;
83
+
84
+ const removed = this.prefixes.delete(chatId);
85
+ if (removed) {
86
+ this.savePrefixes();
87
+ console.log(`🗑️ Prefix für ${chatId} entfernt`);
88
+ }
89
+ return removed;
90
+ }
91
+
92
+ // ===== UTILITY =====
93
+
94
+ getAllPrefixes() {
95
+ return Object.fromEntries(this.prefixes);
96
+ }
97
+
98
+ getPrefixCount() {
99
+ return this.prefixes.size;
100
+ }
101
+
102
+ // Prüft ob Text mit dem Chat-spezifischen Prefix beginnt
103
+ isCommand(text, chatId) {
104
+ if (!text) return false;
105
+
106
+ const prefix = this.getPrefix(chatId);
107
+ return text.startsWith(prefix);
108
+ }
109
+
110
+ // Extrahiert Command und Args basierend auf Chat-spezifischem Prefix
111
+ parseCommand(text, chatId) {
112
+ if (!this.isCommand(text, chatId)) {
113
+ return null;
114
+ }
115
+
116
+ const prefix = this.getPrefix(chatId);
117
+ const commandText = text.slice(prefix.length).trim();
118
+ const [command, ...args] = commandText.split(' ');
119
+
120
+ return {
121
+ prefix,
122
+ command: command.toLowerCase(),
123
+ args,
124
+ commandText,
125
+ fullText: text
126
+ };
127
+ }
128
+
129
+ // ===== STATISTICS =====
130
+
131
+ getStats() {
132
+ const prefixCounts = {};
133
+
134
+ for (const prefix of this.prefixes.values()) {
135
+ prefixCounts[prefix] = (prefixCounts[prefix] || 0) + 1;
136
+ }
137
+
138
+ return {
139
+ totalChats: this.prefixes.size,
140
+ defaultPrefix: this.defaultPrefix,
141
+ prefixDistribution: prefixCounts,
142
+ mostUsedPrefix: Object.keys(prefixCounts).reduce((a, b) =>
143
+ prefixCounts[a] > prefixCounts[b] ? a : b, this.defaultPrefix)
144
+ };
145
+ }
146
+
147
+ // ===== RESET =====
148
+
149
+ resetAllPrefixes() {
150
+ this.prefixes.clear();
151
+ this.savePrefixes();
152
+ console.log('🔄 Alle Prefixes zurückgesetzt');
153
+ }
154
+
155
+ resetToDefault(chatId) {
156
+ return this.removePrefix(chatId);
157
+ }
158
+ }
@@ -0,0 +1,154 @@
1
+ // Session Manager für WAEngine v1.0.6
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ export class SessionManager {
6
+ constructor(authDir) {
7
+ this.authDir = authDir;
8
+ }
9
+
10
+ // Prüft ob Session existiert und gültig ist
11
+ async validateSession() {
12
+ try {
13
+ if (!fs.existsSync(this.authDir)) {
14
+ return { valid: false, reason: 'no_auth_dir' };
15
+ }
16
+
17
+ const credsPath = path.join(this.authDir, 'creds.json');
18
+ if (!fs.existsSync(credsPath)) {
19
+ return { valid: false, reason: 'no_creds' };
20
+ }
21
+
22
+ const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8'));
23
+
24
+ // Prüfe ob User-ID vorhanden (eingeloggt)
25
+ if (!creds.me?.id) {
26
+ return { valid: false, reason: 'not_logged_in' };
27
+ }
28
+
29
+ // Prüfe ob Session nicht zu alt ist (optional)
30
+ const stats = fs.statSync(credsPath);
31
+ const ageInDays = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24);
32
+
33
+ if (ageInDays > 30) { // Session älter als 30 Tage
34
+ return { valid: false, reason: 'session_too_old' };
35
+ }
36
+
37
+ return {
38
+ valid: true,
39
+ userId: creds.me.id,
40
+ lastModified: stats.mtime,
41
+ ageInDays: Math.round(ageInDays)
42
+ };
43
+
44
+ } catch (error) {
45
+ return { valid: false, reason: 'corrupted', error: error.message };
46
+ }
47
+ }
48
+
49
+ // Bereinigt Session komplett
50
+ async cleanupSession() {
51
+ try {
52
+ if (fs.existsSync(this.authDir)) {
53
+ console.log("🧹 Bereinige Session...");
54
+
55
+ // Alle Auth-Dateien löschen
56
+ const files = fs.readdirSync(this.authDir);
57
+ for (const file of files) {
58
+ const filePath = path.join(this.authDir, file);
59
+ fs.unlinkSync(filePath);
60
+ }
61
+
62
+ // Auth-Ordner löschen
63
+ fs.rmdirSync(this.authDir);
64
+ console.log("✅ Session bereinigt");
65
+ return true;
66
+ }
67
+ return true;
68
+ } catch (error) {
69
+ console.error("❌ Fehler beim Session-Cleanup:", error);
70
+ return false;
71
+ }
72
+ }
73
+
74
+ // Erstellt Auth-Ordner falls nicht vorhanden
75
+ async ensureAuthDir() {
76
+ if (!fs.existsSync(this.authDir)) {
77
+ fs.mkdirSync(this.authDir, { recursive: true });
78
+ console.log(`📁 Auth-Ordner erstellt: ${this.authDir}`);
79
+ }
80
+ }
81
+
82
+ // Backup der Session erstellen
83
+ async backupSession() {
84
+ try {
85
+ if (!fs.existsSync(this.authDir)) return false;
86
+
87
+ const backupDir = `${this.authDir}_backup_${Date.now()}`;
88
+ fs.mkdirSync(backupDir, { recursive: true });
89
+
90
+ const files = fs.readdirSync(this.authDir);
91
+ for (const file of files) {
92
+ const srcPath = path.join(this.authDir, file);
93
+ const destPath = path.join(backupDir, file);
94
+ fs.copyFileSync(srcPath, destPath);
95
+ }
96
+
97
+ console.log(`💾 Session-Backup erstellt: ${backupDir}`);
98
+ return backupDir;
99
+ } catch (error) {
100
+ console.error("❌ Backup-Fehler:", error);
101
+ return false;
102
+ }
103
+ }
104
+
105
+ // Session-Status für Debugging
106
+ getSessionStatus() {
107
+ try {
108
+ if (!fs.existsSync(this.authDir)) {
109
+ return { status: 'no_session', files: [] };
110
+ }
111
+
112
+ const files = fs.readdirSync(this.authDir);
113
+ const fileDetails = files.map(file => {
114
+ const filePath = path.join(this.authDir, file);
115
+ const stats = fs.statSync(filePath);
116
+ return {
117
+ name: file,
118
+ size: stats.size,
119
+ modified: stats.mtime
120
+ };
121
+ });
122
+
123
+ return {
124
+ status: 'session_exists',
125
+ files: fileDetails,
126
+ totalFiles: files.length,
127
+ authDir: this.authDir
128
+ };
129
+ } catch (error) {
130
+ return { status: 'error', error: error.message };
131
+ }
132
+ }
133
+
134
+ // Repariert korrupte Session
135
+ async repairSession() {
136
+ console.log("🔧 Versuche Session-Reparatur...");
137
+
138
+ const validation = await this.validateSession();
139
+
140
+ if (validation.reason === 'corrupted') {
141
+ console.log("🗑️ Korrupte Session erkannt - bereinige...");
142
+ await this.cleanupSession();
143
+ return { repaired: true, action: 'cleanup' };
144
+ }
145
+
146
+ if (validation.reason === 'session_too_old') {
147
+ console.log("⏰ Session zu alt - bereinige...");
148
+ await this.cleanupSession();
149
+ return { repaired: true, action: 'cleanup_old' };
150
+ }
151
+
152
+ return { repaired: false, reason: validation.reason };
153
+ }
154
+ }