shadowx-fca 8.0.0

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 (174) hide show
  1. package/README.md +1066 -0
  2. package/build/messagix.dll +0 -0
  3. package/build/messagix.so +0 -0
  4. package/checkUpdate.js +393 -0
  5. package/config.json +17 -0
  6. package/e2ee.js +563 -0
  7. package/e2eetest.js +356 -0
  8. package/index.js +611 -0
  9. package/lib/index.mjs +1412 -0
  10. package/logger.js +500 -0
  11. package/package.json +65 -0
  12. package/src/GetBotInfo.js +66 -0
  13. package/src/OldMessage.js +182 -0
  14. package/src/Screenshot.js +83 -0
  15. package/src/addExternalModule.js +13 -0
  16. package/src/addUserToGroup.js +33 -0
  17. package/src/approveGroupJoinRequests.js +18 -0
  18. package/src/changeAdminStatus.js +16 -0
  19. package/src/changeArchivedStatus.js +17 -0
  20. package/src/changeAvatar.js +136 -0
  21. package/src/changeAvatarV2.js +86 -0
  22. package/src/changeAvt.js +85 -0
  23. package/src/changeBio.js +76 -0
  24. package/src/changeBlockedStatus.js +20 -0
  25. package/src/changeBlockedStatusMqtt.js +80 -0
  26. package/src/changeCover.js +72 -0
  27. package/src/changeGroupImage.js +16 -0
  28. package/src/changeName.js +79 -0
  29. package/src/changeNickname.js +16 -0
  30. package/src/changeThreadColor.js +15 -0
  31. package/src/changeThreadEmoji.js +15 -0
  32. package/src/changeThreadMemberNickname.js +6 -0
  33. package/src/changeUsername.js +59 -0
  34. package/src/createCommentPost.js +230 -0
  35. package/src/createNewGroup.js +38 -0
  36. package/src/createNote.js +35 -0
  37. package/src/createPoll.js +27 -0
  38. package/src/createPost.js +276 -0
  39. package/src/createThemeAI.js +129 -0
  40. package/src/data/cache/system/data.json +4 -0
  41. package/src/data/cache/system/datahandle.js +21 -0
  42. package/src/data/getThreadInfo.json +1 -0
  43. package/src/deleteComment.js +23 -0
  44. package/src/deleteMessage.js +15 -0
  45. package/src/deleteThread.js +15 -0
  46. package/src/denyGroupJoinRequests.js +18 -0
  47. package/src/e2ee/crypto.js +173 -0
  48. package/src/e2ee/index.js +144 -0
  49. package/src/e2ee/proto/ArmadilloApplication.proto +281 -0
  50. package/src/e2ee/proto/ArmadilloICDC.proto +14 -0
  51. package/src/e2ee/proto/ConsumerApplication.proto +232 -0
  52. package/src/e2ee/proto/MessageApplication.proto +82 -0
  53. package/src/e2ee/proto/MessageTransport.proto +77 -0
  54. package/src/e2ee/proto/WACommon.proto +66 -0
  55. package/src/e2ee/proto/WAMediaTransport.proto +176 -0
  56. package/src/e2ee/proto/proto-writer.ts +76 -0
  57. package/src/e2ee/protocol.js +196 -0
  58. package/src/e2ee/ratchet.js +219 -0
  59. package/src/e2ee/store.js +182 -0
  60. package/src/e2ee.js +8 -0
  61. package/src/editMessage.js +56 -0
  62. package/src/editMessageOld.js +67 -0
  63. package/src/enableReactions.js +24 -0
  64. package/src/follow.js +74 -0
  65. package/src/followUser.js +23 -0
  66. package/src/forwardAttachment.js +16 -0
  67. package/src/friendList.js +98 -0
  68. package/src/getAccess.js +112 -0
  69. package/src/getAppState.js +13 -0
  70. package/src/getAvatarUser.js +11 -0
  71. package/src/getBio.js +24 -0
  72. package/src/getBotInitialData.js +42 -0
  73. package/src/getCtx.js +5 -0
  74. package/src/getCurrentUserID.js +6 -0
  75. package/src/getEmojiUrl.js +29 -0
  76. package/src/getFriendsList.js +36 -0
  77. package/src/getMessage.js +37 -0
  78. package/src/getNotes.js +17 -0
  79. package/src/getOptions.js +5 -0
  80. package/src/getPinnedMessages.js +33 -0
  81. package/src/getPostInfo.js +17 -0
  82. package/src/getProfileInfo.js +17 -0
  83. package/src/getPublicData.js +25 -0
  84. package/src/getRegion.js +7 -0
  85. package/src/getRepInfo.js +17 -0
  86. package/src/getStickerPacks.js +25 -0
  87. package/src/getStickers.js +39 -0
  88. package/src/getStoryReactions.js +18 -0
  89. package/src/getThreadHistory.js +45 -0
  90. package/src/getThreadHistoryDeprecated.js +71 -0
  91. package/src/getThreadInfo.js +73 -0
  92. package/src/getThreadInfoDeprecated.js +56 -0
  93. package/src/getThreadList.js +76 -0
  94. package/src/getThreadListDeprecated.js +46 -0
  95. package/src/getThreadPictures.js +59 -0
  96. package/src/getThreadTheme.js +77 -0
  97. package/src/getUID.js +17 -0
  98. package/src/getUserID.js +17 -0
  99. package/src/getUserInfo.js +28 -0
  100. package/src/handleFriendRequest.js +21 -0
  101. package/src/handleMessageRequest.js +15 -0
  102. package/src/httpGet.js +13 -0
  103. package/src/httpPost.js +12 -0
  104. package/src/httpPostFormData.js +12 -0
  105. package/src/listenE2EE.js +75 -0
  106. package/src/listenMqtt.js +802 -0
  107. package/src/listenNotification.js +85 -0
  108. package/src/logout.js +22 -0
  109. package/src/markAsDelivered.js +17 -0
  110. package/src/markAsRead.js +14 -0
  111. package/src/markAsReadAll.js +15 -0
  112. package/src/markAsSeen.js +15 -0
  113. package/src/metaTheme.js +185 -0
  114. package/src/muteThread.js +52 -0
  115. package/src/note.js +228 -0
  116. package/src/pin.js +53 -0
  117. package/src/pinMessage.js +6 -0
  118. package/src/postComment.js +29 -0
  119. package/src/postFormData.js +46 -0
  120. package/src/reactToComment.js +31 -0
  121. package/src/reactToPost.js +32 -0
  122. package/src/refreshFb_dtsg.js +31 -0
  123. package/src/removeSuspiciousAccount.js +74 -0
  124. package/src/removeUserFromGroup.js +15 -0
  125. package/src/reply.js +442 -0
  126. package/src/resolvePhotoUrl.js +15 -0
  127. package/src/searchForThread.js +20 -0
  128. package/src/searchFriends.js +28 -0
  129. package/src/searchStickers.js +53 -0
  130. package/src/send.js +46 -0
  131. package/src/sendAudio.js +8 -0
  132. package/src/sendBroadcast.js +93 -0
  133. package/src/sendButtons.js +161 -0
  134. package/src/sendComment.js +159 -0
  135. package/src/sendEmoji.js +10 -0
  136. package/src/sendFile.js +9 -0
  137. package/src/sendFriendRequest.js +33 -0
  138. package/src/sendGif.js +24 -0
  139. package/src/sendImage.js +9 -0
  140. package/src/sendLocation.js +9 -0
  141. package/src/sendMessage.js +487 -0
  142. package/src/sendMessage1.js +309 -0
  143. package/src/sendMessageMqtt.js +68 -0
  144. package/src/sendSticker.js +8 -0
  145. package/src/sendTypingIndicator.js +36 -0
  146. package/src/sendTypingIndicatorV2.js +28 -0
  147. package/src/sendVideo.js +9 -0
  148. package/src/sessionGuard.js +130 -0
  149. package/src/setActiveStatus.js +16 -0
  150. package/src/setMessageReaction.js +61 -0
  151. package/src/setMessageReactionMqtt.js +62 -0
  152. package/src/setOptions.js +22 -0
  153. package/src/setPollVote.js +17 -0
  154. package/src/setPostReaction.js +112 -0
  155. package/src/setProfileGuard.js +44 -0
  156. package/src/setProfileLock.js +93 -0
  157. package/src/setStoryReaction.js +129 -0
  158. package/src/setStorySeen.js +99 -0
  159. package/src/setThreadTheme.js +17 -0
  160. package/src/setTitle.js +15 -0
  161. package/src/shareContact.js +33 -0
  162. package/src/shareLink.js +8 -0
  163. package/src/sharePost.js +31 -0
  164. package/src/stopListenMqtt.js +23 -0
  165. package/src/storyManager.js +353 -0
  166. package/src/suggestFriend.js +128 -0
  167. package/src/threadColors.js +131 -0
  168. package/src/unfollowUser.js +23 -0
  169. package/src/unfriend.js +15 -0
  170. package/src/unpinMessage.js +6 -0
  171. package/src/unsendMessage.js +14 -0
  172. package/src/uploadAttachment.js +58 -0
  173. package/src/uploadImageToImgbb.js +29 -0
  174. package/utils.js +2945 -0
