fca-neokex-fix 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.
Files changed (114) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/LICENSE +26 -0
  3. package/README.md +346 -0
  4. package/THEME_FEATURES.md +137 -0
  5. package/examples/README.md +131 -0
  6. package/examples/apply-ai-theme.js +127 -0
  7. package/examples/check-current-theme.js +74 -0
  8. package/examples/simple-bot.js +114 -0
  9. package/examples/test-bot.js +752 -0
  10. package/examples/test-logging.js +85 -0
  11. package/examples/theme-usage-example.js +53 -0
  12. package/index.js +2 -0
  13. package/package.json +105 -0
  14. package/src/apis/addExternalModule.js +24 -0
  15. package/src/apis/addUserToGroup.js +108 -0
  16. package/src/apis/changeAdminStatus.js +148 -0
  17. package/src/apis/changeArchivedStatus.js +61 -0
  18. package/src/apis/changeAvatar.js +103 -0
  19. package/src/apis/changeBio.js +69 -0
  20. package/src/apis/changeBlockedStatus.js +54 -0
  21. package/src/apis/changeGroupImage.js +136 -0
  22. package/src/apis/changeThreadColor.js +116 -0
  23. package/src/apis/comment.js +207 -0
  24. package/src/apis/createAITheme.js +129 -0
  25. package/src/apis/createNewGroup.js +79 -0
  26. package/src/apis/createPoll.js +73 -0
  27. package/src/apis/deleteMessage.js +44 -0
  28. package/src/apis/deleteThread.js +52 -0
  29. package/src/apis/editMessage.js +70 -0
  30. package/src/apis/emoji.js +124 -0
  31. package/src/apis/fetchThemeData.js +65 -0
  32. package/src/apis/follow.js +81 -0
  33. package/src/apis/forwardMessage.js +52 -0
  34. package/src/apis/friend.js +243 -0
  35. package/src/apis/gcmember.js +122 -0
  36. package/src/apis/gcname.js +123 -0
  37. package/src/apis/gcrule.js +119 -0
  38. package/src/apis/getAccess.js +111 -0
  39. package/src/apis/getBotInfo.js +88 -0
  40. package/src/apis/getBotInitialData.js +43 -0
  41. package/src/apis/getFriendsList.js +79 -0
  42. package/src/apis/getMessage.js +423 -0
  43. package/src/apis/getTheme.js +104 -0
  44. package/src/apis/getThemeInfo.js +96 -0
  45. package/src/apis/getThreadHistory.js +239 -0
  46. package/src/apis/getThreadInfo.js +257 -0
  47. package/src/apis/getThreadList.js +222 -0
  48. package/src/apis/getThreadPictures.js +58 -0
  49. package/src/apis/getUserID.js +83 -0
  50. package/src/apis/getUserInfo.js +495 -0
  51. package/src/apis/getUserInfoV2.js +146 -0
  52. package/src/apis/handleMessageRequest.js +50 -0
  53. package/src/apis/httpGet.js +63 -0
  54. package/src/apis/httpPost.js +89 -0
  55. package/src/apis/httpPostFormData.js +69 -0
  56. package/src/apis/listenMqtt.js +796 -0
  57. package/src/apis/listenSpeed.js +170 -0
  58. package/src/apis/logout.js +63 -0
  59. package/src/apis/markAsDelivered.js +47 -0
  60. package/src/apis/markAsRead.js +95 -0
  61. package/src/apis/markAsReadAll.js +41 -0
  62. package/src/apis/markAsSeen.js +70 -0
  63. package/src/apis/mqttDeltaValue.js +330 -0
  64. package/src/apis/muteThread.js +45 -0
  65. package/src/apis/nickname.js +132 -0
  66. package/src/apis/notes.js +163 -0
  67. package/src/apis/pinMessage.js +141 -0
  68. package/src/apis/produceMetaTheme.js +180 -0
  69. package/src/apis/realtime.js +161 -0
  70. package/src/apis/removeUserFromGroup.js +117 -0
  71. package/src/apis/resolvePhotoUrl.js +58 -0
  72. package/src/apis/searchForThread.js +154 -0
  73. package/src/apis/sendMessage.js +281 -0
  74. package/src/apis/sendMessageMqtt.js +188 -0
  75. package/src/apis/sendTypingIndicator.js +41 -0
  76. package/src/apis/setMessageReaction.js +27 -0
  77. package/src/apis/setMessageReactionMqtt.js +61 -0
  78. package/src/apis/setThreadTheme.js +260 -0
  79. package/src/apis/setThreadThemeMqtt.js +94 -0
  80. package/src/apis/share.js +107 -0
  81. package/src/apis/shareContact.js +66 -0
  82. package/src/apis/stickers.js +257 -0
  83. package/src/apis/story.js +181 -0
  84. package/src/apis/theme.js +233 -0
  85. package/src/apis/unfriend.js +47 -0
  86. package/src/apis/unsendMessage.js +17 -0
  87. package/src/database/appStateBackup.js +189 -0
  88. package/src/database/models/index.js +56 -0
  89. package/src/database/models/thread.js +31 -0
  90. package/src/database/models/user.js +32 -0
  91. package/src/database/threadData.js +101 -0
  92. package/src/database/userData.js +90 -0
  93. package/src/engine/client.js +91 -0
  94. package/src/engine/models/buildAPI.js +109 -0
  95. package/src/engine/models/loginHelper.js +326 -0
  96. package/src/engine/models/setOptions.js +53 -0
  97. package/src/utils/auth-helpers.js +149 -0
  98. package/src/utils/autoReLogin.js +169 -0
  99. package/src/utils/axios.js +290 -0
  100. package/src/utils/clients.js +270 -0
  101. package/src/utils/constants.js +396 -0
  102. package/src/utils/formatters/data/formatAttachment.js +370 -0
  103. package/src/utils/formatters/data/formatDelta.js +153 -0
  104. package/src/utils/formatters/index.js +159 -0
  105. package/src/utils/formatters/value/formatCookie.js +91 -0
  106. package/src/utils/formatters/value/formatDate.js +36 -0
  107. package/src/utils/formatters/value/formatID.js +16 -0
  108. package/src/utils/formatters.js +1067 -0
  109. package/src/utils/headers.js +199 -0
  110. package/src/utils/index.js +151 -0
  111. package/src/utils/monitoring.js +358 -0
  112. package/src/utils/rateLimiter.js +380 -0
  113. package/src/utils/tokenRefresh.js +311 -0
  114. package/src/utils/user-agents.js +238 -0
