toru-fca 1.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.
- package/CHANGELOG.md +64 -0
- package/README.md +319 -0
- package/advancedSystem.js +95 -0
- package/build/messagix.dll +0 -0
- package/build/messagix.so +0 -0
- package/checkUpdate.js +37 -0
- package/config.json +45 -0
- package/e2ee.js +719 -0
- package/index.js +715 -0
- package/lib/index.mjs +1412 -0
- package/package.json +69 -0
- package/src/OldMessage.js +357 -0
- package/src/addExternalModule.js +25 -0
- package/src/addUserToGroup.js +117 -0
- package/src/changeAdminStatus.js +105 -0
- package/src/changeArchivedStatus.js +57 -0
- package/src/changeAvatar.js +138 -0
- package/src/changeAvatarV2.js +86 -0
- package/src/changeAvt.js +85 -0
- package/src/changeBio.js +78 -0
- package/src/changeBlockedStatus.js +51 -0
- package/src/changeBlockedStatusMqtt.js +80 -0
- package/src/changeCover.js +72 -0
- package/src/changeGroupImage.js +137 -0
- package/src/changeName.js +79 -0
- package/src/changeNickname.js +61 -0
- package/src/changeThreadColor.js +67 -0
- package/src/changeThreadEmoji.js +57 -0
- package/src/changeUsername.js +59 -0
- package/src/createCommentPost.js +230 -0
- package/src/createNewGroup.js +90 -0
- package/src/createPoll.js +73 -0
- package/src/createPost.js +276 -0
- package/src/data/getThreadInfo.json +1 -0
- package/src/deleteMessage.js +58 -0
- package/src/deleteThread.js +58 -0
- package/src/editMessage.js +81 -0
- package/src/editMessageOld.js +67 -0
- package/src/follow.js +74 -0
- package/src/forwardAttachment.js +62 -0
- package/src/friendList.js +104 -0
- package/src/getAccess.js +112 -0
- package/src/getAvatarUser.js +78 -0
- package/src/getBotInitialData.js +42 -0
- package/src/getCtx.js +5 -0
- package/src/getCurrentUserID.js +7 -0
- package/src/getEmojiUrl.js +29 -0
- package/src/getFriendsList.js +85 -0
- package/src/getMessage.js +849 -0
- package/src/getOptions.js +5 -0
- package/src/getRegion.js +7 -0
- package/src/getThreadHistory.js +682 -0
- package/src/getThreadHistoryDeprecated.js +71 -0
- package/src/getThreadInfo.js +232 -0
- package/src/getThreadInfoDeprecated.js +56 -0
- package/src/getThreadList.js +213 -0
- package/src/getThreadListDeprecated.js +46 -0
- package/src/getThreadPictures.js +59 -0
- package/src/getThreadTheme.js +81 -0
- package/src/getUID.js +119 -0
- package/src/getUserID.js +61 -0
- package/src/getUserInfo.js +66 -0
- package/src/handleFriendRequest.js +46 -0
- package/src/handleMessageRequest.js +47 -0
- package/src/httpGet.js +49 -0
- package/src/httpPost.js +48 -0
- package/src/httpPostFormData.js +70 -0
- package/src/listenMqtt.js +955 -0
- package/src/listenNotification.js +85 -0
- package/src/logout.js +19 -0
- package/src/markAsDelivered.js +47 -0
- package/src/markAsRead.js +72 -0
- package/src/markAsReadAll.js +40 -0
- package/src/markAsSeen.js +48 -0
- package/src/metaTheme.js +189 -0
- package/src/muteThread.js +45 -0
- package/src/note.js +228 -0
- package/src/pinMessage.js +59 -0
- package/src/refreshFb_dtsg.js +91 -0
- package/src/removeSuspiciousAccount.js +78 -0
- package/src/removeUserFromGroup.js +81 -0
- package/src/reply.js +442 -0
- package/src/resolvePhotoUrl.js +47 -0
- package/src/searchForThread.js +53 -0
- package/src/searchFriends.js +140 -0
- package/src/searchStickers.js +53 -0
- package/src/send.js +46 -0
- package/src/sendButtons.js +163 -0
- package/src/sendComment.js +159 -0
- package/src/sendFriendRequest.js +112 -0
- package/src/sendMessage.js +440 -0
- package/src/sendMessageMqtt.js +323 -0
- package/src/sendTypingIndicator.js +54 -0
- package/src/setActiveStatus.js +92 -0
- package/src/setMessageReaction.js +149 -0
- package/src/setMessageReactionMqtt.js +62 -0
- package/src/setPostReaction.js +114 -0
- package/src/setProfileGuard.js +44 -0
- package/src/setProfileLock.js +97 -0
- package/src/setStoryReaction.js +133 -0
- package/src/setStorySeen.js +108 -0
- package/src/setThreadTheme.js +102 -0
- package/src/setTitle.js +92 -0
- package/src/shareContact.js +110 -0
- package/src/shareLink.js +59 -0
- package/src/stopListenMqtt.js +37 -0
- package/src/storyManager.js +357 -0
- package/src/suggestFriend.js +132 -0
- package/src/threadColors.js +131 -0
- package/src/unfriend.js +54 -0
- package/src/unsendMessage.js +68 -0
- package/src/uploadAttachment.js +115 -0
- package/utils.js +3044 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Changelog — alpha-fca
|
|
2
|
+
|
|
3
|
+
## v1.0.0 (2026-09-01) — Initial Release
|
|
4
|
+
|
|
5
|
+
### 🎯 What This Is
|
|
6
|
+
A clean, merged, audited Facebook Chat API built from analyzing 6 FCA variants.
|
|
7
|
+
|
|
8
|
+
### ✅ Inclusions (Best-of-all merge)
|
|
9
|
+
|
|
10
|
+
**From hridoy-custom (base):**
|
|
11
|
+
- Full E2EE bridge with Node.js < 22 undici webidl compatibility patch
|
|
12
|
+
- Self-listen filter for E2EE messages (both ID-map and cookie-UID approaches)
|
|
13
|
+
- Multi-domain cookie collection for E2EE (`_cookiesFromJar`)
|
|
14
|
+
- `stopped` flag on bridge to prevent reconnect loops after `disconnect()`
|
|
15
|
+
- MQTT patch stream (fixes Facebook's non-standard PUBACK/SUBACK flag bits)
|
|
16
|
+
- MQTT spinner + connection banner
|
|
17
|
+
- `sessionGuard()` — auto-save appstate with debounce
|
|
18
|
+
- Layered config system (FCA config → bot CWD config → runtime options)
|
|
19
|
+
- Logout disabled (no-op) to preserve Facebook session
|
|
20
|
+
- AdvancedSystem queue for controlled task execution
|
|
21
|
+
|
|
22
|
+
**From hridoy-akash:**
|
|
23
|
+
- Global `process.on("unhandledRejection")` handler with network-error classification
|
|
24
|
+
- Global `process.on("uncaughtException")` handler (non-exit)
|
|
25
|
+
- Clean `BOOL_OPTIONS` setOptions pattern
|
|
26
|
+
|
|
27
|
+
**From ST-FCA (extra API methods):**
|
|
28
|
+
- `sendButtons` — send interactive buttons
|
|
29
|
+
- `sendFriendRequest` — send friend request
|
|
30
|
+
- `searchFriends` — search friends list
|
|
31
|
+
- `setActiveStatus` — set active/online status
|
|
32
|
+
- `setProfileLock` — lock profile visibility
|
|
33
|
+
- `storyManager` — story management utilities
|
|
34
|
+
- `suggestFriend` — suggest a friend
|
|
35
|
+
- `setThreadTheme` — set thread theme
|
|
36
|
+
- `setStorySeen` — mark story as seen
|
|
37
|
+
- `metaTheme` — Meta theme utilities
|
|
38
|
+
- `note` — note utilities
|
|
39
|
+
|
|
40
|
+
**Architecture improvements:**
|
|
41
|
+
- Size-capped E2EE message maps (`_cappedMapSet`, cap: 2000) — prevents memory leak
|
|
42
|
+
- Jittered E2EE reconnect delay (3–4s) — prevents thundering-herd on restarts
|
|
43
|
+
- Fresh `sid` + `cid` on every MQTT reconnect (strips stale params from endpoint)
|
|
44
|
+
- Reconnect state object (`ctx._reconnectState`) with `stopped` flag
|
|
45
|
+
- `stopListenMqtt()` properly cleans up reconnect timers
|
|
46
|
+
- `stopListeningAsync()` on the message emitter
|
|
47
|
+
- Health monitor via `api.getHealth()`
|
|
48
|
+
- Non-blocking update check via `checkUpdate.js`
|
|
49
|
+
- E2EE `devicePath` parent directory auto-created on first use
|
|
50
|
+
|
|
51
|
+
### ❌ Removed / Disabled
|
|
52
|
+
- All background polling/automation (off by default)
|
|
53
|
+
- Aggressive repeated requests
|
|
54
|
+
- Unnecessary logout flows
|
|
55
|
+
- Duplicate event listeners
|
|
56
|
+
- Dead code from outdated API patterns
|
|
57
|
+
- Third-party image upload to unknown accounts (imgbb/imagekit keys must be user-supplied)
|
|
58
|
+
- Sequelize/SQLite database dependency (removed bloat)
|
|
59
|
+
- `fca-unofficial` package dependency (inlined)
|
|
60
|
+
|
|
61
|
+
### ⚠️ Known Limitations
|
|
62
|
+
- E2EE binary (`messagix.so` / `.dll`) is pre-built for x86_64; ARM support depends on available binaries
|
|
63
|
+
- Live MQTT/E2EE behavior cannot be statically tested — depends on active Facebook endpoints
|
|
64
|
+
- Facebook API changes may break parsing without warning (inherent to all unofficial FCAs)
|
package/README.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# alpha-fca v1.0.0
|
|
2
|
+
|
|
3
|
+
> **Ultimate Merged Facebook Chat API** — Stable Inbox · E2EE Bridge · E2EE Group · Low Automation · Clean Architecture
|
|
4
|
+
|
|
5
|
+
Built by analyzing, comparing, auditing and merging the best implementations from **6 FCA variants**:
|
|
6
|
+
`hridoy-akash` · `fca-unofficial` · `ST-FCA` · `fca-azad` · `mahmud-fca` · `hridoy-custom`
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ✨ Features
|
|
11
|
+
|
|
12
|
+
| Feature | Status | Details |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| 📩 Inbox / Normal Messages | ✅ Stable | MQTT-based, auto-reconnect, no duplicate listeners |
|
|
15
|
+
| 🔐 E2EE Bridge | ✅ Working | Labyrinth native bridge, auto-reconnect with jitter |
|
|
16
|
+
| 👥 E2EE Group Messages | ✅ Working | Group JID detection, full event mapping |
|
|
17
|
+
| 🔄 Session / Reconnect | ✅ Stable | sessionGuard, backoff reconnect, no unnecessary logouts |
|
|
18
|
+
| ⚙️ Low Automation | ✅ Enforced | No background polling; automation off by default |
|
|
19
|
+
| 🛡️ Error Handling | ✅ Robust | Global unhandledRejection + uncaughtException guards |
|
|
20
|
+
| 🧠 Memory Safety | ✅ Capped | E2EE message maps size-capped at 2000 entries |
|
|
21
|
+
| 📦 Node.js 18–22 | ✅ Compatible | undici webidl patch for Node < 22 |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 📦 Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Clone or copy the folder, then:
|
|
29
|
+
npm install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Requirements:**
|
|
33
|
+
- Node.js >= 18.0.0
|
|
34
|
+
- `build/messagix.so` (Linux) or `build/messagix.dll` (Windows) — included
|
|
35
|
+
- `lib/index.mjs` — E2EE ESM bundle — included
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🚀 Quick Start
|
|
40
|
+
|
|
41
|
+
### 1. Prepare your appstate
|
|
42
|
+
|
|
43
|
+
Export your Facebook cookies as JSON (using a browser extension like [c3c-fbstate](https://github.com/c3cbot/c3c-fbstate) or similar), save as `appstate.json`.
|
|
44
|
+
|
|
45
|
+
### 2. Basic bot
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
const login = require("alpha-fca");
|
|
49
|
+
const fs = require("fs");
|
|
50
|
+
|
|
51
|
+
const appState = JSON.parse(fs.readFileSync("appstate.json", "utf8"));
|
|
52
|
+
|
|
53
|
+
login({ appState }, { listenEvents: true, autoReconnect: true }, (err, api) => {
|
|
54
|
+
if (err) return console.error(err);
|
|
55
|
+
|
|
56
|
+
console.log("Logged in as:", api.getCurrentUserID());
|
|
57
|
+
|
|
58
|
+
// Auto-save session every 3 minutes
|
|
59
|
+
api.sessionGuard("appstate.json", { interval: 3 * 60 * 1000 });
|
|
60
|
+
|
|
61
|
+
// Listen for messages
|
|
62
|
+
api.listenMqtt((err, event) => {
|
|
63
|
+
if (err) return console.error(err);
|
|
64
|
+
if (event.type === "message") {
|
|
65
|
+
console.log(`[${event.threadID}] ${event.senderID}: ${event.body}`);
|
|
66
|
+
if (event.body === "ping") api.sendMessage("pong!", event.threadID);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. E2EE bot
|
|
73
|
+
|
|
74
|
+
Enable E2EE in `config.json`:
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"e2ee": { "enable": true, "saveType": "memory" }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Then:
|
|
82
|
+
```js
|
|
83
|
+
// After login:
|
|
84
|
+
api.connectE2EE((err, event) => {
|
|
85
|
+
if (err) return console.error(err);
|
|
86
|
+
// event.type === "e2ee_ready" → "e2ee_fully_ready"
|
|
87
|
+
// event.type === "message" with event.isE2EE = true → E2EE message
|
|
88
|
+
if (event.type === "message" && event.isE2EE) {
|
|
89
|
+
api.sendMessage("Hello E2EE!", event.threadID);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See `examples/e2ee-bot.js` for a complete example.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## ⚙️ Configuration (`config.json`)
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"automation": { "enabled": false },
|
|
103
|
+
"inbox": { "enabled": true },
|
|
104
|
+
"smooth": { "enabled": false, "messageDelay": 400 },
|
|
105
|
+
"e2ee": {
|
|
106
|
+
"enable": false,
|
|
107
|
+
"saveType": "memory",
|
|
108
|
+
"devicePath": "./data/e2ee-device.json",
|
|
109
|
+
"autoReconnect": true,
|
|
110
|
+
"logLevel": "none"
|
|
111
|
+
},
|
|
112
|
+
"enableTypingIndicator": false,
|
|
113
|
+
"typingDuration": 4000
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| Key | Default | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `automation.enabled` | `false` | Background task automation. **Keep false.** |
|
|
120
|
+
| `inbox.enabled` | `true` | Enables getThreadList / inbox access |
|
|
121
|
+
| `smooth.enabled` | `false` | Shows typing indicator before sending |
|
|
122
|
+
| `e2ee.enable` | `false` | Activates E2EE Labyrinth bridge |
|
|
123
|
+
| `e2ee.saveType` | `"memory"` | `"memory"` = keys lost on restart · `"path"` = persistent |
|
|
124
|
+
| `e2ee.devicePath` | `"./data/e2ee-device.json"` | Used only when saveType = `"path"` |
|
|
125
|
+
| `enableTypingIndicator` | `false` | Auto typing indicator on sendMessage |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📚 API Reference
|
|
130
|
+
|
|
131
|
+
### Login
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
login(loginData, options, callback)
|
|
135
|
+
// or: await login(loginData, options)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**loginData:**
|
|
139
|
+
- `{ appState }` — cookie-based login (recommended)
|
|
140
|
+
- `{ email, password }` — credentials (use appState instead)
|
|
141
|
+
|
|
142
|
+
**options (defaults):**
|
|
143
|
+
```js
|
|
144
|
+
{
|
|
145
|
+
selfListen : false,
|
|
146
|
+
listenEvents : true,
|
|
147
|
+
listenTyping : false,
|
|
148
|
+
updatePresence: false,
|
|
149
|
+
autoMarkRead : false,
|
|
150
|
+
autoReconnect : true,
|
|
151
|
+
online : false
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Messaging
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
api.sendMessage(msg, threadID, [callback], [replyToMessageID])
|
|
161
|
+
api.sendMessage({ body, attachment, sticker, emoji, mentions, url }, threadID)
|
|
162
|
+
api.unsendMessage(messageID, [callback])
|
|
163
|
+
api.editMessage(body, messageID, [callback])
|
|
164
|
+
api.setMessageReaction(reaction, messageID, [callback])
|
|
165
|
+
api.forwardMessage(messageID, threadID, [callback])
|
|
166
|
+
api.forwardAttachment(attachmentID, userIDs, [callback])
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Threads
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
api.getThreadList(limit, cursor, tags, [callback])
|
|
173
|
+
api.getThreadInfo(threadID, [callback])
|
|
174
|
+
api.getThreadHistory(threadID, amount, timestamp, [callback])
|
|
175
|
+
api.createNewGroup(participantIDs, [groupTitle], [callback])
|
|
176
|
+
api.addUserToGroup(userID, threadID, [callback])
|
|
177
|
+
api.removeUserFromGroup(userID, threadID, [callback])
|
|
178
|
+
api.changeAdminStatus(threadID, adminID, adminStatus, [callback])
|
|
179
|
+
api.setTitle(newTitle, threadID, [callback])
|
|
180
|
+
api.changeGroupImage(imageStream, threadID, [callback])
|
|
181
|
+
api.muteThread(threadID, muteSeconds, [callback])
|
|
182
|
+
api.deleteThread(threadID, [callback])
|
|
183
|
+
api.changeArchivedStatus(threadID, archive, [callback])
|
|
184
|
+
api.createPoll(title, threadID, options, [callback])
|
|
185
|
+
api.pinMessage(messageID, threadID, [callback])
|
|
186
|
+
api.markAsRead(threadID, [read], [callback])
|
|
187
|
+
api.markAsDelivered(threadID, messageID, [callback])
|
|
188
|
+
api.markAsSeen([callback])
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Users
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
api.getUserInfo(userIDs, [callback])
|
|
195
|
+
api.getUserID(name, [callback])
|
|
196
|
+
api.getFriendsList([callback])
|
|
197
|
+
api.handleFriendRequest(userID, accept, [callback])
|
|
198
|
+
api.addFriend(userID, [callback])
|
|
199
|
+
api.unfriend(userID, [callback])
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### E2EE
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
api.connectE2EE(callback) // Start E2EE bridge
|
|
206
|
+
api.getE2EEBridge() // Get live bridge instance
|
|
207
|
+
api.getE2EEDeviceData([callback]) // Get E2EE device keys
|
|
208
|
+
api.downloadE2EEMedia(options) // Decrypt E2EE attachment
|
|
209
|
+
api.resolveE2EEAttachment(att) // Download + return local URL
|
|
210
|
+
api.sendTypingE2EE(chatJid, bool) // Send E2EE typing indicator
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Session
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
api.sessionGuard(accountPath, { interval, debounce })
|
|
217
|
+
api.getAppState() // Get current cookie state
|
|
218
|
+
api.setOptions(options) // Update runtime options
|
|
219
|
+
api.getHealth() // Health status object
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Listening
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
const msgEmitter = api.listenMqtt(callback)
|
|
226
|
+
msgEmitter.stopListening([callback])
|
|
227
|
+
await msgEmitter.stopListeningAsync()
|
|
228
|
+
api.stopListenMqtt()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 🔐 E2EE Events
|
|
234
|
+
|
|
235
|
+
| event.type | Description |
|
|
236
|
+
|---|---|
|
|
237
|
+
| `e2ee_ready` | Bridge loaded, syncing device |
|
|
238
|
+
| `e2ee_fully_ready` | Ready to send/receive messages |
|
|
239
|
+
| `e2ee_connected` | Transport connected |
|
|
240
|
+
| `e2ee_disconnected` | Transport lost (auto-reconnects) |
|
|
241
|
+
| `e2ee_device_data_changed` | Device keys updated |
|
|
242
|
+
| `message` + `isE2EE: true` | Incoming E2EE message (DM or group) |
|
|
243
|
+
| `e2ee_message_edit` | Message was edited |
|
|
244
|
+
| `e2ee_message_reaction` | Reaction added |
|
|
245
|
+
| `e2ee_receipt` | Read/delivery receipt |
|
|
246
|
+
|
|
247
|
+
> **Normal and E2EE listeners never conflict.** The MQTT inbox handles normal chats; the E2EE bridge handles encrypted chats. Both can run simultaneously.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 🔄 Session Stability
|
|
252
|
+
|
|
253
|
+
alpha-fca never calls logout automatically. Session is preserved as long as:
|
|
254
|
+
1. `api.sessionGuard(path)` is active (auto-saves fresh cookies)
|
|
255
|
+
2. The Facebook account is not independently logged out
|
|
256
|
+
|
|
257
|
+
On MQTT disconnect, auto-reconnect fires with exponential backoff (3s–60s).
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## ⚠️ Limitations
|
|
262
|
+
|
|
263
|
+
- **Cannot test live network behavior** — all MQTT/E2EE behavior depends on Facebook's active endpoints and your account cookies.
|
|
264
|
+
- **E2EE requires** the native `build/messagix.so` (Linux) or `build/messagix.dll` (Windows) binary. These are pre-built for x86_64.
|
|
265
|
+
- **Facebook API changes** may break parsing without warning — this is inherent to all unofficial FCAs.
|
|
266
|
+
- **Rate limits** — avoid bulk-sending. alpha-fca does not bypass Facebook's rate limits.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 📁 Project Structure
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
alpha-fca/
|
|
274
|
+
├── index.js # Main entry — login() function
|
|
275
|
+
├── utils.js # HTTP helpers, cookie management
|
|
276
|
+
├── e2ee.js # E2EE bridge (Labyrinth)
|
|
277
|
+
├── advancedSystem.js # Minimal task queue + health monitor
|
|
278
|
+
├── checkUpdate.js # Non-blocking version check
|
|
279
|
+
├── config.json # Default config
|
|
280
|
+
├── fca-config.example.json # Documented config template
|
|
281
|
+
├── package.json
|
|
282
|
+
├── README.md
|
|
283
|
+
├── CHANGELOG.md
|
|
284
|
+
├── build/
|
|
285
|
+
│ ├── messagix.so # E2EE native binary (Linux x86_64)
|
|
286
|
+
│ └── messagix.dll # E2EE native binary (Windows x64)
|
|
287
|
+
├── lib/
|
|
288
|
+
│ └── index.mjs # E2EE ESM bundle (Labyrinth client)
|
|
289
|
+
├── src/ # API method modules (95+ files)
|
|
290
|
+
│ ├── listenMqtt.js # Core inbox listener
|
|
291
|
+
│ ├── sendMessage.js # Message sending (normal + E2EE routing)
|
|
292
|
+
│ ├── OldMessage.js # Legacy DM fallback
|
|
293
|
+
│ ├── stopListenMqtt.js
|
|
294
|
+
│ ├── logout.js # No-op (session preserved)
|
|
295
|
+
│ └── ... (all other FCA methods)
|
|
296
|
+
└── examples/
|
|
297
|
+
├── basic-bot.js # Normal inbox bot
|
|
298
|
+
└── e2ee-bot.js # E2EE + normal combined bot
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 🔬 Merge Analysis
|
|
304
|
+
|
|
305
|
+
| Feature | Winner | Reason |
|
|
306
|
+
|---|---|---|
|
|
307
|
+
| E2EE Bridge | hridoy-custom | undici Node<22 patch, self-listen filter, capped maps, stopped flag |
|
|
308
|
+
| MQTT Core | hridoy-custom | MQTT patch stream, spinner, clean reconnect state |
|
|
309
|
+
| Login/Session | hridoy-custom | Cookie parsing, 2FA, sessionGuard, no unnecessary logouts |
|
|
310
|
+
| Error Handling | hridoy-akash | Global unhandledRejection/uncaughtException with network-specific handling |
|
|
311
|
+
| Extra API Methods | ST-FCA | sendButtons, sendFriendRequest, searchFriends, setActiveStatus, etc. |
|
|
312
|
+
| Low Automation | alpha-fca | All background polling disabled by default, config-driven opt-in only |
|
|
313
|
+
| Config System | alpha-fca | Layered config (FCA defaults → bot CWD override → runtime options) |
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## 📄 License
|
|
318
|
+
|
|
319
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AdvancedSystem — minimal queue + health monitor for alpha-fca.
|
|
5
|
+
* Automation is OFF by default. No background polling, no aggressive requests.
|
|
6
|
+
* Only runs tasks you explicitly enqueue.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const EventEmitter = require("events");
|
|
10
|
+
|
|
11
|
+
class AdvancedSystem extends EventEmitter {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
super();
|
|
14
|
+
options = options || {};
|
|
15
|
+
this.options = Object.assign({
|
|
16
|
+
automationEnabled: false,
|
|
17
|
+
minDelayMs: 1000,
|
|
18
|
+
maxDelayMs: 30000,
|
|
19
|
+
maxQueue: 50
|
|
20
|
+
}, options);
|
|
21
|
+
this.startedAt = Date.now();
|
|
22
|
+
this._queue = [];
|
|
23
|
+
this._running = false;
|
|
24
|
+
this._stats = { enqueued: 0, completed: 0, failed: 0 };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** @returns {boolean} */
|
|
28
|
+
isAutomationEnabled() {
|
|
29
|
+
return this.options.automationEnabled === true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Explicit opt-in only — no background automation started automatically. */
|
|
33
|
+
setAutomationEnabled(enabled) {
|
|
34
|
+
this.options.automationEnabled = Boolean(enabled);
|
|
35
|
+
this.emit("automation", this.options.automationEnabled);
|
|
36
|
+
return this.options.automationEnabled;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Health snapshot — safe to call anytime. */
|
|
40
|
+
health(api) {
|
|
41
|
+
const mqttClient = api && (api.mqttClient || (api.ctx && api.ctx.mqttClient));
|
|
42
|
+
return {
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
uptimeMs: Date.now() - this.startedAt,
|
|
45
|
+
automationEnabled: this.isAutomationEnabled(),
|
|
46
|
+
inboxEnabled: true,
|
|
47
|
+
mqtt: mqttClient ? {
|
|
48
|
+
connected: Boolean(mqttClient.connected),
|
|
49
|
+
reconnecting: Boolean(mqttClient.reconnecting)
|
|
50
|
+
} : null,
|
|
51
|
+
queue: { size: this._queue.length, running: this._running },
|
|
52
|
+
stats: Object.assign({}, this._stats)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Enqueue a task function. Runs sequentially.
|
|
58
|
+
* @param {Function} task async () => result
|
|
59
|
+
* @returns {Promise<any>}
|
|
60
|
+
*/
|
|
61
|
+
enqueue(task) {
|
|
62
|
+
if (typeof task !== "function") return Promise.reject(new TypeError("task must be a function"));
|
|
63
|
+
if (this._queue.length >= this.options.maxQueue) {
|
|
64
|
+
return Promise.reject(new Error("AdvancedSystem queue is full (" + this.options.maxQueue + ")"));
|
|
65
|
+
}
|
|
66
|
+
this._stats.enqueued++;
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
this._queue.push({ task, resolve, reject });
|
|
69
|
+
this._drain();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async _drain() {
|
|
74
|
+
if (this._running || this._queue.length === 0) return;
|
|
75
|
+
this._running = true;
|
|
76
|
+
while (this._queue.length > 0) {
|
|
77
|
+
const { task, resolve, reject } = this._queue.shift();
|
|
78
|
+
try {
|
|
79
|
+
const result = await task();
|
|
80
|
+
this._stats.completed++;
|
|
81
|
+
resolve(result);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
this._stats.failed++;
|
|
84
|
+
reject(err);
|
|
85
|
+
}
|
|
86
|
+
// Small throttle between tasks to avoid burst requests
|
|
87
|
+
if (this._queue.length > 0) {
|
|
88
|
+
await new Promise(r => setTimeout(r, this.options.minDelayMs));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this._running = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = AdvancedSystem;
|
|
Binary file
|
|
Binary file
|
package/checkUpdate.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const CURRENT_VERSION = "1.0.0";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Lightweight, non-blocking update check.
|
|
7
|
+
* Only runs once per process lifetime (guarded by global._alphaFcaUpdateChecked).
|
|
8
|
+
* Never blocks login or throws on failure.
|
|
9
|
+
*/
|
|
10
|
+
async function checkForFCAUpdate() {
|
|
11
|
+
try {
|
|
12
|
+
// Try to fetch latest version from npm registry (or GitHub)
|
|
13
|
+
const https = require("https");
|
|
14
|
+
const pkgUrl = "https://registry.npmjs.org/hridoy-ultimate/latest";
|
|
15
|
+
const data = await new Promise((resolve) => {
|
|
16
|
+
const req = https.get(pkgUrl, { timeout: 5000 }, (res) => {
|
|
17
|
+
let body = "";
|
|
18
|
+
res.on("data", (c) => { body += c; });
|
|
19
|
+
res.on("end", () => {
|
|
20
|
+
try { resolve(JSON.parse(body)); }
|
|
21
|
+
catch (_) { resolve(null); }
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
req.on("error", () => resolve(null));
|
|
25
|
+
req.on("timeout", () => { req.destroy(); resolve(null); });
|
|
26
|
+
});
|
|
27
|
+
if (data && data.version && data.version !== CURRENT_VERSION) {
|
|
28
|
+
const log = require("npmlog");
|
|
29
|
+
log.warn("alpha-fca", `Update available: v${CURRENT_VERSION} → v${data.version}`);
|
|
30
|
+
log.warn("alpha-fca", "Run: npm update alpha-fca");
|
|
31
|
+
}
|
|
32
|
+
} catch (_) {
|
|
33
|
+
// Silently ignore — update check must never crash the bot
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { checkForFCAUpdate, CURRENT_VERSION };
|
package/config.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
|
|
4
|
+
"automation": {
|
|
5
|
+
"enabled": false,
|
|
6
|
+
"comment": "Keep false. Background automation disabled by default for low-automation stable operation."
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
"inbox": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"comment": "Inbox/getThreadList is always active when true."
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
"smooth": {
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"messageDelay": 400,
|
|
17
|
+
"typingDelay": 600,
|
|
18
|
+
"comment": "Smooth mode: shows typing indicator before sending. Keep false to minimize automation."
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
"connection": {
|
|
22
|
+
"minDelayMs": 1000,
|
|
23
|
+
"maxDelayMs": 30000,
|
|
24
|
+
"comment": "Min/max reconnect delay in ms."
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
"e2ee": {
|
|
28
|
+
"enable": true,
|
|
29
|
+
"saveType": "memory",
|
|
30
|
+
"devicePath": "./data/e2ee-device.json",
|
|
31
|
+
"autoReconnect": true,
|
|
32
|
+
"logLevel": "none",
|
|
33
|
+
"comment": "Set enable:true to activate E2EE bridge. saveType: 'memory' (default, keys lost on restart) or 'path' (persistent). devicePath used only when saveType='path'."
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
"imgKeys": {
|
|
37
|
+
"imgbb": null,
|
|
38
|
+
"ik_pub": null,
|
|
39
|
+
"ik_priv": null,
|
|
40
|
+
"comment": "Optional image hosting keys. Leave null to skip image hosting features."
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
"enableTypingIndicator": false,
|
|
44
|
+
"typingDuration": 4000
|
|
45
|
+
}
|