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.
Files changed (124) hide show
  1. package/README.md +81 -0
  2. package/func/checkUpdate.js +13 -0
  3. package/func/logAdapter.js +30 -0
  4. package/func/logger.js +66 -0
  5. package/index.d.ts +751 -0
  6. package/index.js +15 -0
  7. package/module/config.js +38 -0
  8. package/module/login.js +111 -0
  9. package/module/loginHelper.js +1296 -0
  10. package/module/options.js +37 -0
  11. package/package.json +78 -0
  12. package/src/api/action/addExternalModule.js +19 -0
  13. package/src/api/action/changeAvatar.js +137 -0
  14. package/src/api/action/changeBio.js +48 -0
  15. package/src/api/action/enableAutoSaveAppState.js +72 -0
  16. package/src/api/action/getCurrentUserID.js +11 -0
  17. package/src/api/action/handleFriendRequest.js +33 -0
  18. package/src/api/action/logout.js +76 -0
  19. package/src/api/action/refreshFb_dtsg.js +62 -0
  20. package/src/api/action/setPostReaction.js +106 -0
  21. package/src/api/action/story.js +118 -0
  22. package/src/api/action/unfriend.js +30 -0
  23. package/src/api/http/httpGet.js +28 -0
  24. package/src/api/http/httpPost.js +32 -0
  25. package/src/api/http/postFormData.js +23 -0
  26. package/src/api/messaging/J +1 -0
  27. package/src/api/messaging/addUserToGroup.js +70 -0
  28. package/src/api/messaging/changeAdminStatus.js +72 -0
  29. package/src/api/messaging/changeArchivedStatus.js +31 -0
  30. package/src/api/messaging/changeBlockedStatus.js +27 -0
  31. package/src/api/messaging/changeGroupImage.js +91 -0
  32. package/src/api/messaging/changeNickname.js +70 -0
  33. package/src/api/messaging/changeThreadColor.js +44 -0
  34. package/src/api/messaging/changeThreadEmoji.js +111 -0
  35. package/src/api/messaging/createNewGroup.js +50 -0
  36. package/src/api/messaging/createPoll.js +52 -0
  37. package/src/api/messaging/createThemeAI.js +98 -0
  38. package/src/api/messaging/deleteMessage.js +73 -0
  39. package/src/api/messaging/deleteThread.js +29 -0
  40. package/src/api/messaging/editMessage.js +67 -0
  41. package/src/api/messaging/forwardAttachment.js +55 -0
  42. package/src/api/messaging/forwardMessage.js +73 -0
  43. package/src/api/messaging/getEmojiUrl.js +29 -0
  44. package/src/api/messaging/getFriendsList.js +82 -0
  45. package/src/api/messaging/getMessage.js +829 -0
  46. package/src/api/messaging/getThemePictures.js +62 -0
  47. package/src/api/messaging/groupActions.js +119 -0
  48. package/src/api/messaging/handleMessageRequest.js +31 -0
  49. package/src/api/messaging/markAsDelivered.js +31 -0
  50. package/src/api/messaging/markAsRead.js +88 -0
  51. package/src/api/messaging/markAsReadAll.js +28 -0
  52. package/src/api/messaging/markAsSeen.js +30 -0
  53. package/src/api/messaging/muteThread.js +27 -0
  54. package/src/api/messaging/notes.js +101 -0
  55. package/src/api/messaging/removeUserFromGroup.js +51 -0
  56. package/src/api/messaging/resolvePhotoUrl.js +29 -0
  57. package/src/api/messaging/scheduler.js +100 -0
  58. package/src/api/messaging/searchForThread.js +32 -0
  59. package/src/api/messaging/sendMessage.js +270 -0
  60. package/src/api/messaging/sendTypingIndicator.js +62 -0
  61. package/src/api/messaging/setMessageReaction.js +91 -0
  62. package/src/api/messaging/setTitle.js +86 -0
  63. package/src/api/messaging/shareContact.js +47 -0
  64. package/src/api/messaging/threadColors.js +128 -0
  65. package/src/api/messaging/unsendMessage.js +73 -0
  66. package/src/api/messaging/uploadAttachment.js +492 -0
  67. package/src/api/socket/core/connectMqtt.js +259 -0
  68. package/src/api/socket/core/emitAuth.js +79 -0
  69. package/src/api/socket/core/getSeqID.js +170 -0
  70. package/src/api/socket/core/getTaskResponseData.js +27 -0
  71. package/src/api/socket/core/parseDelta.js +377 -0
  72. package/src/api/socket/detail/buildStream.js +215 -0
  73. package/src/api/socket/detail/constants.js +29 -0
  74. package/src/api/socket/listenMqtt.js +377 -0
  75. package/src/api/socket/middleware/index.js +80 -0
  76. package/src/api/threads/getThreadHistory.js +664 -0
  77. package/src/api/threads/getThreadInfo.js +296 -0
  78. package/src/api/threads/getThreadList.js +293 -0
  79. package/src/api/threads/getThreadPictures.js +43 -0
  80. package/src/api/user/J +1 -0
  81. package/src/api/user/getUserID.js +48 -0
  82. package/src/api/user/getUserInfo.js +402 -0
  83. package/src/api/user/getUserInfoV2.js +134 -0
  84. package/src/core/sendReqMqtt.js +69 -0
  85. package/src/database/helpers.js +36 -0
  86. package/src/database/models/index.js +55 -0
  87. package/src/database/models/thread.js +44 -0
  88. package/src/database/models/user.js +39 -0
  89. package/src/database/threadData.js +92 -0
  90. package/src/database/userData.js +88 -0
  91. package/src/remote/remoteClient.js +71 -0
  92. package/src/utils/broadcast.js +62 -0
  93. package/src/utils/client.js +10 -0
  94. package/src/utils/constants.js +53 -0
  95. package/src/utils/cookies.js +73 -0
  96. package/src/utils/format/attachment.js +357 -0
  97. package/src/utils/format/cookie.js +9 -0
  98. package/src/utils/format/date.js +50 -0
  99. package/src/utils/format/decode.js +44 -0
  100. package/src/utils/format/delta.js +194 -0
  101. package/src/utils/format/ids.js +64 -0
  102. package/src/utils/format/index.js +64 -0
  103. package/src/utils/format/message.js +88 -0
  104. package/src/utils/format/presence.js +132 -0
  105. package/src/utils/format/readTyp.js +44 -0
  106. package/src/utils/format/thread.js +42 -0
  107. package/src/utils/format/utils.js +141 -0
  108. package/src/utils/headers.js +96 -0
  109. package/src/utils/loginParser/autoLogin.js +125 -0
  110. package/src/utils/loginParser/helpers.js +43 -0
  111. package/src/utils/loginParser/index.js +10 -0
  112. package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
  113. package/src/utils/loginParser/textUtils.js +28 -0
  114. package/src/utils/request/H +1 -0
  115. package/src/utils/request/client.js +33 -0
  116. package/src/utils/request/config.js +25 -0
  117. package/src/utils/request/defaults.js +40 -0
  118. package/src/utils/request/helpers.js +31 -0
  119. package/src/utils/request/index.js +12 -0
  120. package/src/utils/request/methods.js +92 -0
  121. package/src/utils/request/proxy.js +23 -0
  122. package/src/utils/request/retry.js +87 -0
  123. package/src/utils/request/sanitize.js +41 -0
  124. package/src/utils/sessionKeeper.js +275 -0
