ayman-fca 1.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/README.md +81 -0
- package/func/checkUpdate.js +13 -0
- package/func/logAdapter.js +30 -0
- package/func/logger.js +66 -0
- package/index.d.ts +751 -0
- package/index.js +15 -0
- package/module/config.js +38 -0
- package/module/login.js +111 -0
- package/module/loginHelper.js +1296 -0
- package/module/options.js +37 -0
- package/package.json +78 -0
- package/src/api/action/addExternalModule.js +19 -0
- package/src/api/action/changeAvatar.js +137 -0
- package/src/api/action/changeBio.js +48 -0
- package/src/api/action/enableAutoSaveAppState.js +72 -0
- package/src/api/action/getCurrentUserID.js +11 -0
- package/src/api/action/handleFriendRequest.js +33 -0
- package/src/api/action/logout.js +76 -0
- package/src/api/action/refreshFb_dtsg.js +62 -0
- package/src/api/action/setPostReaction.js +106 -0
- package/src/api/action/story.js +118 -0
- package/src/api/action/unfriend.js +30 -0
- package/src/api/http/httpGet.js +28 -0
- package/src/api/http/httpPost.js +32 -0
- package/src/api/http/postFormData.js +23 -0
- package/src/api/messaging/J +1 -0
- package/src/api/messaging/addUserToGroup.js +70 -0
- package/src/api/messaging/changeAdminStatus.js +72 -0
- package/src/api/messaging/changeArchivedStatus.js +31 -0
- package/src/api/messaging/changeBlockedStatus.js +27 -0
- package/src/api/messaging/changeGroupImage.js +91 -0
- package/src/api/messaging/changeNickname.js +70 -0
- package/src/api/messaging/changeThreadColor.js +44 -0
- package/src/api/messaging/changeThreadEmoji.js +111 -0
- package/src/api/messaging/createNewGroup.js +50 -0
- package/src/api/messaging/createPoll.js +52 -0
- package/src/api/messaging/createThemeAI.js +98 -0
- package/src/api/messaging/deleteMessage.js +73 -0
- package/src/api/messaging/deleteThread.js +29 -0
- package/src/api/messaging/editMessage.js +67 -0
- package/src/api/messaging/forwardAttachment.js +55 -0
- package/src/api/messaging/forwardMessage.js +73 -0
- package/src/api/messaging/getEmojiUrl.js +29 -0
- package/src/api/messaging/getFriendsList.js +82 -0
- package/src/api/messaging/getMessage.js +829 -0
- package/src/api/messaging/getThemePictures.js +62 -0
- package/src/api/messaging/groupActions.js +119 -0
- package/src/api/messaging/handleMessageRequest.js +31 -0
- package/src/api/messaging/markAsDelivered.js +31 -0
- package/src/api/messaging/markAsRead.js +88 -0
- package/src/api/messaging/markAsReadAll.js +28 -0
- package/src/api/messaging/markAsSeen.js +30 -0
- package/src/api/messaging/muteThread.js +27 -0
- package/src/api/messaging/notes.js +101 -0
- package/src/api/messaging/removeUserFromGroup.js +51 -0
- package/src/api/messaging/resolvePhotoUrl.js +29 -0
- package/src/api/messaging/scheduler.js +100 -0
- package/src/api/messaging/searchForThread.js +32 -0
- package/src/api/messaging/sendMessage.js +270 -0
- package/src/api/messaging/sendTypingIndicator.js +62 -0
- package/src/api/messaging/setMessageReaction.js +91 -0
- package/src/api/messaging/setTitle.js +86 -0
- package/src/api/messaging/shareContact.js +47 -0
- package/src/api/messaging/threadColors.js +128 -0
- package/src/api/messaging/unsendMessage.js +73 -0
- package/src/api/messaging/uploadAttachment.js +492 -0
- package/src/api/socket/core/connectMqtt.js +259 -0
- package/src/api/socket/core/emitAuth.js +79 -0
- package/src/api/socket/core/getSeqID.js +170 -0
- package/src/api/socket/core/getTaskResponseData.js +27 -0
- package/src/api/socket/core/parseDelta.js +377 -0
- package/src/api/socket/detail/buildStream.js +215 -0
- package/src/api/socket/detail/constants.js +29 -0
- package/src/api/socket/listenMqtt.js +377 -0
- package/src/api/socket/middleware/index.js +80 -0
- package/src/api/threads/getThreadHistory.js +664 -0
- package/src/api/threads/getThreadInfo.js +296 -0
- package/src/api/threads/getThreadList.js +293 -0
- package/src/api/threads/getThreadPictures.js +43 -0
- package/src/api/user/J +1 -0
- package/src/api/user/getUserID.js +48 -0
- package/src/api/user/getUserInfo.js +402 -0
- package/src/api/user/getUserInfoV2.js +134 -0
- package/src/core/sendReqMqtt.js +69 -0
- package/src/database/helpers.js +36 -0
- package/src/database/models/index.js +55 -0
- package/src/database/models/thread.js +44 -0
- package/src/database/models/user.js +39 -0
- package/src/database/threadData.js +92 -0
- package/src/database/userData.js +88 -0
- package/src/remote/remoteClient.js +71 -0
- package/src/utils/broadcast.js +62 -0
- package/src/utils/client.js +10 -0
- package/src/utils/constants.js +53 -0
- package/src/utils/cookies.js +73 -0
- package/src/utils/format/attachment.js +357 -0
- package/src/utils/format/cookie.js +9 -0
- package/src/utils/format/date.js +50 -0
- package/src/utils/format/decode.js +44 -0
- package/src/utils/format/delta.js +194 -0
- package/src/utils/format/ids.js +64 -0
- package/src/utils/format/index.js +64 -0
- package/src/utils/format/message.js +88 -0
- package/src/utils/format/presence.js +132 -0
- package/src/utils/format/readTyp.js +44 -0
- package/src/utils/format/thread.js +42 -0
- package/src/utils/format/utils.js +141 -0
- package/src/utils/headers.js +96 -0
- package/src/utils/loginParser/autoLogin.js +125 -0
- package/src/utils/loginParser/helpers.js +43 -0
- package/src/utils/loginParser/index.js +10 -0
- package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
- package/src/utils/loginParser/textUtils.js +28 -0
- package/src/utils/request/H +1 -0
- package/src/utils/request/client.js +33 -0
- package/src/utils/request/config.js +25 -0
- package/src/utils/request/defaults.js +40 -0
- package/src/utils/request/helpers.js +31 -0
- package/src/utils/request/index.js +12 -0
- package/src/utils/request/methods.js +92 -0
- package/src/utils/request/proxy.js +23 -0
- package/src/utils/request/retry.js +87 -0
- package/src/utils/request/sanitize.js +41 -0
- package/src/utils/sessionKeeper.js +275 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Proxy Handler
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const { HttpsProxyAgent } = require("https-proxy-agent");
|
|
8
|
+
const { client } = require("./client");
|
|
9
|
+
|
|
10
|
+
function setProxy(proxyUrl) {
|
|
11
|
+
if (!proxyUrl) {
|
|
12
|
+
client.defaults.proxy = false;
|
|
13
|
+
client.defaults.httpAgent = undefined;
|
|
14
|
+
client.defaults.httpsAgent = undefined;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const agent = new HttpsProxyAgent(proxyUrl);
|
|
18
|
+
client.defaults.proxy = false;
|
|
19
|
+
client.defaults.httpAgent = agent;
|
|
20
|
+
client.defaults.httpsAgent = agent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = { setProxy };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Smart Retry System
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
//
|
|
5
|
+
// نظام إعادة محاولة ذكي مع Exponential Backoff + Jitter
|
|
6
|
+
// يتعامل مع: timeout, 429, 5xx, network errors
|
|
7
|
+
// ============================================================
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const { delay } = require("./client");
|
|
11
|
+
|
|
12
|
+
const RETRYABLE_CODES = new Set([
|
|
13
|
+
"UND_ERR_CONNECT_TIMEOUT","ETIMEDOUT","ECONNRESET",
|
|
14
|
+
"ECONNREFUSED","ENOTFOUND","EPIPE","EAI_AGAIN","ENETUNREACH"
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
function isRetryable(e) {
|
|
18
|
+
const code = e?.code || e?.cause?.code || "";
|
|
19
|
+
const msg = (e?.message || "").toLowerCase();
|
|
20
|
+
if (RETRYABLE_CODES.has(code)) return true;
|
|
21
|
+
if (/timeout|connect timeout|network error|fetch failed|socket hang up|econnreset/i.test(msg)) return true;
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function requestWithRetry(fn, retries = 3, baseDelay = 800, ctx) {
|
|
26
|
+
let lastError;
|
|
27
|
+
|
|
28
|
+
const emit = (event, payload) => {
|
|
29
|
+
try {
|
|
30
|
+
if (ctx?._emitter?.emit) ctx._emitter.emit(event, payload);
|
|
31
|
+
} catch {}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < retries; i++) {
|
|
35
|
+
try {
|
|
36
|
+
return await fn();
|
|
37
|
+
} catch (e) {
|
|
38
|
+
lastError = e;
|
|
39
|
+
|
|
40
|
+
// ✅ خطأ Header — لا تعيد المحاولة أبداً
|
|
41
|
+
if (e?.code === "ERR_INVALID_CHAR" || e?.message?.includes("Invalid character in header")) {
|
|
42
|
+
const err = new Error("AYMAN-FCA: Invalid header — request aborted.");
|
|
43
|
+
err.code = "ERR_INVALID_CHAR";
|
|
44
|
+
err.originalError = e;
|
|
45
|
+
return Promise.reject(err);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const status = e?.response?.status || e?.statusCode || 0;
|
|
49
|
+
const url = e?.config?.url || "";
|
|
50
|
+
const method = String(e?.config?.method || "").toUpperCase();
|
|
51
|
+
|
|
52
|
+
// ✅ Rate Limit (429) — انتظر أطول
|
|
53
|
+
if (status === 429) {
|
|
54
|
+
emit("rateLimit", { status, url, method, attempt: i + 1 });
|
|
55
|
+
const wait = Math.min(baseDelay * Math.pow(3, i), 60000);
|
|
56
|
+
await delay(wait);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ✅ 4xx (غير 429) — لا تعيد
|
|
61
|
+
if (status >= 400 && status < 500) {
|
|
62
|
+
return e.response || Promise.reject(e);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ✅ آخر محاولة
|
|
66
|
+
if (i === retries - 1) {
|
|
67
|
+
return e.response || Promise.reject(e);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ✅ أخطاء الشبكة
|
|
71
|
+
if (!status && isRetryable(e)) {
|
|
72
|
+
emit("networkError", { code: e?.code || "", message: e?.message || "", url, method, attempt: i + 1 });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ✅ Exponential Backoff + Jitter
|
|
76
|
+
const wait = Math.min(
|
|
77
|
+
baseDelay * Math.pow(2, i) + Math.floor(Math.random() * 400),
|
|
78
|
+
30000
|
|
79
|
+
);
|
|
80
|
+
await delay(wait);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Promise.reject(lastError || new Error("AYMAN-FCA: Request failed after retries"));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { requestWithRetry };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.0 — Header Sanitizer
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
function sanitizeHeaderValue(value) {
|
|
8
|
+
if (value === null || value === undefined) return "";
|
|
9
|
+
const str = String(value);
|
|
10
|
+
// ✅ إزالة كل الأحرف غير الصالحة في HTTP headers
|
|
11
|
+
return str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n]/g, "").trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function sanitizeHeaderName(name) {
|
|
15
|
+
if (!name || typeof name !== "string") return "";
|
|
16
|
+
return name.replace(/[^\x21-\x7E]/g, "").trim();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function sanitizeHeaders(headers) {
|
|
20
|
+
if (!headers || typeof headers !== "object") return {};
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
23
|
+
const k = sanitizeHeaderName(key);
|
|
24
|
+
if (!k) continue;
|
|
25
|
+
if (Array.isArray(value) || (value !== null && typeof value === "object") || typeof value === "function") continue;
|
|
26
|
+
|
|
27
|
+
// ✅ كشف القيم المسلسلة كـ array خطأً
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
const t = value.trim();
|
|
30
|
+
if (t.startsWith("[") && t.endsWith("]")) {
|
|
31
|
+
try { if (Array.isArray(JSON.parse(t))) continue; } catch (_) {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const v = sanitizeHeaderValue(value);
|
|
36
|
+
if (v !== "") out[k] = v;
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = { sanitizeHeaderValue, sanitizeHeaderName, sanitizeHeaders };
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// AYMAN-FCA v2.2 — Session Keeper (FIXED)
|
|
3
|
+
// © 2025 Ayman. All Rights Reserved.
|
|
4
|
+
// ============================================================
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
|
|
10
|
+
let logger;
|
|
11
|
+
try {
|
|
12
|
+
logger = require("../../../func/logger");
|
|
13
|
+
} catch(_) {
|
|
14
|
+
logger = (msg, type) => process.stderr.write(`[ AYMAN-SK ][ ${type || "info"} ] ${msg}\n`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ── Presence Encoder ──────────────────────────────────────────
|
|
18
|
+
const PRESENCE_MAP = {
|
|
19
|
+
_:"%", A:"%2", B:"000", C:"%7d", D:"%7b%22", E:"%2c%22",
|
|
20
|
+
F:"%22%3a", G:"%2c%22ut%22%3a1", H:"%2c%22bls%22%3a",
|
|
21
|
+
I:"%2c%22n%22%3a%22%", J:"%22%3a%7b%22i%22%3a0%7d",
|
|
22
|
+
K:"%2c%22pt%22%3a0%2c%22vis%22%3a", L:"%2c%22ch%22%3a%7b%22h%22%3a%22",
|
|
23
|
+
M:"%7b%22v%22%3a2%2c%22time%22%3a1", N:".channel%22%2c%22sub%22%3a%5b",
|
|
24
|
+
O:"%2c%22sb%22%3a1%2c%22t%22%3a%5b", P:"%2c%22ud%22%3a100%2c%22lc%22%3a0",
|
|
25
|
+
Q:"%5d%2c%22f%22%3anull%2c%22uct%22%3a", R:".channel%22%2c%22sub%22%3a%5b1%5d",
|
|
26
|
+
Z:"%2c%22sb%22%3a1%2c%22t%22%3a%5b%5d%2c%22f%22%3anull%2c%22uct%22%3a0%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a"
|
|
27
|
+
};
|
|
28
|
+
const encodeMap = {}, decodeList = [];
|
|
29
|
+
for (const [k,v] of Object.entries(PRESENCE_MAP)) { encodeMap[v]=k; decodeList.push(v); }
|
|
30
|
+
decodeList.sort((a,b)=>b.length-a.length);
|
|
31
|
+
const presenceRegex = new RegExp(decodeList.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|"),"g");
|
|
32
|
+
function presenceEncode(str){ return encodeURIComponent(str).replace(presenceRegex,m=>encodeMap[m]||m); }
|
|
33
|
+
|
|
34
|
+
function generatePresence(userID) {
|
|
35
|
+
const time = Date.now();
|
|
36
|
+
return "E" + presenceEncode(JSON.stringify({
|
|
37
|
+
v:3, time:Math.floor(time/1000), user:userID,
|
|
38
|
+
state:{ ut:0, t2:[], lm2:null, uct2:time, tr:null,
|
|
39
|
+
tw:Math.floor(Math.random()*4294967295)+1, at:time },
|
|
40
|
+
ch:{ [`p_${userID}`]:0 }
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function generateAccessibilityCookie() {
|
|
45
|
+
const time = Date.now();
|
|
46
|
+
return encodeURIComponent(JSON.stringify({
|
|
47
|
+
sr:0,"sr-ts":time,jk:0,"jk-ts":time,kb:0,"kb-ts":time,hcm:0,"hcm-ts":time
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function saveAppStateAtomic(statePath, state) {
|
|
52
|
+
try {
|
|
53
|
+
const tmp = statePath + ".tmp";
|
|
54
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, "\t"), "utf8");
|
|
55
|
+
fs.renameSync(tmp, statePath);
|
|
56
|
+
return true;
|
|
57
|
+
} catch(e) {
|
|
58
|
+
logger(`خطأ في حفظ AppState: ${e?.message||e}`, "error");
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function setCookieSafe(jar, cookieStr, url) {
|
|
64
|
+
try {
|
|
65
|
+
if (typeof jar?.setCookieSync==="function") jar.setCookieSync(cookieStr, url);
|
|
66
|
+
else if (typeof jar?.setCookie==="function") jar.setCookie(cookieStr, url);
|
|
67
|
+
} catch(_) {}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ✅ استخراج ctx الحقيقي من api
|
|
71
|
+
function extractCtx(api, hint) {
|
|
72
|
+
if (hint && hint.jar && hint.userID && hint.userID !== "0") return hint;
|
|
73
|
+
for (const key of Object.getOwnPropertyNames(api || {})) {
|
|
74
|
+
try {
|
|
75
|
+
const v = api[key];
|
|
76
|
+
if (v && typeof v==="object" && v.jar && v.userID && v.userID!=="0") return v;
|
|
77
|
+
} catch(_) {}
|
|
78
|
+
}
|
|
79
|
+
return hint || {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ✅ xs refresh آمن — المسار الصحيح
|
|
83
|
+
async function safeFetch(url, jar, ctx) {
|
|
84
|
+
// ✅ الإصلاح: require("./request") وليس require("../request")
|
|
85
|
+
try {
|
|
86
|
+
const { get } = require("./request");
|
|
87
|
+
const res = await get(url, jar, null, ctx?.globalOptions||{}, ctx);
|
|
88
|
+
const sc = res?.headers?.["set-cookie"] || [];
|
|
89
|
+
for (const c of sc) { try { setCookieSafe(jar, c, "https://www.facebook.com"); } catch(_) {} }
|
|
90
|
+
return res;
|
|
91
|
+
} catch(_) {
|
|
92
|
+
// fallback: axios مباشرة
|
|
93
|
+
try {
|
|
94
|
+
const axios = require("axios");
|
|
95
|
+
const cookies = jar?.getCookiesSync?.(url)?.map(c=>`${c.key}=${c.value}`).join("; ")||"";
|
|
96
|
+
const res = await axios.get(url, {
|
|
97
|
+
headers:{ "Cookie":cookies, "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36" },
|
|
98
|
+
timeout:20000, validateStatus:s=>s<600
|
|
99
|
+
});
|
|
100
|
+
const sc = res.headers?.["set-cookie"]||[];
|
|
101
|
+
for (const c of sc) { try { setCookieSafe(jar, c, "https://www.facebook.com"); } catch(_) {} }
|
|
102
|
+
return res;
|
|
103
|
+
} catch(_) { return null; }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ════════════════════════════════════════════════════════════════
|
|
108
|
+
function createSessionKeeper(api, ctxHint, options = {}) {
|
|
109
|
+
const appStatePath = options.appStatePath || path.join(process.cwd(), "appstate.json");
|
|
110
|
+
const onSave = typeof options.onSave==="function" ? options.onSave : null;
|
|
111
|
+
|
|
112
|
+
let ctx = extractCtx(api, ctxHint);
|
|
113
|
+
|
|
114
|
+
let _presence=null, _activity=null, _dtsg=null, _save=null;
|
|
115
|
+
let _access=null, _ping=null, _xsRefresh=null, _watchdog=null;
|
|
116
|
+
let _active=false, _lastHash=null;
|
|
117
|
+
|
|
118
|
+
function getCtx() {
|
|
119
|
+
if (!ctx?.jar || !ctx?.userID || ctx.userID==="0") ctx = extractCtx(api, ctxHint);
|
|
120
|
+
return ctx;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function _triggerSave(force=false) {
|
|
124
|
+
try {
|
|
125
|
+
if (!api?.getAppState) return;
|
|
126
|
+
const state = api.getAppState();
|
|
127
|
+
if (!state || state.length===0) return;
|
|
128
|
+
const xs = state.find(c=>(c.key||c.name)==="xs");
|
|
129
|
+
const cu = state.find(c=>(c.key||c.name)==="c_user");
|
|
130
|
+
const hash= `${state.length}_${cu?.value?.slice(0,6)||""}_${xs?.value?.slice(0,8)||""}`;
|
|
131
|
+
if (!force && hash===_lastHash) return;
|
|
132
|
+
_lastHash = hash;
|
|
133
|
+
const ok = saveAppStateAtomic(appStatePath, state);
|
|
134
|
+
if (ok) { logger("AppState محفوظ ✅","info"); if (onSave) onSave(state); }
|
|
135
|
+
} catch(_) {}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ① Presence كل 45 ثانية
|
|
139
|
+
function startPresence() {
|
|
140
|
+
if (_presence) return;
|
|
141
|
+
_presence = setInterval(()=>{
|
|
142
|
+
try {
|
|
143
|
+
const c = getCtx();
|
|
144
|
+
if (!c?.mqttClient?.connected || !c?.userID) return;
|
|
145
|
+
const p = generatePresence(c.userID);
|
|
146
|
+
c.mqttClient.publish("/orca_presence", JSON.stringify({p, c:c.userID}), {qos:0});
|
|
147
|
+
} catch(_) {}
|
|
148
|
+
}, 45*1000);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ② نشاط عشوائي كل 3-7 دقائق
|
|
152
|
+
function scheduleActivity() {
|
|
153
|
+
const ms = (3 + Math.random()*4)*60*1000;
|
|
154
|
+
_activity = setTimeout(async ()=>{
|
|
155
|
+
try {
|
|
156
|
+
const c = getCtx();
|
|
157
|
+
if (Math.random()>0.5) { if (api?.markAsReadAll) api.markAsReadAll(()=>{}); }
|
|
158
|
+
else if (c?.mqttClient?.connected)
|
|
159
|
+
c.mqttClient.publish("/foreground_state", JSON.stringify({foreground:true}), {qos:0});
|
|
160
|
+
} catch(_) {}
|
|
161
|
+
scheduleActivity();
|
|
162
|
+
}, ms);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ③ تجديد fb_dtsg كل 4 ساعات
|
|
166
|
+
function startDtsgRefresh() {
|
|
167
|
+
if (_dtsg) return;
|
|
168
|
+
_dtsg = setInterval(async ()=>{
|
|
169
|
+
try {
|
|
170
|
+
if (api?.refreshFb_dtsg) { await api.refreshFb_dtsg(); logger("fb_dtsg مجدد ✅","info"); _triggerSave(); }
|
|
171
|
+
} catch(_) {}
|
|
172
|
+
}, 4*60*60*1000);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ④ حفظ كل 8 دقائق
|
|
176
|
+
function startAutoSave() {
|
|
177
|
+
if (_save) return;
|
|
178
|
+
_save = setInterval(()=> _triggerSave(), 8*60*1000);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ⑤ Accessibility cookie كل 30 دقيقة
|
|
182
|
+
function startAccessibilityCookie() {
|
|
183
|
+
if (_access) return;
|
|
184
|
+
function update() {
|
|
185
|
+
try {
|
|
186
|
+
const c = getCtx();
|
|
187
|
+
if (!c?.jar) return;
|
|
188
|
+
const val = generateAccessibilityCookie();
|
|
189
|
+
const exp = new Date(Date.now()+365*24*3600*1000).toUTCString();
|
|
190
|
+
setCookieSafe(c.jar, `wd=${val}; domain=.facebook.com; path=/; expires=${exp}`, "https://www.facebook.com");
|
|
191
|
+
} catch(_) {}
|
|
192
|
+
}
|
|
193
|
+
update();
|
|
194
|
+
_access = setInterval(update, 30*60*1000);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ⑥ ✅ تجديد xs كل 4 ساعات — إصلاح المسار
|
|
198
|
+
function startXsRefresh() {
|
|
199
|
+
if (_xsRefresh) return;
|
|
200
|
+
_xsRefresh = setInterval(async ()=>{
|
|
201
|
+
try {
|
|
202
|
+
const c = getCtx();
|
|
203
|
+
if (!c?.jar) return;
|
|
204
|
+
const res = await safeFetch("https://www.facebook.com/", c.jar, c);
|
|
205
|
+
if (res) { logger("xs cookie مجدد ✅","info"); _triggerSave(); }
|
|
206
|
+
} catch(_) {}
|
|
207
|
+
}, 4*60*60*1000);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ⑦ Ping MQTT كل ساعة
|
|
211
|
+
function startPing() {
|
|
212
|
+
if (_ping) return;
|
|
213
|
+
_ping = setInterval(()=>{
|
|
214
|
+
try {
|
|
215
|
+
const c = getCtx();
|
|
216
|
+
if (!c?.mqttClient?.connected) return;
|
|
217
|
+
c.mqttClient.publish("/set_client_settings",
|
|
218
|
+
JSON.stringify({make_user_available_when_in_foreground:true}), {qos:0});
|
|
219
|
+
} catch(_) {}
|
|
220
|
+
}, 60*60*1000);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ⑧ Watchdog — يراقب MQTT كل دقيقتين
|
|
224
|
+
function startWatchdog() {
|
|
225
|
+
if (_watchdog) return;
|
|
226
|
+
let lastAlive = Date.now(), deadCount = 0;
|
|
227
|
+
_watchdog = setInterval(()=>{
|
|
228
|
+
try {
|
|
229
|
+
const c = getCtx();
|
|
230
|
+
if (!c?.mqttClient) return;
|
|
231
|
+
if (c.mqttClient?.connected) { lastAlive=Date.now(); deadCount=0; return; }
|
|
232
|
+
const deadMs = Date.now()-lastAlive;
|
|
233
|
+
if (deadMs > 5*60*1000 && !c.mqttClient?.reconnecting) {
|
|
234
|
+
deadCount++;
|
|
235
|
+
logger(`[ Watchdog ] MQTT منقطع ${Math.round(deadMs/60000)} دقيقة (${deadCount}/3)`, "warn");
|
|
236
|
+
if (deadCount>=3) {
|
|
237
|
+
deadCount=0; lastAlive=Date.now();
|
|
238
|
+
try { if (c?._emitter?.emit) c._emitter.emit("watchdog_reconnect",{reason:"mqtt_dead"}); }
|
|
239
|
+
catch(_) {}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} catch(_) {}
|
|
243
|
+
}, 2*60*1000);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function start() {
|
|
247
|
+
if (_active) return;
|
|
248
|
+
_active = true;
|
|
249
|
+
setTimeout(()=>{ ctx = extractCtx(api, ctxHint); }, 1000);
|
|
250
|
+
startPresence();
|
|
251
|
+
scheduleActivity();
|
|
252
|
+
startDtsgRefresh();
|
|
253
|
+
startAutoSave();
|
|
254
|
+
startAccessibilityCookie();
|
|
255
|
+
startXsRefresh();
|
|
256
|
+
startPing();
|
|
257
|
+
startWatchdog();
|
|
258
|
+
logger("Session Keeper v2.2 ✅ — 8 أنظمة تعمل", "info");
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function stop() {
|
|
262
|
+
_active = false;
|
|
263
|
+
[_presence,_dtsg,_save,_access,_xsRefresh,_ping,_watchdog].forEach(t=>{ try{if(t)clearInterval(t);}catch(_){} });
|
|
264
|
+
try{if(_activity)clearTimeout(_activity);}catch(_){}
|
|
265
|
+
_presence=_activity=_dtsg=_save=_access=_xsRefresh=_ping=_watchdog=null;
|
|
266
|
+
logger("Session Keeper موقوف","info");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function saveNow() { _triggerSave(true); return true; }
|
|
270
|
+
function updateCtx(c) { if (c?.jar&&c?.userID) { ctx=c; logger("ctx مُحدَّث ✅","info"); } }
|
|
271
|
+
|
|
272
|
+
return { start, stop, saveNow, updateCtx, generatePresence, generateAccessibilityCookie };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = { createSessionKeeper, generatePresence, generateAccessibilityCookie, saveAppStateAtomic };
|