nexus-fca 3.2.3 → 3.2.4

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/README.md CHANGED
@@ -187,6 +187,7 @@ const login = require('nexus-fca');
187
187
  ## 📚 Documentation Map
188
188
  | Resource | Location |
189
189
  |----------|----------|
190
+ | **Usage Guide (Examples)** | `USAGE-GUIDE.md` |
190
191
  | Full API Reference | `DOCS.md` |
191
192
  | Feature Guides | `docs/*.md` |
192
193
  | Configuration Reference | `docs/configuration-reference.md` |
@@ -183,6 +183,9 @@ class ApiFactory {
183
183
  globalOptions[key] = options[key];
184
184
  });
185
185
  },
186
+ autoTyping: (enable = true) => {
187
+ globalOptions.autoTyping = !!enable;
188
+ },
186
189
  getAppState: function () {
187
190
  const appState = utils.getAppState(ctx.jar);
188
191
  return appState.filter((item, index, self) =>
@@ -217,6 +220,11 @@ class ApiFactory {
217
220
  }
218
221
  };
219
222
 
223
+ // Default options
224
+ if (typeof globalOptions.autoTyping === 'undefined') {
225
+ globalOptions.autoTyping = true; // Enabled by default for safety
226
+ }
227
+
220
228
  // Default edit settings
221
229
  if (!globalOptions.editSettings) {
222
230
  globalOptions.editSettings = {
@@ -293,9 +301,18 @@ class ApiFactory {
293
301
  globalOptions.groupQueueIdleMs = 30 * 60 * 1000;
294
302
 
295
303
  api._sendMessageDirect = DIRECT_FN;
296
- api.sendMessage = function (message, threadID, cb) {
304
+ api.sendMessage = function (message, threadID, cb, replyToMessage) {
305
+ // New: Auto-Typing support for improved human-like behavior
306
+ if (globalOptions.autoTyping) {
307
+ try {
308
+ api.sendTypingIndicator(threadID, (err) => {
309
+ // Ignore typing errors to avoid blocking the message
310
+ });
311
+ } catch (_) { /* ignore */ }
312
+ }
313
+
297
314
  if (!globalOptions.groupQueueEnabled || !isGroupThread(threadID)) {
298
- return api._sendMessageDirect(message, threadID, cb);
315
+ return api._sendMessageDirect(message, threadID, cb, replyToMessage);
299
316
  }
300
317
  let entry = groupQueues.get(threadID);
301
318
  if (!entry) { entry = { q: [], sending: false, lastActive: Date.now() }; groupQueues.set(threadID, entry); }
@@ -304,7 +321,7 @@ class ApiFactory {
304
321
  entry.q.shift();
305
322
  if (ctx.health) ctx.health.recordGroupQueuePrune(0, 0, 1);
306
323
  }
307
- entry.q.push({ message, threadID, cb });
324
+ entry.q.push({ message, threadID, cb, replyToMessage });
308
325
  processQueue(threadID, entry);
309
326
  };
310
327
 
@@ -312,13 +329,13 @@ class ApiFactory {
312
329
  if (entry.sending) return;
313
330
  if (!entry.q.length) return;
314
331
  entry.sending = true;
315
- const { message, threadID: tid, cb } = entry.q.shift();
316
- api._sendMessageDirect(message, tid, function (err, res) {
332
+ const item = entry.q.shift();
333
+ api._sendMessageDirect(item.message, item.threadID, function (err, res) {
317
334
  try { if (!err && this.globalSafety) this.globalSafety.recordEvent(); } catch (_) { }
318
- if (typeof cb === 'function') cb(err, res);
335
+ if (typeof item.cb === 'function') item.cb(err, res);
319
336
  entry.sending = false;
320
337
  setImmediate(() => processQueue(threadID, entry));
321
- }.bind(this));
338
+ }.bind(this), item.replyToMessage);
322
339
  }
323
340
 
324
341
  api._flushGroupQueue = function (threadID) {
@@ -49,13 +49,13 @@ class FacebookSafety {
49
49
  this.regions = ['ASH', 'ATL', 'DFW', 'ORD', 'PHX', 'SJC', 'IAD'];
50
50
  this.currentRegion = this.regions[Math.floor(Math.random() * this.regions.length)];
51
51
 
52
- // ULTRA-SAFE human delay patterns - Relaxed for usability
52
+ // ULTRA-SAFE human delay patterns - More conservative
53
53
  this.humanDelayPatterns = {
54
- typing: { min: 500, max: 1500 }, // Normal typing (0.5-1.5s)
55
- reading: { min: 1000, max: 3000 }, // Normal reading (1-3s)
56
- thinking: { min: 1000, max: 4000 }, // Normal thinking (1-4s)
57
- browsing: { min: 500, max: 2000 }, // Normal browsing (0.5-2s)
58
- messageDelay: { min: 1000, max: 3000 } // 1-3s between messages (much faster)
54
+ typing: { min: 800, max: 2500 }, // Normal typing (0.8-2.5s)
55
+ reading: { min: 1500, max: 5000 }, // Normal reading (1.5-5s)
56
+ thinking: { min: 1500, max: 6000 }, // Normal thinking (1.5-6s)
57
+ browsing: { min: 1000, max: 3000 }, // Normal browsing (1-3s)
58
+ messageDelay: { min: 1500, max: 4000 } // 1.5-4s between messages (Conservative)
59
59
  };
60
60
 
61
61
  this.sessionMetrics = {
@@ -800,16 +800,17 @@ class FacebookSafety {
800
800
  const risk = this.sessionMetrics.riskLevel;
801
801
  const since = Date.now() - this._lastHeavyMaintenanceTs;
802
802
  const inWindow = since < this._adaptivePacingWindowMs;
803
- let min = 0, max = 0;
804
- if (inWindow) {
805
- if (risk === 'high') { min = 600; max = 1500; }
806
- else if (risk === 'medium') { min = 200; max = 800; }
807
- else { min = 0; max = 300; }
808
- } else {
809
- // outside pacing window only high risk adds mild delay
810
- if (risk === 'high') { min = 150; max = 600; }
803
+
804
+ let min = 1000, max = 2500; // Default baseline human pace
805
+
806
+ if (risk === 'high') {
807
+ min = 3500; max = 6500;
808
+ } else if (risk === 'medium') {
809
+ min = 2000; max = 4500;
810
+ } else if (inWindow) {
811
+ min = 1500; max = 3000;
811
812
  }
812
- if (max <= 0) return 0;
813
+
813
814
  return Math.floor(min + Math.random() * (max - min));
814
815
  }
815
816
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nexus-fca",
3
- "version": "3.2.3",
4
- "description": "Nexus-FCA 3.2.3 – Advanced, Secure & Stable Facebook Messenger API.",
3
+ "version": "3.2.4",
4
+ "description": "Nexus-FCA 3.2.4 – Advanced, Secure & Stable Facebook Messenger API.",
5
5
  "main": "index.js",
6
6
  "repository": {
7
7
  "type": "git",
package/utils.js CHANGED
@@ -87,23 +87,44 @@ function getJar() {
87
87
  }
88
88
 
89
89
  function getHeaders(url, options, ctx, customHeader) {
90
+ const ua = (options?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36");
91
+ const isWindows = ua.includes("Windows NT");
92
+ const isAndroid = ua.includes("Android");
93
+ const isChrome = ua.includes("Chrome") && !ua.includes("Edg");
94
+
90
95
  var headers = {
91
96
  Referer: "https://www.facebook.com/",
92
97
  Host: url.replace("https://", "").split("/")[0],
93
98
  Origin: "https://www.facebook.com",
94
- "user-agent": (options?.userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"),
99
+ "user-agent": ua,
95
100
  Connection: "keep-alive",
96
- "sec-fetch-site": 'same-origin',
97
- "sec-fetch-mode": 'cors',
98
- "sec-fetch-dest": "empty",
99
101
  "accept": "*/*",
100
102
  "accept-language": "en-US,en;q=0.9",
101
- "sec-ch-ua": '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
102
- "sec-ch-ua-mobile": "?0",
103
- "sec-ch-ua-platform": '"Windows"',
104
103
  "dnt": "1",
105
104
  "upgrade-insecure-requests": "1"
106
105
  };
106
+
107
+ // Human-like Fetch headers
108
+ if (url.includes("/api/graphql/") || url.includes("/messaging/")) {
109
+ headers["sec-fetch-site"] = 'same-origin';
110
+ headers["sec-fetch-mode"] = 'cors';
111
+ headers["sec-fetch-dest"] = "empty";
112
+ } else {
113
+ headers["sec-fetch-site"] = 'none';
114
+ headers["sec-fetch-mode"] = 'navigate';
115
+ headers["sec-fetch-dest"] = "document";
116
+ }
117
+
118
+ // Dynamic Client Hints - CRITICAL: Must match User-Agent
119
+ if (isChrome && isWindows) {
120
+ headers["sec-ch-ua"] = '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"';
121
+ headers["sec-ch-ua-mobile"] = "?0";
122
+ headers["sec-ch-ua-platform"] = '"Windows"';
123
+ } else if (isAndroid) {
124
+ headers["sec-ch-ua-mobile"] = "?1";
125
+ // Remove Windows-specific headers for Android UAs
126
+ }
127
+
107
128
  if (customHeader) Object.assign(headers, customHeader);
108
129
  if (ctx && ctx.region) headers["X-MSGR-Region"] = ctx.region;
109
130