@@ -0,0 +1,37 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Options Handler
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { getType } = require("../src/utils/format");
8
+ const { setProxy } = require("../src/utils/request");
9
+ const logger = require("../func/logger");
10
+
11
+ const BOOL_OPTIONS = [
12
+ "online","selfListen","listenEvents","updatePresence","forceLogin",
13
+ "autoMarkRead","autoMarkDelivery","listenTyping","autoReconnect",
14
+ "emitReady","selfListenEvent"
15
+ ];
16
+
17
+ // خيارات قديمة يتم تجاهلها بصمت
18
+ const IGNORED = new Set(["logLevel","pauseLog","logRecordSize","updateSeq"]);
19
+
20
+ function setOptions(globalOptions, options) {
21
+ for (const key of Object.keys(options || {})) {
22
+ if (IGNORED.has(key)) continue;
23
+ if (BOOL_OPTIONS.includes(key)) { globalOptions[key] = Boolean(options[key]); continue; }
24
+ switch (key) {
25
+ case "userAgent": globalOptions.userAgent = options.userAgent; break;
26
+ case "pageID": globalOptions.pageID = String(options.pageID); break;
27
+ case "proxy":
28
+ if (typeof options.proxy !== "string") { delete globalOptions.proxy; setProxy(); }
29
+ else { globalOptions.proxy = options.proxy; setProxy(options.proxy); }
30
+ break;
31
+ default:
32
+ logger(`[ AYMAN ] setOptions: خيار غير معروف "${key}"`, "warn");
33
+ }
34
+ }
35
+ }
36
+
37
+ module.exports = { setOptions, BOOL_OPTIONS };
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "ayman-fca",
3
+ "version": "1.0.0",
4
+ "description": "Facebook Chat API for Node.js — مكتبة KIRA بوت | © 2025 Ayman",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "require": "./index.js",
10
+ "default": "./index.js",
11
+ "types": "./index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "index.js",
16
+ "index.d.ts",
17
+ "module/",
18
+ "func/",
19
+ "src/",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "scripts": {
24
+ "test": "echo \"ayman-fca v1.0 by Ayman\""
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/ayman/ayman-fca.git"
29
+ },
30
+ "keywords": [
31
+ "facebook", "messenger", "chat", "api", "bot",
32
+ "kira", "ayman", "fca", "unofficial", "nodejs",
33
+ "automation", "facebook-api", "chatbot"
34
+ ],
35
+ "author": {
36
+ "name": "Ayman",
37
+ "url": "https://www.facebook.com/ayman"
38
+ },
39
+ "contributors": [
40
+ {
41
+ "name": "Ayman",
42
+ "url": "https://github.com/ayman"
43
+ }
44
+ ],
45
+ "license": "MIT",
46
+ "bugs": {
47
+ "url": "https://github.com/ayman/ayman-fca/issues"
48
+ },
49
+ "homepage": "https://github.com/ayman/ayman-fca#readme",
50
+ "engines": {
51
+ "node": ">=16.0.0"
52
+ },
53
+ "dependencies": {
54
+ "axios": "^1.13.5",
55
+ "axios-cookiejar-support": "^5.0.5",
56
+ "bluebird": "^3.7.2",
57
+ "chalk": "^4.1.2",
58
+ "cheerio": "^1.0.0-rc.10",
59
+ "duplexify": "^4.1.3",
60
+ "form-data": "^4.0.0",
61
+ "gradient-string": "^2.0.2",
62
+ "https-proxy-agent": "^7.0.0",
63
+ "mqtt": "^5.3.4",
64
+ "sequelize": "^6.37.6",
65
+ "sqlite3": "^5.1.7",
66
+ "tough-cookie": "^4.1.4",
67
+ "totp-generator": "^1.0.0",
68
+ "ws": "^8.18.1"
69
+ },
70
+ "devDependencies": {
71
+ "eslint": "^8.50.0",
72
+ "mocha": "^10.2.0"
73
+ },
74
+ "publishConfig": {
75
+ "access": "public",
76
+ "registry": "https://registry.npmjs.org/"
77
+ }
78
+ }
@@ -0,0 +1,19 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Add External Module
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { getType } = require("../../utils/format");
8
+
9
+ module.exports = function(defaultFuncs, api, ctx) {
10
+ return function addExternalModule(moduleObj) {
11
+ if (getType(moduleObj) !== "Object")
12
+ throw new Error(`moduleObj يجب أن يكون Object وليس ${getType(moduleObj)}`);
13
+ for (const name in moduleObj) {
14
+ if (getType(moduleObj[name]) !== "Function")
15
+ throw new Error(`"${name}" يجب أن يكون Function`);
16
+ api[name] = moduleObj[name](defaultFuncs, api, ctx);
17
+ }
18
+ };
19
+ };
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { isReadableStream } = require("../../utils/constants");
5
+ const { parseAndCheckLogin } = require("../../utils/client");
6
+ const { formatID, getType } = require("../../utils/format");
7
+ module.exports = function(defaultFuncs, api, ctx) {
8
+ function handleUpload(image, callback) {
9
+ const uploads = [];
10
+
11
+ const form = {
12
+ profile_id: ctx.userID,
13
+ photo_source: 57,
14
+ av: ctx.userID,
15
+ file: image
16
+ };
17
+
18
+ uploads.push(
19
+ defaultFuncs
20
+ .postFormData(
21
+ "https://www.facebook.com/profile/picture/upload/",
22
+ ctx.jar,
23
+ form,
24
+ {}
25
+ )
26
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
27
+ .then(function(resData) {
28
+ if (resData.error) {
29
+ throw resData;
30
+ }
31
+ return resData;
32
+ })
33
+ );
34
+
35
+ // resolve all promises
36
+ Promise.all(uploads)
37
+ .then(function(resData) {
38
+ callback(null, resData);
39
+ })
40
+ .catch(function(err) {
41
+ log.error("handleUpload", err);
42
+ return callback(err);
43
+ });
44
+ }
45
+
46
+ return function changeAvatar(
47
+ image,
48
+ caption = "",
49
+ timestamp = null,
50
+ callback
51
+ ) {
52
+ let resolveFunc = function() {};
53
+ let rejectFunc = function() {};
54
+ const returnPromise = new Promise(function(resolve, reject) {
55
+ resolveFunc = resolve;
56
+ rejectFunc = reject;
57
+ });
58
+
59
+ if (!timestamp && getType(caption) === "Number") {
60
+ timestamp = caption;
61
+ caption = "";
62
+ }
63
+
64
+ if (
65
+ !timestamp &&
66
+ !callback &&
67
+ (getType(caption) == "Function" ||
68
+ getType(caption) == "AsyncFunction")
69
+ ) {
70
+ callback = caption;
71
+ caption = "";
72
+ timestamp = null;
73
+ }
74
+
75
+ if (!callback)
76
+ callback = function(err, data) {
77
+ if (err) {
78
+ return rejectFunc(err);
79
+ }
80
+ resolveFunc(data);
81
+ };
82
+
83
+ if (!isReadableStream(image))
84
+ return callback("Image is not a readable stream");
85
+
86
+ handleUpload(image, function(err, payload) {
87
+ if (err) {
88
+ return callback(err);
89
+ }
90
+
91
+ const form = {
92
+ av: ctx.i_userID || ctx.userID,
93
+ fb_api_req_friendly_name: "ProfileCometProfilePictureSetMutation",
94
+ fb_api_caller_class: "RelayModern",
95
+ doc_id: "5066134240065849",
96
+ variables: JSON.stringify({
97
+ input: {
98
+ caption,
99
+ existing_photo_id: payload[0].payload.fbid,
100
+ expiration_time: timestamp,
101
+ profile_id: ctx.i_userID || ctx.userID,
102
+ profile_pic_method: "EXISTING",
103
+ profile_pic_source: "TIMELINE",
104
+ scaled_crop_rect: {
105
+ height: 1,
106
+ width: 1,
107
+ x: 0,
108
+ y: 0
109
+ },
110
+ skip_cropping: true,
111
+ actor_id: ctx.i_userID || ctx.userID,
112
+ client_mutation_id: Math.round(Math.random() * 19).toString()
113
+ },
114
+ isPage: false,
115
+ isProfile: true,
116
+ scale: 3
117
+ })
118
+ };
119
+
120
+ defaultFuncs
121
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
122
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
123
+ .then(function(resData) {
124
+ if (resData.errors) {
125
+ throw resData;
126
+ }
127
+ return callback(null, resData[0].data.profile_picture_set);
128
+ })
129
+ .catch(function(err) {
130
+ log.error("changeAvatar", err);
131
+ return callback(err);
132
+ });
133
+ });
134
+
135
+ return returnPromise;
136
+ };
137
+ };
@@ -0,0 +1,48 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Change Bio
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin } = require("../../utils/client");
9
+ const { getType } = require("../../utils/format");
10
+
11
+ module.exports = function(defaultFuncs, api, ctx) {
12
+ return function changeBio(bio, publish, callback) {
13
+ let resolve, reject;
14
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
15
+
16
+ if (getType(publish) === "Function" || getType(publish) === "AsyncFunction") {
17
+ callback = publish; publish = false;
18
+ }
19
+ callback = callback || (err => err ? reject(err) : resolve());
20
+ if (getType(publish) !== "Boolean") publish = false;
21
+ if (getType(bio) !== "String") { bio = ""; publish = false; }
22
+
23
+ const form = {
24
+ fb_api_caller_class: "RelayModern",
25
+ fb_api_req_friendly_name: "ProfileCometSetBioMutation",
26
+ doc_id: "2725043627607610",
27
+ variables: JSON.stringify({
28
+ input: {
29
+ bio,
30
+ publish_bio_feed_story: publish,
31
+ actor_id: ctx.i_userID || ctx.userID,
32
+ client_mutation_id: String(Math.round(Math.random() * 1024))
33
+ },
34
+ hasProfileTileViewID: false,
35
+ profileTileViewID: null,
36
+ scale: 1
37
+ }),
38
+ av: ctx.i_userID || ctx.userID
39
+ };
40
+
41
+ defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
42
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
43
+ .then(res => { if (res.errors) throw res; callback(); })
44
+ .catch(err => { log.error("changeBio", err); callback(err); });
45
+
46
+ return p;
47
+ };
48
+ };
@@ -0,0 +1,72 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Auto Save AppState
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ //
5
+ // حفظ ذكي: لا يحفظ إذا لم تتغير البيانات
6
+ // Atomic write: يحمي الملف من التلف
7
+ // يحفظ عند SIGINT/SIGTERM
8
+ // ============================================================
9
+ "use strict";
10
+
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const logger = require("../../../func/logger");
14
+
15
+ module.exports = function(defaultFuncs, api, ctx) {
16
+ return function enableAutoSaveAppState(options = {}) {
17
+ const filePath = options.filePath || path.join(process.cwd(), "appstate.json");
18
+ const intervalMs = options.interval || 8 * 60 * 1000; // 8 دقائق
19
+ const saveOnLogin= options.saveOnLogin !== false;
20
+
21
+ let lastHash = null;
22
+
23
+ function hashState(state) {
24
+ return state.length + "_" + (state[0]?.value?.length || 0);
25
+ }
26
+
27
+ function saveState(force = false) {
28
+ try {
29
+ const state = api.getAppState();
30
+ if (!state || state.length === 0) { logger("[ AYMAN ] AppState فارغ — تخطي", "warn"); return; }
31
+
32
+ const h = hashState(state);
33
+ if (!force && h === lastHash) return; // لا تغيير
34
+ lastHash = h;
35
+
36
+ // Atomic write
37
+ const tmp = filePath + ".tmp";
38
+ fs.writeFileSync(tmp, JSON.stringify(state, null, "\t"), "utf8");
39
+ fs.renameSync(tmp, filePath);
40
+ logger(`[ AYMAN ] AppState محفوظ ✅ (${filePath})`, "info");
41
+ } catch (err) {
42
+ logger(`[ AYMAN ] خطأ حفظ AppState: ${err?.message || err}`, "error");
43
+ }
44
+ }
45
+
46
+ // حفظ فوري عند اللوجين
47
+ let initTimer = null;
48
+ if (saveOnLogin) { initTimer = setTimeout(() => { saveState(true); initTimer = null; }, 2000); }
49
+
50
+ // حفظ دوري
51
+ const intervalId = setInterval(() => saveState(), intervalMs);
52
+ logger(`[ AYMAN ] حفظ تلقائي كل ${Math.round(intervalMs/60000)} دقيقة ✅`, "info");
53
+
54
+ if (!ctx._autoSaveInterval) ctx._autoSaveInterval = [];
55
+ ctx._autoSaveInterval.push(intervalId);
56
+
57
+ // حفظ عند الإيقاف
58
+ const exitHandler = () => saveState(true);
59
+ process.once("SIGINT", exitHandler);
60
+ process.once("SIGTERM", exitHandler);
61
+
62
+ return function disableAutoSaveAppState() {
63
+ if (initTimer) { clearTimeout(initTimer); initTimer = null; }
64
+ clearInterval(intervalId);
65
+ process.removeListener("SIGINT", exitHandler);
66
+ process.removeListener("SIGTERM", exitHandler);
67
+ const idx = ctx._autoSaveInterval?.indexOf(intervalId) ?? -1;
68
+ if (idx !== -1) ctx._autoSaveInterval.splice(idx, 1);
69
+ logger("[ AYMAN ] تم إيقاف الحفظ التلقائي", "info");
70
+ };
71
+ };
72
+ };
@@ -0,0 +1,11 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Get Current User ID
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ module.exports = function(defaultFuncs, api, ctx) {
8
+ return function getCurrentUserID() {
9
+ return ctx.userID;
10
+ };
11
+ };
@@ -0,0 +1,33 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Handle Friend Request
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin } = require("../../utils/client");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function handleFriendRequest(userID, accept, callback) {
12
+ if (typeof accept !== "boolean") throw { error: "accept يجب أن يكون boolean" };
13
+
14
+ let resolve, reject;
15
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
16
+ callback = callback || (err => err ? reject(err) : resolve());
17
+
18
+ const form = {
19
+ viewer_id: ctx.userID,
20
+ "frefs[0]": "jwl",
21
+ floc: "friend_center_requests",
22
+ ref: "/reqs.php",
23
+ action: accept ? "confirm" : "reject"
24
+ };
25
+
26
+ defaultFuncs.post("https://www.facebook.com/requests/friends/ajax/", ctx.jar, form)
27
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
28
+ .then(res => { if (res.payload?.err) throw { err: res.payload.err }; callback(); })
29
+ .catch(err => { log.error("handleFriendRequest", err); callback(err); });
30
+
31
+ return p;
32
+ };
33
+ };
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { getFrom } = require("../../utils/constants");
6
+ const { saveCookies } = require("../../utils/client");
7
+ module.exports = function(defaultFuncs, api, ctx) {
8
+ return function logout(callback) {
9
+ let resolveFunc = function() {};
10
+ let rejectFunc = function() {};
11
+ const returnPromise = new Promise(function(resolve, reject) {
12
+ resolveFunc = resolve;
13
+ rejectFunc = reject;
14
+ });
15
+
16
+ if (!callback) {
17
+ callback = function(err, friendList) {
18
+ if (err) {
19
+ return rejectFunc(err);
20
+ }
21
+ resolveFunc(friendList);
22
+ };
23
+ }
24
+
25
+ const form = {
26
+ pmid: "0"
27
+ };
28
+
29
+ defaultFuncs
30
+ .post(
31
+ "https://www.facebook.com/bluebar/modern_settings_menu/?help_type=364455653583099&show_contextual_help=1",
32
+ ctx.jar,
33
+ form
34
+ )
35
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(function(resData) {
37
+ const elem = resData.jsmods.instances[0][2][0].filter(function(v) {
38
+ return v.value === "logout";
39
+ })[0];
40
+
41
+ const html = resData.jsmods.markup.filter(function(v) {
42
+ return v[0] === elem.markup.__m;
43
+ })[0][1].__html;
44
+
45
+ const form = {
46
+ fb_dtsg: getFrom(html, '"fb_dtsg" value="', '"'),
47
+ ref: getFrom(html, '"ref" value="', '"'),
48
+ h: getFrom(html, '"h" value="', '"')
49
+ };
50
+
51
+ return defaultFuncs
52
+ .post("https://www.facebook.com/logout.php", ctx.jar, form)
53
+ .then(saveCookies(ctx.jar));
54
+ })
55
+ .then(function(res) {
56
+ if (!res.headers) {
57
+ throw { error: "An error occurred when logging out." };
58
+ }
59
+
60
+ return defaultFuncs
61
+ .get(res.headers.location, ctx.jar)
62
+ .then(saveCookies(ctx.jar));
63
+ })
64
+ .then(function() {
65
+ ctx.loggedIn = false;
66
+ log.info("logout", "Logged out successfully.");
67
+ callback();
68
+ })
69
+ .catch(function(err) {
70
+ log.error("logout", err);
71
+ return callback(err);
72
+ });
73
+
74
+ return returnPromise;
75
+ };
76
+ };
@@ -0,0 +1,62 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Refresh fb_dtsg
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ //
5
+ // تجديد تلقائي كل 6 ساعات + retry 3 مرات عند الفشل
6
+ // ============================================================
7
+ "use strict";
8
+
9
+ const { getFrom } = require("../../utils/constants");
10
+ const { get } = require("../../utils/request");
11
+ const { getType } = require("../../utils/format");
12
+ const logger = require("../../../func/logger");
13
+
14
+ module.exports = function(defaultFuncs, api, ctx) {
15
+
16
+ // ✅ تجديد تلقائي كل 6 ساعات
17
+ if (ctx._fbDtsgInterval) clearInterval(ctx._fbDtsgInterval);
18
+ ctx._fbDtsgInterval = setInterval(async () => {
19
+ try {
20
+ await api.refreshFb_dtsg();
21
+ logger("[ AYMAN ] fb_dtsg مجدد تلقائياً ✅", "info");
22
+ } catch (_) {}
23
+ }, 6 * 60 * 60 * 1000);
24
+
25
+ return function refreshFb_dtsg(obj, callback) {
26
+ if (typeof obj === "function") { callback = obj; obj = {}; }
27
+ if (!obj || getType(obj) !== "Object") obj = {};
28
+
29
+ let resolve, reject;
30
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
31
+ if (!callback) callback = (err, data) => err ? reject(err) : resolve(data);
32
+
33
+ if (Object.keys(obj).length === 0) {
34
+ // ✅ 3 محاولات عند الفشل
35
+ const tryRefresh = async (attempt = 0) => {
36
+ try {
37
+ const res = await get("https://www.facebook.com/", ctx.jar, null, ctx.globalOptions, { noRef: true });
38
+ const html = res?.data || "";
39
+ const dtsg = getFrom(html, '["DTSGInitData",[],{"token":"', '","');
40
+ const jaz = getFrom(html, "jazoest=", '",');
41
+
42
+ if (!dtsg) {
43
+ if (attempt < 2) { await new Promise(r => setTimeout(r, 2000)); return tryRefresh(attempt + 1); }
44
+ throw new Error("[ AYMAN ] لم يُعثر على fb_dtsg بعد 3 محاولات");
45
+ }
46
+
47
+ Object.assign(ctx, { fb_dtsg: dtsg, ...(jaz ? { jazoest: jaz } : {}) });
48
+ callback(null, { data: { fb_dtsg: dtsg, jazoest: jaz }, message: "تم تجديد fb_dtsg ✅" });
49
+ } catch (err) {
50
+ if (attempt < 2) { await new Promise(r => setTimeout(r, 2000)); return tryRefresh(attempt + 1); }
51
+ callback(err);
52
+ }
53
+ };
54
+ tryRefresh();
55
+ } else {
56
+ Object.assign(ctx, obj);
57
+ callback(null, { data: obj, message: `تم تجديد: ${Object.keys(obj).join(", ")}` });
58
+ }
59
+
60
+ return p;
61
+ };
62
+ };
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { getType } = require("../../utils/format");
6
+ function formatData(resData) {
7
+ return {
8
+ viewer_feedback_reaction_info:
9
+ resData.feedback_react.feedback.viewer_feedback_reaction_info,
10
+ supported_reactions: resData.feedback_react.feedback.supported_reactions,
11
+ top_reactions: resData.feedback_react.feedback.top_reactions.edges,
12
+ reaction_count: resData.feedback_react.feedback.reaction_count
13
+ };
14
+ }
15
+
16
+ module.exports = function(defaultFuncs, api, ctx) {
17
+ return function setPostReaction(postID, type, callback) {
18
+ let resolveFunc = function() {};
19
+ let rejectFunc = function() {};
20
+ const returnPromise = new Promise(function(resolve, reject) {
21
+ resolveFunc = resolve;
22
+ rejectFunc = reject;
23
+ });
24
+
25
+ if (!callback) {
26
+ if (
27
+ getType(type) === "Function" ||
28
+ getType(type) === "AsyncFunction"
29
+ ) {
30
+ callback = type;
31
+ type = 0;
32
+ } else {
33
+ callback = function(err, data) {
34
+ if (err) {
35
+ return rejectFunc(err);
36
+ }
37
+ resolveFunc(data);
38
+ };
39
+ }
40
+ }
41
+
42
+ const map = {
43
+ unlike: 0,
44
+ like: 1,
45
+ heart: 2,
46
+ love: 16,
47
+ haha: 4,
48
+ wow: 3,
49
+ sad: 7,
50
+ angry: 8
51
+ };
52
+
53
+ if (getType(type) !== "Number" && getType(type) === "String") {
54
+ type = map[type.toLowerCase()];
55
+ }
56
+
57
+ if (getType(type) !== "Number" && getType(type) !== "String") {
58
+ throw {
59
+ error: "setPostReaction: Invalid reaction type"
60
+ };
61
+ }
62
+
63
+ if (type != 0 && !type) {
64
+ throw {
65
+ error: "setPostReaction: Invalid reaction type"
66
+ };
67
+ }
68
+
69
+ const form = {
70
+ av: ctx.userID,
71
+ fb_api_caller_class: "RelayModern",
72
+ fb_api_req_friendly_name: "CometUFIFeedbackReactMutation",
73
+ doc_id: "4769042373179384",
74
+ variables: JSON.stringify({
75
+ input: {
76
+ actor_id: ctx.userID,
77
+ feedback_id: Buffer.from("feedback:" + postID).toString("base64"),
78
+ feedback_reaction: type,
79
+ feedback_source: "OBJECT",
80
+ is_tracking_encrypted: true,
81
+ tracking: [],
82
+ session_id: "f7dd50dd-db6e-4598-8cd9-561d5002b423",
83
+ client_mutation_id: Math.round(Math.random() * 19).toString()
84
+ },
85
+ useDefaultActor: false,
86
+ scale: 3
87
+ })
88
+ };
89
+
90
+ defaultFuncs
91
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
92
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
93
+ .then(function(resData) {
94
+ if (resData.errors) {
95
+ throw resData;
96
+ }
97
+ return callback(null, formatData(resData.data));
98
+ })
99
+ .catch(function(err) {
100
+ log.error("setPostReaction", err);
101
+ return callback(err);
102
+ });
103
+
104
+ return returnPromise;
105
+ };
106
+ };