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,62 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { getType } = require("../../utils/format");
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ return function getThemePictures(id, callback) {
8
+ let resolveFunc = function () { };
9
+ let rejectFunc = function () { };
10
+ const returnPromise = new Promise(function (resolve, reject) {
11
+ resolveFunc = resolve;
12
+ rejectFunc = reject;
13
+ });
14
+
15
+ if (!callback) {
16
+ if (
17
+ getType(callback) == "Function" ||
18
+ getType(callback) == "AsyncFunction"
19
+ ) {
20
+ callback = callback;
21
+ } else {
22
+ callback = function (err, data) {
23
+ if (err) {
24
+ return rejectFunc(err);
25
+ }
26
+ resolveFunc(data);
27
+ };
28
+ }
29
+ }
30
+
31
+ if (getType(id) != "String") {
32
+ id = "";
33
+ }
34
+
35
+ const form = {
36
+ fb_api_caller_class: "RelayModern",
37
+ fb_api_req_friendly_name: "MWPThreadThemeProviderQuery",
38
+ doc_id: "9734829906576883",
39
+ server_timestamps: true,
40
+ variables: JSON.stringify({
41
+ id
42
+ }),
43
+ av: ctx.userID
44
+ };
45
+ defaultFuncs
46
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
47
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
48
+ .then(function (resData) {
49
+ if (resData.errors) {
50
+ throw resData;
51
+ }
52
+
53
+ return callback(null, resData);
54
+ })
55
+ .catch(function (err) {
56
+ log.error("getThemePictures", err);
57
+ return callback(err);
58
+ });
59
+
60
+ return returnPromise;
61
+ };
62
+ };
@@ -0,0 +1,119 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Group Actions (FIXED EXPORT)
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { generateOfflineThreadingID } = require("../../utils/format");
8
+ const logger = require("../../../func/logger");
9
+
10
+ // ✅ إصلاح: يصدّر function واحدة تُضيف gcmember + gcrule + emoji للـ api
11
+ module.exports = function(defaultFuncs, api, ctx) {
12
+
13
+ // ── gcmember ──────────────────────────────────────────────
14
+ api.gcmember = async function gcmember(action, userIDs, threadID, callback) {
15
+ let _cb;
16
+ if (typeof threadID === "function") { _cb = threadID; threadID = null; }
17
+ else if (typeof callback === "function") { _cb = callback; }
18
+ let resolve, reject;
19
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
20
+ if (!_cb) _cb = (err, data) => err ? reject(err) : resolve(data);
21
+ try {
22
+ if (!["add","remove"].includes((action||"").toLowerCase()))
23
+ return _cb(null, { type:"error_gc", error:"action يجب أن يكون add أو remove" });
24
+ if (!userIDs || !threadID)
25
+ return _cb(null, { type:"error_gc", error:"userIDs و threadID مطلوبان" });
26
+ if (!ctx.mqttClient)
27
+ return _cb(null, { type:"error_gc", error:"MQTT غير متصل" });
28
+ const users = Array.isArray(userIDs) ? userIDs : [userIDs];
29
+ const info = await api.getThreadInfo(threadID);
30
+ if (!info?.isGroup) return _cb(null, { type:"error_gc", error:"يعمل فقط مع مجموعات" });
31
+ const members = info.participantIDs || [];
32
+ ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
33
+ ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1;
34
+ let payload, label, qname;
35
+ if (action === "add") {
36
+ const toAdd = users.filter(id => !members.includes(id));
37
+ if (!toAdd.length) return _cb(null, { type:"error_gc", error:"الأعضاء موجودون مسبقاً" });
38
+ payload = { thread_key: parseInt(threadID), contact_ids: toAdd.map(Number), sync_group: 1 };
39
+ label = "7"; qname = "add_participants";
40
+ } else {
41
+ payload = { thread_key: parseInt(threadID), contact_id: parseInt(users[0]), sync_group: 1 };
42
+ label = "8"; qname = "remove_participant";
43
+ }
44
+ const content = {
45
+ app_id: "2220391788200892",
46
+ payload: JSON.stringify({ epoch_id: parseInt(generateOfflineThreadingID()), tasks: [{ failure_count:null, label, payload: JSON.stringify(payload), queue_name:qname, task_id:ctx.wsTaskNumber }], version_id:"24631415369801570" }),
47
+ request_id: ctx.wsReqNumber, type: 3
48
+ };
49
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos:1, retain:false }, err => {
50
+ if (err) return _cb(err);
51
+ _cb(null, { type:"gc_member_update", action, threadID, userIDs:users, timestamp:Date.now() });
52
+ });
53
+ } catch(e) { _cb(null, { type:"error_gc", error:e?.message||String(e) }); }
54
+ return p;
55
+ };
56
+
57
+ // ── gcrule ────────────────────────────────────────────────
58
+ api.gcrule = async function gcrule(action, userID, threadID, callback) {
59
+ let _cb;
60
+ if (typeof threadID === "function") { _cb = threadID; threadID = null; }
61
+ else if (typeof callback === "function") { _cb = callback; }
62
+ let resolve, reject;
63
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
64
+ if (!_cb) _cb = (err, data) => err ? reject(err) : resolve(data);
65
+ try {
66
+ action = (action||"").toLowerCase();
67
+ if (!["admin","unadmin"].includes(action))
68
+ return _cb(null, { type:"error_gc_rule", error:"action يجب admin أو unadmin" });
69
+ if (!userID || !threadID)
70
+ return _cb(null, { type:"error_gc_rule", error:"userID و threadID مطلوبان" });
71
+ if (!ctx.mqttClient)
72
+ return _cb(null, { type:"error_gc_rule", error:"MQTT غير متصل" });
73
+ const info = await api.getThreadInfo(threadID);
74
+ const admins = (info?.adminIDs||[]).map(a => a.id||a);
75
+ const isAdm = admins.includes(String(userID));
76
+ if (action==="admin" && isAdm) return _cb(null, { type:"error_gc_rule", error:"المستخدم مشرف مسبقاً" });
77
+ if (action==="unadmin" && !isAdm) return _cb(null, { type:"error_gc_rule", error:"المستخدم ليس مشرفاً" });
78
+ ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
79
+ ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1;
80
+ const payload = { thread_key:parseInt(threadID), contact_id:parseInt(userID), is_admin:action==="admin"?1:0 };
81
+ const content = {
82
+ app_id:"2220391788200892",
83
+ payload:JSON.stringify({ epoch_id:parseInt(generateOfflineThreadingID()), tasks:[{ failure_count:null, label:"25", payload:JSON.stringify(payload), queue_name:"admin_status", task_id:ctx.wsTaskNumber }], version_id:"24631415369801570" }),
84
+ request_id:ctx.wsReqNumber, type:3
85
+ };
86
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos:1, retain:false }, err => {
87
+ if (err) return _cb(err);
88
+ _cb(null, { type:"gc_rule_update", action, threadID, userID, timestamp:Date.now() });
89
+ });
90
+ } catch(e) { _cb(null, { type:"error_gc_rule", error:e?.message||String(e) }); }
91
+ return p;
92
+ };
93
+
94
+ // ── emoji ─────────────────────────────────────────────────
95
+ api.emoji = function setEmoji(emoji, threadID, callback) {
96
+ let resolve, reject;
97
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
98
+ if (typeof callback !== "function") callback = (err,d) => err ? reject(err) : resolve(d);
99
+ if (!emoji) return callback(new Error("emoji مطلوب"));
100
+ if (!threadID) return callback(new Error("threadID مطلوب"));
101
+ if (!ctx.mqttClient) return callback(new Error("MQTT غير متصل"));
102
+ ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
103
+ ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1;
104
+ const payload = { thread_key:String(threadID), custom_emoji:emoji, avatar_sticker_instruction_key_id:null, sync_group:1 };
105
+ const content = {
106
+ app_id:"2220391788200892",
107
+ payload:JSON.stringify({ epoch_id:parseInt(generateOfflineThreadingID()), tasks:[{ failure_count:null, label:"100003", payload:JSON.stringify(payload), queue_name:"thread_quick_reaction", task_id:ctx.wsTaskNumber }], version_id:"24631415369801570" }),
108
+ request_id:ctx.wsReqNumber, type:3
109
+ };
110
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos:1, retain:false }, err => {
111
+ if (err) return callback(err);
112
+ callback(null, { type:"thread_emoji_update", threadID, emoji, timestamp:Date.now() });
113
+ });
114
+ return p;
115
+ };
116
+
117
+ // ✅ لازم نُرجع شيء حتى loginHelper ما يتجاهله
118
+ return api.gcmember;
119
+ };
@@ -0,0 +1,31 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Handle Message 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
+ const { getType } = require("../../utils/format");
10
+
11
+ module.exports = function(defaultFuncs, api, ctx) {
12
+ return function handleMessageRequest(threadID, accept, callback) {
13
+ if (getType(accept) !== "Boolean") throw { error: "accept يجب أن يكون boolean" };
14
+
15
+ let resolve, reject;
16
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
17
+ callback = callback || (err => err ? reject(err) : resolve());
18
+
19
+ if (getType(threadID) !== "Array") threadID = [threadID];
20
+ const box = accept ? "inbox" : "other";
21
+ const form = { client: "mercury" };
22
+ threadID.forEach((id, i) => { form[`${box}[${i}]`] = id; });
23
+
24
+ defaultFuncs.post("https://www.facebook.com/ajax/mercury/move_thread.php", ctx.jar, form)
25
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
26
+ .then(res => { if (res.error) throw res; callback(); })
27
+ .catch(err => { log.error("handleMessageRequest", err); callback(err); });
28
+
29
+ return p;
30
+ };
31
+ };
@@ -0,0 +1,31 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Mark As Delivered
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function markAsDelivered(threadID, messageID, callback) {
12
+ let resolve, reject;
13
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
14
+ callback = callback || (err => err ? reject(err) : resolve());
15
+
16
+ if (!threadID || !messageID) return callback("threadID و messageID مطلوبان");
17
+
18
+ const form = {
19
+ [`message_ids[0]`]: messageID,
20
+ [`thread_ids[${threadID}][0]`]: messageID
21
+ };
22
+
23
+ defaultFuncs.post("https://www.facebook.com/ajax/mercury/delivery_receipts.php", ctx.jar, form)
24
+ .then(saveCookies(ctx.jar))
25
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
26
+ .then(res => { if (res.error) throw res; callback(); })
27
+ .catch(err => { log.error("markAsDelivered", err); callback(err); });
28
+
29
+ return p;
30
+ };
31
+ };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
5
+ const { getType } = require("../../utils/format");
6
+ module.exports = function(defaultFuncs, api, ctx) {
7
+ return async function markAsRead(threadID, read, callback) {
8
+ if (
9
+ getType(read) === "Function" ||
10
+ getType(read) === "AsyncFunction"
11
+ ) {
12
+ callback = read;
13
+ read = true;
14
+ }
15
+ if (read == undefined) {
16
+ read = true;
17
+ }
18
+
19
+ if (!callback) {
20
+ callback = () => {};
21
+ }
22
+
23
+ const form = {};
24
+
25
+ if (typeof ctx.globalOptions.pageID !== "undefined") {
26
+ form["source"] = "PagesManagerMessagesInterface";
27
+ form["request_user_id"] = ctx.globalOptions.pageID;
28
+ form["ids[" + threadID + "]"] = read;
29
+ form["watermarkTimestamp"] = new Date().getTime();
30
+ form["shouldSendReadReceipt"] = true;
31
+ form["commerce_last_message_type"] = "";
32
+ //form["titanOriginatedThreadId"] = utils.generateThreadingID(ctx.clientID);
33
+
34
+ let resData;
35
+ try {
36
+ resData = await defaultFuncs
37
+ .post(
38
+ "https://www.facebook.com/ajax/mercury/change_read_status.php",
39
+ ctx.jar,
40
+ form
41
+ )
42
+ .then(saveCookies(ctx.jar))
43
+ .then(parseAndCheckLogin(ctx, defaultFuncs));
44
+ } catch (e) {
45
+ callback(e);
46
+ return e;
47
+ }
48
+
49
+ if (resData.error) {
50
+ const err = resData.error;
51
+ log.error("markAsRead", err);
52
+ if (getType(err) == "Object" && err.error === "Not logged in.") {
53
+ ctx.loggedIn = false;
54
+ }
55
+ callback(err);
56
+ return err;
57
+ }
58
+
59
+ callback();
60
+ return null;
61
+ } else {
62
+ try {
63
+ if (ctx.mqttClient) {
64
+ const err = await new Promise(r =>
65
+ ctx.mqttClient.publish(
66
+ "/mark_thread",
67
+ JSON.stringify({
68
+ threadID,
69
+ mark: "read",
70
+ state: read
71
+ }),
72
+ { qos: 1, retain: false },
73
+ r
74
+ )
75
+ );
76
+ if (err) throw err;
77
+ } else {
78
+ throw {
79
+ error: "You can only use this function after you start listening."
80
+ };
81
+ }
82
+ } catch (e) {
83
+ callback(e);
84
+ return e;
85
+ }
86
+ }
87
+ };
88
+ };
@@ -0,0 +1,28 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Mark As Read All
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function markAsReadAll(callback) {
12
+ let resolve, reject;
13
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
14
+ callback = callback || (err => err ? reject(err) : resolve());
15
+
16
+ defaultFuncs.post(
17
+ "https://www.facebook.com/ajax/mercury/mark_folder_as_read.php",
18
+ ctx.jar,
19
+ { folder: "inbox" }
20
+ )
21
+ .then(saveCookies(ctx.jar))
22
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
23
+ .then(res => { if (res.error) throw res; callback(); })
24
+ .catch(err => { log.error("markAsReadAll", err); callback(err); });
25
+
26
+ return p;
27
+ };
28
+ };
@@ -0,0 +1,30 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Mark As Seen
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
9
+ const { getType } = require("../../utils/format");
10
+
11
+ module.exports = function(defaultFuncs, api, ctx) {
12
+ return function markAsSeen(seen_timestamp, callback) {
13
+ if (getType(seen_timestamp) === "Function" || getType(seen_timestamp) === "AsyncFunction") {
14
+ callback = seen_timestamp; seen_timestamp = Date.now();
15
+ }
16
+ let resolve, reject;
17
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
18
+ callback = callback || (err => err ? reject(err) : resolve());
19
+
20
+ defaultFuncs.post("https://www.facebook.com/ajax/mercury/mark_seen.php", ctx.jar, {
21
+ seen_timestamp: seen_timestamp || Date.now()
22
+ })
23
+ .then(saveCookies(ctx.jar))
24
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
25
+ .then(res => { if (res.error) throw res; callback(); })
26
+ .catch(err => { log.error("markAsSeen", err); callback(err); });
27
+
28
+ return p;
29
+ };
30
+ };
@@ -0,0 +1,27 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Mute Thread
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function muteThread(threadID, muteSeconds, callback) {
12
+ let resolve, reject;
13
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
14
+ callback = callback || (err => err ? reject(err) : resolve());
15
+
16
+ defaultFuncs.post("https://www.facebook.com/ajax/mercury/change_mute_thread.php", ctx.jar, {
17
+ thread_fbid: threadID,
18
+ mute_settings: muteSeconds
19
+ })
20
+ .then(saveCookies(ctx.jar))
21
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
22
+ .then(res => { if (res.error) throw res; callback(); })
23
+ .catch(err => { log.error("muteThread", err); callback(err); });
24
+
25
+ return p;
26
+ };
27
+ };
@@ -0,0 +1,101 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Messenger Notes API
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // مستوحى من: ws3-fca
5
+ //
6
+ // api.notes.create(text, privacy?)
7
+ // api.notes.delete(noteID)
8
+ // api.notes.check()
9
+ // api.notes.recreate(oldID, newText)
10
+ // ============================================================
11
+ "use strict";
12
+
13
+ const logger = require("../../../func/logger");
14
+
15
+ module.exports = function(defaultFuncs, api, ctx) {
16
+
17
+ async function request(form) {
18
+ const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form);
19
+ const data = res?.data || res;
20
+ if (data?.errors) throw data.errors[0];
21
+ return data;
22
+ }
23
+
24
+ function checkNote(callback) {
25
+ if (typeof callback !== "function") callback = () => {};
26
+ const form = {
27
+ fb_api_caller_class: "RelayModern",
28
+ fb_api_req_friendly_name: "MWInboxTrayNoteCreationDialogQuery",
29
+ variables: JSON.stringify({ scale: 2 }),
30
+ doc_id: "30899655739648624"
31
+ };
32
+ request(form)
33
+ .then(d => callback(null, d?.data?.viewer?.actor?.msgr_user_rich_status || null))
34
+ .catch(err => { logger(`[ AYMAN ] notes.check: ${err?.message || err}`, "error"); callback(err); });
35
+ }
36
+
37
+ function createNote(text, privacy = "EVERYONE", callback) {
38
+ if (typeof privacy === "function") { callback = privacy; privacy = "EVERYONE"; }
39
+ if (typeof callback !== "function") callback = () => {};
40
+ const form = {
41
+ fb_api_caller_class: "RelayModern",
42
+ fb_api_req_friendly_name: "MWInboxTrayNoteCreationDialogCreationStepContentMutation",
43
+ variables: JSON.stringify({
44
+ input: {
45
+ client_mutation_id: String(Math.round(Math.random() * 10)),
46
+ actor_id: ctx.userID,
47
+ description: text,
48
+ duration: 86400,
49
+ note_type: "TEXT_NOTE",
50
+ privacy,
51
+ session_id: String(Date.now())
52
+ }
53
+ }),
54
+ doc_id: "24060573783603122"
55
+ };
56
+ request(form)
57
+ .then(d => {
58
+ const status = d?.data?.xfb_rich_status_create?.status;
59
+ if (!status) throw new Error("AYMAN-FCA: لم يُعثر على status");
60
+ callback(null, status);
61
+ })
62
+ .catch(err => { logger(`[ AYMAN ] notes.create: ${err?.message || err}`, "error"); callback(err); });
63
+ }
64
+
65
+ function deleteNote(noteID, callback) {
66
+ if (typeof callback !== "function") callback = () => {};
67
+ const form = {
68
+ fb_api_caller_class: "RelayModern",
69
+ fb_api_req_friendly_name: "useMWInboxTrayDeleteNoteMutation",
70
+ variables: JSON.stringify({
71
+ input: {
72
+ client_mutation_id: String(Math.round(Math.random() * 10)),
73
+ actor_id: ctx.userID,
74
+ rich_status_id: noteID
75
+ }
76
+ }),
77
+ doc_id: "9532619970198958"
78
+ };
79
+ request(form)
80
+ .then(d => callback(null, d?.data?.xfb_rich_status_delete))
81
+ .catch(err => { logger(`[ AYMAN ] notes.delete: ${err?.message || err}`, "error"); callback(err); });
82
+ }
83
+
84
+ function recreateNote(oldNoteID, newText, callback) {
85
+ if (typeof callback !== "function") callback = () => {};
86
+ deleteNote(oldNoteID, (err, deleted) => {
87
+ if (err) return callback(err);
88
+ createNote(newText, (err2, created) => {
89
+ if (err2) return callback(err2);
90
+ callback(null, { deleted, created });
91
+ });
92
+ });
93
+ }
94
+
95
+ return {
96
+ create: createNote,
97
+ delete: deleteNote,
98
+ check: checkNote,
99
+ recreate: recreateNote
100
+ };
101
+ };
@@ -0,0 +1,51 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Remove User From Group
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { getType, generateOfflineThreadingID } = require("../../utils/format");
8
+
9
+ module.exports = function(defaultFuncs, api, ctx) {
10
+ return function removeUserFromGroup(userID, threadID, callback) {
11
+ if (!ctx.mqttClient) {
12
+ const err = new Error("AYMAN-FCA: MQTT غير متصل");
13
+ return callback ? callback(err) : Promise.reject(err);
14
+ }
15
+ if (getType(threadID) !== "Number" && getType(threadID) !== "String")
16
+ throw { error: "threadID يجب أن يكون Number أو String" };
17
+ if (getType(userID) !== "Number" && getType(userID) !== "String")
18
+ throw { error: "userID يجب أن يكون Number أو String" };
19
+
20
+ let resolve, reject;
21
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
22
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
23
+
24
+ if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
25
+ const reqID = ++ctx.wsReqNumber;
26
+
27
+ const content = {
28
+ app_id: "2220391788200892",
29
+ payload: JSON.stringify({
30
+ epoch_id: generateOfflineThreadingID(),
31
+ tasks: [{
32
+ failure_count: null,
33
+ label: "140",
34
+ payload: JSON.stringify({ thread_id: threadID, contact_id: userID, sync_group: 1 }),
35
+ queue_name: "remove_participant_v2",
36
+ task_id: Math.random() * 1001 << 0
37
+ }],
38
+ version_id: "25002366262773827"
39
+ }),
40
+ request_id: reqID,
41
+ type: 3
42
+ };
43
+
44
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, err => {
45
+ if (err) { callback(err); reject(err); }
46
+ else { callback(null, true); resolve(true); }
47
+ });
48
+
49
+ return p;
50
+ };
51
+ };
@@ -0,0 +1,29 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Resolve Photo URL
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function resolvePhotoUrl(photoID, callback) {
12
+ let resolve, reject;
13
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
14
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
15
+
16
+ defaultFuncs.get(
17
+ "https://www.facebook.com/mercury/attachments/photo",
18
+ ctx.jar, { photo_id: photoID }
19
+ )
20
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
21
+ .then(res => {
22
+ if (res.error) throw res;
23
+ callback(null, res.jsmods?.require?.[0]?.[3]?.[0]);
24
+ })
25
+ .catch(err => { log.error("resolvePhotoUrl", err); callback(err); });
26
+
27
+ return p;
28
+ };
29
+ };