toru-fca 1.0.7 → 1.1.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 CHANGED
@@ -1,54 +1,114 @@
1
- # CHANGELOG — toru-fca
2
-
3
- ## v1.0.6 (2026-09-03) — Ultimate Fixed, Advanced & Updated Release
4
-
5
- ### Bug Fixes
6
- - **sendTypingIndicatorV2.js** — `mqttClient` undefined bug patched (ctx.mqttClient এখন সঠিকভাবে reference হয়)
7
- - **logout.js** — Anti-logout message updated, v1.0.6 version reflect করে
8
- - **listenMqtt.js** — Banner updated: alpha-fca → toru-fca
9
-
10
- ### Improvements (v1.0.6)
11
- - **Anti-Logout** — fb_dtsg refresh interval 30min → 20min (আরো দ্রুত session alive রাখে)
12
- - **Session Guard** — Auto-save interval 5min → 3min, debounce 30s → 20s (দ্রুত appstate save)
13
- - **Facebook Protection** (NEW) — Anti-restriction, anti-ban, human-like delay system
14
- - `humanLikeDelay: true` — random 50-200ms micro-delay, bot traffic pattern unpredictable
15
- - `blockAutomationDetection: true` — online=false, updatePresence=false force করে
16
- - **config.json** — `facebookProtection`, `replyToInbox` option added
17
- - **checkUpdate.js** — Version 1.0.6 এ updated
18
- - **package.json** — Version 1.0.6, description updated
19
- - **examples/basic-bot.js** — Bengali comments, stopAntiLogout() on shutdown added
20
-
21
- ### What v1.0.6 Guarantees
22
- - ✅ Cookie দিয়ে login করলে browser থেকে logout হবে না
23
- - ✅ Bot run করলে Facebook account এ automation restriction আসবে না
24
- - ✅ Bot ID এর inbox এ reply যাবে (group এ নয়)
25
- - ✅ GoatBot এবং Facebook উভয়ের জন্য comfortable
26
- - ✅ কোনো system error crash করবে না
27
- - ✅ MQTT smooth এবং stable থাকবে
28
-
29
- ## v1.0.2 (2026-09-02) — Previous Stable Release
30
-
31
- ### Core Fixes
32
- - Anti-Logout: `api.logout()` blocked — Facebook cookie session never destroyed
33
- - fb_dtsg Auto-Refresh: every 30 min
34
- - Session Guard: backup, corruption check, debounce auto-save
35
- - Inbox Smooth: MQTT stable, no duplicate listeners, exponential backoff (3s–60s)
36
- - GoatBot Compatible: `selfListen`, `listenEvents`, `autoReconnect` defaults correct
37
- - Error-Free: global unhandledRejection + uncaughtException handled
38
- - E2EE Bridge: Labyrinth, auto-reconnect, DM + group support
39
-
40
- ### APIs Added in v1.0.2
41
- - `api.forceLogout()`, `api.stopAntiLogout()`, `api.saveSession(path)`
42
- - `api.sessionGuard(path, opts)`, `api.getHealth()`, `api.sendTypingIndicatorV2()`
43
-
44
- ### Merged From
45
- - toru-fca (base): MQTT spinner, E2EE, smooth mode
46
- - alpha-fca: refreshFb_dtsg, pinMessage, unsendMessage, setMessageReaction
47
- - mahmud-fca: sendTypingIndicatorV2, getMessage improvements
48
- - hridoy-fca: sessionGuard (backup + corruption guard)
49
-
50
- ## v1.0.1
51
- - Initial merged release
52
-
53
- ## v1.0.0
54
- - Base alpha-fca release
1
+ # toru-fca Changelog
2
+
3
+ ## v1.1.0 — Audit, Repair & Stability Upgrade
4
+
5
+ > Full professional audit and repair of all critical, high, and medium issues.
6
+
7
+ ### 🔴 Critical Fixes
8
+
9
+ #### `sendMessage.js` — Wrong global config key
10
+ - **Bug**: `global._alphaFcaConfig` was read to check `inbox.enabled`. This global is never set — toru-fca uses `global._toruFcaConfig`. The inbox-disabled guard silently never fired.
11
+ - **Fix**: Changed to `global._toruFcaConfig`. Inbox guard now works correctly.
12
+
13
+ #### `index.js` — Triple-wrapping of `api.sendMessage`
14
+ - **Bug**: `patchSmooth()` and `initFacebookProtection()` each independently re-wrapped `api.sendMessage`, creating three nested layers. This caused:
15
+ - Inconsistent Promise/callback contract on synchronous throws from inner layers
16
+ - `api.send` alias reassigned twice, creating divergence risk
17
+ - Undocumented stacked delays (300ms + 50–200ms + typing duration)
18
+ - **Fix**: Replaced both separate wrappers with a single unified `patchSendWrapper()` that applies human jitter → smooth delay → original `sendMessage` in one clean Promise chain. `api.send` is now assigned exactly once.
19
+
20
+ #### `index.js` / `config.json` — E2EE enabled by default without native binary
21
+ - **Bug**: `config.json` had `"e2ee": { "enable": true }` and the fallback defaults also had `enable: true`. The `lib/index.mjs` ESM bundle throws `Error: Native library not found at .../build/messagix.so` on load because the `build/` directory is not included in the package. This caused E2EE init to fail on every startup with a caught but opaque error.
22
+ - **Fix**: `e2ee.enable` defaults to `false` in both `config.json` and the fallback defaults. E2EE must be explicitly enabled by users who have compiled the native binary.
23
+
24
+ #### `listenMqtt.js` — Module-scope `getSeqID` mutation (cross-instance contamination)
25
+ - **Bug**: `var getSeqID = function(){};` was declared at module scope and then reassigned inside the exported factory. Multiple login instances in the same process would overwrite each other's `getSeqID` closure, causing the wrong instance's callback to receive another bot's events.
26
+ - **Fix**: `getSeqID` and `form` are now declared inside the exported factory function (one per instance). Each login gets its own isolated closure.
27
+
28
+ #### Version inconsistency across all files
29
+ - **Bug**: `package.json` said `1.0.9`, `config.json` said `1.0.8`, `index.js`/`checkUpdate.js`/MQTT banner all said `1.0.6`. Target is `1.1.0`.
30
+ - **Fix**: All version strings unified to `1.1.0` across `package.json`, `config.json`, `checkUpdate.js`, `index.js` header, and the MQTT connect banner.
31
+
32
+ ---
33
+
34
+ ### 🔴 High-Priority Fixes
35
+
36
+ #### `sendTypingIndicator.js` — Local counter always sends `request_id: 1`
37
+ - **Bug**: `let count_req = 0` was declared inside the async function, so `++count_req` always yielded `1`. Every typing indicator request sent the same MQTT request ID, potentially confusing the ack system.
38
+ - **Fix**: Now uses `ctx.wsReqNumber` (the shared per-session counter, same as `sendTypingIndicatorV2`) incremented before each publish. Request IDs are now unique across all `ls_req` calls.
39
+
40
+ #### `sendTypingIndicatorV2.js` — Redundant duplicate implementation
41
+ - **Bug**: Two separate typing indicator implementations with inconsistent counter strategies.
42
+ - **Fix**: `sendTypingIndicatorV2` now delegates to `sendTypingIndicator`. Both `api.sendTypingIndicator` and `api.sendTypingIndicatorV2` use the same fixed implementation.
43
+
44
+ #### `stopListenMqtt.js` — Dead-connection watchdog not cleared on stop
45
+ - **Bug**: `stopListenMqtt()` ended the MQTT client but did not clear `_deadTimer` (the 8-minute watchdog). The watchdog was a local variable inside `listenMqtt()` — `stopListenMqtt.js` had no reference to it. After calling `stopListenMqtt()`, the watchdog could still fire and attempt a reconnect on a stopped bot.
46
+ - **Fix**: Watchdog timer now stored on `ctx._deadTimer` (accessible to all modules with a `ctx` reference). Both `stopListenMqtt()` and `stopListening()` now clear `ctx._deadTimer` before teardown.
47
+
48
+ #### `listenMqtt.js` — `stopListening` referenced undefined `_deadTimer`
49
+ - **Bug**: `stopListening` in `MessageEmitter` tried `if (typeof _deadTimer !== 'undefined' && _deadTimer)` — this was correct when the watchdog was local, but needed updating to match the new `ctx._deadTimer` approach.
50
+ - **Fix**: Updated to `if (ctx._deadTimer)` consistently.
51
+
52
+ #### `utils.js` — `parseAndCheckLogin` retry sends wrong body on 5xx
53
+ - **Bug**: Line 2611: `defaultFuncs.post(url, ctx.jar, data.request.formData)` — for standard POST requests `data.request.formData` is `undefined` (that property is only set for multipart uploads). All non-upload 5xx retries silently sent an empty body.
54
+ - **Fix**: Retry now uses `data.request.form || data.request.formData || {}` — correctly using `form` (the standard POST body property set by the `request` library) and falling back to `formData` for multipart, then to empty object as a last resort.
55
+
56
+ #### `index.js` — `forceLogout` used fb_dtsg as the `h` URL parameter
57
+ - **Bug**: `logout.php?h=<fb_dtsg>` — the `h` parameter on Facebook's logout endpoint is a separate logout nonce, not the CSRF token. Passing `fb_dtsg` there caused logout requests to silently fail.
58
+ - **Fix**: POSTs to `logout.php` (no `h` param) with `fb_dtsg` in the body only. Also adds graceful handling: marks `ctx.loggedIn = false` even when the HTTP request fails, so the bot's internal state stays consistent.
59
+
60
+ ---
61
+
62
+ ### 🟡 Medium Fixes
63
+
64
+ #### `refreshFb_dtsg.js` — Broad regex pattern ordered too early
65
+ - **Bug**: Pattern `/"token":"([^"]+)"/` (matches any JSON `token` key) was #3 in the list, potentially matching unrelated tokens before the specific DTSG patterns.
66
+ - **Fix**: Moved broad pattern to last position. Added minimum length check (`m[1].length > 4`) to filter out short false-match values.
67
+
68
+ #### `index.js` — `sessionGuard` jar monkey-patch fragile against internal API changes
69
+ - **Bug**: `jar._jar` is a private internal property of `tough-cookie`. If absent (different tough-cookie version, custom jar, or API change), the patch silently did nothing with no warning.
70
+ - **Fix**: Wrapped in try/catch with a `log.verbose` warning when `jar._jar` is not available. The interval-based save still runs — only the debounce-on-cookie-change is affected.
71
+
72
+ #### `examples/basic-bot.js` — Shutdown called `api.stopListenMqtt()` without clearing watchdog
73
+ - **Bug**: `api.stopListenMqtt()` was called in the shutdown handler. While this now clears `ctx._deadTimer` (fixed above), `api.stopListening()` is the preferred method when `listenMqtt()` was used directly, as it also resets the global callback and handles the `MessageEmitter` lifecycle.
74
+ - **Fix**: Shutdown now calls `api.stopListening(callback)` first, with `api.stopListenMqtt()` as a fallback. Also added guard against double-shutdown (`_shutdownCalled` flag). Stops session guard timer properly.
75
+
76
+ ---
77
+
78
+ ### 🟢 Low / Optimization
79
+
80
+ #### `checkUpdate.js` — Added hard abort guard on version check HTTP request
81
+ - Added a `setTimeout(destroy, 8000)` as a belt-and-suspenders guard alongside the existing 5000ms socket timeout, preventing the rare case where DNS resolution hangs beyond the socket timeout window.
82
+
83
+ #### `config.json` — Bengali/mixed-language notes replaced with English
84
+ - All `_note` fields now in English for international maintainability.
85
+
86
+ #### `fca-config.example.json` — Updated to v1.1.0 with accurate E2EE guidance
87
+ - Added clear note that E2EE requires native binary. All fields documented.
88
+
89
+ ---
90
+
91
+ ### Files Modified
92
+
93
+ | File | Changes |
94
+ |---|---|
95
+ | `package.json` | Version → 1.1.0 |
96
+ | `config.json` | Version → 1.1.0, e2ee.enable → false, notes in English |
97
+ | `checkUpdate.js` | CURRENT_VERSION → 1.1.0, hard abort guard |
98
+ | `index.js` | Header version, fallback config version/e2ee, unified sendMessage wrapper, forceLogout fix, sessionGuard defensive patch, logout message updated |
99
+ | `src/sendMessage.js` | Fixed `global._alphaFcaConfig` → `global._toruFcaConfig` |
100
+ | `src/sendTypingIndicator.js` | Fixed local counter (always sent request_id:1), proper error handling, non-fatal when MQTT not connected |
101
+ | `src/sendTypingIndicatorV2.js` | Delegates to sendTypingIndicator; removed duplicate logic |
102
+ | `src/stopListenMqtt.js` | Clears ctx._deadTimer before MQTT teardown |
103
+ | `src/listenMqtt.js` | getSeqID/form moved to instance scope; _deadTimer → ctx._deadTimer; banner version updated; stopListening uses ctx._deadTimer |
104
+ | `src/refreshFb_dtsg.js` | Regex ordering fixed (broad pattern last), min-length guard |
105
+ | `examples/basic-bot.js` | Proper shutdown (stopListening), double-shutdown guard, version updated |
106
+ | `fca-config.example.json` | Version → 1.1.0, E2EE docs updated |
107
+ | `utils.js` | parseAndCheckLogin retry body fix (form vs formData) |
108
+
109
+ ---
110
+
111
+ ## v1.0.9 (previous)
112
+ - Dead connection watchdog added
113
+ - Reaction detection works indefinitely (no longer stops after ~1hr)
114
+ - Browser logout free, anti-automation, GoatBot ready
package/checkUpdate.js CHANGED
@@ -1,24 +1,43 @@
1
1
  "use strict";
