nexus-fca 2.1.7 → 2.1.10
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 +47 -1
- package/README.md +23 -11
- package/docs/account-safety.md +22 -1
- package/index.js +13 -15
- package/lib/safety/FacebookSafety.js +189 -19
- package/lib/safety/FacebookSafetyManager.js +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.10] - 2025-09-08 - Publish Meta Bump
|
|
4
|
+
### Changed
|
|
5
|
+
- Fixed Major Problems found in 2.1.9 and Its the last version of 2.1.xxx
|
|
6
|
+
|
|
7
|
+
### Notes
|
|
8
|
+
- 2.1.8 And 2.1.10 is the most stable verion!
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## [2.1.9] - 2025-09-08 - Advanced Stability Prep
|
|
13
|
+
### Added
|
|
14
|
+
- Dynamic risk-tier tuning: heartbeat interval, backoff delay, spacing guard adjust automatically on risk changes.
|
|
15
|
+
- Adaptive outbound pacing: micro-delays after heavy maintenance (refresh/reconnect) to reduce burst patterns (2m adaptive window).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Reconnect backoff now computed via risk-aware curve (faster recovery in high risk, quieter in low risk).
|
|
19
|
+
|
|
20
|
+
### Notes
|
|
21
|
+
- Optional, transparent; no API break. Can expose stats later via planned getSafetyTimingStats.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [2.1.8] - 2025-09-08 - Safety Consolidation & Collision Guard
|
|
26
|
+
### Added
|
|
27
|
+
- Unified safety orchestrator (single module coordinates safe refresh, light poke, periodic recycle) with timer registry and structured teardown.
|
|
28
|
+
- Collision spacing guard (45m) preventing clustered token operations (refresh/poke/recycle).
|
|
29
|
+
- Recycle suppression logic (defers 20–30m if a refresh/poke occurred inside spacing window).
|
|
30
|
+
- Light poke integration moved inside `FacebookSafety.scheduleLightPoke()` (duplicate inline scheduling removed).
|
|
31
|
+
- Deprecation warning emitted when legacy `FacebookSafetyManager` is instantiated.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- Removed duplicate mid-session poke timer from `index.js`.
|
|
35
|
+
- Safe refresh participates in collision guard and spacing tracking (`_lastRefreshTs`).
|
|
36
|
+
- Periodic recycle respects `_minSpacingMs` and defers if necessary.
|
|
37
|
+
|
|
38
|
+
### Improved
|
|
39
|
+
- Lower probability of rapid successive token / connection maintenance clustering.
|
|
40
|
+
- Simplified lifecycle cleanup through timer registry.
|
|
41
|
+
|
|
42
|
+
### Deprecated
|
|
43
|
+
- `FacebookSafetyManager` (legacy) – retained for backward compatibility only.
|
|
44
|
+
|
|
45
|
+
### Notes
|
|
46
|
+
- No public API break; users should remove custom light poke timers.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
3
50
|
## [2.1.7] - 2025-09-01 - Session Stability Patch
|
|
4
51
|
### Added
|
|
5
52
|
- User-Agent continuity (anchored single UA for entire session via safety module; eliminates mid-session UA drift increasing 20–22h expiry risk).
|
|
@@ -118,7 +165,6 @@ Stability-focused release improving long‑running bot sessions, reducing false
|
|
|
118
165
|
### Changed
|
|
119
166
|
- 🔁 `listenMqtt` now performs silent initial validation; only emits `not_logged_in` after a confirmatory retry
|
|
120
167
|
- 🧠 `parseAndCheckLogin` now robustly handles 3xx chains & HTML login fallback pages
|
|
121
|
-
- 🔐 Default behavior: device identity no longer rotates unless explicitly overridden
|
|
122
168
|
- 🧩 Refactored internal cookie & session utilities (centralized in `utils.js`)
|
|
123
169
|
- 📄 Rewritten documentation (README, DOCS, CHANGELOG) for concise modern onboarding
|
|
124
170
|
|
package/README.md
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
# Nexus-FCA v2.1.
|
|
1
|
+
# Nexus-FCA v2.1.10
|
|
2
|
+
<!-- 2.1.10 Safety Consolidation -->
|
|
3
|
+
>Fixed Major Problems found in 2.1.9 and Its the last version of 2.1.xxx
|
|
4
|
+
|
|
5
|
+
<!-- 2.1.9 Safety Consolidation -->
|
|
6
|
+
> New in 2.1.9: Safety Consolidation & Collision Guard – unified safety orchestrator (single scheduler for safe refresh, light poke, periodic recycle) + 45m spacing guard (prevents clustered token actions), timer registry cleanup, recycle suppression after recent refresh, deprecates legacy FacebookSafetyManager.
|
|
2
7
|
|
|
3
8
|
<!-- 2.1.7 Session Stability Patch -->
|
|
4
|
-
>
|
|
9
|
+
> 2.1.7: Session Stability Patch – anchored User-Agent continuity (eliminates 20–22h silent expiry pattern), lightweight mid‑session token poke (6h ±40m randomized) + existing adaptive safeRefresh, retains ultra‑low ban profile.
|
|
5
10
|
|
|
6
11
|
<!-- 2.1.6 Memory Guard -->
|
|
7
12
|
> 2.1.6: Memory Guard & Queue Sweeping – bounded group queues, pending edit TTL sweeper, memory metrics exporter.
|
|
@@ -21,16 +26,17 @@
|
|
|
21
26
|
- 🔐 Integrated secure login system (username/password + TOTP 2FA) → auto appstate
|
|
22
27
|
- 🛡️ Ultra-low ban rate design (human timing, safety limiter, anchored UA, risk heuristics)
|
|
23
28
|
- 🔄 Resilient MQTT listener (adaptive backoff + idle / ghost detection + periodic recycle)
|
|
24
|
-
- ♻️ Session continuity: anchored UA + adaptive safe refresh + lightweight mid-session poke
|
|
29
|
+
- ♻️ Session continuity: anchored UA + adaptive safe refresh + integrated lightweight mid-session poke
|
|
25
30
|
- 🧠 Smart session validation (lazy preflight, multi-endpoint retry, reduced false logouts)
|
|
26
31
|
- 📊 Live health & memory metrics (`api.getHealthMetrics()`, `api.getMemoryMetrics()`)
|
|
27
32
|
- 🧾 Type definitions (`index.d.ts`) & modern Promise / callback API
|
|
28
33
|
- 🧩 Modular architecture (safety, performance, error, mqtt managers)
|
|
29
34
|
|
|
30
35
|
---
|
|
31
|
-
## 🚀 Recent Stability Enhancements (2.1.7 / 2.1.6 / 2.1.5)
|
|
36
|
+
## 🚀 Recent Stability Enhancements (2.1.8 / 2.1.7 / 2.1.6 / 2.1.5)
|
|
32
37
|
| Version | Focus | Key Additions |
|
|
33
38
|
|---------|-------|---------------|
|
|
39
|
+
| 2.1.8 | Safety Consolidation | Unified orchestrator, collision spacing (45m), timer registry, recycle suppression, legacy manager deprecated |
|
|
34
40
|
| 2.1.7 | Session Longevity | UA continuity anchor, lightweight token poke, removal of mid-login UA drift |
|
|
35
41
|
| 2.1.6 | Memory Safety | Group queue idle purge + overflow trim, pendingEdits TTL sweeper, memory guard metrics |
|
|
36
42
|
| 2.1.5 | Edit Reliability | PendingEdits buffer (cap+TTL), ACK watchdog, resend limits, p95 ACK latency |
|
|
@@ -38,8 +44,8 @@
|
|
|
38
44
|
### Why UA Continuity Matters
|
|
39
45
|
Previously, dual-phase login could swap user agents (mobile → desktop) causing server-side heuristic expiry near 20–22h. Anchoring a single UA eliminates the inconsistent device fingerprint pattern and extends stable runtime under identical safety posture.
|
|
40
46
|
|
|
41
|
-
### Lightweight Mid-Session Poke
|
|
42
|
-
A subtle `fb_dtsg` refresh every ~6h ±40m
|
|
47
|
+
### Lightweight Mid-Session Poke (Integrated)
|
|
48
|
+
Originally introduced in 2.1.7, now centrally scheduled inside the unified safety orchestrator (no duplicate inline timers). A subtle `fb_dtsg` refresh every ~6h (±40m randomized, alongside adaptive risk-based safe refresh) keeps tokens warm without aggressive churn while avoiding noisy traffic patterns. Collision guard ensures it never triggers too close to a full safe refresh or periodic recycle.
|
|
43
49
|
|
|
44
50
|
---
|
|
45
51
|
## 🧪 Key API Additions
|
|
@@ -69,6 +75,7 @@ setInterval(() => {
|
|
|
69
75
|
3. Avoid changing UA manually; continuity is automatic post‑2.1.7.
|
|
70
76
|
4. Inspect health metrics before manually forcing reconnects.
|
|
71
77
|
5. Let adaptive backoff handle transient network instability.
|
|
78
|
+
6. Avoid using deprecated `FacebookSafetyManager`; the consolidated safety layer activates automatically when `login()` resolves.
|
|
72
79
|
|
|
73
80
|
---
|
|
74
81
|
## ⚡ Quick Start (Appstate)
|
|
@@ -103,18 +110,22 @@ const login = require('nexus-fca');
|
|
|
103
110
|
```
|
|
104
111
|
|
|
105
112
|
---
|
|
106
|
-
## 🛡️ Safety Layer (Updated)
|
|
113
|
+
## 🛡️ Safety Layer (Updated 2.1.8)
|
|
107
114
|
| Feature | Benefit |
|
|
108
115
|
|---------|---------|
|
|
109
116
|
| Anchored User-Agent | Eliminates fingerprint drift (prevents 20–22h expiry) |
|
|
110
|
-
|
|
|
111
|
-
|
|
|
117
|
+
| Unified Orchestrator | Single scheduler for refresh, light poke, recycle (no overlap clashes) |
|
|
118
|
+
| Adaptive Safe Refresh | Risk‑sensitive token renewal bands (multi‑hour low risk, shorter high risk) |
|
|
119
|
+
| Lightweight Token Poke | Quiet longevity without churn (integrated + collision guarded) |
|
|
112
120
|
| Idle / Ghost Detection | Auto probe + reconnect on silent stalls |
|
|
113
|
-
| Periodic Recycle | 6h ±
|
|
121
|
+
| Periodic Recycle | ~6h (±30m) randomized connection rejuvenation (suppressed if recent refresh) |
|
|
114
122
|
| Persistent Device Profile | Fewer checkpoints / trust continuity |
|
|
115
123
|
| Lazy Preflight | Skips heavy validation when recently healthy |
|
|
116
124
|
| Human-like Timing | Reduces automation signal surface |
|
|
117
125
|
|
|
126
|
+
### Consolidation / Collision Guard (2.1.8)
|
|
127
|
+
The unified safety module keeps a registry of all scheduled timers (safe refresh, light poke, post-refresh health checks, periodic recycle) and enforces a minimum 45 minute spacing window so heavy or light token actions never cluster. Legacy `FacebookSafetyManager` now only emits a deprecation warning and should not be instantiated going forward.
|
|
128
|
+
|
|
118
129
|
Disable preflight if needed:
|
|
119
130
|
```js
|
|
120
131
|
await login({ appState }, { disablePreflight: true });
|
|
@@ -216,7 +227,7 @@ const login = require('nexus-fca');
|
|
|
216
227
|
## 📚 Documentation
|
|
217
228
|
- Full API reference: `DOCS.md`
|
|
218
229
|
- Per-feature guides: `/docs/*.md`
|
|
219
|
-
- Safety: `docs/account-safety.md`
|
|
230
|
+
- Safety: `docs/account-safety.md` (unified orchestrator & deprecation note)
|
|
220
231
|
- Examples: `/examples`
|
|
221
232
|
|
|
222
233
|
---
|
|
@@ -224,6 +235,7 @@ const login = require('nexus-fca');
|
|
|
224
235
|
| Change | Action |
|
|
225
236
|
|--------|--------|
|
|
226
237
|
| UA Continuity (2.1.7) | No action; auto applied |
|
|
238
|
+
| Safety Consolidation (2.1.8) | Remove any manual timers/light poke code – handled internally |
|
|
227
239
|
| Memory Guard (2.1.6) | Inspect `api.getMemoryMetrics()` periodically |
|
|
228
240
|
| PendingEdits (2.1.5) | Tune via `api.setEditOptions()` if needed |
|
|
229
241
|
| Lazy Preflight | Optionally disable when embedding in other frameworks |
|
package/docs/account-safety.md
CHANGED
|
@@ -11,6 +11,8 @@ Nexus-FCA Ultra-Safe Edition is designed to minimize Facebook account ban, lock,
|
|
|
11
11
|
- **Proactive Safety Alerts:** If a risk is detected (lock, checkpoint, block), the bot will pause or stop to prevent further issues
|
|
12
12
|
- **Session & Token Management:** Automatic session validation and safe token refresh keep your login secure
|
|
13
13
|
- **Region & Connection Protection:** Advanced region bypass and safe reconnection logic avoid suspicious activity triggers
|
|
14
|
+
- **Unified Safety Orchestrator (2.1.8+):** Single scheduler coordinates safe refresh, light poke (~6h ±40m), and periodic recycle (~6h ±30m) with collision spacing (45m) to prevent clustered token actions
|
|
15
|
+
- **Ghost / Idle Detection:** Soft-stale probing (2m30s) and ghost recovery before full disconnect patterns emerge
|
|
14
16
|
|
|
15
17
|
---
|
|
16
18
|
|
|
@@ -24,6 +26,7 @@ Nexus-FCA Ultra-Safe Edition is designed to minimize Facebook account ban, lock,
|
|
|
24
26
|
- Always use cookies less than 7 days old for best results
|
|
25
27
|
- **Monitor Risk Level:**
|
|
26
28
|
- Listen for `riskLevelHigh`, `accountLocked`, `checkpointRequired` events and take action if triggered
|
|
29
|
+
- **Avoid Deprecated Manager:** Do not instantiate `FacebookSafetyManager` (legacy); consolidated `FacebookSafety` handles everything automatically.
|
|
27
30
|
|
|
28
31
|
---
|
|
29
32
|
|
|
@@ -34,6 +37,8 @@ Nexus-FCA Ultra-Safe Edition is designed to minimize Facebook account ban, lock,
|
|
|
34
37
|
- **Update your appstate.json regularly**
|
|
35
38
|
- **Monitor your Facebook account for security notifications**
|
|
36
39
|
- **If you see a checkpoint or lock, stop the bot and verify your account manually**
|
|
40
|
+
- **Do not schedule custom token poke timers; built‑in orchestrator already manages safe refresh cadence & spacing**
|
|
41
|
+
- **Keep `persistent-device.json` stable—don’t delete unless forced by actual session invalidation**
|
|
37
42
|
|
|
38
43
|
---
|
|
39
44
|
|
|
@@ -55,6 +60,13 @@ client.login({ appState: require('./appstate.json') });
|
|
|
55
60
|
- `checkpointRequired` — Facebook requires manual verification
|
|
56
61
|
- `riskLevelHigh` — High risk detected, bot will increase delays and reduce activity
|
|
57
62
|
- `sessionExpired` — Session expired, update your appstate.json
|
|
63
|
+
- `safeRefresh` — Safe token refresh attempted (payload includes success/failure, duration)
|
|
64
|
+
- `lightPoke` — Lightweight fb_dtsg keep-alive executed
|
|
65
|
+
- `mqttReconnect` — Reconnect cycle triggered (reason + attempt)
|
|
66
|
+
- `heartbeat` — Periodic keepalive ping succeeded
|
|
67
|
+
|
|
68
|
+
### Event Spacing (2.1.8+)
|
|
69
|
+
The orchestrator enforces a minimum spacing window (~45m) between maintenance actions (refresh, recycle, light poke). If a recycle is scheduled too soon after a refresh/poke it defers 20–30m automatically to avoid clustering patterns.
|
|
58
70
|
|
|
59
71
|
---
|
|
60
72
|
|
|
@@ -66,7 +78,16 @@ client.login({ appState: require('./appstate.json') });
|
|
|
66
78
|
> Stop the bot immediately, log in to Facebook manually, and follow the verification steps. Only restart the bot after your account is fully restored.
|
|
67
79
|
|
|
68
80
|
**Q: How often should I update my appstate.json?**
|
|
69
|
-
> At least once a week, or whenever you see a session expired or checkpoint event.
|
|
81
|
+
> At least once a week, or whenever you see a session expired or checkpoint event (less often if persistent device + long stable runs).
|
|
82
|
+
|
|
83
|
+
**Q: How often are tokens refreshed now?**
|
|
84
|
+
> Adaptive. Low risk uses multi‑hour windows; high risk shortens interval. Lightweight mid-session poke (~6h ±40m) and periodic recycle (~6h ±30m) are collision‑guarded with 45m spacing.
|
|
85
|
+
|
|
86
|
+
**Q: Do I need to keep my own refresh timers?**
|
|
87
|
+
> No. Remove custom refresh/poke loops—duplication increases clustering risk.
|
|
88
|
+
|
|
89
|
+
**Q: Is legacy `FacebookSafetyManager` still required?**
|
|
90
|
+
> No. It is deprecated and only logs a warning if used. Migrate entirely to the integrated safety layer (automatic on login).
|
|
70
91
|
|
|
71
92
|
---
|
|
72
93
|
|
package/index.js
CHANGED
|
@@ -296,6 +296,15 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
296
296
|
api[v.replace(".js", "")] = require("./src/" + v)(defaultFuncs, api, ctx);
|
|
297
297
|
});
|
|
298
298
|
api.listen = api.listenMqtt;
|
|
299
|
+
// Adaptive outbound pacing wrapper (dynamic risk + post-maintenance window)
|
|
300
|
+
if (!api._adaptivePacingWrapped && typeof api.sendMessage === 'function') {
|
|
301
|
+
const _origSend = api.sendMessage;
|
|
302
|
+
api.sendMessage = async function(message, threadID, callback){
|
|
303
|
+
try { if (globalSafety && typeof globalSafety.applyAdaptiveSendDelay === 'function') await globalSafety.applyAdaptiveSendDelay(); } catch(_) {}
|
|
304
|
+
return _origSend(message, threadID, callback);
|
|
305
|
+
};
|
|
306
|
+
api._adaptivePacingWrapped = true;
|
|
307
|
+
}
|
|
299
308
|
// Safety wrapper: ensure every inbound MQTT event updates safety lastEvent timestamp
|
|
300
309
|
if (!api._safetyWrappedListen) {
|
|
301
310
|
const _origListen = api.listenMqtt;
|
|
@@ -505,21 +514,10 @@ function loginHelper(appState, email, password, globalOptions, callback, prCallb
|
|
|
505
514
|
logger('✅ Session authenticated successfully', 'info');
|
|
506
515
|
// Initialize safety monitoring
|
|
507
516
|
globalSafety.startMonitoring(ctx, api);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const jitter = (Math.random()*80 - 40) * 60 * 1000; // ±40m
|
|
513
|
-
globalOptions._lightRefreshTimer = setTimeout(async () => {
|
|
514
|
-
try {
|
|
515
|
-
if(api && typeof api.refreshFb_dtsg === 'function'){
|
|
516
|
-
await api.refreshFb_dtsg().catch(()=>{});
|
|
517
|
-
}
|
|
518
|
-
} catch(_) {}
|
|
519
|
-
scheduleLight();
|
|
520
|
-
}, base + jitter);
|
|
521
|
-
};
|
|
522
|
-
scheduleLight();
|
|
517
|
+
try { globalSafety.startDynamicSystems(); } catch(_) {}
|
|
518
|
+
// Consolidated: delegate light poke to unified safety module (prevents duplicate refresh scheduling)
|
|
519
|
+
if (globalSafety && typeof globalSafety.scheduleLightPoke === 'function') {
|
|
520
|
+
globalSafety.scheduleLightPoke();
|
|
523
521
|
}
|
|
524
522
|
// Post-login identity banner
|
|
525
523
|
try {
|
|
@@ -76,6 +76,17 @@ class FacebookSafety {
|
|
|
76
76
|
this._ghostChecking = false;
|
|
77
77
|
// Periodic recycle timer
|
|
78
78
|
this._periodicRecycleTimer = null;
|
|
79
|
+
// Consolidation additions
|
|
80
|
+
this._lastRefreshTs = 0; // track last successful refresh-like action
|
|
81
|
+
this._lastRecycleTs = 0;
|
|
82
|
+
this._lastLightPokeTs = 0;
|
|
83
|
+
this._timerRegistry = new Set();
|
|
84
|
+
this._minSpacingMs = 45 * 60 * 1000; // 45m guard between heavy/light actions
|
|
85
|
+
// Adaptive pacing + dynamic tuning additions
|
|
86
|
+
this._lastHeavyMaintenanceTs = 0; // last refresh OR successful reconnect
|
|
87
|
+
this._adaptivePacingWindowMs = 2 * 60 * 1000; // apply outbound pacing first 2m after heavy maintenance
|
|
88
|
+
this._dynamicHeartbeatTimer = null; // replaces fixed interval heartbeat for risk-tier tuning
|
|
89
|
+
this._riskLast = 'low';
|
|
79
90
|
|
|
80
91
|
this.initSafety();
|
|
81
92
|
}
|
|
@@ -268,19 +279,26 @@ class FacebookSafety {
|
|
|
268
279
|
clearTimeout(this._safeRefreshTimer);
|
|
269
280
|
this._safeRefreshTimer = null;
|
|
270
281
|
}
|
|
271
|
-
//
|
|
272
|
-
// risk
|
|
282
|
+
// USER REQUEST: widen refresh window to random 3–5 hours (stealth longevity)
|
|
283
|
+
// Previous risk-tier windows (25–60m) replaced per instruction.
|
|
273
284
|
const schedule = () => {
|
|
274
285
|
if (this._destroyed) return;
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
// Base window 3h–5h. If risk escalates HIGH, clamp to 1h–1.5h for safety.
|
|
287
|
+
let minMs, maxMs;
|
|
288
|
+
if (this.sessionMetrics.riskLevel === 'high') {
|
|
289
|
+
minMs = 60 * 60 * 1000; // 1h
|
|
290
|
+
maxMs = 90 * 60 * 1000; // 1.5h
|
|
291
|
+
} else {
|
|
292
|
+
minMs = 3 * 60 * 60 * 1000; // 3h
|
|
293
|
+
maxMs = 5 * 60 * 60 * 1000; // 5h
|
|
294
|
+
}
|
|
295
|
+
const interval = minMs + Math.random() * (maxMs - minMs);
|
|
296
|
+
const t = setTimeout(async () => {
|
|
281
297
|
await this.refreshSafeSession();
|
|
282
298
|
schedule();
|
|
283
299
|
}, interval);
|
|
300
|
+
this._registerTimer(t);
|
|
301
|
+
this._safeRefreshTimer = t;
|
|
284
302
|
};
|
|
285
303
|
schedule();
|
|
286
304
|
}
|
|
@@ -300,13 +318,17 @@ class FacebookSafety {
|
|
|
300
318
|
updateRiskLevel() {
|
|
301
319
|
const timeSinceLastActivity = Date.now() - this.sessionMetrics.lastActivity;
|
|
302
320
|
const errorRate = this.sessionMetrics.errorCount / Math.max(1, this.sessionMetrics.requestCount);
|
|
303
|
-
|
|
321
|
+
let next;
|
|
304
322
|
if (errorRate > 0.3 || timeSinceLastActivity < 1000) {
|
|
305
|
-
|
|
323
|
+
next = 'high';
|
|
306
324
|
} else if (errorRate > 0.1 || timeSinceLastActivity < 5000) {
|
|
307
|
-
|
|
325
|
+
next = 'medium';
|
|
308
326
|
} else {
|
|
309
|
-
|
|
327
|
+
next = 'low';
|
|
328
|
+
}
|
|
329
|
+
if (next !== this.sessionMetrics.riskLevel) {
|
|
330
|
+
this.sessionMetrics.riskLevel = next;
|
|
331
|
+
this._onRiskLevelChanged(next);
|
|
310
332
|
}
|
|
311
333
|
}
|
|
312
334
|
|
|
@@ -366,10 +388,7 @@ class FacebookSafety {
|
|
|
366
388
|
const now = Date.now();
|
|
367
389
|
if (now < this._backoff.next) { return; }
|
|
368
390
|
const attempt = ++this._backoff.attempt;
|
|
369
|
-
|
|
370
|
-
const baseDelay = Math.min(20000, 1200 * Math.pow(1.8, Math.min(attempt, 6)));
|
|
371
|
-
const jitter = Math.random() * 500;
|
|
372
|
-
const delay = baseDelay + jitter;
|
|
391
|
+
const delay = this._computeBackoffDelay(attempt);
|
|
373
392
|
this._backoff.next = now + delay;
|
|
374
393
|
await new Promise(r => setTimeout(r, delay));
|
|
375
394
|
if (this._activeListenerStop && typeof this._activeListenerStop === 'function') { try { this._activeListenerStop(); } catch(_) {} }
|
|
@@ -377,6 +396,7 @@ class FacebookSafety {
|
|
|
377
396
|
const stop = this.api.listenMqtt((err, event) => { if (!err && event) this.recordEvent(); });
|
|
378
397
|
this._activeListenerStop = stop;
|
|
379
398
|
this.safetyEmit('mqttReconnect', { success: true, reason, attempt, delay });
|
|
399
|
+
this._markHeavyMaintenance();
|
|
380
400
|
}
|
|
381
401
|
setTimeout(() => {
|
|
382
402
|
if (this.ctx && this.ctx.mqttClient && this.ctx.mqttClient.connected) { this._backoff.attempt = 0; }
|
|
@@ -400,11 +420,22 @@ class FacebookSafety {
|
|
|
400
420
|
const base = 6 * 60 * 60 * 1000; // 6h
|
|
401
421
|
const jitter = (Math.random() * 60 - 30) * 60 * 1000; // ±30m
|
|
402
422
|
const delay = base + jitter;
|
|
403
|
-
|
|
423
|
+
const t = setTimeout(() => {
|
|
404
424
|
if (this._destroyed) return;
|
|
425
|
+
// Suppress recycle if a refresh/poke just happened inside spacing window
|
|
426
|
+
if (Date.now() - this._lastRefreshTs < this._minSpacingMs) {
|
|
427
|
+
// reschedule shorter backoff (add 20m) to avoid clustering
|
|
428
|
+
const defer = 20 * 60 * 1000 + Math.random() * 10 * 60 * 1000; // 20–30m
|
|
429
|
+
const dt = setTimeout(()=> this._schedulePeriodicRecycle(), defer);
|
|
430
|
+
this._registerTimer(dt);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
this._lastRecycleTs = Date.now();
|
|
405
434
|
this.forceReconnect('periodic');
|
|
406
435
|
this._schedulePeriodicRecycle();
|
|
407
436
|
}, delay);
|
|
437
|
+
this._registerTimer(t);
|
|
438
|
+
this._periodicRecycleTimer = t;
|
|
408
439
|
}
|
|
409
440
|
|
|
410
441
|
// Heartbeat ping & watchdog
|
|
@@ -499,6 +530,10 @@ class FacebookSafety {
|
|
|
499
530
|
async refreshSafeSession() {
|
|
500
531
|
// Improved safe session refresh implementation
|
|
501
532
|
if (this._refreshing) return; // prevent concurrent refreshes
|
|
533
|
+
// Collision guard – skip if a refresh/poke happened very recently
|
|
534
|
+
if (Date.now() - this._lastRefreshTs < this._minSpacingMs / 2) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
502
537
|
this._refreshing = true;
|
|
503
538
|
const refreshId = ++this._inFlightRefreshId;
|
|
504
539
|
const startedAt = Date.now();
|
|
@@ -527,6 +562,8 @@ class FacebookSafety {
|
|
|
527
562
|
durationMs: Date.now() - startedAt,
|
|
528
563
|
message: 'Session tokens refreshed'
|
|
529
564
|
});
|
|
565
|
+
this._lastRefreshTs = Date.now();
|
|
566
|
+
this._markHeavyMaintenance();
|
|
530
567
|
// Immediate MQTT health ensure
|
|
531
568
|
await this._ensureMqttAlive();
|
|
532
569
|
// Schedule layered post-refresh checks (1s, 10s, 30s) to catch silent drops
|
|
@@ -565,11 +602,51 @@ class FacebookSafety {
|
|
|
565
602
|
}
|
|
566
603
|
}
|
|
567
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Lightweight poke (fb_dtsg refresh only) integrated to remove duplicate logic in index.js
|
|
607
|
+
*/
|
|
608
|
+
scheduleLightPoke() {
|
|
609
|
+
if (this._lightPokeTimer || this._destroyed) return;
|
|
610
|
+
const base = 6 * 60 * 60 * 1000; // 6h
|
|
611
|
+
const jitter = (Math.random()*80 - 40) * 60 * 1000; // ±40m
|
|
612
|
+
const schedule = () => {
|
|
613
|
+
if (this._destroyed) return;
|
|
614
|
+
const t = setTimeout(async () => {
|
|
615
|
+
if (this._destroyed) return;
|
|
616
|
+
// Respect spacing: skip if recent heavy refresh
|
|
617
|
+
if (Date.now() - this._lastRefreshTs < this._minSpacingMs / 2) {
|
|
618
|
+
schedule();
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
try {
|
|
622
|
+
if (this.api && typeof this.api.refreshFb_dtsg === 'function') {
|
|
623
|
+
await this.api.refreshFb_dtsg().catch(()=>{});
|
|
624
|
+
this._lastRefreshTs = Date.now();
|
|
625
|
+
this._lastLightPokeTs = Date.now();
|
|
626
|
+
this.safetyEmit('lightPoke', { ts: Date.now() });
|
|
627
|
+
}
|
|
628
|
+
} catch(_) {}
|
|
629
|
+
schedule();
|
|
630
|
+
}, base + (Math.random()*80 - 40) * 60 * 1000);
|
|
631
|
+
this._registerTimer(t);
|
|
632
|
+
this._lightPokeTimer = t;
|
|
633
|
+
};
|
|
634
|
+
schedule();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
_registerTimer(t){
|
|
638
|
+
if (!t) return;
|
|
639
|
+
this._timerRegistry.add(t);
|
|
640
|
+
}
|
|
641
|
+
|
|
568
642
|
// Cleanup / destroy resources (to prevent dangling timers)
|
|
569
643
|
destroy() {
|
|
570
644
|
this._destroyed = true;
|
|
571
|
-
const timers = [this._safeRefreshInterval, this._safeRefreshTimer, this._heartbeatTimer, this._watchdogTimer, this._periodicRecycleTimer];
|
|
645
|
+
const timers = [this._safeRefreshInterval, this._safeRefreshTimer, this._heartbeatTimer, this._watchdogTimer, this._periodicRecycleTimer, this._lightPokeTimer];
|
|
572
646
|
timers.forEach(t => t && clearTimeout(t));
|
|
647
|
+
// Clear any registered anonymous timers
|
|
648
|
+
this._timerRegistry.forEach(t => clearTimeout(t));
|
|
649
|
+
this._timerRegistry.clear();
|
|
573
650
|
if (this._activeListenerStop) {
|
|
574
651
|
try { this._activeListenerStop(); } catch (_) {}
|
|
575
652
|
this._activeListenerStop = null;
|
|
@@ -617,6 +694,99 @@ class FacebookSafety {
|
|
|
617
694
|
}
|
|
618
695
|
}
|
|
619
696
|
|
|
697
|
+
/* ======================== Dynamic Tuning & Pacing ======================== */
|
|
698
|
+
_onRiskLevelChanged(risk){
|
|
699
|
+
// Adjust spacing guard slightly (high risk allow earlier refresh to recover)
|
|
700
|
+
if (risk === 'high') this._minSpacingMs = 30 * 60 * 1000; else this._minSpacingMs = 45 * 60 * 1000;
|
|
701
|
+
// Reschedule heartbeat dynamically
|
|
702
|
+
this._scheduleDynamicHeartbeat(true);
|
|
703
|
+
this.safetyEmit('riskLevelChanged', { risk });
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
_computeBackoffDelay(attempt){
|
|
707
|
+
const risk = this.sessionMetrics.riskLevel;
|
|
708
|
+
const a = Math.min(attempt, 6);
|
|
709
|
+
let base;
|
|
710
|
+
if (risk === 'high') {
|
|
711
|
+
base = 900 * Math.pow(1.6, a); // faster recovery
|
|
712
|
+
} else if (risk === 'medium') {
|
|
713
|
+
base = 1100 * Math.pow(1.7, a);
|
|
714
|
+
} else { // low
|
|
715
|
+
base = 1500 * Math.pow(1.9, a); // slower to reduce noise
|
|
716
|
+
}
|
|
717
|
+
const cap = (risk === 'low') ? 25000 : (risk === 'medium' ? 22000 : 18000);
|
|
718
|
+
const delay = Math.min(cap, base) + Math.random()*600; // jitter
|
|
719
|
+
return delay;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
_scheduleDynamicHeartbeat(reset){
|
|
723
|
+
if (reset && this._dynamicHeartbeatTimer){ clearTimeout(this._dynamicHeartbeatTimer); this._dynamicHeartbeatTimer = null; }
|
|
724
|
+
if (this._destroyed) return;
|
|
725
|
+
const interval = this._computeHeartbeatInterval();
|
|
726
|
+
this._dynamicHeartbeatTimer = setTimeout(()=>{
|
|
727
|
+
if (this._destroyed) return;
|
|
728
|
+
try {
|
|
729
|
+
if (this.ctx && this.ctx.mqttClient && this.ctx.mqttClient.connected) {
|
|
730
|
+
if (this.ctx.mqttClient.ping) this.ctx.mqttClient.ping();
|
|
731
|
+
try { this.ctx.mqttClient.publish('/foreground_state', JSON.stringify({ foreground: true })); } catch(_) {}
|
|
732
|
+
this.safetyEmit('heartbeat', { ts: Date.now(), dynamic: true });
|
|
733
|
+
}
|
|
734
|
+
} catch(_) {}
|
|
735
|
+
// Watchdog like check
|
|
736
|
+
this._runDynamicWatchdog();
|
|
737
|
+
this._scheduleDynamicHeartbeat(false);
|
|
738
|
+
}, interval);
|
|
739
|
+
this._registerTimer(this._dynamicHeartbeatTimer);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
_computeHeartbeatInterval(){
|
|
743
|
+
const risk = this.sessionMetrics.riskLevel;
|
|
744
|
+
if (risk === 'high') return (55 + Math.random()*20) * 1000; // 55–75s
|
|
745
|
+
if (risk === 'medium') return (70 + Math.random()*20) * 1000; // 70–90s
|
|
746
|
+
return (80 + Math.random()*20) * 1000; // 80–100s
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
_runDynamicWatchdog(){
|
|
750
|
+
const idle = Date.now() - this._lastEventTs;
|
|
751
|
+
// escalate thresholds slightly by risk (high risk shorter tolerance)
|
|
752
|
+
const hard = (this.sessionMetrics.riskLevel === 'high') ? 8*60*1000 : 12*60*1000;
|
|
753
|
+
if (idle > hard) {
|
|
754
|
+
this._backoff.attempt = 0;
|
|
755
|
+
this._ensureMqttAlive();
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
_markHeavyMaintenance(){
|
|
760
|
+
this._lastHeavyMaintenanceTs = Date.now();
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
computeAdaptiveSendDelay(){
|
|
764
|
+
const risk = this.sessionMetrics.riskLevel;
|
|
765
|
+
const since = Date.now() - this._lastHeavyMaintenanceTs;
|
|
766
|
+
const inWindow = since < this._adaptivePacingWindowMs;
|
|
767
|
+
let min=0, max=0;
|
|
768
|
+
if (inWindow){
|
|
769
|
+
if (risk === 'high'){ min=600; max=1500; }
|
|
770
|
+
else if (risk === 'medium'){ min=200; max=800; }
|
|
771
|
+
else { min=0; max=300; }
|
|
772
|
+
} else {
|
|
773
|
+
// outside pacing window only high risk adds mild delay
|
|
774
|
+
if (risk === 'high'){ min=150; max=600; }
|
|
775
|
+
}
|
|
776
|
+
if (max<=0) return 0;
|
|
777
|
+
return Math.floor(min + Math.random()*(max-min));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
applyAdaptiveSendDelay(){
|
|
781
|
+
const d = this.computeAdaptiveSendDelay();
|
|
782
|
+
if (!d) return Promise.resolve();
|
|
783
|
+
return new Promise(r=> setTimeout(r, d));
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
startDynamicSystems(){
|
|
787
|
+
this._scheduleDynamicHeartbeat(true);
|
|
788
|
+
}
|
|
789
|
+
|
|
620
790
|
/**
|
|
621
791
|
* Set safety event handler
|
|
622
792
|
*/
|
|
@@ -625,4 +795,4 @@ class FacebookSafety {
|
|
|
625
795
|
}
|
|
626
796
|
}
|
|
627
797
|
|
|
628
|
-
module.exports = FacebookSafety;
|
|
798
|
+
module.exports = FacebookSafety;
|
|
@@ -13,7 +13,8 @@ class FacebookSafetyManager extends EventEmitter {
|
|
|
13
13
|
constructor(options = {}) {
|
|
14
14
|
super();
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
console.warn('[DEPRECATION] FacebookSafetyManager is deprecated. The unified FacebookSafety module now handles all safety logic. Avoid using this manager.');
|
|
17
|
+
this.options = {
|
|
17
18
|
// Auto re-login detection
|
|
18
19
|
autoReloginEnabled: options.autoReloginEnabled !== false,
|
|
19
20
|
autoReloginRetries: options.autoReloginRetries || 3,
|
|
@@ -112,7 +113,7 @@ class FacebookSafetyManager extends EventEmitter {
|
|
|
112
113
|
this.startUserAgentRotation();
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
logger('🛡️ (Deprecated) Facebook Safety Manager initialized (prefer unified FacebookSafety)', 'info');
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-fca",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.10",
|
|
4
4
|
"description": "A modern, safe, and advanced Facebook Chat API for Node.js with fully integrated Nexus Login System. NPM-ready with ID/password/2FA support, ultra-low ban rate protection, and zero external dependencies.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|