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 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.7
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
- > New in 2.1.7: Session Stability Patch – anchored User-Agent continuity (eliminates 20–22h silent expiry pattern), lightweight mid‑session token poke (6h ±40m) + existing adaptive safeRefresh, retains ultra‑low ban profile.
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 (in addition to adaptive risk-based safeRefresh) keeps tokens warm without aggressive churn, lowering validation friction while avoiding noisy traffic patterns.
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
- | Adaptive Safe Refresh | Risk‑sensitive token renewal bands |
111
- | Lightweight Token Poke | Quiet longevity without churn |
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 ± jitter connection rejuvenation |
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 |
@@ -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
- // Schedule mid-session lightweight token poke (~ every 6h ±40m) to keep cookies warm
509
- if(!globalOptions._lightRefreshTimer){
510
- const scheduleLight = () => {
511
- const base = 6 * 60 * 60 * 1000; // 6h
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
- // Stealth+Resilient profile refresh policy:
272
- // risk low: 50-60m, medium: 40-50m, high: 25-35m (random inside band)
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
- let minM, maxM;
276
- if (this.sessionMetrics.riskLevel === 'high') { minM = 25; maxM = 35; }
277
- else if (this.sessionMetrics.riskLevel === 'medium') { minM = 40; maxM = 50; }
278
- else { minM = 50; maxM = 60; }
279
- const interval = (minM * 60 * 1000) + Math.random() * ((maxM - minM) * 60 * 1000);
280
- this._safeRefreshTimer = setTimeout(async () => {
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
- this.sessionMetrics.riskLevel = 'high';
323
+ next = 'high';
306
324
  } else if (errorRate > 0.1 || timeSinceLastActivity < 5000) {
307
- this.sessionMetrics.riskLevel = 'medium';
325
+ next = 'medium';
308
326
  } else {
309
- this.sessionMetrics.riskLevel = 'low';
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
- // Stealth backoff: 1.2s * 1.8^n capped ~20s, add jitter 0-500ms
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
- this._periodicRecycleTimer = setTimeout(() => {
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
- this.options = {
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
- logger('🛡️ Facebook Safety Manager initialized with maximum protection', 'info');
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.7",
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": {