@@ -0,0 +1,752 @@
1
+ const { login } = require('../index');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const APPSTATE_PATH = path.join(__dirname, '../test/appstate.json');
6
+ const appState = JSON.parse(fs.readFileSync(APPSTATE_PATH, 'utf8'));
7
+
8
+ const PREFIX = '/';
9
+ const ADMIN_ID = null; // Set to your user ID to restrict some commands
10
+
11
+ console.log('🤖 NeoKEX-FCA Test Bot Starting...\n');
12
+
13
+ login({ appState }, (err, api) => {
14
+ if (err) {
15
+ console.error('❌ Login failed:', err);
16
+ return;
17
+ }
18
+
19
+ console.log('✅ Login successful!');
20
+ const botID = api.getCurrentUserID();
21
+ console.log(`🤖 Bot ID: ${botID}\n`);
22
+
23
+ api.listenMqtt((err, event) => {
24
+ if (err) {
25
+ console.error('MQTT Error:', err);
26
+ return;
27
+ }
28
+
29
+ if (event.type === 'message' && event.body) {
30
+ const { threadID, messageID, senderID, body, isGroup } = event;
31
+
32
+ if (senderID === botID) return;
33
+
34
+ if (!body.startsWith(PREFIX)) return;
35
+
36
+ const args = body.slice(PREFIX.length).trim().split(/\s+/);
37
+ const command = args.shift().toLowerCase();
38
+
39
+ console.log(`📨 Command: ${command} from ${senderID} in ${threadID}`);
40
+
41
+ handleCommand(api, command, args, event);
42
+ }
43
+ });
44
+
45
+ console.log('🎧 Bot is listening for commands...');
46
+ console.log(`📝 Use prefix: ${PREFIX}`);
47
+ console.log('💡 Example: /help\n');
48
+ });
49
+
50
+ async function handleCommand(api, command, args, event) {
51
+ const { threadID, messageID, senderID, isGroup } = event;
52
+ try {
53
+ switch (command) {
54
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
55
+ // 📌 BASIC COMMANDS
56
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
57
+ case 'help':
58
+ case 'commands':
59
+ await api.sendMessage(`🤖 NeoKEX-FCA Test Bot Commands
60
+
61
+ 📌 BASIC
62
+ ${PREFIX}help - Show this menu
63
+ ${PREFIX}ping - Test response time
64
+ ${PREFIX}about - Bot information
65
+
66
+ 👤 USER INFO
67
+ ${PREFIX}me - Your user info
68
+ ${PREFIX}userid <name> - Get user ID by name
69
+ ${PREFIX}friends - List your friends
70
+ ${PREFIX}userv2 <userID> - Get detailed user info (v2)
71
+ ${PREFIX}bio <text> - Change your bio
72
+
73
+ 💬 THREAD COMMANDS
74
+ ${PREFIX}info - Thread information
75
+ ${PREFIX}history [limit] - Get message history
76
+ ${PREFIX}members - List thread members
77
+ ${PREFIX}photo - Thread photo URL
78
+ ${PREFIX}threads - List your threads
79
+ ${PREFIX}themeinfo - Get current theme info
80
+ ${PREFIX}mute - Toggle mute for this thread
81
+ ${PREFIX}archive - Toggle archive status
82
+ ${PREFIX}deletethis - Delete this thread
83
+
84
+ 🎨 THEMES
85
+ ${PREFIX}themes - List all available themes
86
+ ${PREFIX}theme <name> - Change thread theme
87
+ ${PREFIX}color <hex> - Change thread color
88
+ ${PREFIX}changetheme <prompt> - Generate & apply AI theme
89
+
90
+ ✏️ THREAD SETTINGS
91
+ ${PREFIX}name <name> - Change thread name
92
+ ${PREFIX}emoji <emoji> - Change thread emoji
93
+ ${PREFIX}nickname <@mention> <nickname> - Set nickname
94
+
95
+ 📎 MESSAGING
96
+ ${PREFIX}typing - Send typing indicator
97
+ ${PREFIX}react <emoji> - React to this message
98
+ ${PREFIX}unsend - Unsend this message
99
+ ${PREFIX}edit <text> - Edit this message
100
+ ${PREFIX}forward <threadID> - Forward this message
101
+ ${PREFIX}poll <question> | <option1> | <option2> - Create poll
102
+ ${PREFIX}pin - Pin this message
103
+ ${PREFIX}unpin - Unpin this message
104
+ ${PREFIX}markread - Mark thread as read
105
+ ${PREFIX}markreadall - Mark all threads as read
106
+
107
+ 👥 GROUP MANAGEMENT
108
+ ${PREFIX}creategroup <name> | <userID1> | <userID2> - Create group
109
+ ${PREFIX}adduser <userID> - Add user to group
110
+ ${PREFIX}removeuser <userID> - Remove user from group
111
+ ${PREFIX}groupimage - Info about changing group image
112
+
113
+ 🔗 SOCIAL
114
+ ${PREFIX}block <userID> - Block a user
115
+ ${PREFIX}unblock <userID> - Unblock a user
116
+ ${PREFIX}addfriend <userID> - Add friend
117
+ ${PREFIX}removefriend <userID> - Remove friend
118
+ ${PREFIX}follow <userID> - Follow user
119
+ ${PREFIX}unfollow <userID> - Unfollow user
120
+ ${PREFIX}sharecontact <userID> - Share contact
121
+
122
+ 🔍 SEARCH
123
+ ${PREFIX}searchthread <query> - Search threads
124
+
125
+ 📊 STATS & ADMIN
126
+ ${PREFIX}status - Bot status
127
+ ${PREFIX}test - Run quick API test
128
+ ${PREFIX}logout - Logout bot`, threadID);
129
+ break;
130
+
131
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132
+ // 📌 BASIC COMMANDS
133
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
134
+ case 'ping':
135
+ const start = Date.now();
136
+ await api.sendMessage('🏓 Pong!', threadID, () => {
137
+ const latency = Date.now() - start;
138
+ api.sendMessage(`⏱️ Response time: ${latency}ms`, threadID);
139
+ });
140
+ break;
141
+
142
+ case 'about':
143
+ await api.sendMessage(`🤖 NeoKEX-FCA Test Bot
144
+
145
+ 📦 Library: NeoKEX-FCA v4.4.4
146
+ ✅ Success Rate: 98.2%
147
+ 🔒 Security: 0 vulnerabilities
148
+ 🎯 Tested APIs: 77 functions
149
+
150
+ Built to test and demonstrate the comprehensive API capabilities of NeoKEX-FCA.`, threadID);
151
+ break;
152
+
153
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
154
+ // 👤 USER INFO COMMANDS
155
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
156
+ case 'me':
157
+ const myInfo = await api.getUserInfo(senderID);
158
+ const user = myInfo[senderID];
159
+ await api.sendMessage(`👤 Your Information
160
+
161
+ Name: ${user.name}
162
+ ID: ${senderID}
163
+ Username: ${user.vanity || 'None'}
164
+ Profile: https://facebook.com/${senderID}`, threadID);
165
+ break;
166
+
167
+ case 'friends':
168
+ const friends = await api.getFriendsList();
169
+ const friendsList = friends.slice(0, 10).map((f, i) => `${i + 1}. ${f.fullName}`).join('\n');
170
+ await api.sendMessage(`👥 Your Friends (showing first 10/${friends.length})
171
+
172
+ ${friendsList}
173
+
174
+ Total: ${friends.length} friends`, threadID);
175
+ break;
176
+
177
+ case 'userid':
178
+ if (args.length === 0) {
179
+ await api.sendMessage(`❌ Usage: ${PREFIX}userid <name>`, threadID);
180
+ break;
181
+ }
182
+ const name = args.join(' ');
183
+ const uid = await api.getUserID(name);
184
+ await api.sendMessage(`🔍 User ID for "${name}": ${uid}`, threadID);
185
+ break;
186
+
187
+ case 'userv2':
188
+ if (args.length === 0) {
189
+ await api.sendMessage(`❌ Usage: ${PREFIX}userv2 <userID>`, threadID);
190
+ break;
191
+ }
192
+ const targetUserID = args[0];
193
+ const userInfoV2 = await api.getUserInfoV2(targetUserID);
194
+ const v2User = userInfoV2[targetUserID];
195
+ if (v2User) {
196
+ await api.sendMessage(`👤 Detailed User Info (v2)
197
+
198
+ Name: ${v2User.name || 'Unknown'}
199
+ ID: ${targetUserID}
200
+ Username: ${v2User.vanity || 'None'}
201
+ Gender: ${v2User.gender || 'Unknown'}
202
+ Is Friend: ${v2User.isFriend ? 'Yes' : 'No'}
203
+ Profile: https://facebook.com/${targetUserID}`, threadID);
204
+ } else {
205
+ await api.sendMessage(`❌ Could not fetch user info for ${targetUserID}`, threadID);
206
+ }
207
+ break;
208
+
209
+ case 'bio':
210
+ if (args.length === 0) {
211
+ await api.sendMessage(`❌ Usage: ${PREFIX}bio <text>`, threadID);
212
+ break;
213
+ }
214
+ const bioText = args.join(' ');
215
+ await api.changeBio(bioText);
216
+ await api.sendMessage(`✅ Bio changed to: ${bioText}`, threadID);
217
+ break;
218
+
219
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
220
+ // 💬 THREAD COMMANDS
221
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
222
+ case 'info':
223
+ const threadInfo = await api.getThreadInfo(threadID);
224
+ await api.sendMessage(`💬 Thread Information
225
+
226
+ Name: ${threadInfo.threadName || 'Unnamed'}
227
+ ID: ${threadID}
228
+ Type: ${isGroup ? 'Group' : 'Direct Message'}
229
+ Members: ${threadInfo.participantIDs?.length || 0}
230
+ Messages: ${threadInfo.messageCount || 'Unknown'}
231
+ Emoji: ${threadInfo.emoji || '👍'}`, threadID);
232
+ break;
233
+
234
+ case 'history':
235
+ const limit = parseInt(args[0]) || 5;
236
+ const history = await api.getThreadHistory(threadID, limit);
237
+ const messages = history.map((msg, i) =>
238
+ `${i + 1}. ${msg.senderName}: ${msg.body?.substring(0, 50) || '[Attachment]'}`
239
+ ).join('\n');
240
+ await api.sendMessage(`📜 Recent Messages (${limit}):
241
+
242
+ ${messages}`, threadID);
243
+ break;
244
+
245
+ case 'members':
246
+ const info = await api.getThreadInfo(threadID);
247
+ const memberInfo = await api.getUserInfo(info.participantIDs);
248
+ const memberList = Object.values(memberInfo).map((m, i) =>
249
+ `${i + 1}. ${m.name}`
250
+ ).join('\n');
251
+ await api.sendMessage(`👥 Thread Members:
252
+
253
+ ${memberList}
254
+
255
+ Total: ${info.participantIDs.length} members`, threadID);
256
+ break;
257
+
258
+ case 'photo':
259
+ const photos = await api.getThreadPictures(threadID, 0, 1);
260
+ if (photos.length > 0) {
261
+ await api.sendMessage(`📸 Thread Photo: ${photos[0].uri}`, threadID);
262
+ } else {
263
+ await api.sendMessage(`❌ No thread photo available`, threadID);
264
+ }
265
+ break;
266
+
267
+ case 'threads':
268
+ const threadList = await api.getThreadList(20, null);
269
+ const threadListFormatted = threadList.slice(0, 10).map((t, i) =>
270
+ `${i + 1}. ${t.name || 'Unnamed'} (${t.threadID})`
271
+ ).join('\n');
272
+ await api.sendMessage(`📋 Your Threads (showing 10/${threadList.length}):
273
+
274
+ ${threadListFormatted}`, threadID);
275
+ break;
276
+
277
+ case 'themeinfo':
278
+ const currentThemeInfo = await api.getThemeInfo(threadID);
279
+ await api.sendMessage(`🎨 Current Theme Info
280
+
281
+ Thread: ${currentThemeInfo.threadName || 'Unnamed'}
282
+ Color: ${currentThemeInfo.color || 'Default'}
283
+ Emoji: ${currentThemeInfo.emoji || '👍'}
284
+ Theme ID: ${currentThemeInfo.theme_id || 'Default'}`, threadID);
285
+ break;
286
+
287
+ case 'mute':
288
+ const currentInfo = await api.getThreadInfo(threadID);
289
+ const isMuted = currentInfo.muteUntil > Date.now();
290
+ await api.muteThread(threadID, isMuted ? -1 : 9999999999);
291
+ await api.sendMessage(`🔇 Thread ${isMuted ? 'unmuted' : 'muted'}`, threadID);
292
+ break;
293
+
294
+ case 'archive':
295
+ const archiveThreadInfo = await api.getThreadInfo(threadID);
296
+ const isArchived = archiveThreadInfo.isArchived;
297
+ await api.changeArchivedStatus(threadID, !isArchived);
298
+ await api.sendMessage(`📦 Thread ${isArchived ? 'unarchived' : 'archived'}`, threadID);
299
+ break;
300
+
301
+ case 'deletethis':
302
+ await api.sendMessage(`⚠️ Deleting this thread in 3 seconds...`, threadID);
303
+ setTimeout(async () => {
304
+ await api.deleteThread(threadID);
305
+ }, 3000);
306
+ break;
307
+
308
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
309
+ // 🎨 THEME COMMANDS
310
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
311
+ case 'themes':
312
+ const allThemes = await api.getTheme(threadID);
313
+ const themeList = allThemes.slice(0, 15).map((t, i) =>
314
+ `${i + 1}. ${t.name} (ID: ${t.id})`
315
+ ).join('\n');
316
+ await api.sendMessage(`🎨 Available Themes (showing 15/${allThemes.length}):
317
+
318
+ ${themeList}
319
+
320
+ Use ${PREFIX}theme <name> to apply`, threadID);
321
+ break;
322
+
323
+ case 'theme':
324
+ if (args.length === 0) {
325
+ await api.sendMessage(`❌ Usage: ${PREFIX}theme <name or ID>`, threadID);
326
+ break;
327
+ }
328
+ const themeName = args.join(' ');
329
+ const themesList = await api.getTheme(threadID);
330
+ const selectedTheme = themesList.find(t =>
331
+ t.name.toLowerCase().includes(themeName.toLowerCase()) ||
332
+ t.id === themeName
333
+ );
334
+ if (selectedTheme) {
335
+ await api.sendMessage(`🎨 Applying theme: ${selectedTheme.name}...`, threadID);
336
+ await api.setThreadThemeMqtt(threadID, selectedTheme.id);
337
+ await api.sendMessage(`✅ Theme changed to: ${selectedTheme.name}`, threadID);
338
+ } else {
339
+ await api.sendMessage(`❌ Theme not found. Use ${PREFIX}themes to see available themes`, threadID);
340
+ }
341
+ break;
342
+
343
+ case 'color':
344
+ if (args.length === 0) {
345
+ await api.sendMessage(`❌ Usage: ${PREFIX}color <hex color>
346
+ Example: ${PREFIX}color #0084ff`, threadID);
347
+ break;
348
+ }
349
+ const color = args[0];
350
+ await api.changeThreadColor(color, threadID);
351
+ await api.sendMessage(`🎨 Thread color changed to: ${color}`, threadID);
352
+ break;
353
+
354
+ case 'aitheme':
355
+ case 'changetheme':
356
+ if (args.length === 0) {
357
+ await api.sendMessage(`❌ Usage: ${PREFIX}changetheme <AI prompt>
358
+ Example: ${PREFIX}changetheme ocean sunset vibes
359
+ Example: ${PREFIX}changetheme purple pink galaxy stars`, threadID);
360
+ break;
361
+ }
362
+ const aiPrompt = args.join(' ');
363
+ await api.sendMessage(`🎨 Generating AI theme: "${aiPrompt}"...`, threadID);
364
+
365
+ try {
366
+ // Step 1: Generate AI theme
367
+ const aiThemes = await api.createAITheme(aiPrompt);
368
+
369
+ if (!aiThemes || aiThemes.length === 0) {
370
+ await api.sendMessage(`❌ No themes generated. AI theme feature may not be available for your account.
371
+ Try using ${PREFIX}themes to see standard themes.`, threadID);
372
+ break;
373
+ }
374
+
375
+ const generatedTheme = aiThemes[0];
376
+ await api.sendMessage(`✅ Theme generated!
377
+ Name: ${generatedTheme.accessibility_label || aiPrompt}
378
+ ID: ${generatedTheme.id}
379
+
380
+ Applying theme...`, threadID);
381
+
382
+ // Step 2: Apply the theme using MQTT
383
+ await new Promise(resolve => setTimeout(resolve, 1000));
384
+
385
+ try {
386
+ await api.setThreadThemeMqtt(threadID, generatedTheme.id);
387
+ await api.sendMessage(`🎉 AI theme applied successfully!`, threadID);
388
+ } catch (applyError) {
389
+ console.error('❌ Theme Application Error:', applyError.message);
390
+ await api.sendMessage(`⚠️ Theme generated but failed to apply: ${applyError.message}
391
+
392
+ You can try applying it manually using theme ID: ${generatedTheme.id}`, threadID);
393
+ }
394
+
395
+ } catch (error) {
396
+ console.error('❌ AI Theme Generation Error:', error.message || error);
397
+ await api.sendMessage(`❌ Error generating AI theme: ${error.message || 'Unknown error'}
398
+
399
+ This feature may not be available for your account.
400
+ Try using ${PREFIX}themes for standard themes instead.`, threadID);
401
+ }
402
+ break;
403
+
404
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
405
+ // ✏️ THREAD SETTINGS
406
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
407
+ case 'name':
408
+ if (args.length === 0) {
409
+ await api.sendMessage(`❌ Usage: ${PREFIX}name <new name>`, threadID);
410
+ break;
411
+ }
412
+ const newName = args.join(' ');
413
+ await api.setThreadName(newName, threadID);
414
+ await api.sendMessage(`✅ Thread name changed to: ${newName}`, threadID);
415
+ break;
416
+
417
+ case 'emoji':
418
+ if (args.length === 0) {
419
+ await api.sendMessage(`❌ Usage: ${PREFIX}emoji <emoji>
420
+ Example: ${PREFIX}emoji 🔥`, threadID);
421
+ break;
422
+ }
423
+ await api.changeThreadEmoji(args[0], threadID);
424
+ await api.sendMessage(`✅ Thread emoji changed to: ${args[0]}`, threadID);
425
+ break;
426
+
427
+ case 'nickname':
428
+ const mentions = event.mentions;
429
+ if (!mentions || mentions.length === 0 || args.length < 2) {
430
+ await api.sendMessage(`❌ Usage: ${PREFIX}nickname @mention <nickname>`, threadID);
431
+ break;
432
+ }
433
+ const targetID = Object.keys(mentions)[0];
434
+ const nickname = args.slice(1).join(' ');
435
+ await api.changeNickname(nickname, threadID, targetID);
436
+ await api.sendMessage(`✅ Nickname changed to: ${nickname}`, threadID);
437
+ break;
438
+
439
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
440
+ // 📎 MESSAGING COMMANDS
441
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
442
+ case 'typing':
443
+ await api.sendTypingIndicator(threadID);
444
+ await api.sendMessage('✅ Typing indicator sent!', threadID);
445
+ break;
446
+
447
+ case 'react':
448
+ if (args.length === 0) {
449
+ await api.sendMessage(`❌ Usage: ${PREFIX}react <emoji>`, threadID);
450
+ break;
451
+ }
452
+ await api.setMessageReaction(args[0], messageID);
453
+ break;
454
+
455
+ case 'unsend':
456
+ await api.unsendMessage(messageID);
457
+ break;
458
+
459
+ case 'poll':
460
+ const pollData = args.join(' ').split('|').map(s => s.trim());
461
+ if (pollData.length < 3) {
462
+ await api.sendMessage(`❌ Usage: ${PREFIX}poll <question> | <option1> | <option2>
463
+ Example: ${PREFIX}poll Pizza or Burger? | Pizza | Burger`, threadID);
464
+ break;
465
+ }
466
+ const [question, ...options] = pollData;
467
+ await api.createPoll(question, threadID, { options });
468
+ break;
469
+
470
+ case 'edit':
471
+ if (args.length === 0) {
472
+ await api.sendMessage(`❌ Usage: ${PREFIX}edit <new text>`, threadID);
473
+ break;
474
+ }
475
+ const newText = args.join(' ');
476
+ await api.editMessage(newText, messageID);
477
+ await api.sendMessage(`✅ Message edited to: "${newText}"`, threadID);
478
+ break;
479
+
480
+ case 'forward':
481
+ if (args.length === 0) {
482
+ await api.sendMessage(`❌ Usage: ${PREFIX}forward <threadID>`, threadID);
483
+ break;
484
+ }
485
+ const targetThreadID = args[0];
486
+ await api.forwardMessage(messageID, targetThreadID);
487
+ await api.sendMessage(`✅ Message forwarded to thread ${targetThreadID}`, threadID);
488
+ break;
489
+
490
+ case 'pin':
491
+ await api.pin('pin', threadID, messageID);
492
+ await api.sendMessage(`📌 Message pinned!`, threadID);
493
+ break;
494
+
495
+ case 'unpin':
496
+ await api.pin('unpin', threadID, messageID);
497
+ await api.sendMessage(`📌 Message unpinned!`, threadID);
498
+ break;
499
+
500
+ case 'markread':
501
+ await api.markAsRead(threadID, true);
502
+ await api.sendMessage(`✅ Thread marked as read`, threadID);
503
+ break;
504
+
505
+ case 'markreadall':
506
+ await api.markAsReadAll();
507
+ await api.sendMessage(`✅ All threads marked as read`, threadID);
508
+ break;
509
+
510
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
511
+ // 👥 GROUP MANAGEMENT COMMANDS
512
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
513
+ case 'creategroup':
514
+ const groupData = args.join(' ').split('|').map(s => s.trim());
515
+ if (groupData.length < 2) {
516
+ await api.sendMessage(`❌ Usage: ${PREFIX}creategroup <name> | <userID1> | <userID2>
517
+ Example: ${PREFIX}creategroup My Group | 100001 | 100002`, threadID);
518
+ break;
519
+ }
520
+ const [groupName, ...userIDs] = groupData;
521
+ await api.createNewGroup(userIDs, groupName);
522
+ await api.sendMessage(`✅ Group "${groupName}" created with ${userIDs.length} members`, threadID);
523
+ break;
524
+
525
+ case 'adduser':
526
+ if (!isGroup) {
527
+ await api.sendMessage(`❌ This command only works in group chats`, threadID);
528
+ break;
529
+ }
530
+ if (args.length === 0) {
531
+ await api.sendMessage(`❌ Usage: ${PREFIX}adduser <userID>`, threadID);
532
+ break;
533
+ }
534
+ const userToAdd = args[0];
535
+ await api.addUserToGroup(userToAdd, threadID);
536
+ await api.sendMessage(`✅ User ${userToAdd} added to group`, threadID);
537
+ break;
538
+
539
+ case 'removeuser':
540
+ if (!isGroup) {
541
+ await api.sendMessage(`❌ This command only works in group chats`, threadID);
542
+ break;
543
+ }
544
+ if (args.length === 0) {
545
+ await api.sendMessage(`❌ Usage: ${PREFIX}removeuser <userID>`, threadID);
546
+ break;
547
+ }
548
+ const userToRemove = args[0];
549
+ await api.removeUserFromGroup(userToRemove, threadID);
550
+ await api.sendMessage(`✅ User ${userToRemove} removed from group`, threadID);
551
+ break;
552
+
553
+ case 'groupimage':
554
+ if (!isGroup) {
555
+ await api.sendMessage(`❌ This command only works in group chats`, threadID);
556
+ break;
557
+ }
558
+ await api.sendMessage(`ℹ️ Note: changeGroupImage requires a readable stream (file), not a URL.
559
+ Example: api.changeGroupImage(fs.createReadStream('image.jpg'), threadID)`, threadID);
560
+ break;
561
+
562
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
563
+ // 🔗 SOCIAL COMMANDS
564
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
565
+ case 'block':
566
+ if (args.length === 0) {
567
+ await api.sendMessage(`❌ Usage: ${PREFIX}block <userID>`, threadID);
568
+ break;
569
+ }
570
+ const userToBlock = args[0];
571
+ await api.changeBlockedStatus(userToBlock, true);
572
+ await api.sendMessage(`🚫 User ${userToBlock} has been blocked`, threadID);
573
+ break;
574
+
575
+ case 'unblock':
576
+ if (args.length === 0) {
577
+ await api.sendMessage(`❌ Usage: ${PREFIX}unblock <userID>`, threadID);
578
+ break;
579
+ }
580
+ const userToUnblock = args[0];
581
+ await api.changeBlockedStatus(userToUnblock, false);
582
+ await api.sendMessage(`✅ User ${userToUnblock} has been unblocked`, threadID);
583
+ break;
584
+
585
+ case 'addfriend':
586
+ if (args.length === 0) {
587
+ await api.sendMessage(`❌ Usage: ${PREFIX}addfriend <userID>`, threadID);
588
+ break;
589
+ }
590
+ const friendToAdd = args[0];
591
+ await api.friend(friendToAdd, true);
592
+ await api.sendMessage(`✅ Friend request sent to ${friendToAdd}`, threadID);
593
+ break;
594
+
595
+ case 'removefriend':
596
+ if (args.length === 0) {
597
+ await api.sendMessage(`❌ Usage: ${PREFIX}removefriend <userID>`, threadID);
598
+ break;
599
+ }
600
+ const friendToRemove = args[0];
601
+ await api.unfriend(friendToRemove);
602
+ await api.sendMessage(`✅ Removed ${friendToRemove} from friends`, threadID);
603
+ break;
604
+
605
+ case 'follow':
606
+ if (args.length === 0) {
607
+ await api.sendMessage(`❌ Usage: ${PREFIX}follow <userID>`, threadID);
608
+ break;
609
+ }
610
+ const userToFollow = args[0];
611
+ await api.follow(userToFollow, true);
612
+ await api.sendMessage(`✅ Now following ${userToFollow}`, threadID);
613
+ break;
614
+
615
+ case 'unfollow':
616
+ if (args.length === 0) {
617
+ await api.sendMessage(`❌ Usage: ${PREFIX}unfollow <userID>`, threadID);
618
+ break;
619
+ }
620
+ const userToUnfollow = args[0];
621
+ await api.follow(userToUnfollow, false);
622
+ await api.sendMessage(`✅ Unfollowed ${userToUnfollow}`, threadID);
623
+ break;
624
+
625
+ case 'sharecontact':
626
+ if (args.length === 0) {
627
+ await api.sendMessage(`❌ Usage: ${PREFIX}sharecontact <userID> [message]
628
+ Example: ${PREFIX}sharecontact 100001234567890 Check out this contact!`, threadID);
629
+ break;
630
+ }
631
+ const contactUserID = args[0];
632
+ const contactMessage = args.slice(1).join(' ') || '';
633
+ api.shareContact(contactMessage, contactUserID, threadID);
634
+ await api.sendMessage(`✅ Contact card for user ${contactUserID} shared in this thread`, threadID);
635
+ break;
636
+
637
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
638
+ // 🔍 SEARCH COMMANDS
639
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
640
+ case 'searchthread':
641
+ if (args.length === 0) {
642
+ await api.sendMessage(`❌ Usage: ${PREFIX}searchthread <query>`, threadID);
643
+ break;
644
+ }
645
+ const threadQuery = args.join(' ');
646
+ const searchResults = await api.searchForThread(threadQuery);
647
+ if (searchResults.length === 0) {
648
+ await api.sendMessage(`❌ No threads found for "${threadQuery}"`, threadID);
649
+ } else {
650
+ const searchResultsFormatted = searchResults.slice(0, 5).map((t, i) =>
651
+ `${i + 1}. ${t.name} (${t.threadID})`
652
+ ).join('\n');
653
+ await api.sendMessage(`🔍 Thread search results:
654
+
655
+ ${searchResultsFormatted}
656
+
657
+ Found: ${searchResults.length} threads`, threadID);
658
+ }
659
+ break;
660
+
661
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
662
+ // 📊 STATUS COMMANDS
663
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
664
+ case 'status':
665
+ const status = api.getTokenRefreshStatus();
666
+ const uptime = process.uptime();
667
+ const hours = Math.floor(uptime / 3600);
668
+ const minutes = Math.floor((uptime % 3600) / 60);
669
+ await api.sendMessage(`📊 Bot Status
670
+
671
+ ⏱️ Uptime: ${hours}h ${minutes}m
672
+ 🔄 Token Refresh: ${status.isRefreshing ? 'Active' : 'Idle'}
673
+ 📅 Last Refresh: ${status.lastRefreshTime ? new Date(status.lastRefreshTime).toLocaleString() : 'Never'}
674
+ 📈 Refresh Count: ${status.refreshCount}
675
+ ✅ MQTT: Connected`, threadID);
676
+ break;
677
+
678
+ case 'test':
679
+ await api.sendMessage('🧪 Running quick API test...', threadID);
680
+ const testResults = [];
681
+
682
+ try {
683
+ await api.getUserInfo(senderID);
684
+ testResults.push('✅ getUserInfo');
685
+ } catch (e) {
686
+ testResults.push('❌ getUserInfo');
687
+ }
688
+
689
+ try {
690
+ await api.getThreadInfo(threadID);
691
+ testResults.push('✅ getThreadInfo');
692
+ } catch (e) {
693
+ testResults.push('❌ getThreadInfo');
694
+ }
695
+
696
+ try {
697
+ await api.getTheme(threadID);
698
+ testResults.push('✅ getTheme');
699
+ } catch (e) {
700
+ testResults.push('❌ getTheme');
701
+ }
702
+
703
+ try {
704
+ await api.sendTypingIndicator(threadID);
705
+ testResults.push('✅ sendTypingIndicator');
706
+ } catch (e) {
707
+ testResults.push('❌ sendTypingIndicator');
708
+ }
709
+
710
+ await api.sendMessage(`🧪 Test Results:
711
+
712
+ ${testResults.join('\n')}
713
+
714
+ ${testResults.filter(r => r.startsWith('✅')).length}/${testResults.length} tests passed`, threadID);
715
+ break;
716
+
717
+ case 'logout':
718
+ await api.sendMessage('👋 Logging out bot...', threadID);
719
+ await api.logout();
720
+ console.log('Bot logged out');
721
+ process.exit(0);
722
+ break;
723
+
724
+ default:
725
+ await api.sendMessage(`❓ Unknown command: ${command}
726
+ Type ${PREFIX}help for available commands`, threadID);
727
+ }
728
+ } catch (error) {
729
+ console.error(`\n❌ ERROR in command /${command}:`);
730
+ console.error(` Message: ${error.message}`);
731
+ console.error(` Stack:`, error.stack);
732
+ console.error(` Thread ID: ${threadID}`);
733
+ console.error(` Sender ID: ${senderID}`);
734
+ console.error(` Args:`, args);
735
+
736
+ await api.sendMessage(`❌ Error executing /${command}:
737
+ ${error.message || 'Unknown error occurred'}
738
+
739
+ If this persists, check the console logs for details.`, threadID).catch(err => {
740
+ console.error('Failed to send error message:', err.message);
741
+ });
742
+ }
743
+ }
744
+
745
+ process.on('unhandledRejection', (reason, promise) => {
746
+ console.error('⚠️ Unhandled Rejection:', reason);
747
+ });
748
+
749
+ process.on('SIGINT', () => {
750
+ console.log('\n\n👋 Bot shutting down gracefully...');
751
+ process.exit(0);
752
+ });