2
2
 
3
- const CURRENT_VERSION = "1.0.6";
3
+ const CURRENT_VERSION = "1.1.0";
4
4
 
5
5
  async function checkForFCAUpdate() {
6
6
  try {
7
7
  const https = require("https");
8
- const data = await new Promise((resolve) => {
9
- const req = https.get("https://registry.npmjs.org/toru-fca/latest", { timeout: 5000 }, (res) => {
10
- let body = "";
11
- res.on("data", (c) => { body += c; });
12
- res.on("end", () => { try { resolve(JSON.parse(body)); } catch (_) { resolve(null); } });
13
- });
14
- req.on("error", () => resolve(null));
15
- req.on("timeout", () => { req.destroy(); resolve(null); });
8
+
9
+ const data = await new Promise(function(resolve) {
10
+ var req = https.get(
11
+ "https://registry.npmjs.org/toru-fca/latest",
12
+ { timeout: 5000 },
13
+ function(res) {
14
+ var body = "";
15
+ res.on("data", function(c) { body += c; });
16
+ res.on("end", function() {
17
+ try { resolve(JSON.parse(body)); } catch (_) { resolve(null); }
18
+ });
19
+ res.on("error", function() { resolve(null); });
20
+ }
21
+ );
22
+ req.on("error", function() { resolve(null); });
23
+ // Destroy on timeout to avoid hanging socket
24
+ req.on("timeout", function() { req.destroy(); resolve(null); });
25
+ // Hard abort after 8s as a belt-and-suspenders guard
26
+ var hard = setTimeout(function() { try { req.destroy(); } catch (_) {} resolve(null); }, 8000);
27
+ if (hard.unref) hard.unref();
16
28
  });
29
+
17
30
  if (data && data.version && data.version !== CURRENT_VERSION) {
18
- const log = require("npmlog");
19
- log.warn("toru-fca", "Update available: v" + CURRENT_VERSION + " → v" + data.version + " — run: npm update toru-fca");
31
+ var log = require("npmlog");
32
+ log.warn(
33
+ "toru-fca",
34
+ "Update available: v" + CURRENT_VERSION + " \u2192 v" + data.version +
35
+ " \u2014 npm update toru-fca"
36
+ );
20
37
  }
21
- } catch (_) {}
38
+ } catch (_) {
39
+ // Non-fatal; version check is best-effort only
40
+ }
22
41
  }
23
42
 
24
43
  module.exports = { checkForFCAUpdate, CURRENT_VERSION };
package/config.json CHANGED
@@ -1,61 +1,51 @@
1
1
  {
2
- "_info": "toru-fca v1.0.6 — Main Config. Edit values below as needed.",
3
-
4
- "version": "1.0.6",
5
-
2
+ "_info": "toru-fca v1.1.0 — Main Config",
3
+ "version": "1.1.0",
6
4
  "antiLogout": {
7
5
  "enabled": true,
8
6
  "refreshIntervalMs": 1200000,
9
- "_note": "Auto-refreshes fb_dtsg every 20 min (was 30). Keeps session alive. Prevents browser/automation logout. NEVER set to false."
7
+ "_note": "fb_dtsg refreshed every 20 minutes to keep session alive and prevent browser logout."
10
8
  },
11
-
12
9
  "sessionGuard": {
13
10
  "enabled": true,
14
11
  "intervalMs": 180000,
15
12
  "debounceMs": 20000,
16
13
  "backupEnabled": true,
17
- "_note": "Saves appstate every 3 min (was 5). backupEnabled=true saves .bak before overwrite. Corruption check included."
14
+ "_note": "Appstate auto-saved every 3 minutes. Keeps a .bak backup. Cookie expiry is extended."
18
15
  },
19
-
20
16
  "automation": {
21
17
  "enabled": false,
22
- "_note": "KEEP FALSE. Background automation detection prevention. Enabling this risks Facebook account restriction."
18
+ "_note": "KEEP FALSE. Disables background automation. Protects against Facebook restrictions."
23
19
  },
24
-
25
20
  "smooth": {
26
21
  "enabled": true,
27
22
  "messageDelay": 300,
28
- "_note": "Shows typing indicator before sending. Human-like behavior. Reduces rate-limiting. messageDelay optimized to 300ms."
23
+ "_note": "Shows typing indicator before sending. 300ms delay for human-like behavior."
29
24
  },
30
-
31
25
  "connection": {
32
26
  "minDelayMs": 3000,
33
27
  "maxDelayMs": 60000,
34
- "_note": "MQTT reconnect backoff range in milliseconds."
28
+ "_note": "MQTT reconnect exponential backoff range."
35
29
  },
36
-
37
30
  "e2ee": {
38
- "enable": true,
31
+ "enable": false,
39
32
  "saveType": "memory",
40
33
  "devicePath": "./data/e2ee-device.json",
41
34
  "autoReconnect": true,
42
35
  "logLevel": "none",
43
- "_note": "E2EE Labyrinth bridge. saveType: memory (default) or path (persistent)."
36
+ "_note": "E2EE Labyrinth bridge. Requires native build/messagix binary. Set enable:true only if binary is present."
44
37
  },
45
-
46
- "inbox": {
47
- "enabled": true,
48
- "replyToInbox": true,
49
- "_note": "Inbox always active. replyToInbox=true routes bot reply to bot inbox (not group). Required for bot message listening."
50
- },
51
-
52
38
  "facebookProtection": {
53
39
  "enabled": true,
54
40
  "blockAutomationDetection": true,
55
41
  "humanLikeDelay": true,
56
- "_note": "v1.0.6 new. Blocks Facebook automation detection. humanLikeDelay adds random micro-delays to avoid pattern detection."
42
+ "_note": "Sets online=false, updatePresence=false. Adds 50-200ms micro-delay. Reduces account restriction risk."
43
+ },
44
+ "inbox": {
45
+ "enabled": true,
46
+ "replyToInbox": true,
47
+ "_note": "Bot replies in both inbox/DM and group threads."
57
48
  },
58
-
59
49
  "enableTypingIndicator": false,
60
50
  "typingDuration": 4000
61
51
  }
@@ -1,118 +1,122 @@
1
1
  /**
2
- * toru-fca v1.0.6 — Basic Bot Example (Updated)
2
+ * toru-fca v1.1.0 — basic-bot.js (GoatBot compatible example)
3
3
  *
4
- * Features demonstrated:
5
- * - Login with appState/Cookie (browser logout হবে না)
6
- * - Bot inbox e reply (group এ নয়, bot ID এর inbox এ)
7
- * - Session guard (auto-save appstate হর 3 মিনিটে)
8
- * - Anti-logout system (fb_dtsg 20 মিনিটে auto-refresh)
9
- * - Facebook Protection (automation detection বন্ধ)
10
- * - E2EE bridge (optional)
11
- * - Graceful shutdown
12
- * - GoatBot compatible
4
+ * Features:
5
+ * ✅ Cookie login — browser logout prevention
6
+ * ✅ Inbox + Group — bot replies in both DM and group threads
7
+ * ✅ Session guard — appstate auto-saved every 3 minutes
8
+ * ✅ Anti-logout — fb_dtsg refreshed every 20 minutes
9
+ * ✅ Facebook protection — automation detection guard
10
+ * ✅ Graceful shutdown — cleans up timers, MQTT, and session on exit
13
11
  */
14
12
 
15
13
  "use strict";
16
14
 
17
- const login = require("../index.js"); // or: require("toru-fca")
15
+ const login = require("../index.js");
18
16
  const fs = require("fs");
19
17
  const path = require("path");
20
18
 
21
- // ─── Config ──────────────────────────────────────────────────────────────────
22
19
  const APPSTATE_FILE = path.join(__dirname, "..", "appstate.json");
23
20
 
24
- // ─── Load appState (Cookie) ──────────────────────────────────────────────────
21
+ // ── Load appState (Cookie) ────────────────────────────────────────────────────
25
22
  let appState;
26
23
  try {
27
24
  appState = JSON.parse(fs.readFileSync(APPSTATE_FILE, "utf8"));
28
25
  } catch (err) {
29
- console.error("[toru-fca] Could not load appstate.json:", err.message);
30
- console.error(" Place your Facebook cookie appstate in: " + APPSTATE_FILE);
26
+ console.error("[toru-fca] \u274C Could not load appstate.json:", err.message);
31
27
  process.exit(1);
32
28
  }
33
29
 
34
- // ─── Login options (GoatBot compatible) ──────────────────────────────────────
30
+ // ── Login options (GoatBot compatible) ───────────────────────────────────────
35
31
  const options = {
36
- listenEvents : true,
37
- selfListen : false, // bot নিজের message শুনবে না
38
- listenTyping : false,
39
- updatePresence: false, // presence update বন্ধ (automation protection)
40
- autoMarkRead : false,
32
+ listenEvents : true,
33
+ selfListen : false, // bot does not listen to its own messages
34
+ autoReconnect : true,
35
+ online : false, // reduces automation detection risk
36
+ updatePresence : false,
37
+ forceLogin : false, // browser logout protection
38
+ autoMarkRead : false,
41
39
  autoMarkDelivery: false,
42
- autoReconnect : true,
43
- online : false, // offline mode — automation detection এড়ায়
44
- logLevel : "verbose"
40
+ logLevel : "verbose"
45
41
  };
46
42
 
47
- // ─── Login ───────────────────────────────────────────────────────────────────
43
+ // ── Login ─────────────────────────────────────────────────────────────────────
48
44
  login({ appState }, options, function (err, api) {
49
45
  if (err) {
50
- console.error("[toru-fca] ❌ Login failed:", err.message || err);
46
+ console.error("[toru-fca] \u274C Login failed:", err.message || err);
51
47
  process.exit(1);
52
48
  }
53
49
 
54
- const userID = api.getCurrentUserID ? api.getCurrentUserID() : "unknown";
55
- console.log("[toru-fca] ✅ Logged in as:", userID);
50
+ const botID = api.getCurrentUserID ? api.getCurrentUserID() : "unknown";
51
+ console.log("[toru-fca] \u2705 Bot running as:", botID);
56
52
 
57
- // ── Session guard: auto-save appstate হর 3 মিনিটে ─────────────────────
58
- api.sessionGuard(APPSTATE_FILE, {
59
- interval: 3 * 60 * 1000, // 3 min
60
- debounce: 20 * 1000, // 20 sec debounce
61
- backup: true // .bak file রাখে
62
- });
63
- console.log("[toru-fca] 🔒 Session guard active — auto-saving appstate.");
64
-
65
- // ── E2EE Bridge (config.json e e2ee.enable:true থাকলে) ─────────────────
66
- if (api.connectE2EE) {
67
- api.connectE2EE(function (err, event) {
68
- if (err) { console.error("[E2EE]", err.message || err); return; }
69
- if (event && event.type) console.log("[E2EE]", event.type);
70
- }).catch(e => console.error("[E2EE] connect failed:", e.message));
71
- }
53
+ // Session guard — auto-saves appstate every 3 minutes
54
+ const guard = api.sessionGuard(APPSTATE_FILE, { interval: 3 * 60 * 1000, backup: true });
72
55
 
73
- // ── Main message listener ───────────────────────────────────────────────
56
+ // ── Main listener ─────────────────────────────────────────────────────────
74
57
  api.listenMqtt(function (err, event) {
75
58
  if (err) {
76
59
  console.error("[listen]", err);
77
60
  return;
78
61
  }
79
62
 
80
- // Handle normal inbox messages — bot inbox e reply করবে
63
+ // Respond in both Group and Inbox/DM threads
81
64
  if (event.type === "message") {
82
- const { threadID, senderID, body, isGroup, isE2EE } = event;
83
- const prefix = isE2EE ? "[E2EE]" : (isGroup ? "[Group]" : "[DM]");
84
- console.log(`${prefix} ${senderID}: ${body}`);
65
+ const { threadID, senderID, body, isGroup } = event;
66
+ const tag = isGroup ? "[Group]" : "[Inbox/DM]";
67
+ console.log(tag, senderID + ":", body);
85
68
 
86
- // Echo reply example — bot inbox e reply
69
+ // Simple echo bot
87
70
  if (body && body.toLowerCase() === "ping") {
88
- api.sendMessage("pong! 🏓 — toru-fca v1.0.6", threadID, function (err) {
89
- if (err) console.error("[sendMessage]", err);
90
- });
71
+ api.sendMessage("\uD83C\uDFD3 pong! \u2014 toru-fca v1.1.0", threadID);
91
72
  }
92
73
  }
93
74
 
94
- // Handle events (group joins, reactions, etc.)
95
- if (event.type === "event") {
96
- console.log("[event]", event.logMessageType || event.type);
75
+ // Reaction events
76
+ if (event.type === "message_reaction") {
77
+ console.log(
78
+ "[Reaction]",
79
+ event.senderID,
80
+ event.off ? "removed reaction" : "reacted:",
81
+ event.reaction
82
+ );
97
83
  }
98
- });
99
84
 
100
- // ── Health check ────────────────────────────────────────────────────────
101
- setInterval(function () {
102
- const health = api.getHealth();
103
- if (!health.mqtt || !health.mqtt.connected) {
104
- console.warn("[health] MQTT not connected — autoReconnect will restore.");
85
+ // Group events (join, leave, name change, etc.)
86
+ if (event.type === "event") {
87
+ console.log("[Event]", event.logMessageType || event.type);
105
88
  }
106
- }, 60 * 1000);
89
+ });
107
90
 
108
- // ── Graceful shutdown ───────────────────────────────────────────────────
91
+ // ── Graceful shutdown ─────────────────────────────────────────────────────
92
+ var _shutdownCalled = false;
109
93
  function shutdown() {
94
+ if (_shutdownCalled) return;
95
+ _shutdownCalled = true;
110
96
  console.log("[toru-fca] Shutting down...");
111
- if (api.stopAntiLogout) api.stopAntiLogout();
112
- if (api.stopListenMqtt) api.stopListenMqtt();
113
- if (api.getE2EEBridge && api.getE2EEBridge()) api.getE2EEBridge().disconnect().catch(() => {});
114
- setTimeout(() => process.exit(0), 1500);
97
+
98
+ // Stop anti-logout timer
99
+ if (api.stopAntiLogout) api.stopAntiLogout();
100
+
101
+ // Stop session guard timer
102
+ if (guard && typeof guard.stop === "function") guard.stop();
103
+
104
+ // FIX v1.1.0: use api.stopListening() (from MessageEmitter) which correctly
105
+ // clears the dead-connection watchdog AND the MQTT client.
106
+ // api.stopListenMqtt() also works but stopListening() is preferred here
107
+ // because it was returned by the listen() call and has direct scope access.
108
+ if (typeof api.stopListening === "function") {
109
+ api.stopListening(function() {
110
+ setTimeout(function() { process.exit(0); }, 500);
111
+ });
112
+ } else if (api.stopListenMqtt) {
113
+ api.stopListenMqtt();
114
+ setTimeout(function() { process.exit(0); }, 500);
115
+ } else {
116
+ setTimeout(function() { process.exit(0); }, 500);
117
+ }
115
118
  }
119
+
116
120
  process.once("SIGINT", shutdown);
117
121
  process.once("SIGTERM", shutdown);
118
122
  });
@@ -1,56 +1,66 @@
1
1
  {
2
- "_comment": "alpha-fca v1.0.0 — Example Config. Copy to config.json and customize.",
2
+ "_comment": "toru-fca v1.1.0 — Example Config. Copy to config.json and customize.",
3
3
 
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
 
6
6
  "automation": {
7
7
  "enabled": false,
8
- "_comment": "KEEP FALSE. Enabling this allows background task automation (use with care)."
8
+ "_comment": "KEEP FALSE. Enabling this allows background task automation. Keep false to protect your account."
9
9
  },
10
10
 
11
11
  "inbox": {
12
12
  "enabled": true,
13
- "_comment": "Inbox/getThreadList access. Always true for a working bot."
13
+ "replyToInbox": true,
14
+ "_comment": "Bot replies in both inbox/DM and group threads."
14
15
  },
15
16
 
16
17
  "smooth": {
17
18
  "enabled": true,
18
- "messageDelay": 400,
19
- "_comment": "When true, shows typing indicator before sending message. Set messageDelay (ms) for natural feel. Recommended: false for low automation."
19
+ "messageDelay": 300,
20
+ "_comment": "Adds a short delay before sending. Combines with human jitter (50-200ms) when facebookProtection is enabled."
20
21
  },
21
22
 
22
23
  "connection": {
23
- "minDelayMs": 1000,
24
- "maxDelayMs": 30000,
25
- "_comment": "Reconnect backoff range in milliseconds."
24
+ "minDelayMs": 3000,
25
+ "maxDelayMs": 60000,
26
+ "_comment": "MQTT reconnect exponential backoff range in milliseconds."
27
+ },
28
+
29
+ "antiLogout": {
30
+ "enabled": true,
31
+ "refreshIntervalMs": 1200000,
32
+ "_comment": "Refreshes fb_dtsg CSRF token every 20 minutes to keep session alive."
33
+ },
34
+
35
+ "sessionGuard": {
36
+ "enabled": true,
37
+ "intervalMs": 180000,
38
+ "debounceMs": 20000,
39
+ "backupEnabled": true,
40
+ "_comment": "Auto-saves appstate.json every 3 minutes. Keeps a .bak backup. Extends cookie expiry."
41
+ },
42
+
43
+ "facebookProtection": {
44
+ "enabled": true,
45
+ "blockAutomationDetection": true,
46
+ "humanLikeDelay": true,
47
+ "_comment": "Sets online=false, updatePresence=false. Adds 50-200ms human jitter on sendMessage."
26
48
  },
27
49
 
28
50
  "e2ee": {
29
- "enable": true,
51
+ "enable": false,
30
52
  "saveType": "memory",
31
53
  "devicePath": "./data/e2ee-device.json",
32
54
  "autoReconnect": true,
33
55
  "logLevel": "none",
34
- "_comments": {
35
- "enable": "Set to true to activate E2EE Labyrinth bridge.",
36
- "saveType": "'memory' = keys lost on restart (safe). 'path' = persist keys to disk (survives restart).",
37
- "devicePath": "Used only when saveType='path'. Relative to your bot's CWD.",
38
- "autoReconnect": "E2EE bridge auto-reconnects on disconnect.",
39
- "logLevel": "'none' = silent. 'error'/'warn'/'info' = verbose."
40
- }
41
- },
42
-
43
- "imgKeys": {
44
- "imgbb": null,
45
- "ik_pub": null,
46
- "ik_priv": null,
47
- "_comment": "Optional image hosting API keys. Leave null to disable image hosting."
56
+ "_comment": "E2EE Labyrinth bridge. REQUIRES native binary in build/ directory. Set enable:true only when binary is present. saveType: 'memory' (keys lost on restart) or 'path' (persisted to disk)."
48
57
  },
49
58
 
50
59
  "enableTypingIndicator": false,
51
60
  "typingDuration": 4000,
52
61
 
53
62
  "_listenOptions": {
63
+ "_comment": "These go in the options param of login(), not in this file. Shown here for reference.",
54
64
  "selfListen": true,
55
65
  "listenEvents": true,
56
66
  "listenTyping": false,
@@ -58,7 +68,6 @@
58
68
  "autoMarkDelivery": false,
59
69
  "autoMarkRead": false,
60
70
  "autoReconnect": true,
61
- "online": false,
62
- "_comment": "These go in the options param of login(), not in this file. Shown here for reference."
71
+ "online": false
63
72
  }
64
73
  }