nexus-fca 2.1.8 → 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 +40 -7
- package/README.md +23 -11
- package/docs/account-safety.md +22 -1
- package/index.js +13 -15
- package/lib/safety/FacebookSafety.js +177 -12
- package/lib/safety/FacebookSafetyManager.js +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [2.1.
|
|
3
|
+
## [2.1.10] - 2025-09-08 - Publish Meta Bump
|
|
4
4
|
### Changed
|
|
5
|
-
-
|
|
5
|
+
- Fixed Major Problems found in 2.1.9 and Its the last version of 2.1.xxx
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
-
|
|
9
|
-
|
|
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.
|
|
10
44
|
|
|
11
45
|
### Notes
|
|
12
|
-
-
|
|
46
|
+
- No public API break; users should remove custom light poke timers.
|
|
13
47
|
|
|
14
48
|
---
|
|
15
49
|
|
|
@@ -131,7 +165,6 @@ Stability-focused release improving long‑running bot sessions, reducing false
|
|
|
131
165
|
### Changed
|
|
132
166
|
- 🔁 `listenMqtt` now performs silent initial validation; only emits `not_logged_in` after a confirmatory retry
|
|
133
167
|
- 🧠 `parseAndCheckLogin` now robustly handles 3xx chains & HTML login fallback pages
|
|
134
|
-
- 🔐 Default behavior: device identity no longer rotates unless explicitly overridden
|
|
135
168
|
- 🧩 Refactored internal cookie & session utilities (centralized in `utils.js`)
|
|
136
169
|
- 📄 Rewritten documentation (README, DOCS, CHANGELOG) for concise modern onboarding
|
|
137
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
|
}
|
|
@@ -282,10 +293,12 @@ class FacebookSafety {
|
|
|
282
293
|
maxMs = 5 * 60 * 60 * 1000; // 5h
|
|
283
294
|
}
|
|
284
295
|
const interval = minMs + Math.random() * (maxMs - minMs);
|
|
285
|
-
|
|
296
|
+
const t = setTimeout(async () => {
|
|
286
297
|
await this.refreshSafeSession();
|
|
287
298
|
schedule();
|
|
288
299
|
}, interval);
|
|
300
|
+
this._registerTimer(t);
|
|
301
|
+
this._safeRefreshTimer = t;
|
|
289
302
|
};
|
|
290
303
|
schedule();
|
|
291
304
|
}
|
|
@@ -305,13 +318,17 @@ class FacebookSafety {
|
|
|
305
318
|
updateRiskLevel() {
|
|
306
319
|
const timeSinceLastActivity = Date.now() - this.sessionMetrics.lastActivity;
|
|
307
320
|
const errorRate = this.sessionMetrics.errorCount / Math.max(1, this.sessionMetrics.requestCount);
|
|
308
|
-
|
|
321
|
+
let next;
|
|
309
322
|
if (errorRate > 0.3 || timeSinceLastActivity < 1000) {
|
|
310
|
-
|
|
323
|
+
next = 'high';
|
|
311
324
|
} else if (errorRate > 0.1 || timeSinceLastActivity < 5000) {
|
|
312
|
-
|
|
325
|
+
next = 'medium';
|
|
313
326
|
} else {
|
|
314
|
-
|
|
327
|
+
next = 'low';
|
|
328
|
+
}
|
|
329
|
+
if (next !== this.sessionMetrics.riskLevel) {
|
|
330
|
+
this.sessionMetrics.riskLevel = next;
|
|
331
|
+
this._onRiskLevelChanged(next);
|
|
315
332
|
}
|
|
316
333
|
}
|
|
317
334
|
|
|
@@ -371,10 +388,7 @@ class FacebookSafety {
|
|
|
371
388
|
const now = Date.now();
|
|
372
389
|
if (now < this._backoff.next) { return; }
|
|
373
390
|
const attempt = ++this._backoff.attempt;
|
|
374
|
-
|
|
375
|
-
const baseDelay = Math.min(20000, 1200 * Math.pow(1.8, Math.min(attempt, 6)));
|
|
376
|
-
const jitter = Math.random() * 500;
|
|
377
|
-
const delay = baseDelay + jitter;
|
|
391
|
+
const delay = this._computeBackoffDelay(attempt);
|
|
378
392
|
this._backoff.next = now + delay;
|
|
379
393
|
await new Promise(r => setTimeout(r, delay));
|
|
380
394
|
if (this._activeListenerStop && typeof this._activeListenerStop === 'function') { try { this._activeListenerStop(); } catch(_) {} }
|
|
@@ -382,6 +396,7 @@ class FacebookSafety {
|
|
|
382
396
|
const stop = this.api.listenMqtt((err, event) => { if (!err && event) this.recordEvent(); });
|
|
383
397
|
this._activeListenerStop = stop;
|
|
384
398
|
this.safetyEmit('mqttReconnect', { success: true, reason, attempt, delay });
|
|
399
|
+
this._markHeavyMaintenance();
|
|
385
400
|
}
|
|
386
401
|
setTimeout(() => {
|
|
387
402
|
if (this.ctx && this.ctx.mqttClient && this.ctx.mqttClient.connected) { this._backoff.attempt = 0; }
|
|
@@ -405,11 +420,22 @@ class FacebookSafety {
|
|
|
405
420
|
const base = 6 * 60 * 60 * 1000; // 6h
|
|
406
421
|
const jitter = (Math.random() * 60 - 30) * 60 * 1000; // ±30m
|
|
407
422
|
const delay = base + jitter;
|
|
408
|
-
|
|
423
|
+
const t = setTimeout(() => {
|
|
409
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();
|
|
410
434
|
this.forceReconnect('periodic');
|
|
411
435
|
this._schedulePeriodicRecycle();
|
|
412
436
|
}, delay);
|
|
437
|
+
this._registerTimer(t);
|
|
438
|
+
this._periodicRecycleTimer = t;
|
|
413
439
|
}
|
|
414
440
|
|
|
415
441
|
// Heartbeat ping & watchdog
|
|
@@ -504,6 +530,10 @@ class FacebookSafety {
|
|
|
504
530
|
async refreshSafeSession() {
|
|
505
531
|
// Improved safe session refresh implementation
|
|
506
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
|
+
}
|
|
507
537
|
this._refreshing = true;
|
|
508
538
|
const refreshId = ++this._inFlightRefreshId;
|
|
509
539
|
const startedAt = Date.now();
|
|
@@ -532,6 +562,8 @@ class FacebookSafety {
|
|
|
532
562
|
durationMs: Date.now() - startedAt,
|
|
533
563
|
message: 'Session tokens refreshed'
|
|
534
564
|
});
|
|
565
|
+
this._lastRefreshTs = Date.now();
|
|
566
|
+
this._markHeavyMaintenance();
|
|
535
567
|
// Immediate MQTT health ensure
|
|
536
568
|
await this._ensureMqttAlive();
|
|
537
569
|
// Schedule layered post-refresh checks (1s, 10s, 30s) to catch silent drops
|
|
@@ -570,11 +602,51 @@ class FacebookSafety {
|
|
|
570
602
|
}
|
|
571
603
|
}
|
|
572
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
|
+
|
|
573
642
|
// Cleanup / destroy resources (to prevent dangling timers)
|
|
574
643
|
destroy() {
|
|
575
644
|
this._destroyed = true;
|
|
576
|
-
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];
|
|
577
646
|
timers.forEach(t => t && clearTimeout(t));
|
|
647
|
+
// Clear any registered anonymous timers
|
|
648
|
+
this._timerRegistry.forEach(t => clearTimeout(t));
|
|
649
|
+
this._timerRegistry.clear();
|
|
578
650
|
if (this._activeListenerStop) {
|
|
579
651
|
try { this._activeListenerStop(); } catch (_) {}
|
|
580
652
|
this._activeListenerStop = null;
|
|
@@ -622,6 +694,99 @@ class FacebookSafety {
|
|
|
622
694
|
}
|
|
623
695
|
}
|
|
624
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
|
+
|
|
625
790
|
/**
|
|
626
791
|
* Set safety event handler
|
|
627
792
|
*/
|
|
@@ -630,4 +795,4 @@ class FacebookSafety {
|
|
|
630
795
|
}
|
|
631
796
|
}
|
|
632
797
|
|
|
633
|
-
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": {
|