nexus-fca 2.1.10 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -226
- package/README.md +112 -182
- package/index.js +1 -0
- package/lib/health/HealthMetrics.js +12 -0
- package/lib/mqtt/MqttDiagnostics.js +20 -0
- package/package.json +2 -2
- package/src/listenMqtt.js +26 -7
- package/src/markAsDelivered.js +54 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,235 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
## [3.0.0] - 2025-09-11 - Advanced Core Release
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
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.
|
|
4
|
+
### Overview
|
|
5
|
+
Version 3.0.0 represents a pivotal milestone in the evolution of the Nexus-fCA platform, transitioning from the iterative stabilization efforts of the 2.1.x series to a unified, production-ready foundation. This release is the culmination of extensive engineering, rigorous validation, and a commitment to delivering enterprise-grade reliability. The legacy diagnostics harness has been formally retired, replaced by a standardized internal instrumentation framework that streamlines monitoring, troubleshooting, and ongoing maintenance. These enhancements collectively reinforce the platform’s robustness, scalability, and operational transparency.
|
|
44
6
|
|
|
45
|
-
### Notes
|
|
46
|
-
- No public API break; users should remove custom light poke timers.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## [2.1.7] - 2025-09-01 - Session Stability Patch
|
|
51
7
|
### Added
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
8
|
+
- **Delivery Receipt Health Metrics:** Introduced a comprehensive suite of metrics for delivery receipts, encompassing attempt counts, success rates, failure rates, timeout tracking, and adaptive disablement flags. These metrics provide granular visibility into delivery performance and facilitate proactive issue resolution.
|
|
9
|
+
- **Advanced Timeout Suppression Logic:** Implemented sophisticated suppression mechanisms for repeated delivery timeouts. This ensures consistent reply performance, mitigates the risk of systemic degradation, and enhances overall service reliability.
|
|
10
|
+
- **Internal Instrumentation Standardization:** All diagnostic and monitoring capabilities have been consolidated under a unified instrumentation framework, simplifying maintenance and enabling more effective root cause analysis.
|
|
55
11
|
|
|
56
12
|
### Changed
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
### Improved
|
|
61
|
-
- Extended resilience against 20–22h cookie invalidation observed with prior dual-phase UA pattern.
|
|
62
|
-
- Reduced unnecessary full refresh churn while preserving stealth (`safeRefresh` + light poke coexist).
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## [2.1.6] - 2025-08-31 - Memory Guard & Queue Sweeping
|
|
67
|
-
### Added
|
|
68
|
-
- Central lightweight memory guard sweeps: group queue pruning (idle >30m, overflow trim) and pendingEdits TTL sweeper (every 4m).
|
|
69
|
-
- Health metrics extended: memoryGuardRuns, memoryGuardActions, groupQueueDroppedMessages, groupQueueExpiredQueues, groupQueuePrunedThreads, pendingEditSweeps.
|
|
70
|
-
- API: `api.getMemoryMetrics()` returns focused memory-related counters.
|
|
71
|
-
- Typings updated (`EditOptions`, new API methods) in `index.d.ts`.
|
|
72
|
-
|
|
73
|
-
### Improved
|
|
74
|
-
- Group queue now tracks `lastActive` and enforces idle purge + overflow protection with metrics.
|
|
75
|
-
- Pending edits TTL enforcement separated from resend watchdog for deterministic expiry.
|
|
13
|
+
- **Documentation and Package Description:** The package description and README have undergone a comprehensive revision to align with professional standards and accurately reflect the platform’s positioning, capabilities, and intended use cases.
|
|
14
|
+
- **Semantic Versioning:** The major version increment to 3.0.0 signifies the platform’s maturity, stability, and readiness for mission-critical deployments. Importantly, there are no breaking changes to public APIs compared to the 2.1.x series, ensuring continuity for existing integrations.
|
|
76
15
|
|
|
77
16
|
### Notes
|
|
78
|
-
- All
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## [2.1.5] - 2025-08-28 - PendingEdits & ACK Metrics
|
|
83
|
-
### Added
|
|
84
|
-
- PendingEdits buffer with cap (default 200) + TTL (5m) + resend attempts (2) + ACK timeout (12s).
|
|
85
|
-
- Automatic edit resend watchdog with safe limits and metrics (editResends, editFailed, pendingEditsDropped, pendingEditsExpired).
|
|
86
|
-
- API: `api.setEditOptions({ maxPendingEdits, editTTLms, ackTimeoutMs, maxResendAttempts })`.
|
|
87
|
-
- Edit ACK integration: pending edit removed on ACK receipt.
|
|
88
|
-
- Health metrics: p95AckLatencyMs, editResends, editFailed.
|
|
89
|
-
|
|
90
|
-
### Improved
|
|
91
|
-
- Safer edit pipeline: prevents uncontrolled retries, bounds memory, tracks expirations.
|
|
92
|
-
- Enhanced HealthMetrics with percentile latency sample retention (50-sample window).
|
|
93
|
-
|
|
94
|
-
### Notes
|
|
95
|
-
- Durable outbound queue & metrics exporter planned next.
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
## [2.1.4] - Adaptive Backoff & Core Metrics
|
|
100
|
-
### Added
|
|
101
|
-
- Adaptive reconnect backoff with jitter (caps at 5 minutes) for safer, stealthier recovery loops.
|
|
102
|
-
- Lazy preflight session validation (skips heavy validation if a recent successful connect occurred) toggle via `api.enableLazyPreflight()`.
|
|
103
|
-
- Health metrics collector (uptime, idle time, reconnect counts, failures, message/ack counters, synthetic keepalives) accessible with `api.getHealthMetrics()` and included in `api.healthCheck()`.
|
|
104
|
-
- Randomized synthetic keepalive interval (55-75s) to reduce detection patterns.
|
|
105
|
-
- Backoff configuration hook: `api.setBackoffOptions()`.
|
|
106
|
-
|
|
107
|
-
### Improved
|
|
108
|
-
- Reduced noisy session validation on every `listenMqtt` invocation unless needed.
|
|
109
|
-
- More structured error classification feeding metrics (`session_invalid`, `timeout_no_t_ms`, `mqtt_error`, `message_parse`, `not_logged_in`).
|
|
110
|
-
|
|
111
|
-
### Planned (Next)
|
|
112
|
-
- ACK tracking refinement & resend logic.
|
|
113
|
-
- Pending edits buffer with TTL and cap.
|
|
114
|
-
- Durable outbound queue & health exporter.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## [2.1.2] - CONTINUOUS IDLE RECOVERY
|
|
119
|
-
### Added
|
|
120
|
-
- Soft-stale probing at 2 minutes idle (ping + conditional forced reconnect if no events within 5-8s)
|
|
121
|
-
- Wrapper around `listenMqtt` to automatically feed events into safety heartbeat (`recordEvent`) for precise idle detection
|
|
122
|
-
- Ghost connection detection (10m silent but socket connected triggers forced reconnect after probe)
|
|
123
|
-
- Periodic connection recycle every ~6h ±30m to prevent long-lived silent degradation
|
|
124
|
-
- Force reconnect API: `globalSafety.forceReconnect(tag)`
|
|
125
|
-
|
|
126
|
-
### Improved
|
|
127
|
-
- Faster recovery from silent idle states (previously required >5 min or external trigger)
|
|
128
|
-
- Reduced chance of appearing online but unresponsive after short inactivity
|
|
129
|
-
- Added keepalive foreground_state publishes each heartbeat
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## [2.1.1] - 2025-08-27 - ADVANCED SESSION STABILITY
|
|
134
|
-
### 🛠 Added
|
|
135
|
-
- Adaptive safe session refresh interval (dynamic based on risk level)
|
|
136
|
-
- Heartbeat + watchdog timers to detect stale MQTT connections early
|
|
137
|
-
- Progressive backoff with jitter for MQTT reconnect attempts
|
|
138
|
-
- Layered post-refresh health checks (1s / 10s / 30s) to catch silent drops
|
|
139
|
-
- Abortable refresh with timeout safeguard (25s) to prevent hangs
|
|
140
|
-
- Automatic reconnection trigger if no events within thresholds (2m soft, 15m hard)
|
|
141
|
-
- `destroy()` method to cleanup timers/listeners (prevents memory leaks)
|
|
142
|
-
|
|
143
|
-
### 🔄 Changed
|
|
144
|
-
- Safe refresh now records in‑flight ID and supersedes outdated checks
|
|
145
|
-
- Reconnect logic centralized in `_reconnectMqttWithBackoff`
|
|
146
|
-
|
|
147
|
-
### ✅ Improved
|
|
148
|
-
- Stability after long runtimes / multiple token refresh cycles
|
|
149
|
-
- Reduced risk of listener not resuming after refresh
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## [2.1.0] - 2025-08-20 - SESSION RELIABILITY & PROMISE LOGIN
|
|
154
|
-
### 🚀 Highlights
|
|
155
|
-
Stability-focused release improving long‑running bot sessions, reducing false `not_logged_in` events, and modernizing the login flow.
|
|
156
|
-
|
|
157
|
-
### Added
|
|
158
|
-
- ✅ Promise support for `login()` (dual callback + Promise API)
|
|
159
|
-
- 🆔 Persistent device fingerprint (saved to `persistent-device.json`) to reduce checkpoint / lock frequency
|
|
160
|
-
- 🛡️ New `validateSession()` multi-endpoint heuristic (lightweight, resilient preflight)
|
|
161
|
-
- ⚙️ New global option: `disablePreflight` (skip session validation if desired)
|
|
162
|
-
- 🔄 Structured error types from `parseAndCheckLogin` (`login_redirect`, `html_login_page`, `network_redirect`, etc.)
|
|
163
|
-
- 🧪 Example: `examples/echo-test.js` (Promise style, supports env credentials or appstate)
|
|
164
|
-
|
|
165
|
-
### Changed
|
|
166
|
-
- 🔁 `listenMqtt` now performs silent initial validation; only emits `not_logged_in` after a confirmatory retry
|
|
167
|
-
- 🧠 `parseAndCheckLogin` now robustly handles 3xx chains & HTML login fallback pages
|
|
168
|
-
- 🧩 Refactored internal cookie & session utilities (centralized in `utils.js`)
|
|
169
|
-
- 📄 Rewritten documentation (README, DOCS, CHANGELOG) for concise modern onboarding
|
|
170
|
-
|
|
171
|
-
### Fixed
|
|
172
|
-
- ❌ Spurious `parseAndCheckLogin got status code: 302` fatal errors now classified & recovered when possible
|
|
173
|
-
- 💤 False negatives from legacy preflight removed (no premature `not_logged_in` during transient redirects)
|
|
174
|
-
- 🔄 Edge reconnect loop where MQTT closed before revalidation completed
|
|
175
|
-
|
|
176
|
-
### Migration Notes (2.0.x → 2.1.0)
|
|
177
|
-
- Existing code using callbacks continues to work. To use Promises: `const api = await login(opts);`
|
|
178
|
-
- If you previously depended on device rotation, disable persistent device via option (see README) or delete `persistent-device.json`.
|
|
179
|
-
- Remove any custom preflight hacks; built‑in `validateSession` supersedes them.
|
|
180
|
-
|
|
181
|
-
### Developer / Internal
|
|
182
|
-
- Centralized session validation pipeline
|
|
183
|
-
- Added granular error classification to aid future retry/backoff strategies
|
|
184
|
-
- Prepared foundation for upcoming metrics hooks in 2.2.x
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## [2.0.5] - 2025-07-29 - FULLY INTEGRATED NPM EDITION
|
|
189
|
-
### 🎯 MAJOR: Full NPM Integration
|
|
190
|
-
- **✅ FULLY INTEGRATED**: Entire Nexus Login System now embedded directly in main `index.js`
|
|
191
|
-
- **📦 NPM COMPATIBLE**: Works perfectly when installed via `npm install nexus-fca` - no external folder dependencies
|
|
192
|
-
- **⚡ ZERO CONFIG**: Everything works out of the box - no separate folder setup required
|
|
193
|
-
- **🔄 SEAMLESS MIGRATION**: Existing code continues to work, new code benefits from integration
|
|
194
|
-
|
|
195
|
-
### Added
|
|
196
|
-
- 🎯 **Direct exports**: `nexusLogin` and `IntegratedNexusLoginSystem` available directly from main package
|
|
197
|
-
- 🧪 **Updated test files**: All test scripts now use integrated system (`require('nexus-fca')` instead of `./nexloginsystem`)
|
|
198
|
-
- 📖 **New documentation**: `npm-integration-guide.md` with complete NPM usage guide
|
|
199
|
-
- 🛠️ **NPM scripts**: Added `test:login`, `test:simple`, `test:2fa`, `test:all` for easy testing
|
|
200
|
-
- 📦 **Enhanced package.json**: Updated keywords, description, and version for NPM integration
|
|
201
|
-
|
|
202
|
-
### Changed
|
|
203
|
-
- 🏗️ **Architecture**: Moved entire Nexus Login System from external folder into main index.js (lines 372-860+)
|
|
204
|
-
- 📝 **Documentation**: Updated README.md to reflect NPM installation and integrated usage
|
|
205
|
-
- 🔧 **Test files**: Fixed all test imports to use main package instead of external folder
|
|
206
|
-
- 📦 **Package info**: Updated to v2.0.5 with new description highlighting NPM integration
|
|
207
|
-
|
|
208
|
-
### Fixed
|
|
209
|
-
- ❌ **NPM module errors**: Eliminated "Cannot find module './nexloginsystem'" when using as npm package
|
|
210
|
-
- 🔗 **Import paths**: All test files and examples now use correct import paths for npm usage
|
|
211
|
-
- 🎯 **Distribution**: Package now works identically whether used locally or installed via npm
|
|
212
|
-
|
|
213
|
-
## [2.0.4] - 2025-07-29
|
|
214
|
-
### Fixed
|
|
215
|
-
- 🐛 **Missing nexloginsystem folder**: Added `nexloginsystem/` to npm package files array to fix "Cannot find module './nexloginsystem'" error
|
|
216
|
-
- 🔄 **Legacy login fallback**: Added automatic fallback to appstate-only login when Nexus Login System is not available
|
|
217
|
-
- 🛡️ **Backward compatibility**: Enhanced compatibility for users using nexus-fca as npm dependency without full login system
|
|
218
|
-
|
|
219
|
-
### Changed
|
|
220
|
-
- Updated package.json to include nexloginsystem folder in published package
|
|
221
|
-
- Enhanced error handling with graceful fallback mechanisms
|
|
222
|
-
|
|
223
|
-
## [2.0.1] - 2025-07-28
|
|
224
|
-
### Added
|
|
225
|
-
- 🚀 **Nexus Login System**: Advanced, safe, and automatic Facebook login system added under `/nexloginsystem`.
|
|
226
|
-
- 🔐 **Appstate auto-generation**: Login with username/password/2FA, auto-save appstate, and seamless bot start.
|
|
227
|
-
- 🛡️ **Maximum safety**: Human-like device simulation, TOTP/2FA support, and advanced error handling.
|
|
228
|
-
- 📦 **Auto-backup & validation**: Appstate backup, validation, and lifecycle management.
|
|
229
|
-
- 📚 **Full documentation**: Usage, API, and safety docs in `/nexloginsystem/README.md`.
|
|
230
|
-
|
|
231
|
-
### Changed
|
|
232
|
-
- Updated main `README.md` with Nexus Login System quick start and features.
|
|
17
|
+
- **Upgrade Path:** Transitioning from 2.1.x to 3.0.0 is seamless. All documented interfaces remain unchanged, and the upgrade process requires no code modifications for existing consumers. The major version bump reflects strategic lifecycle consolidation and a renewed focus on long-term maintainability, rather than disruptive changes.
|
|
18
|
+
- **Lifecycle Consolidation:** This release unifies prior stabilization efforts, setting a new baseline for future enhancements and support. Users can expect ongoing improvements in reliability, observability, and operational efficiency.
|
|
233
19
|
|
|
234
|
-
###
|
|
235
|
-
|
|
20
|
+
### Historical Logs
|
|
21
|
+
Version logs for the 2.1.x series have been archived and are available upon request for reference and audit purposes.
|
package/README.md
CHANGED
|
@@ -1,84 +1,30 @@
|
|
|
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.
|
|
7
|
-
|
|
8
|
-
<!-- 2.1.7 Session Stability Patch -->
|
|
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.
|
|
10
|
-
|
|
11
|
-
<!-- 2.1.6 Memory Guard -->
|
|
12
|
-
> 2.1.6: Memory Guard & Queue Sweeping – bounded group queues, pending edit TTL sweeper, memory metrics exporter.
|
|
13
|
-
|
|
14
|
-
<!-- 2.1.5 PendingEdits -->
|
|
15
|
-
> 2.1.5: PendingEdits buffer (cap + TTL + safe resend), edit ACK watchdog, p95 ACK latency & edit resend/failure metrics, configurable via `api.setEditOptions()`.
|
|
16
|
-
|
|
17
1
|
<p align="center">
|
|
18
|
-
|
|
19
|
-
<a href="https://ibb.co/8ymR1tw"><img src="https://i.ibb.co/Sk61FGg/Dragon-Fruit-1.jpg" alt="Nexus-FCA Dragon Fruit" width="520" border="0" /></a>
|
|
2
|
+
<img src="https://i.ibb.co/Sk61FGg/Dragon-Fruit-1.jpg" alt="Nexus-FCA" width="520" />
|
|
20
3
|
</p>
|
|
21
4
|
|
|
22
|
-
|
|
5
|
+
# Nexus-FCA v3.0.0 – Advanced Core Release
|
|
23
6
|
|
|
24
|
-
|
|
25
|
-
## ✨ Highlights (Core Pillars)
|
|
26
|
-
- 🔐 Integrated secure login system (username/password + TOTP 2FA) → auto appstate
|
|
27
|
-
- 🛡️ Ultra-low ban rate design (human timing, safety limiter, anchored UA, risk heuristics)
|
|
28
|
-
- 🔄 Resilient MQTT listener (adaptive backoff + idle / ghost detection + periodic recycle)
|
|
29
|
-
- ♻️ Session continuity: anchored UA + adaptive safe refresh + integrated lightweight mid-session poke
|
|
30
|
-
- 🧠 Smart session validation (lazy preflight, multi-endpoint retry, reduced false logouts)
|
|
31
|
-
- 📊 Live health & memory metrics (`api.getHealthMetrics()`, `api.getMemoryMetrics()`)
|
|
32
|
-
- 🧾 Type definitions (`index.d.ts`) & modern Promise / callback API
|
|
33
|
-
- 🧩 Modular architecture (safety, performance, error, mqtt managers)
|
|
7
|
+
Modern, safe, production‑ready Messenger (Facebook Chat) API layer with integrated secure login (credentials + 2FA), adaptive session & connection resilience, delivery reliability safeguards, memory protection, and rich runtime metrics. Promise + callback compatible, TypeScript typed, minimal friction.
|
|
34
8
|
|
|
35
9
|
---
|
|
36
|
-
##
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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.
|
|
10
|
+
## ✅ Core Value
|
|
11
|
+
| Pillar | What You Get |
|
|
12
|
+
|--------|--------------|
|
|
13
|
+
| Integrated Secure Login | Username / Password / TOTP 2FA → stable appstate generation & reuse |
|
|
14
|
+
| Session Resilience | Anchored User‑Agent continuity, adaptive safe refresh, lightweight token poke, periodic recycle |
|
|
15
|
+
| Connection Stability | Adaptive MQTT backoff, idle & ghost detection, layered post-refresh health probes, synthetic keepalives |
|
|
16
|
+
| Delivery Reliability | Multi-path message send fallback (MQTT → HTTP → direct) + delivery receipt timeout suppression |
|
|
17
|
+
| Memory Guard | Bounded queues, edit TTL sweeps, controlled resend limits |
|
|
18
|
+
| Observability | Health + memory + delivery metrics (`api.getHealthMetrics()`, `api.getMemoryMetrics()`) |
|
|
19
|
+
| Edit Safety | Pending edit buffer, ACK watchdog, p95 ACK latency tracking |
|
|
20
|
+
| Type Definitions | First-class `index.d.ts` with modern Promise signatures |
|
|
49
21
|
|
|
50
22
|
---
|
|
51
|
-
##
|
|
52
|
-
|
|
53
|
-
api.setEditOptions({ maxPendingEdits, editTTLms, ackTimeoutMs, maxResendAttempts });
|
|
54
|
-
api.setBackoffOptions({ base, factor, max, jitter });
|
|
55
|
-
api.enableLazyPreflight(true); // Skip heavy validation if a recent good connect exists
|
|
56
|
-
api.getHealthMetrics(); // uptime, reconnect stats, ack latency, synthetic keepalives
|
|
57
|
-
api.getMemoryMetrics(); // queue depths, drops, guard run counters
|
|
58
|
-
```
|
|
23
|
+
## 🔄 What Changed in 3.0.0
|
|
24
|
+
Major version signals maturity & consolidation. No breaking public API changes versus late 2.1.x – upgrade is drop‑in. Temporary diagnostic harness removed; internal instrumentation formalized. Delivery receipt timeouts now intelligently retried & optionally auto-suppressed to protect outbound responsiveness.
|
|
59
25
|
|
|
60
26
|
---
|
|
61
|
-
##
|
|
62
|
-
```js
|
|
63
|
-
setInterval(() => {
|
|
64
|
-
const h = api.getHealthMetrics();
|
|
65
|
-
const m = api.getMemoryMetrics();
|
|
66
|
-
console.log('[HEALTH]', h?.status, 'acks', h?.ackCount, 'p95Ack', h?.p95AckLatencyMs);
|
|
67
|
-
console.log('[MEM]', m);
|
|
68
|
-
}, 60000);
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
## 🧷 Long Session Best Practices
|
|
73
|
-
1. Use appstate login when possible (avoid frequent credential logins).
|
|
74
|
-
2. Keep `persistent-device.json` – do not rotate unless forced.
|
|
75
|
-
3. Avoid changing UA manually; continuity is automatic post‑2.1.7.
|
|
76
|
-
4. Inspect health metrics before manually forcing reconnects.
|
|
77
|
-
5. Let adaptive backoff handle transient network instability.
|
|
78
|
-
6. Avoid using deprecated `FacebookSafetyManager`; the consolidated safety layer activates automatically when `login()` resolves.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
## ⚡ Quick Start (Appstate)
|
|
27
|
+
## 🚀 Quick Start (Appstate Preferred)
|
|
82
28
|
```js
|
|
83
29
|
const login = require('nexus-fca');
|
|
84
30
|
|
|
@@ -92,15 +38,14 @@ const login = require('nexus-fca');
|
|
|
92
38
|
})();
|
|
93
39
|
```
|
|
94
40
|
|
|
95
|
-
|
|
41
|
+
### Credentials + 2FA Flow
|
|
96
42
|
```js
|
|
97
43
|
const login = require('nexus-fca');
|
|
98
|
-
|
|
99
44
|
(async () => {
|
|
100
45
|
const api = await login({
|
|
101
46
|
email: process.env.FB_EMAIL,
|
|
102
47
|
password: process.env.FB_PASS,
|
|
103
|
-
twofactor: process.env.FB_2FA_SECRET // optional
|
|
48
|
+
twofactor: process.env.FB_2FA_SECRET // optional TOTP secret
|
|
104
49
|
});
|
|
105
50
|
api.listen((err, msg) => {
|
|
106
51
|
if (err) return console.error(err);
|
|
@@ -110,147 +55,132 @@ const login = require('nexus-fca');
|
|
|
110
55
|
```
|
|
111
56
|
|
|
112
57
|
---
|
|
113
|
-
##
|
|
114
|
-
| Feature | Benefit |
|
|
115
|
-
|---------|---------|
|
|
116
|
-
| Anchored User-Agent | Eliminates fingerprint drift (prevents 20–22h expiry) |
|
|
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) |
|
|
120
|
-
| Idle / Ghost Detection | Auto probe + reconnect on silent stalls |
|
|
121
|
-
| Periodic Recycle | ~6h (±30m) randomized connection rejuvenation (suppressed if recent refresh) |
|
|
122
|
-
| Persistent Device Profile | Fewer checkpoints / trust continuity |
|
|
123
|
-
| Lazy Preflight | Skips heavy validation when recently healthy |
|
|
124
|
-
| Human-like Timing | Reduces automation signal surface |
|
|
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
|
-
|
|
129
|
-
Disable preflight if needed:
|
|
58
|
+
## 🧪 Key Runtime APIs
|
|
130
59
|
```js
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- Adaptive exponential backoff with jitter (caps 5m)
|
|
137
|
-
- Soft-stale probing (2m30s) + hard watchdog tiers
|
|
138
|
-
- Layered post-refresh health checks (1s / 10s / 30s) after token renewal
|
|
139
|
-
- Synthetic keepalives (randomized 55–75s) feeding metrics
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
## 📦 Example Echo Test
|
|
143
|
-
`examples/echo-test.js`:
|
|
144
|
-
```bash
|
|
145
|
-
node examples/echo-test.js
|
|
60
|
+
api.setEditOptions({ maxPendingEdits, editTTLms, ackTimeoutMs, maxResendAttempts });
|
|
61
|
+
api.setBackoffOptions({ base, factor, max, jitter });
|
|
62
|
+
api.enableLazyPreflight(true); // Skip heavy validation if recent success
|
|
63
|
+
api.getHealthMetrics(); // uptime, reconnects, ack latency, delivery stats
|
|
64
|
+
api.getMemoryMetrics(); // queue sizes & guard counters
|
|
146
65
|
```
|
|
147
|
-
Provide `appstate.json` or set `EMAIL` / `PASSWORD` env variables.
|
|
148
66
|
|
|
149
|
-
|
|
150
|
-
## 🧠 Advanced Login Flow
|
|
151
|
-
1. Integrated system safely generates / refreshes cookies (if credentials supplied)
|
|
152
|
-
2. Core consumes resulting appstate for stable API behavior
|
|
153
|
-
3. Persistent device JSON: `persistent-device.json`
|
|
154
|
-
|
|
155
|
-
Persistent device toggle:
|
|
67
|
+
### Monitoring Snippet
|
|
156
68
|
```js
|
|
157
|
-
|
|
158
|
-
|
|
69
|
+
setInterval(() => {
|
|
70
|
+
const h = api.getHealthMetrics();
|
|
71
|
+
const m = api.getMemoryMetrics();
|
|
72
|
+
console.log('[HEALTH]', h?.status, 'acks', h?.ackCount, 'p95Ack', h?.p95AckLatencyMs);
|
|
73
|
+
console.log('[DELIVERY]', {
|
|
74
|
+
attempts: h?.deliveryAttempts,
|
|
75
|
+
success: h?.deliverySuccess,
|
|
76
|
+
failed: h?.deliveryFailed,
|
|
77
|
+
timeouts: h?.deliveryTimeouts,
|
|
78
|
+
disabledSince: h?.deliveryDisabledSince
|
|
79
|
+
});
|
|
80
|
+
console.log('[MEM]', m);
|
|
81
|
+
}, 60000);
|
|
159
82
|
```
|
|
160
83
|
|
|
161
84
|
---
|
|
162
|
-
##
|
|
163
|
-
|
|
85
|
+
## 🛡️ Safety & Stability Architecture
|
|
86
|
+
| Layer | Mechanism | Purpose |
|
|
87
|
+
|-------|-----------|---------|
|
|
88
|
+
| UA Continuity | Single anchored fingerprint | Avoid heuristic expiry & drift |
|
|
89
|
+
| Adaptive Refresh | Risk-aware timing bands | Token longevity without bursts |
|
|
90
|
+
| Lightweight Poke | Subtle `fb_dtsg` renewal | Keeps session warm quietly |
|
|
91
|
+
| Collision Guard | 45m spacing window | Prevent clustered maintenance events |
|
|
92
|
+
| Idle / Ghost Probe | Timed silent detection | Force reconnect on stale sockets |
|
|
93
|
+
| Periodic Recycle | Randomized (~6h ±30m) | Pre-empt silent degradation |
|
|
94
|
+
| Backoff Strategy | Exponential + jitter | Graceful network recovery |
|
|
95
|
+
| Delivery Suppression | Disable after repeated timeouts | Preserve send latency |
|
|
164
96
|
|
|
165
|
-
|
|
166
|
-
1. In a separate script, run Nexus-FCA credential login (with 2FA if needed):
|
|
97
|
+
Disable heavy preflight if embedding inside a framework already doing checks:
|
|
167
98
|
```js
|
|
168
|
-
|
|
169
|
-
(async () => {
|
|
170
|
-
const api = await login({ email: process.env.FB_EMAIL, password: process.env.FB_PASS, twofactor: process.env.FB_2FA });
|
|
171
|
-
const appState = api.getAppState();
|
|
172
|
-
require('fs').writeFileSync('./appstate.json', JSON.stringify(appState, null, 2));
|
|
173
|
-
console.log('Saved appstate.json');
|
|
174
|
-
})();
|
|
99
|
+
await login({ appState }, { disablePreflight: true });
|
|
175
100
|
```
|
|
176
|
-
2. Configure GoatBot to use that `appstate.json` (no credential scraping needed).
|
|
177
|
-
3. Repeat only when session truly expires (persistent device reduces frequency).
|
|
178
101
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
2. Rename GoatBot’s original folder for backup:
|
|
186
|
-
```bash
|
|
187
|
-
mv fb-chat-api fb-chat-api.orig # (Windows: rename manually)
|
|
188
|
-
```
|
|
189
|
-
3. Create a shim folder `fb-chat-api/index.js` with:
|
|
190
|
-
```js
|
|
191
|
-
module.exports = require('nexus-fca');
|
|
192
|
-
```
|
|
193
|
-
4. Start GoatBot normally. All calls (`login`, `api.listen`, send methods) now use Nexus-FCA (Promise supported).
|
|
102
|
+
---
|
|
103
|
+
## 🛰️ MQTT Enhancements (Since 2.1.x)
|
|
104
|
+
- Adaptive reconnect curve (caps 5m)
|
|
105
|
+
- Layered post-refresh probes (1s / 10s / 30s)
|
|
106
|
+
- Synthetic randomized keepalives (55–75s)
|
|
107
|
+
- Structured error classification feeding metrics
|
|
194
108
|
|
|
195
|
-
|
|
196
|
-
|
|
109
|
+
---
|
|
110
|
+
## ✉️ Delivery Reliability
|
|
111
|
+
- Multi-path send fallback (MQTT publish → HTTP send → direct fallback)
|
|
112
|
+
- Per-attempt timeout & retry for message delivery receipts
|
|
113
|
+
- Automatic classification of transient timeouts (ETIMEDOUT / ECONNRESET / EAI_AGAIN)
|
|
114
|
+
- Adaptive suppression of delivery receipt calls when environment unstable (protects primary send throughput)
|
|
197
115
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const login = require('nexus-fca');
|
|
206
|
-
const api = await login(loginData); // supports { appState } or { email, password, twofactor }
|
|
207
|
-
```
|
|
116
|
+
---
|
|
117
|
+
## 🧠 Long Session Best Practices
|
|
118
|
+
1. Prefer appstate reuse (minimal credential logins).
|
|
119
|
+
2. Preserve `persistent-device.json` (only delete if forced challenge).
|
|
120
|
+
3. Don’t manually rotate User-Agent – built-in continuity handles it.
|
|
121
|
+
4. Inspect metrics before forcing reconnect; let backoff work.
|
|
122
|
+
5. Keep dependencies updated; review CHANGELOG for operational notes.
|
|
208
123
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
124
|
+
---
|
|
125
|
+
## 🐐 Using with GoatBot V2 (Summary)
|
|
126
|
+
| Goal | Steps |
|
|
127
|
+
|------|-------|
|
|
128
|
+
| Generate appstate | Run credential login script → save `appstate.json` → configure GoatBot |
|
|
129
|
+
| Full replacement | Install `nexus-fca` → shim `fb-chat-api/index.js` exporting module |
|
|
130
|
+
| Direct require swap | Replace `require('fb-chat-api')` with `require('nexus-fca')` |
|
|
213
131
|
|
|
214
|
-
|
|
132
|
+
Minimal example:
|
|
215
133
|
```js
|
|
216
134
|
const login = require('nexus-fca');
|
|
217
135
|
(async () => {
|
|
218
136
|
const api = await login({ appState: require('./appstate.json') });
|
|
219
|
-
api.listen(
|
|
220
|
-
if (err) return console.error(
|
|
137
|
+
api.listen((err, event) => {
|
|
138
|
+
if (err) return console.error(err);
|
|
221
139
|
if (event.body === '!ping') api.sendMessage('pong', event.threadID);
|
|
222
140
|
});
|
|
223
141
|
})();
|
|
224
142
|
```
|
|
225
143
|
|
|
226
144
|
---
|
|
227
|
-
## 📚 Documentation
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
145
|
+
## 📚 Documentation Map
|
|
146
|
+
| Resource | Location |
|
|
147
|
+
|----------|----------|
|
|
148
|
+
| Full API Reference | `DOCS.md` |
|
|
149
|
+
| Feature Guides | `docs/*.md` |
|
|
150
|
+
| Safety Details | `docs/account-safety.md` |
|
|
151
|
+
| Examples | `examples/` |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
## � Migrating 2.1.x → 3.0.0
|
|
155
|
+
| Area | Action Needed |
|
|
156
|
+
|------|---------------|
|
|
157
|
+
| Public API | None (fully compatible) |
|
|
158
|
+
| Diagnostics Harness | Removed (no action) |
|
|
159
|
+
| Delivery Metrics | Optionally surface in dashboards |
|
|
160
|
+
| Safety Manager (legacy) | Keep removed / unused |
|
|
232
161
|
|
|
233
162
|
---
|
|
234
|
-
##
|
|
235
|
-
|
|
|
236
|
-
|
|
237
|
-
|
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
241
|
-
|
|
|
242
|
-
| Persistent Device | Keep file unless forced reset required |
|
|
163
|
+
## 🗂 Previous 2.1.x Highlights (Condensed)
|
|
164
|
+
| Version | Focus | Key Additions |
|
|
165
|
+
|---------|-------|---------------|
|
|
166
|
+
| 2.1.10 | Stabilization | Final 2.1.x meta adjustments |
|
|
167
|
+
| 2.1.8 | Safety Consolidation | Unified orchestrator, collision spacing, recycle suppression |
|
|
168
|
+
| 2.1.7 | Session Longevity | UA continuity, lightweight poke |
|
|
169
|
+
| 2.1.6 | Memory Guard | Queue pruning, edit TTL sweeps |
|
|
170
|
+
| 2.1.5 | Edit Reliability | PendingEdits buffer, ACK watchdog |
|
|
243
171
|
|
|
244
|
-
|
|
172
|
+
Full details remain in `CHANGELOG.md`.
|
|
245
173
|
|
|
246
174
|
---
|
|
247
175
|
## ⚠️ Disclaimer
|
|
248
|
-
|
|
176
|
+
Not affiliated with Facebook. Use responsibly and comply with platform terms & local laws.
|
|
249
177
|
|
|
250
178
|
---
|
|
251
|
-
## 🤝
|
|
252
|
-
PRs
|
|
179
|
+
## 🤝 Contributing
|
|
180
|
+
Focused PRs improving stability, safety heuristics, protocol coverage, or typings are welcome.
|
|
253
181
|
|
|
254
182
|
---
|
|
255
183
|
## 📜 License
|
|
256
|
-
|
|
184
|
+
[Team Nexus](https://www.facebook.com/profile.php?id=61572587854836)
|
|
185
|
+
|
|
186
|
+
MIT © 2025 Nexus (Team Nexus)
|
package/index.js
CHANGED
|
@@ -271,6 +271,7 @@ function buildAPI(globalOptions, html, jar) {
|
|
|
271
271
|
});
|
|
272
272
|
},
|
|
273
273
|
getHealthMetrics: function(){ return ctx.health ? ctx.health.snapshot() : null; },
|
|
274
|
+
getMqttDiagnostics: function(){ return ctx.getMqttDiagnostics ? ctx.getMqttDiagnostics() : (ctx._mqttDiag || null); },
|
|
274
275
|
enableLazyPreflight(enable=true){ ctx.globalOptions.disablePreflight = !enable; },
|
|
275
276
|
setBackoffOptions(opts={}){ ctx.globalOptions.backoff = Object.assign(ctx.globalOptions.backoff||{}, opts); },
|
|
276
277
|
setEditOptions(opts={}){ Object.assign(ctx.globalOptions.editSettings, opts); },
|
|
@@ -34,6 +34,12 @@ class HealthMetrics {
|
|
|
34
34
|
this.groupQueueExpiredQueues = 0;
|
|
35
35
|
this.groupQueueDroppedMessages = 0;
|
|
36
36
|
this.pendingEditSweeps = 0;
|
|
37
|
+
// Delivery receipt metrics
|
|
38
|
+
this.deliveryAttempts = 0;
|
|
39
|
+
this.deliverySuccess = 0;
|
|
40
|
+
this.deliveryFailed = 0;
|
|
41
|
+
this.deliveryTimeouts = 0;
|
|
42
|
+
this.deliveryDisabledSince = 0; // timestamp if adaptive disable engaged
|
|
37
43
|
}
|
|
38
44
|
onConnect() { this.lastConnectTs = Date.now(); this.consecutiveFailures = 0; }
|
|
39
45
|
onDisconnect() { this.lastDisconnectTs = Date.now(); }
|
|
@@ -57,6 +63,7 @@ class HealthMetrics {
|
|
|
57
63
|
this.p95AckLatencyMs = sorted[idx];
|
|
58
64
|
}
|
|
59
65
|
onError(type){ this.lastErrorTs = Date.now(); this.lastErrorType = type || 'unknown'; }
|
|
66
|
+
incFailure(){ this.consecutiveFailures++; }
|
|
60
67
|
onReconnectScheduled(delay){ this.reconnects++; this.currentBackoffDelay = delay; if(delay > (this.maxObservedBackoff||0)) this.maxObservedBackoff = delay; }
|
|
61
68
|
trackOutbound(depth){ this.outboundQueueDepth = depth; }
|
|
62
69
|
incOutboundDropped(){ this.outboundQueueDropped++; }
|
|
@@ -114,6 +121,11 @@ class HealthMetrics {
|
|
|
114
121
|
groupQueueExpiredQueues: this.groupQueueExpiredQueues,
|
|
115
122
|
groupQueueDroppedMessages: this.groupQueueDroppedMessages,
|
|
116
123
|
pendingEditSweeps: this.pendingEditSweeps,
|
|
124
|
+
deliveryAttempts: this.deliveryAttempts,
|
|
125
|
+
deliverySuccess: this.deliverySuccess,
|
|
126
|
+
deliveryFailed: this.deliveryFailed,
|
|
127
|
+
deliveryTimeouts: this.deliveryTimeouts,
|
|
128
|
+
deliveryDisabled: !!this.deliveryDisabledSince,
|
|
117
129
|
healthy: this.isHealthy(idleMs)
|
|
118
130
|
};
|
|
119
131
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Lightweight diagnostics helper for MQTT/WebSocket connection lifecycle.
|
|
3
|
+
// Captures low-level events so we can understand repeated reconnect loops.
|
|
4
|
+
module.exports = function attachMqttDiagnostics(ws, ctx, log){
|
|
5
|
+
if(!ws || typeof ws.on !== 'function') return;
|
|
6
|
+
const diag = ctx._mqttDiag = ctx._mqttDiag || { attempts:0, events:[] };
|
|
7
|
+
function push(evt){
|
|
8
|
+
try {
|
|
9
|
+
diag.events.push({ t: Date.now(), ...evt });
|
|
10
|
+
if(diag.events.length > 50) diag.events.shift();
|
|
11
|
+
} catch(_) {}
|
|
12
|
+
}
|
|
13
|
+
ws.on('upgrade', (res)=>{ push({ type:'upgrade', status: res.statusCode, headers: safeHeaders(res.headers) }); });
|
|
14
|
+
ws.on('unexpected-response', (req, res)=>{ push({ type:'unexpected_response', status: res && res.statusCode, headers: res && safeHeaders(res.headers) }); });
|
|
15
|
+
ws.on('close', (code, reason)=>{ push({ type:'close', code, reason: reason && reason.toString() }); });
|
|
16
|
+
ws.on('error', (err)=>{ push({ type:'error', message: err && (err.message||err.code||'').toString(), code: err && err.code }); });
|
|
17
|
+
function safeHeaders(h){ if(!h) return {}; const out={}; for(const k of Object.keys(h)){ if(k.startsWith('cookie')) continue; out[k]=h[k]; } return out; }
|
|
18
|
+
// expose a snapshot method
|
|
19
|
+
ctx.getMqttDiagnostics = () => ({ attempts: diag.attempts, recent: [...diag.events] });
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-fca",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Nexus-FCA 3.0 – stable, low-risk Facebook Messenger automation API with integrated secure login (ID / Password / 2FA), adaptive MQTT core, safety orchestration, metrics, and TypeScript support.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
package/src/listenMqtt.js
CHANGED
|
@@ -166,9 +166,15 @@ function buildStream(options, WebSocket, Proxy) {
|
|
|
166
166
|
return Stream;
|
|
167
167
|
}
|
|
168
168
|
function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
169
|
+
const attemptStartTs = Date.now();
|
|
169
170
|
// Attach health metrics container lazily
|
|
170
171
|
if(!ctx.health) ctx.health = new (require('../lib/health/HealthMetrics').HealthMetrics)();
|
|
172
|
+
// Ensure tasks map exists to track ls_req -> ls_resp correlations (avoid TypeError on undefined)
|
|
173
|
+
if(!ctx.tasks) ctx.tasks = new Map();
|
|
171
174
|
const backoff = getBackoffState(ctx);
|
|
175
|
+
if(!ctx._mqttDiag) ctx._mqttDiag = { attempts:0, events:[] };
|
|
176
|
+
ctx._mqttDiag.attempts++;
|
|
177
|
+
log.info('listenMqtt', `Attempt #${ctx._mqttDiag.attempts} starting (backoffCurrent=${backoff.current||0})`);
|
|
172
178
|
const runPreflight = shouldRunPreflight(ctx);
|
|
173
179
|
if (runPreflight) {
|
|
174
180
|
(async () => {
|
|
@@ -263,20 +269,27 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
263
269
|
log.error("listenMqtt", `Failed to create proxy agent: ${error.message}`);
|
|
264
270
|
}
|
|
265
271
|
}
|
|
272
|
+
// Create raw WebSocket first so we can attach diagnostics hooks.
|
|
273
|
+
const rawWs = new WebSocket(host, options.wsOptions);
|
|
274
|
+
try { require('../lib/mqtt/MqttDiagnostics')(rawWs, ctx, log); } catch(_) {}
|
|
266
275
|
ctx.mqttClient = new mqtt.Client(
|
|
267
|
-
() =>
|
|
268
|
-
buildStream(
|
|
269
|
-
options,
|
|
270
|
-
new WebSocket(host, options.wsOptions),
|
|
271
|
-
buildProxy()
|
|
272
|
-
),
|
|
276
|
+
() => buildStream(options, rawWs, buildProxy()),
|
|
273
277
|
options
|
|
274
278
|
);
|
|
279
|
+
log.info('listenMqtt', `Connecting to ${host}`);
|
|
275
280
|
const mqttClient = ctx.mqttClient;
|
|
276
281
|
global.mqttClient = mqttClient;
|
|
277
282
|
mqttClient.on('error', function (err) {
|
|
278
283
|
const errMsg = (err && (err.error || err.message || "")).toString();
|
|
279
284
|
ctx.health.onError(errMsg.includes('not logged in') ? 'not_logged_in' : 'mqtt_error');
|
|
285
|
+
// Increment failure counter for health tracking
|
|
286
|
+
if(ctx.health && typeof ctx.health.incFailure === 'function') ctx.health.incFailure();
|
|
287
|
+
if(!errMsg){
|
|
288
|
+
log.error('listenMqtt', 'Empty error message (mqtt error event). Raw err object: ' + JSON.stringify(Object.getOwnPropertyNames(err || {}).reduce((a,k)=>{a[k]=err[k];return a;},{})));
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
log.error('listenMqtt', `MQTT error after ${(Date.now()-attemptStartTs)}ms: ${errMsg}`);
|
|
292
|
+
}
|
|
280
293
|
log.error("listenMqtt", errMsg);
|
|
281
294
|
try { mqttClient.end(true); } catch(_){ }
|
|
282
295
|
if (/not logged in|login_redirect|html_login_page/i.test(errMsg)) {
|
|
@@ -294,6 +307,8 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
294
307
|
// Ensure reconnection also triggers on unexpected close without prior error
|
|
295
308
|
mqttClient.on('close', function () {
|
|
296
309
|
ctx.health.onDisconnect();
|
|
310
|
+
if(ctx.health && typeof ctx.health.incFailure === 'function'){ ctx.health.incFailure(); }
|
|
311
|
+
log.warn('listenMqtt', `Socket closed after ${(Date.now()-attemptStartTs)}ms (attempt #${ctx._mqttDiag.attempts}).`);
|
|
297
312
|
if (!ctx.loggedIn) return; // avoid loops if logged out
|
|
298
313
|
if (ctx.globalOptions.autoReconnect) {
|
|
299
314
|
scheduleAdaptiveReconnect(defaultFuncs, api, ctx, globalCallback);
|
|
@@ -301,6 +316,8 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
301
316
|
});
|
|
302
317
|
mqttClient.on('disconnect', function(){
|
|
303
318
|
ctx.health.onDisconnect();
|
|
319
|
+
if(ctx.health && typeof ctx.health.incFailure === 'function'){ ctx.health.incFailure(); }
|
|
320
|
+
log.warn('listenMqtt', `MQTT disconnect event after ${(Date.now()-attemptStartTs)}ms (attempt #${ctx._mqttDiag.attempts}).`);
|
|
304
321
|
if (!ctx.loggedIn) return;
|
|
305
322
|
if (ctx.globalOptions.autoReconnect) {
|
|
306
323
|
scheduleAdaptiveReconnect(defaultFuncs, api, ctx, globalCallback);
|
|
@@ -309,6 +326,7 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
309
326
|
mqttClient.on("connect", function () {
|
|
310
327
|
resetBackoff(backoff);
|
|
311
328
|
ctx.health.onConnect();
|
|
329
|
+
log.info('listenMqtt', `Connected in ${(Date.now()-attemptStartTs)}ms (attempt #${ctx._mqttDiag.attempts}).`);
|
|
312
330
|
if (ctx.globalSafety) { try { ctx.globalSafety.recordEvent(); } catch(_) {} }
|
|
313
331
|
if (process.env.OnStatus === undefined) {
|
|
314
332
|
logger("Nexus-FCA premium features works only with Nexus-Bot framework(Kidding)", "info");
|
|
@@ -418,7 +436,8 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
418
436
|
} else if (topic == "/ls_resp") {
|
|
419
437
|
const parsedPayload = JSON.parse(jsonMessage.payload);
|
|
420
438
|
const reqID = jsonMessage.request_id;
|
|
421
|
-
|
|
439
|
+
// Guard: ctx.tasks may be empty; only proceed if it's a Map and contains the reqID
|
|
440
|
+
if (ctx.tasks && typeof ctx.tasks.has === 'function' && ctx.tasks.has(reqID)) {
|
|
422
441
|
const taskData = ctx["tasks"].get(reqID);
|
|
423
442
|
const { type: taskType, callback: taskCallback } = taskData;
|
|
424
443
|
const taskRespData = getTaskResponseData(taskType, parsedPayload);
|
package/src/markAsDelivered.js
CHANGED
|
@@ -30,28 +30,61 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
30
30
|
form["message_ids[0]"] = messageID;
|
|
31
31
|
form["thread_ids[" + threadID + "][0]"] = messageID;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
.
|
|
42
|
-
if (resData.error) {
|
|
43
|
-
throw resData;
|
|
44
|
-
}
|
|
45
|
-
|
|
33
|
+
// Lightweight retry with exponential backoff for transient network timeouts.
|
|
34
|
+
const maxAttempts = 3;
|
|
35
|
+
let attempt = 0;
|
|
36
|
+
const baseDelay = 500; // ms
|
|
37
|
+
const transientCodes = ['ETIMEDOUT','ECONNRESET','EAI_AGAIN'];
|
|
38
|
+
if(ctx.health){
|
|
39
|
+
ctx.health.deliveryAttempts++;
|
|
40
|
+
// If we previously disabled delivery receipts due to repeated timeouts, short-circuit success.
|
|
41
|
+
if(ctx.health.deliveryDisabledSince){
|
|
46
42
|
return callback();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function doPost(){
|
|
46
|
+
attempt++;
|
|
47
|
+
defaultFuncs
|
|
48
|
+
.post(
|
|
49
|
+
"https://www.facebook.com/ajax/mercury/delivery_receipts.php",
|
|
50
|
+
ctx.jar,
|
|
51
|
+
form
|
|
52
|
+
)
|
|
53
|
+
.then(utils.saveCookies(ctx.jar))
|
|
54
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
55
|
+
.then(function (resData) {
|
|
56
|
+
if (resData.error) { throw resData; }
|
|
57
|
+
if(ctx.health){ ctx.health.deliverySuccess++; }
|
|
58
|
+
return callback();
|
|
59
|
+
})
|
|
60
|
+
.catch(function (err) {
|
|
61
|
+
const code = err && (err.code || err.errno || (err.error && err.error.code));
|
|
62
|
+
const isTransient = code && transientCodes.includes(code);
|
|
63
|
+
if(code === 'ETIMEDOUT' && ctx.health){ ctx.health.deliveryTimeouts++; }
|
|
64
|
+
if(isTransient && attempt < maxAttempts){
|
|
65
|
+
const delay = Math.round(baseDelay * Math.pow(2, attempt-1) * (1 + Math.random()*0.2));
|
|
66
|
+
log.warn('markAsDelivered', `Transient ${code} attempt ${attempt}/${maxAttempts} -> retrying in ${delay}ms`);
|
|
67
|
+
return setTimeout(doPost, delay);
|
|
68
|
+
}
|
|
69
|
+
// Suppress noisy timeout logs after final retry unless verbose
|
|
70
|
+
if(!(isTransient && attempt >= maxAttempts)){
|
|
71
|
+
log.error("markAsDelivered", err);
|
|
72
|
+
}else{
|
|
73
|
+
log.warn('markAsDelivered', `Giving up after ${attempt} attempts (${code})`);
|
|
74
|
+
// Adaptive disable: if too many timeouts overall, stop calling delivery receipts for this run
|
|
75
|
+
if(code === 'ETIMEDOUT' && ctx.health && ctx.health.deliveryTimeouts >= 5){
|
|
76
|
+
ctx.health.deliveryDisabledSince = Date.now();
|
|
77
|
+
log.warn('markAsDelivered', 'Adaptive disable engaged after repeated ETIMEDOUT. Further receipts suppressed.');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (utils.getType(err) == "Object" && err.error === "Not logged in.") {
|
|
81
|
+
ctx.loggedIn = false;
|
|
82
|
+
}
|
|
83
|
+
if(ctx.health){ ctx.health.deliveryFailed++; }
|
|
84
|
+
return callback(err);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
doPost();
|
|
55
88
|
|
|
56
89
|
return returnPromise;
|
|
57
90
|
};
|