ayman-fca 1.0.3 → 1.0.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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // ============================================================
2
2
  // AYMAN-FCA v2.0 — ULTRA MASTER ENGINE
3
- // © 2025 Ayman. All Rights Reserved.
3
+ // © 2026 Ayman. All Rights Reserved.
4
4
  //
5
5
  // يجمع كل الأنظمة:
6
6
  // ① SessionManager — جلسة + backup + validate
@@ -20,7 +20,9 @@
20
20
  const EventEmitter = require("events");
21
21
  const path = require("path");
22
22
 
23
+ // المسار المصحح للوصول إلى المجلد الوظيفي في الجذر
23
24
  const logger = require("../func/logger");
25
+
24
26
  const SessionManager = require("./core/sessionManager");
25
27
  const ReconnectEngine = require("./core/reconnectEngine");
26
28
  const KeepAliveEngine = require("./core/keepAliveEngine");
@@ -59,36 +61,32 @@ class AymanFCAUltra extends EventEmitter {
59
61
  this.geo = new GeoGuard({ lockRegion: true });
60
62
 
61
63
  this._wireSystems();
62
- logger.banner();
64
+ // تأكد أن logger يحتوي على دالة banner لتجنب الأخطاء
65
+ if (logger && typeof logger.banner === "function") logger.banner();
63
66
  }
64
67
 
65
68
  // ── ربط الأنظمة ببعضها ──────────────────────────────────