package/e2eetest.js ADDED
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
6
+ * โ•‘ SHADOWX-FCA โ€” E2EE Test Bot โ•‘
7
+ * โ•‘ Dev by Mueid Mursalin Rifat โ•‘
8
+ * โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
9
+ *
10
+ * Uses SHADOWX-FCA's own index.js login (no Koffi / lib/index.mjs).
11
+ * Auto-discovers all src/ modules and tests them via bot commands.
12
+ * Supports both E2EE encrypted and standard MQTT messages.
13
+ *
14
+ * Usage:
15
+ * node e2eetest.js # reads ./appstate.json
16
+ * node e2eetest.js --cookie cookie.txt # reads JSON cookie file
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
23
+ // ยง 1 AUTO-DISCOVER SRC MODULES
24
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
25
+ function discoverModules() {
26
+ const srcDir = path.join(__dirname, 'src');
27
+ const SKIP_DIRS = new Set(['e2ee', 'vendor', 'data']);
28
+ return fs.readdirSync(srcDir)
29
+ .filter(f => f.endsWith('.js') && !SKIP_DIRS.has(f.replace('.js', '')))
30
+ .map(f => f.replace('.js', ''))
31
+ .sort();
32
+ }
33
+
34
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
35
+ // ยง 2 MODULE HEALTH CHECK
36
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
+ function checkAllModules() {
38
+ const srcDir = path.join(__dirname, 'src');
39
+ const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.js'));
40
+ const ok = [], failed = [];
41
+
42
+ for (const f of files) {
43
+ try {
44
+ const mod = require(path.join(srcDir, f));
45
+ if (typeof mod === 'function' || typeof mod === 'object')
46
+ ok.push(f.replace('.js', ''));
47
+ else
48
+ failed.push({ name: f, reason: 'unexpected export type' });
49
+ } catch (e) {
50
+ failed.push({ name: f, reason: e.message });
51
+ }
52
+ }
53
+ return { ok, failed };
54
+ }
55
+
56
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
57
+ // ยง 3 APPSTATE / COOKIE LOADER
58
+ // Supports: appstate.json | cookie.txt | --cookie <file> CLI arg
59
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
60
+ function loadAppState() {
61
+ // CLI: --cookie <path>
62
+ const idx = process.argv.indexOf('--cookie');
63
+ if (idx !== -1 && process.argv[idx + 1]) {
64
+ return readJsonFile(path.resolve(process.argv[idx + 1]), 'cookie');
65
+ }
66
+ // default: appstate.json beside the script
67
+ const candidates = [
68
+ path.join(process.cwd(), 'appstate.json'),
69
+ path.join(process.cwd(), 'cookie.txt'),
70
+ path.join(__dirname, 'appstate.json'),
71
+ ];
72
+ for (const p of candidates) {
73
+ if (fs.existsSync(p)) {
74
+ console.log(`[AUTH] Using: ${p}`);
75
+ return readJsonFile(p, path.basename(p));
76
+ }
77
+ }
78
+ throw new Error(
79
+ 'No appstate found.\n' +
80
+ ' Put appstate.json in the working directory, or run:\n' +
81
+ ' node e2eetest.js --cookie /path/to/cookie.json'
82
+ );
83
+ }
84
+
85
+ function readJsonFile(filePath, label) {
86
+ const raw = fs.readFileSync(filePath, 'utf8').trim();
87
+ try {
88
+ const parsed = JSON.parse(raw);
89
+ if (Array.isArray(parsed) && parsed.length > 0) {
90
+ console.log(`[AUTH] โœ“ Loaded ${parsed.length} cookies from ${label}`);
91
+ return parsed;
92
+ }
93
+ throw new Error('Expected a JSON array of cookies');
94
+ } catch (e) {
95
+ throw new Error(`Cannot parse ${filePath}: ${e.message}`);
96
+ }
97
+ }
98
+
99
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
100
+ // ยง 4 COMMAND HANDLER
101
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
102
+ async function handleMessage(api, event, allModules) {
103
+ const PREFIX = '!';
104
+ const body = (event.body || '').trim();
105
+ if (!body.startsWith(PREFIX)) return;
106
+
107
+ const parts = body.slice(PREFIX.length).trim().split(/\s+/);
108
+ const cmd = (parts.shift() || '').toLowerCase();
109
+ const args = parts;
110
+ const threadID = event.threadID;
111
+
112
+ const tag = event.isE2EE ? '๐Ÿ”' : '๐Ÿ“จ';
113
+ console.log(`\n${tag} Command: !${cmd} args: ${JSON.stringify(args)}`);
114
+
115
+ const send = (text) => api.sendMessage(text, threadID);
116
+
117
+ try {
118
+ switch (cmd) {
119
+
120
+ // โ”€โ”€ Basic โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
121
+ case 'ping':
122
+ await send('๐Ÿ“ Pong! SHADOWX-FCA is alive!');
123
+ break;
124
+
125
+ case 'info':
126
+ await send(
127
+ `โ„น๏ธ SHADOWX-FCA Info\n` +
128
+ `โ”œโ”€ MsgID : ${event.messageID || 'N/A'}\n` +
129
+ `โ”œโ”€ Sender : ${event.senderID}\n` +
130
+ `โ”œโ”€ Thread : ${threadID}\n` +
131
+ `โ”œโ”€ E2EE : ${event.isE2EE ? '๐Ÿ” Yes' : '๐Ÿ“จ No'}\n` +
132
+ `โ”œโ”€ Type : ${event.isGroup ? '๐Ÿ‘ฅ GROUP' : '๐Ÿ‘ค DM'}\n` +
133
+ `โ””โ”€ Time : ${new Date(event.timestamp || Date.now()).toLocaleString()}`
134
+ );
135
+ break;
136
+
137
+ case 'echo':
138
+ await send(`๐Ÿ”Š ${args.join(' ') || '(nothing to echo)'}`);
139
+ break;
140
+
141
+ // โ”€โ”€ Module listing & checking โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
142
+ case 'modules': {
143
+ const page = parseInt(args[0]) || 1;
144
+ const size = 40;
145
+ const start = (page - 1) * size;
146
+ const slice = allModules.slice(start, start + size);
147
+ const total = allModules.length;
148
+ const pages = Math.ceil(total / size);
149
+ await send(
150
+ `๐Ÿ“ฆ Modules (${total} total) โ€” page ${page}/${pages}:\n` +
151
+ slice.join(', ') +
152
+ (page < pages ? `\n\nSend !modules ${page + 1} for next page` : '')
153
+ );
154
+ break;
155
+ }
156
+
157
+ case 'check': {
158
+ await send('๐Ÿ” Checking all src/ modules, please wait...');
159
+ const results = checkAllModules();
160
+ const failText = results.failed.length
161
+ ? results.failed.map(f => ` โœ— ${f.name}: ${f.reason.slice(0, 80)}`).join('\n')
162
+ : ' (none)';
163
+ await send(
164
+ `๐Ÿ“Š Module Check โ€” ${results.ok.length + results.failed.length} files\n` +
165
+ `โœ… OK : ${results.ok.length}\n` +
166
+ `โŒ Failed : ${results.failed.length}\n\n` +
167
+ (results.failed.length
168
+ ? `Failed modules:\n${failText}`
169
+ : `๐ŸŽ‰ All modules loaded successfully!`)
170
+ );
171
+ break;
172
+ }
173
+
174
+ case 'find': {
175
+ const kw = (args[0] || '').toLowerCase();
176
+ if (!kw) { await send('โ“ Usage: !find <keyword>'); break; }
177
+ const matches = allModules.filter(m => m.toLowerCase().includes(kw));
178
+ await send(
179
+ matches.length
180
+ ? `๐Ÿ”Ž "${kw}" โ€” ${matches.length} match(es):\n${matches.join(', ')}`
181
+ : `โŒ No modules matching "${kw}"`
182
+ );
183
+ break;
184
+ }
185
+
186
+ case 'has': {
187
+ const mod = args[0] || '';
188
+ await send(
189
+ allModules.includes(mod)
190
+ ? `โœ… Module "${mod}" exists in SHADOWX-FCA`
191
+ : `โŒ Module "${mod}" not found โ€” try !find ${mod}`
192
+ );
193
+ break;
194
+ }
195
+
196
+ case 'categories': {
197
+ const groups = {};
198
+ for (const m of allModules) {
199
+ const prefix = m.replace(/([A-Z])/g, ' $1').trim().split(' ')[0].toLowerCase();
200
+ (groups[prefix] = groups[prefix] || []).push(m);
201
+ }
202
+ const lines = Object.entries(groups)
203
+ .sort((a, b) => b[1].length - a[1].length)
204
+ .map(([k, v]) => ` ${k.padEnd(12)}: ${v.length}`);
205
+ await send(`๐Ÿ“‚ Module Categories (${allModules.length} total):\n${lines.join('\n')}`);
206
+ break;
207
+ }
208
+
209
+ // โ”€โ”€ E2EE status โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
210
+ case 'e2ee': {
211
+ const e2eeDir = path.join(__dirname, 'src', 'e2ee');
212
+ const e2eeFiles = fs.readdirSync(e2eeDir)
213
+ .filter(f => !fs.statSync(path.join(e2eeDir, f)).isDirectory());
214
+ const connected = !!(api.e2ee && api.e2ee.connected);
215
+ await send(
216
+ `๐Ÿ” E2EE Engine Status\n` +
217
+ `โ”œโ”€ Connected : ${connected ? 'โœ… Yes' : 'โŒ No'}\n` +
218
+ `โ”œโ”€ Engine files : ${e2eeFiles.join(', ')}\n` +
219
+ `โ”œโ”€ Store path : .shadowx-fca/e2ee_device.json\n` +
220
+ `โ””โ”€ Protocol : Signal (Double Ratchet + Noise_XX)`
221
+ );
222
+ break;
223
+ }
224
+
225
+ // โ”€โ”€ Help โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
226
+ case 'help':
227
+ default:
228
+ await send(
229
+ `๐Ÿ“‹ SHADOWX-FCA E2EE Test Bot\n` +
230
+ `Dev: Mueid Mursalin Rifat\n\n` +
231
+ `!ping โ€” Bot alive check\n` +
232
+ `!info โ€” Message & thread info\n` +
233
+ `!echo <text> โ€” Echo text back\n` +
234
+ `!modules [page] โ€” List all src/ modules (paged)\n` +
235
+ `!check โ€” Health-check all src/ files\n` +
236
+ `!find <keyword> โ€” Search modules by name\n` +
237
+ `!has <name> โ€” Check if module exists\n` +
238
+ `!categories โ€” Modules grouped by type\n` +
239
+ `!e2ee โ€” E2EE engine status\n` +
240
+ `!help โ€” Show this help`
241
+ );
242
+ break;
243
+ }
244
+ } catch (err) {
245
+ console.error(`โœ— Error in !${cmd}: ${err.message}`);
246
+ try { await send(`โŒ Error in !${cmd}: ${err.message}`); } catch (_) {}
247
+ }
248
+ }
249
+
250
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
251
+ // ยง 5 MAIN โ€” login via SHADOWX-FCA index.js (no Koffi / lib/index.mjs)
252
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
253
+ async function main() {
254
+ console.log('\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—');
255
+ console.log('โ•‘ SHADOWX-FCA โ€” E2EE Test Bot โ•‘');
256
+ console.log('โ•‘ Dev by Mueid Mursalin Rifat โ•‘');
257
+ console.log('โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n');
258
+
259
+ // โ”€โ”€ Module discovery & health check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
260
+ const allModules = discoverModules();
261
+ console.log(`[MODULES] โœ“ Discovered ${allModules.length} src modules`);
262
+
263
+ const check = checkAllModules();
264
+ if (check.failed.length) {
265
+ console.warn(`[MODULES] โš  ${check.failed.length} module(s) failed to load:`);
266
+ check.failed.forEach(f => console.warn(` โœ— ${f.name}: ${f.reason}`));
267
+ } else {
268
+ console.log(`[MODULES] โœ“ ${check.ok.length} / ${check.ok.length} modules OK`);
269
+ }
270
+
271
+ // โ”€โ”€ Load appstate โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
272
+ const appState = loadAppState();
273
+
274
+ // โ”€โ”€ Login via SHADOWX-FCA's own index.js โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
275
+ console.log('[LOGIN] Logging in via SHADOWX-FCA...');
276
+ const login = require('./index.js');
277
+
278
+ const api = await new Promise((resolve, reject) => {
279
+ login({ appState }, { listenEvents: true }, (err, api) => {
280
+ if (err) return reject(err);
281
+ resolve(api);
282
+ });
283
+ });
284
+
285
+ console.log(`[LOGIN] โœ“ Logged in as UID: ${api.getCurrentUserID()}\n`);
286
+
287
+ // โ”€โ”€ Try to connect E2EE (gracefully falls back if engine not available) โ”€
288
+ let e2eeActive = false;
289
+ try {
290
+ console.log('[E2EE] Connecting E2EE encryption bridge...');
291
+ await api.connectE2EE();
292
+ e2eeActive = true;
293
+ console.log('[E2EE] โœ“ E2EE bridge connected\n');
294
+ } catch (err) {
295
+ console.warn(`[E2EE] โš  E2EE not available: ${err.message}`);
296
+ console.warn('[E2EE] Falling back to standard MQTT only.\n');
297
+ }
298
+
299
+ // โ”€โ”€ Choose listener: E2EE combined or standard MQTT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
300
+ const listenFn = (e2eeActive && typeof api.listenE2EE === 'function')
301
+ ? api.listenE2EE.bind(api)
302
+ : api.listen.bind(api);
303
+
304
+ const mode = e2eeActive ? '๐Ÿ” E2EE + MQTT' : '๐Ÿ“จ MQTT only';
305
+
306
+ console.log('โ”€'.repeat(62));
307
+ console.log(`๐Ÿš€ SHADOWX-FCA E2EE Test Bot is ready!`);
308
+ console.log(` UID : ${api.getCurrentUserID()}`);
309
+ console.log(` Modules loaded : ${allModules.length}`);
310
+ console.log(` Listen mode : ${mode}`);
311
+ console.log(' Send !help in any chat to see all commands.');
312
+ console.log(' Press Ctrl+C to stop');
313
+ console.log('โ”€'.repeat(62) + '\n');
314
+
315
+ // โ”€โ”€ Start listening โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
316
+ listenFn((err, event) => {
317
+ if (err) {
318
+ console.error('โŒ [listen error]', err);
319
+ return;
320
+ }
321
+ if (!event) return;
322
+
323
+ const tag = event.isE2EE ? '๐Ÿ”' : '๐Ÿ“จ';
324
+
325
+ // Log every event
326
+ console.log(`${tag} [${event.type}] thread:${event.threadID} sender:${event.senderID}`);
327
+ if (event.body) console.log(` body: ${event.body.slice(0, 120)}`);
328
+
329
+ // Handle bot commands
330
+ if (event.type === 'message' || event.type === 'message_reply') {
331
+ handleMessage(api, event, allModules).catch(e =>
332
+ console.error('handleMessage error:', e.message)
333
+ );
334
+ }
335
+ });
336
+ }
337
+
338
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
339
+ // ยง 6 SHUTDOWN
340
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
341
+ process.on('SIGINT', () => { console.log('\n\n๐Ÿ‘‹ Shutting down...'); process.exit(0); });
342
+ process.on('SIGTERM', () => { console.log('\n๐Ÿ’ฅ Force shutdown'); process.exit(1); });
343
+ process.on('uncaughtException', err => {
344
+ console.error('\n๐Ÿ’ฅ Uncaught Exception:', err.message);
345
+ console.error(err.stack);
346
+ process.exit(1);
347
+ });
348
+
349
+ main().catch(err => {
350
+ console.error('\nโŒ FATAL:', err.message);
351
+ console.error('\nTroubleshooting:');
352
+ console.error(' 1. Make sure appstate.json is in the current directory');
353
+ console.error(' 2. Or run: node e2eetest.js --cookie /path/to/cookie.json');
354
+ console.error(' 3. Run: npm install (if you see missing module errors)');
355
+ process.exit(1);
356
+ });