66
69
  _wireSystems() {
67
- // Watchdog → restart
68
70
  this.watchdog.on(EVENTS.WATCHDOG_RESTART, ({ reasons }) => {
69
71
  this.health.penalize("mqtt_dead");
70
72
  this._restart("watchdog: " + reasons);
71
73
  });
72
74
 
73
- // Health Critical → restart
74
75
  this.health.on(EVENTS.HEALTH_CRITICAL, ({ score }) => {
75
76
  logger.error(`Health منخفض (${score}) — restart`, "ULTRA");
76
77
  this._restart("health_critical");
77
78
  });
78
79
 
79
- // Session Expired → restart
80
80
  this.session.on(EVENTS.SESSION_EXPIRED, () => {
81
81
  this.health.penalize("session_expired");
82
82
  this._restart("session_expired");
83
83
  });
84
84
 
85
- // Memory High → risk up + pause queue
86
85
  this.memory.on(EVENTS.MEMORY_HIGH, () => {
87
86
  this.health.penalize("memory_high");
88
87
  this.queue.setRiskLevel("high");
89
88
  });
90
89
 
91
- // Silent Mode → pause queue
92
90
  this.silent.on("silent:enter", () => {
93
91
  this.queue.pause("silent_mode");
94
92
  this.cooldown.recordError();
@@ -97,7 +95,6 @@ class AymanFCAUltra extends EventEmitter {
97
95
  this.queue.resume();
98
96
  });
99
97
 
100
- // Reconnect events
101
98
  this.reconnect.on(EVENTS.RECONNECT_DONE, () => {
102
99
  this.health.reward("reconnect_done");
103
100
  this.cooldown.reset();
@@ -107,21 +104,17 @@ class AymanFCAUltra extends EventEmitter {
107
104
  this.health.penalize("reconnect_fail");
108
105
  });
109
106
 
110
- // Geo instability
111
107
  this.geo.on("region:unstable", () => {
112
108
  logger.warn("GeoGuard: عدم استقرار — Silent Mode", "ULTRA");
113
109
  this.silent.enterSilentMode("geo_instability");
114
110
  });
115
111
 
116
- // Cooldown → Smart Queue speed
117
- // health low → risk up
118
112
  this.health.on(EVENTS.HEALTH_LOW, () => {
119
113
  this.queue.setRiskLevel("high");
120
114
  this.cooldown.recordError();
121
115
  });
122
116
  }
123
117
 
124
- // ── استخراج ctx ─────────────────────────────────────────
125
118
  _extractCtx(api) {
126
119
  for (const k of Object.getOwnPropertyNames(api)) {
127
120
  try {
@@ -132,7 +125,6 @@ class AymanFCAUltra extends EventEmitter {
132
125
  return null;
133
126
  }
134
127
 
135
- // ── تشغيل كل الأنظمة بعد Login ─────────────────────────
136
128
  _startSystems(api, ctx) {
137
129
  this.session.attach(api);
138
130
  this.keepAlive.attach(api, ctx);
@@ -141,10 +133,8 @@ class AymanFCAUltra extends EventEmitter {
141
133
  if (ctx?.tasks instanceof Map && ctx.tasks.size > 100) ctx.tasks.clear();
142
134
  });
143
135
 
144
- // تسجيل region
145
136
  if (ctx?.region) this.geo.recordRegion(ctx.region);
146
137
 
147
- // تشغيل الأنظمة
148
138
  this.session.start();
149
139
  this.keepAlive.start();
150
140
  this.watchdog.start();
@@ -157,20 +147,17 @@ class AymanFCAUltra extends EventEmitter {
157
147
  this.emit("ready", { uid: ctx?.userID });
158
148
  }
159
149
 
160
- // ── إيقاف كل الأنظمة ────────────────────────────────────
161
150
  _stopSystems() {
162
151
  ["session","keepAlive","watchdog","health","memory","queue","behavior","silent"].forEach(s => {
163
152
  try { this[s].stop(); } catch(_) {}
164
153
  });
165
154
  }
166
155
 
167
- // ── إعادة تشغيل ذكية (Soft Restart) ─────────────────────
168
156
  async _restart(reason) {
169
157
  if (this._restarting) return;
170
158
  this._restarting = true;
171
159
  logger.warn(`ULTRA: إعادة تشغيل — ${reason}`, "ULTRA");
172
160
 
173
- // Soft restart بدل Hard restart
174
161
  const ok = await this.silent.softRestart(async () => {
175
162
  this._stopSystems();
176
163
  try {
@@ -188,13 +175,11 @@ class AymanFCAUltra extends EventEmitter {
188
175
  this._restarting = false;
189
176
  }
190
177
 
191
- // ── بناء Listener Callback ────────────────────────────────
192
178
  buildListenerCallback() {
193
179
  return (error, message) => {
194
180
  if (error) {
195
181
  if (error?.type === "stop_listen") return;
196
182
 
197
- // Silent Mode إذا لزم
198
183
  if (this.silent.shouldGoSilent(error)) {
199
184
  this.silent.handleError(error, () => this._restart("silent_recovery"));
200
185
  return;
@@ -214,12 +199,10 @@ class AymanFCAUltra extends EventEmitter {
214
199
 
215
200
  if (!message) return;
216
201
 
217
- // تحديث Watchdog + Health
218
202
  this.watchdog.heartbeat();
219
203
  this.health.reward("message_ok");
220
204
  this.cooldown.recordSuccess();
221
205
 
222
- // تحديث Geo إذا تغير
223
206
  if (message.region) this.geo.recordRegion(message.region);
224
207
 
225
208
  if (["presence","typ","read_receipt"].includes(message.type)) return;
@@ -231,7 +214,6 @@ class AymanFCAUltra extends EventEmitter {
231
214
  };
232
215
  }
233
216
 
234
- // ── ربط بـ API بعد Login ──────────────────────────────────
235
217
  async attachToApi(api) {
236
218
  this._api = api;
237
219
  this._ctx = this._extractCtx(api);
@@ -242,26 +224,20 @@ class AymanFCAUltra extends EventEmitter {
242
224
  logger.info(`ULTRA مرتبط | UID: ${this._ctx.userID} | Region: ${this._ctx.region || "?"}`, "ULTRA");
243
225
  }
244
226
 
245
- // Connection Warm-Up قبل أي نشاط
246
227
  await this.behavior.warmUp();
247
228
 
248
- // حفظ الجلسة فوراً
249
229
  try { this.session.save(api.getAppState(), true); } catch(_) {}
250
230
 
251
- // تشغيل الأنظمة
252
231
  this._startSystems(api, this._ctx || {});
253
232
 
254
233
  return api;
255
234
  }
256
235
 
257
- // ── wrap sendMessage بـ Queue + Cooldown ─────────────────
258
236
  wrapSendMessage(api) {
259
237
  const original = api.sendMessage.bind(api);
260
238
  api.sendMessage = (msg, threadID, callback, messageID) => {
261
- // Anti-Repeat
262
239
  this.behavior.antiRepeatDelay("send", typeof msg === "string" ? msg.slice(0, 30) : "obj");
263
240
 
264
- // Queue
265
241
  this.queue.enqueue(async () => {
266
242
  await this.cooldown.waitBeforeSend();
267
243
  const start = Date.now();
@@ -277,14 +253,12 @@ class AymanFCAUltra extends EventEmitter {
277
253
  logger.info("ULTRA: sendMessage wrapped ✅", "ULTRA");
278
254
  }
279
255
 
280
- // ── إيقاف آمن ────────────────────────────────────────────
281
256
  async stop() {
282
257
  this._stopSystems();
283
258
  try { if (this._api?.stopListening) this._api.stopListening(); } catch(_) {}
284
259
  logger.info("ULTRA: موقوف ✅", "ULTRA");
285
260
  }
286
261
 
287
- // ── Getters ───────────────────────────────────────────────
288
262
  get api() { return this._api; }
289
263
  get ctx() { return this._ctx; }
290
264
  getHealth() { return this.health.getStats(); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ayman-fca",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Facebook Chat API for Node.js — مكتبة KIRA بوت | © 2025 Ayman",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,10 +1,12 @@
1
1
  // ============================================================
2
- // AYMAN-FCA v2.0 — Auto Save AppState
2
+ // AYMAN-FCA v2.0 — Auto Save AppState [FIXED]
3
3
  // © 2025 Ayman. All Rights Reserved.
4
4
  //
5
- // حفظ ذكي: لا يحفظ إذا لم تتغير البيانات
6
- // Atomic write: يحمي الملف من التلف
7
- // يحفظ عند SIGINT/SIGTERM
5
+ // الإصلاحات:
6
+ // hashState أقوى يكشف أي تغيير في القيم
7
+ // حفظ كل 5 دقائق (كان 8)
8
+ // ✅ backup نسخة ثانية في session_backups/
9
+ // ✅ cleanup للـ backup القديمة (يحتفظ بآخر 3 فقط)
8
10
  // ============================================================
9
11
  "use strict";
10
12
 
@@ -12,32 +14,65 @@ const fs = require("fs");
12
14
  const path = require("path");
13
15
  const logger = require("../../../func/logger");
14
16
 
17
+ const BACKUP_DIR = path.join(process.cwd(), "session_backups");
18
+ const MAX_BACKUPS = 3;
19
+
20
+ function ensureBackupDir() {
21
+ try {
22
+ if (!fs.existsSync(BACKUP_DIR)) fs.mkdirSync(BACKUP_DIR, { recursive: true });
23
+ } catch (_) {}
24
+ }
25
+
26
+ // ✅ hash أقوى — يأخذ عينة من القيم الفعلية
27
+ function hashState(state) {
28
+ if (!state || !state.length) return "empty";
29
+ const sample = state.slice(0, 5).map(c => `${c.key}=${String(c.value || "").slice(0, 8)}`).join("|");
30
+ return `${state.length}:${sample}`;
31
+ }
32
+
33
+ // ✅ حفظ backup مع تنظيف القديمة
34
+ function saveBackup(state) {
35
+ try {
36
+ ensureBackupDir();
37
+ const ts = Date.now();
38
+ const file = path.join(BACKUP_DIR, `backup_${ts}.json`);
39
+ fs.writeFileSync(file, JSON.stringify(state, null, "\t"), "utf8");
40
+
41
+ // احذف القديمة — احتفظ بآخر MAX_BACKUPS
42
+ const files = fs.readdirSync(BACKUP_DIR)
43
+ .filter(f => f.startsWith("backup_") && f.endsWith(".json"))
44
+ .sort().reverse();
45
+ for (const old of files.slice(MAX_BACKUPS)) {
46
+ try { fs.unlinkSync(path.join(BACKUP_DIR, old)); } catch (_) {}
47
+ }
48
+ } catch (_) {}
49
+ }
50
+
15
51
  module.exports = function(defaultFuncs, api, ctx) {
16
52
  return function enableAutoSaveAppState(options = {}) {
17
53
  const filePath = options.filePath || path.join(process.cwd(), "appstate.json");
18
- const intervalMs = options.interval || 8 * 60 * 1000; // 8 دقائق
54
+ const intervalMs = options.interval || 5 * 60 * 1000; // ✅ كان 8 دقائق → 5 دقائق
19
55
  const saveOnLogin= options.saveOnLogin !== false;
20
56
 
21
57
  let lastHash = null;
22
58
 
23
- function hashState(state) {
24
- return state.length + "_" + (state[0]?.value?.length || 0);
25
- }
26
-
27
59
  function saveState(force = false) {
28
60
  try {
29
61
  const state = api.getAppState();
30
62
  if (!state || state.length === 0) { logger("[ AYMAN ] AppState فارغ — تخطي", "warn"); return; }
31
63
 
32
- const h = hashState(state);
64
+ const h = hashState(state); // ✅ hash أقوى
33
65
  if (!force && h === lastHash) return; // لا تغيير
34
66
  lastHash = h;
35
67
 
36
- // Atomic write
68
+ // Atomic write للملف الرئيسي
37
69
  const tmp = filePath + ".tmp";
38
70
  fs.writeFileSync(tmp, JSON.stringify(state, null, "\t"), "utf8");
39
71
  fs.renameSync(tmp, filePath);
40
72
  logger(`[ AYMAN ] AppState محفوظ ✅ (${filePath})`, "info");
73
+
74
+ // ✅ حفظ backup نسخة احتياطية
75
+ saveBackup(state);
41
76
  } catch (err) {
42
77
  logger(`[ AYMAN ] خطأ حفظ AppState: ${err?.message || err}`, "error");
43
78
  }
@@ -1,8 +1,12 @@
1
1
  // ============================================================
2
- // AYMAN-FCA v2.0 — Refresh fb_dtsg
2
+ // AYMAN-FCA v2.0 — Refresh fb_dtsg [FIXED]
3
3
  // © 2025 Ayman. All Rights Reserved.
4
4
  //
5
- // تجديد تلقائي كل 6 ساعات + retry 3 مرات عند الفشل
5
+ // الإصلاحات:
6
+ // ✅ Interval من 6 ساعات → 90 دقيقة (fb_dtsg يحتاج تجديد أكثر)
7
+ // ✅ تجديد lsd أيضاً (كان مفقوداً)
8
+ // ✅ حفظ AppState بعد كل تجديد ناجح
9
+ // ✅ فحص أن المكتبة لا تزال متصلة قبل التجديد
6
10
  // ============================================================
7
11
  "use strict";
8
12
 
@@ -10,17 +14,43 @@ const { getFrom } = require("../../utils/constants");
10
14
  const { get } = require("../../utils/request");
11
15
  const { getType } = require("../../utils/format");
12
16
  const logger = require("../../../func/logger");
17
+ const fs = require("fs");
18
+ const path = require("path");
19
+
20
+ // ✅ كان 6 ساعات — مخفض إلى 90 دقيقة للاستقرار
21
+ const REFRESH_INTERVAL_MS = 90 * 60 * 1000;
22
+
23
+ function saveAppState(api) {
24
+ try {
25
+ if (!api?.getAppState) return;
26
+ const state = api.getAppState();
27
+ if (!state || !state.length) return;
28
+ const file = path.join(process.cwd(), "appstate.json");
29
+ const tmp = file + ".tmp";
30
+ fs.writeFileSync(tmp, JSON.stringify(state, null, "\t"), "utf8");
31
+ fs.renameSync(tmp, file);
32
+ } catch (_) {}
33
+ }
13
34
 
14
35
  module.exports = function(defaultFuncs, api, ctx) {
15
36
 
16
- // ✅ تجديد تلقائي كل 6 ساعات
17
- if (ctx._fbDtsgInterval) clearInterval(ctx._fbDtsgInterval);
37
+ // ✅ إلغاء أي interval سابق قبل إنشاء جديد
38
+ if (ctx._fbDtsgInterval) {
39
+ clearInterval(ctx._fbDtsgInterval);
40
+ ctx._fbDtsgInterval = null;
41
+ }
42
+
43
+ // ✅ تجديد تلقائي كل 90 دقيقة
18
44
  ctx._fbDtsgInterval = setInterval(async () => {
19
45
  try {
46
+ // لا تجدد إذا كان MQTT منقطعاً (لا فائدة)
47
+ if (!ctx.mqttClient?.connected && !ctx.jar) return;
20
48
  await api.refreshFb_dtsg();
21
49
  logger("[ AYMAN ] fb_dtsg مجدد تلقائياً ✅", "info");
50
+ // حفظ appstate بعد كل تجديد ناجح
51
+ saveAppState(api);
22
52
  } catch (_) {}
23
- }, 6 * 60 * 60 * 1000);
53
+ }, REFRESH_INTERVAL_MS);
24
54
 
25
55
  return function refreshFb_dtsg(obj, callback) {
26
56
  if (typeof obj === "function") { callback = obj; obj = {}; }
@@ -31,23 +61,44 @@ module.exports = function(defaultFuncs, api, ctx) {
31
61
  if (!callback) callback = (err, data) => err ? reject(err) : resolve(data);
32
62
 
33
63
  if (Object.keys(obj).length === 0) {
34
- // ✅ 3 محاولات عند الفشل
64
+ // ✅ 3 محاولات مع تأخير تصاعدي
35
65
  const tryRefresh = async (attempt = 0) => {
36
66
  try {
37
67
  const res = await get("https://www.facebook.com/", ctx.jar, null, ctx.globalOptions, { noRef: true });
38
68
  const html = res?.data || "";
39
- const dtsg = getFrom(html, '["DTSGInitData",[],{"token":"', '","');
40
- const jaz = getFrom(html, "jazoest=", '",');
69
+
70
+ // استخراج fb_dtsg
71
+ const dtsg = getFrom(html, '["DTSGInitData",[],{"token":"', '",')
72
+ || getFrom(html, '"token":"', '","ttl"');
73
+ // ✅ استخراج jazoest
74
+ const jaz = getFrom(html, "jazoest=", "&")
75
+ || getFrom(html, 'name="jazoest" value="', '"');
76
+ // ✅ استخراج lsd (مُضاف جديد)
77
+ const lsd = getFrom(html, '["LSD",[],{"token":"', '"}')
78
+ || getFrom(html, '"lsd":{"token":"', '"');
41
79
 
42
80
  if (!dtsg) {
43
- if (attempt < 2) { await new Promise(r => setTimeout(r, 2000)); return tryRefresh(attempt + 1); }
81
+ if (attempt < 2) {
82
+ await new Promise(r => setTimeout(r, 2000 * (attempt + 1)));
83
+ return tryRefresh(attempt + 1);
84
+ }
44
85
  throw new Error("[ AYMAN ] لم يُعثر على fb_dtsg بعد 3 محاولات");
45
86
  }
46
87
 
47
- Object.assign(ctx, { fb_dtsg: dtsg, ...(jaz ? { jazoest: jaz } : {}) });
48
- callback(null, { data: { fb_dtsg: dtsg, jazoest: jaz }, message: "تم تجديد fb_dtsg ✅" });
88
+ // تحديث ctx بكل القيم الجديدة
89
+ ctx.fb_dtsg = dtsg;
90
+ if (jaz) ctx.jazoest = jaz;
91
+ if (lsd) ctx.lsd = lsd;
92
+
93
+ callback(null, {
94
+ data: { fb_dtsg: dtsg, jazoest: jaz, lsd },
95
+ message: "تم تجديد fb_dtsg ✅"
96
+ });
49
97
  } catch (err) {
50
- if (attempt < 2) { await new Promise(r => setTimeout(r, 2000)); return tryRefresh(attempt + 1); }
98
+ if (attempt < 2) {
99
+ await new Promise(r => setTimeout(r, 2000 * (attempt + 1)));
100
+ return tryRefresh(attempt + 1);
101
+ }
51
102
  callback(err);
52
103
  }
53
104
  };
@@ -1,14 +1,30 @@
1
1
  // ============================================================
2
- // AYMAN-FCA v2.0 — MQTT Core Connection
2
+ // AYMAN-FCA v2.0 — MQTT Core Connection [FIXED]
3
3
  // © 2025 Ayman. All Rights Reserved.
4
+ //
5
+ // الإصلاحات:
6
+ // ✅ keepalive: 10 (كان 60 — السبب الرئيسي للانقطاع)
7
+ // ✅ clean: true (كان false — يُسبب puback errors)
8
+ // ✅ reconnectPeriod: 1000 (كان 0 — يُغرق الشبكة)
9
+ // ✅ T_MS_WAIT_MS: 30000 (كان 12000 — قصير جداً)
10
+ // ✅ MAX_RECONNECT: Infinity (كان 15 — بعدها يموت نهائياً)
11
+ // ✅ exponential backoff لـ reconnect (بدلاً من delay ثابت)
12
+ // ✅ foreground heartbeat كل 8 دقائق داخل MQTT
4
13
  // ============================================================
5
14
  "use strict";
6
15
 
7
16
  const { formatID } = require("../../../utils/format");
8
17
 
9
- const DEFAULT_RECONNECT_MS = 3000;
10
- const T_MS_WAIT_MS = 12000;
11
- const MAX_RECONNECT = 15;
18
+ const DEFAULT_RECONNECT_MS = 2000;
19
+ const T_MS_WAIT_MS = 30000; // ✅ كان 12000 — زيادة للشبكات البطيئة
20
+ const MAX_RECONNECT = Infinity; // ✅ كان 15 — لا توقف نهائي
21
+
22
+ // Backoff: 2s, 4s, 8s, 16s, 30s, 30s, 30s...
23
+ function calcBackoff(attempt) {
24
+ const base = Math.min(DEFAULT_RECONNECT_MS * Math.pow(2, attempt), 30000);
25
+ const jitter = Math.random() * 1000;
26
+ return Math.round(base + jitter);
27
+ }
12
28
 
13
29
  function generateUUID() {
14
30
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
@@ -65,18 +81,21 @@ module.exports = function createListenMqtt(deps) {
65
81
 
66
82
  if (typeof ctx._reconnectAttempts !== "number") ctx._reconnectAttempts = 0;
67
83
 
84
+ // ✅ exponential backoff — لا يتوقف أبداً
68
85
  function scheduleReconnect(delayMs) {
69
86
  if (ctx._reconnectTimer) return;
70
87
  if (ctx._ending) return;
71
- if (ctx._reconnectAttempts >= MAX_RECONNECT) {
72
- logger(`[ AYMAN ] MQTT وصل الحد الأقصى (${MAX_RECONNECT}) — إيقاف`, "error");
73
- ctx._reconnectAttempts = 0;
74
- globalCallback({ type: "stop_listen", error: "max_reconnect_reached" }, null);
75
- return;
76
- }
77
- const ms = typeof delayMs === "number" ? delayMs : (ctx._mqttOpt?.reconnectDelayMs || DEFAULT_RECONNECT_MS);
88
+
89
+ const ms = typeof delayMs === "number"
90
+ ? delayMs
91
+ : calcBackoff(ctx._reconnectAttempts);
92
+
78
93
  ctx._reconnectAttempts++;
79
- logger(`[ AYMAN ] MQTT إعادة اتصال بعد ${ms}ms (${ctx._reconnectAttempts}/${MAX_RECONNECT})`, "warn");
94
+
95
+ // بعد 20 محاولة: أعد العداد إلى 10 (يبقى عند ~30s)
96
+ if (ctx._reconnectAttempts > 20) ctx._reconnectAttempts = 10;
97
+
98
+ logger(`[ AYMAN ] MQTT إعادة اتصال #${ctx._reconnectAttempts} بعد ${ms}ms`, "warn");
80
99
  ctx._reconnectTimer = setTimeout(() => {
81
100
  ctx._reconnectTimer = null;
82
101
  ctx.clientId = generateUUID();
@@ -110,7 +129,7 @@ module.exports = function createListenMqtt(deps) {
110
129
  protocolId: "MQIsdp",
111
130
  protocolVersion: 3,
112
131
  username: JSON.stringify(username),
113
- clean: false, // ✅ إصلاح puback error
132
+ clean: true, // ✅ كان false — true أفضل مع syncToken
114
133
  wsOptions: {
115
134
  headers: {
116
135
  Cookie: cookies,
@@ -130,12 +149,12 @@ module.exports = function createListenMqtt(deps) {
130
149
  origin: "https://www.facebook.com",
131
150
  protocolVersion: 13,
132
151
  binaryType: "arraybuffer",
133
- handshakeTimeout: 15000
152
+ handshakeTimeout: 20000
134
153
  },
135
- keepalive: 60,
154
+ keepalive: 10, // ✅ كان 60 — Facebook يحتاج ping كل 10s
136
155
  reschedulePings: true,
137
- reconnectPeriod: 0,
138
- connectTimeout: 15000
156
+ reconnectPeriod: 1000, // ✅ كان 0 — 1s انتظار قبل retry
157
+ connectTimeout: 20000 // ✅ كان 15000 — زيادة للشبكات البطيئة
139
158
  };
140
159
 
141
160
  if (ctx.globalOptions?.proxy) {
@@ -187,6 +206,17 @@ module.exports = function createListenMqtt(deps) {
187
206
  mqttClient.publish("/foreground_state", JSON.stringify({ foreground: chatOn }), { qos: 1 });
188
207
  mqttClient.publish("/set_client_settings", JSON.stringify({ make_user_available_when_in_foreground: true }), { qos: 1 });
189
208
 
209
+ // ✅ foreground heartbeat كل 8 دقائق (يُثبت النشاط لـ Facebook)
210
+ if (ctx._fgHeartbeat) clearInterval(ctx._fgHeartbeat);
211
+ ctx._fgHeartbeat = setInterval(() => {
212
+ try {
213
+ if (!mqttClient?.connected) return;
214
+ mqttClient.publish("/foreground_state", JSON.stringify({ foreground: true }), { qos: 0 });
215
+ mqttClient.publish("/set_client_settings", JSON.stringify({ make_user_available_when_in_foreground: true }), { qos: 0 });
216
+ } catch (_) {}
217
+ }, 8 * 60 * 1000);
218
+
219
+ // ✅ T_MS_WAIT_MS مرفوع إلى 30s
190
220
  let rTimeout = setTimeout(() => {
191
221
  rTimeout = null;
192
222
  if (ctx._ending) return;
@@ -248,6 +278,8 @@ module.exports = function createListenMqtt(deps) {
248
278
  });
249
279
 
250
280
  mqttClient.on("close", function() {
281
+ // ✅ تنظيف heartbeat عند الإغلاق
282
+ if (ctx._fgHeartbeat) { clearInterval(ctx._fgHeartbeat); ctx._fgHeartbeat = null; }
251
283
  if (ctx._ending || ctx._cycling) return;
252
284
  logger("[ AYMAN ] MQTT انقطع — إعادة اتصال", "warn");
253
285
  if (ctx.globalOptions?.autoReconnect !== false && !ctx._reconnectTimer) scheduleReconnect();