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,111 @@
1
+ "use strict";
2
+
3
+ const { generateOfflineThreadingID } = require("../../utils/format");
4
+ const log = require("../../../func/logAdapter");
5
+ const { parseAndCheckLogin } = require("../../utils/client");
6
+ module.exports = function (defaultFuncs, api, ctx) {
7
+ function changeThreadEmojiNoMqtt(emoji, threadID, callback) {
8
+ var resolveFunc = function () { };
9
+ var rejectFunc = function () { };
10
+ var returnPromise = new Promise(function (resolve, reject) {
11
+ resolveFunc = resolve;
12
+ rejectFunc = reject;
13
+ });
14
+ if (!callback) {
15
+ callback = function (err) {
16
+ if (err) {
17
+ return rejectFunc(err);
18
+ }
19
+ resolveFunc();
20
+ };
21
+ }
22
+ var form = {
23
+ emoji_choice: emoji,
24
+ thread_or_other_fbid: threadID,
25
+ };
26
+ defaultFuncs
27
+ .post(
28
+ "https://www.facebook.com/messaging/save_thread_emoji/?source=thread_settings&__pc=EXP1%3Amessengerdotcom_pkg",
29
+ ctx.jar,
30
+ form,
31
+ )
32
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
33
+ .then(function (resData) {
34
+ if (resData.error === 1357031) {
35
+ throw {
36
+ error:
37
+ "Trying to change emoji of a chat that doesn't exist. Have at least one message in the thread before trying to change the emoji.",
38
+ };
39
+ }
40
+ if (resData.error) {
41
+ throw resData;
42
+ }
43
+ return callback();
44
+ })
45
+ .catch(function (err) {
46
+ log.error("changeThreadEmoji", err);
47
+ return callback(err);
48
+ });
49
+ return returnPromise;
50
+ };
51
+ function changeThreadEmojiMqtt(emoji, threadID, callback) {
52
+ if (!ctx.mqttClient) {
53
+ throw new Error("Not connected to MQTT");
54
+ }
55
+ if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
56
+ const reqID = ++ctx.wsReqNumber;
57
+ var resolveFunc = function () { };
58
+ var rejectFunc = function () { };
59
+ var returnPromise = new Promise(function (resolve, reject) {
60
+ resolveFunc = resolve;
61
+ rejectFunc = reject;
62
+ });
63
+ const done = (err, data) => {
64
+ if (err) {
65
+ if (callback) callback(err);
66
+ return rejectFunc(err);
67
+ }
68
+ if (callback) callback(null, data);
69
+ resolveFunc(data);
70
+ };
71
+ var form = JSON.stringify({
72
+ "app_id": "2220391788200892",
73
+ "payload": JSON.stringify({
74
+ epoch_id: generateOfflineThreadingID(),
75
+ tasks: [
76
+ {
77
+ failure_count: null,
78
+ label: '100003',
79
+ payload: JSON.stringify({
80
+ "thread_key": threadID,
81
+ "custom_emoji": emoji,
82
+ "avatar_sticker_instruction_key_id": null,
83
+ "sync_group": 1
84
+ }),
85
+ queue_name: 'thread_quick_reaction',
86
+ task_id: Math.random() * 1001 << 0
87
+ }
88
+ ],
89
+ version_id: '8798795233522156'
90
+ }),
91
+ "request_id": reqID,
92
+ "type": 3
93
+ });
94
+ ctx.mqttClient.publish("/ls_req", form, { qos: 1, retain: false }, (err) => {
95
+ if (err) return done(err);
96
+ done(null, { success: true });
97
+ });
98
+ return returnPromise;
99
+ };
100
+ return function changeThreadEmoji(emoji, threadID, callback) {
101
+ if (ctx.mqttClient) {
102
+ try {
103
+ return changeThreadEmojiMqtt(emoji, threadID, callback);
104
+ } catch (e) {
105
+ return changeThreadEmojiNoMqtt(emoji, threadID, callback);
106
+ }
107
+ } else {
108
+ return changeThreadEmojiNoMqtt(emoji, threadID, callback);
109
+ }
110
+ };
111
+ };
@@ -0,0 +1,50 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Create New Group
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 createNewGroup(participantIDs, groupTitle, callback) {
13
+ if (getType(groupTitle) === "Function") { callback = groupTitle; groupTitle = null; }
14
+ if (getType(participantIDs) !== "Array") throw { error: "participantIDs يجب أن يكون Array" };
15
+ if (participantIDs.length < 2) throw { error: "participantIDs يحتاج عضوين على الأقل" };
16
+
17
+ let resolve, reject;
18
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
19
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
20
+
21
+ const pids = participantIDs.map(id => ({ fbid: id }));
22
+ pids.push({ fbid: ctx.i_userID || ctx.userID });
23
+
24
+ const form = {
25
+ fb_api_caller_class: "RelayModern",
26
+ fb_api_req_friendly_name: "MessengerGroupCreateMutation",
27
+ av: ctx.i_userID || ctx.userID,
28
+ doc_id: "577041672419534",
29
+ variables: JSON.stringify({
30
+ input: {
31
+ entry_point: "jewel_new_group",
32
+ actor_id: ctx.i_userID || ctx.userID,
33
+ participants: pids,
34
+ client_mutation_id:String(Math.round(Math.random() * 1024)),
35
+ thread_settings: { name: groupTitle, joinable_mode: "PRIVATE", thread_image_fbid: null }
36
+ }
37
+ })
38
+ };
39
+
40
+ defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
41
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
42
+ .then(res => {
43
+ if (res.errors) throw res;
44
+ callback(null, res.data?.messenger_group_thread_create?.thread?.thread_key?.thread_fbid);
45
+ })
46
+ .catch(err => { log.error("createNewGroup", err); callback(err); });
47
+
48
+ return p;
49
+ };
50
+ };
@@ -0,0 +1,52 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Create Poll
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { generateOfflineThreadingID } = require("../../utils/format");
8
+
9
+ module.exports = function(defaultFuncs, api, ctx) {
10
+ return function createPoll(threadID, questionText, options, callback) {
11
+ let resolve, reject;
12
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
13
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
14
+
15
+ if (!ctx.mqttClient) {
16
+ const err = new Error("AYMAN-FCA: MQTT غير متصل");
17
+ callback(err); return p;
18
+ }
19
+ if (!questionText) return callback(new Error("questionText مطلوب"));
20
+ if (!Array.isArray(options) || !options.length) return callback(new Error("options مطلوب"));
21
+
22
+ const form = JSON.stringify({
23
+ app_id: "2220391788200892",
24
+ payload: JSON.stringify({
25
+ epoch_id: generateOfflineThreadingID(),
26
+ tasks: [{
27
+ failure_count: null,
28
+ label: "163",
29
+ payload: JSON.stringify({
30
+ question_text: questionText,
31
+ thread_key: threadID,
32
+ options,
33
+ sync_group: 1
34
+ }),
35
+ queue_name: "poll_creation",
36
+ task_id: Math.floor(Math.random() * 1001)
37
+ }],
38
+ version_id: "34195258046739157"
39
+ }),
40
+ request_id: ++ctx.wsReqNumber,
41
+ type: 3
42
+ });
43
+
44
+ ctx.mqttClient.publish("/ls_req", form, { qos: 1, retain: false }, err => {
45
+ if (err) return callback(err);
46
+ callback(null, { success: true, threadID, question: questionText });
47
+ resolve({ success: true });
48
+ });
49
+
50
+ return p;
51
+ };
52
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ const log = require("../../../func/logAdapter");
4
+ const { getType } = require("../../utils/format");
5
+ const { parseAndCheckLogin } = require("../../utils/client");
6
+
7
+ module.exports = function (defaultFuncs, api, ctx) {
8
+ return function createThemeAI(prompt, 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, data) {
18
+ if (err) return rejectFunc(err);
19
+ resolveFunc(data);
20
+ };
21
+ }
22
+
23
+ if (getType(prompt) !== "String") {
24
+ return callback({ error: "Invalid prompt. Please provide a string." });
25
+ }
26
+
27
+ if (!prompt || prompt.trim().length === 0) {
28
+ return callback({ error: "Prompt cannot be empty." });
29
+ }
30
+
31
+ const form = {
32
+ av: ctx.userID,
33
+ fb_api_caller_class: "RelayModern",
34
+ fb_api_req_friendly_name: "useGenerateAIThemeMutation",
35
+ doc_id: "23873748445608673",
36
+ variables: JSON.stringify({
37
+ input: {
38
+ client_mutation_id: Math.round(Math.random() * 19).toString(),
39
+ actor_id: ctx.userID,
40
+ bypass_cache: true,
41
+ caller: "MESSENGER",
42
+ num_themes: 1,
43
+ prompt: prompt.trim()
44
+ }
45
+ }),
46
+ server_timestamps: true
47
+ };
48
+
49
+ defaultFuncs
50
+ .post("https://www.facebook.com/api/graphql/", ctx.jar, form)
51
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
52
+ .then(function (resData) {
53
+ if (resData.errors) {
54
+ throw resData;
55
+ }
56
+
57
+ if (!resData.data || !resData.data.xfb_generate_ai_themes_from_prompt) {
58
+ throw {
59
+ error: "Invalid response from Facebook API",
60
+ res: resData
61
+ };
62
+ }
63
+
64
+ const themes = resData.data.xfb_generate_ai_themes_from_prompt.themes;
65
+ if (!themes || !Array.isArray(themes) || themes.length === 0) {
66
+ throw {
67
+ error: "No themes generated",
68
+ res: resData
69
+ };
70
+ }
71
+
72
+ const theme = themes[0];
73
+ if (!theme || !theme.id || !theme.background_asset) {
74
+ throw {
75
+ error: "Invalid theme data",
76
+ res: resData
77
+ };
78
+ }
79
+
80
+ callback(null, {
81
+ id: theme.id,
82
+ accessibility_label: theme.accessibility_label || null,
83
+ background_asset: {
84
+ id: theme.background_asset.id,
85
+ image: {
86
+ url: theme.background_asset.image?.uri || null
87
+ }
88
+ }
89
+ });
90
+ })
91
+ .catch(function (err) {
92
+ log.error("createThemeAI", err);
93
+ return callback(err);
94
+ });
95
+
96
+ return returnPromise;
97
+ };
98
+ };
@@ -0,0 +1,73 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Delete Message
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const log = require("../../../func/logAdapter");
8
+ const { getType, generateOfflineThreadingID } = require("../../utils/format");
9
+
10
+ module.exports = function(defaultFuncs, api, ctx) {
11
+ return function deleteMessage(messageOrMessages, 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 (getType(messageOrMessages) !== "Array") messageOrMessages = [messageOrMessages];
17
+ if (!ctx?.mqttClient) {
18
+ const err = new Error("AYMAN-FCA: MQTT غير متصل");
19
+ callback(err); return reject(err);
20
+ }
21
+
22
+ if (typeof ctx.wsTaskNumber !== "number") ctx.wsTaskNumber = 0;
23
+ if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
24
+
25
+ const epochId = String(generateOfflineThreadingID());
26
+ const tasks = messageOrMessages.map(id => ({
27
+ failure_count: null,
28
+ label: "146",
29
+ payload: `{"thread_key":${String(id)},"remove_type":0,"sync_group":1}`,
30
+ queue_name: String(id),
31
+ task_id: ++ctx.wsTaskNumber
32
+ }));
33
+
34
+ const reqID = ++ctx.wsReqNumber;
35
+ const form = JSON.stringify({
36
+ app_id: "2220391788200892",
37
+ payload: `{"epoch_id":${epochId},"tasks":${JSON.stringify(tasks)},"version_id":"25909428212080747"}`,
38
+ request_id: reqID,
39
+ type: 3
40
+ });
41
+
42
+ let done = false;
43
+
44
+ const cleanup = () => {
45
+ if (done) return; done = true;
46
+ clearTimeout(timer);
47
+ ctx.mqttClient?.removeListener("message", handleRes);
48
+ };
49
+
50
+ const handleRes = (topic, message) => {
51
+ if (topic !== "/ls_resp") return;
52
+ let msg;
53
+ try { msg = JSON.parse(message.toString()); } catch { return; }
54
+ if (msg.request_id !== reqID) return;
55
+ cleanup();
56
+ try { msg.payload = typeof msg.payload === "string" ? JSON.parse(msg.payload) : msg.payload; } catch {}
57
+ callback(null, { success: true }); resolve({ success: true });
58
+ };
59
+
60
+ ctx.mqttClient.on("message", handleRes);
61
+
62
+ const timer = setTimeout(() => {
63
+ cleanup();
64
+ callback(null, { success: true }); resolve({ success: true });
65
+ }, 15000);
66
+
67
+ ctx.mqttClient.publish("/ls_req", form, { qos: 1, retain: false }, err => {
68
+ if (err) { cleanup(); log.error("deleteMessage", err); callback(err); reject(err); }
69
+ });
70
+
71
+ return p;
72
+ };
73
+ };
@@ -0,0 +1,29 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Delete Thread
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 deleteThread(threadOrThreads, callback) {
13
+ let resolve, reject;
14
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
15
+ callback = callback || (err => err ? reject(err) : resolve());
16
+
17
+ if (getType(threadOrThreads) !== "Array") threadOrThreads = [threadOrThreads];
18
+
19
+ const form = { client: "mercury" };
20
+ threadOrThreads.forEach((id, i) => { form[`ids[${i}]`] = id; });
21
+
22
+ defaultFuncs.post("https://www.facebook.com/ajax/mercury/delete_thread.php", ctx.jar, form)
23
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
24
+ .then(res => { if (res.error) throw res; callback(); })
25
+ .catch(err => { log.error("deleteThread", err); callback(err); });
26
+
27
+ return p;
28
+ };
29
+ };
@@ -0,0 +1,67 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Edit Message
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { generateOfflineThreadingID } = require("../../utils/format");
8
+
9
+ module.exports = function(defaultFuncs, api, ctx) {
10
+ return function editMessage(text, messageID, callback) {
11
+ let resolve, reject;
12
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
13
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
14
+
15
+ if (!ctx.mqttClient) return callback(new Error("AYMAN-FCA: MQTT غير متصل"));
16
+
17
+ const reqID = ++ctx.wsReqNumber;
18
+
19
+ const content = {
20
+ app_id: "2220391788200892",
21
+ payload: JSON.stringify({
22
+ data_trace_id: null,
23
+ epoch_id: parseInt(generateOfflineThreadingID()),
24
+ tasks: [{
25
+ failure_count: null,
26
+ label: "742",
27
+ payload: JSON.stringify({ message_id: messageID, text }),
28
+ queue_name: "edit_message",
29
+ task_id: ++ctx.wsTaskNumber
30
+ }],
31
+ version_id: "6903494529735864"
32
+ }),
33
+ request_id: reqID,
34
+ type: 3
35
+ };
36
+
37
+ let done = false;
38
+ const timer = setTimeout(() => {
39
+ if (done) return; done = true;
40
+ ctx.mqttClient?.removeListener("message", handleRes);
41
+ callback(null, { success: true });
42
+ }, 10000);
43
+
44
+ const handleRes = (topic, message) => {
45
+ if (topic !== "/ls_resp") return;
46
+ let msg;
47
+ try { msg = JSON.parse(message.toString()); msg.payload = JSON.parse(msg.payload); } catch { return; }
48
+ if (msg.request_id !== reqID) return;
49
+ if (done) return; done = true;
50
+ clearTimeout(timer);
51
+ ctx.mqttClient?.removeListener("message", handleRes);
52
+ try {
53
+ const msgID = msg.payload.step?.[1]?.[2]?.[2]?.[1]?.[2];
54
+ const msgReplace= msg.payload.step?.[1]?.[2]?.[2]?.[1]?.[4];
55
+ const bodies = { body: msgReplace, messageID: msgID };
56
+ if (msgReplace !== text) return callback({ error: "الرسالة قديمة أو ليست منك" }, bodies);
57
+ callback(null, bodies); resolve(bodies);
58
+ } catch {
59
+ callback(null, { success: true }); resolve({ success: true });
60
+ }
61
+ };
62
+
63
+ ctx.mqttClient.on("message", handleRes);
64
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false });
65
+ return p;
66
+ };
67
+ };
@@ -0,0 +1,55 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Forward Attachment
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // ============================================================
5
+ "use strict";
6
+
7
+ const { generateOfflineThreadingID } = require("../../utils/format");
8
+
9
+ module.exports = function(defaultFuncs, api, ctx) {
10
+ return function forwardAttachment(threadID, forwardedMsgID, callback) {
11
+ let resolve, reject;
12
+ const p = new Promise((res, rej) => { resolve = res; reject = rej; });
13
+ callback = callback || ((err, data) => err ? reject(err) : resolve(data));
14
+
15
+ if (!ctx.mqttClient) {
16
+ const err = new Error("AYMAN-FCA: MQTT غير متصل");
17
+ callback(err); return p;
18
+ }
19
+
20
+ const form = JSON.stringify({
21
+ app_id: "772021112871879",
22
+ payload: JSON.stringify({
23
+ epoch_id: generateOfflineThreadingID(),
24
+ tasks: [{
25
+ failure_count: null,
26
+ label: "46",
27
+ payload: JSON.stringify({
28
+ thread_id: threadID,
29
+ otid: generateOfflineThreadingID(),
30
+ source: 65544,
31
+ send_type: 5,
32
+ sync_group: 1,
33
+ mark_thread_read: 0,
34
+ forwarded_msg_id: forwardedMsgID,
35
+ strip_forwarded_msg_caption:0,
36
+ initiating_source: 1
37
+ }),
38
+ queue_name: String(threadID),
39
+ task_id: Math.floor(Math.random() * 1001)
40
+ }],
41
+ version_id: "8768858626531631"
42
+ }),
43
+ request_id: ++ctx.wsReqNumber,
44
+ type: 3
45
+ });
46
+
47
+ ctx.mqttClient.publish("/ls_req", form, { qos: 1, retain: false }, err => {
48
+ if (err) return callback(err);
49
+ callback(null, { success: true });
50
+ resolve({ success: true });
51
+ });
52
+
53
+ return p;
54
+ };
55
+ };
@@ -0,0 +1,73 @@
1
+ // ============================================================
2
+ // AYMAN-FCA v2.0 — Forward Message via MQTT
3
+ // © 2025 Ayman. All Rights Reserved.
4
+ // مستوحى من: fca-unofficial-master
5
+ //
6
+ // api.forwardMessage(messageID, threadID, callback?)
7
+ // ============================================================
8
+ "use strict";
9
+
10
+ const { generateOfflineThreadingID } = require("../../utils/format");
11
+
12
+ module.exports = function(defaultFuncs, api, ctx) {
13
+ return function forwardMessage(messageID, threadID, callback) {
14
+ let resolveFunc, rejectFunc;
15
+ const returnPromise = new Promise((resolve, reject) => {
16
+ resolveFunc = resolve;
17
+ rejectFunc = reject;
18
+ });
19
+
20
+ if (typeof callback !== "function") {
21
+ callback = (err, data) => err ? rejectFunc(err) : resolveFunc(data);
22
+ }
23
+
24
+ if (!ctx.mqttClient) {
25
+ const err = new Error("AYMAN-FCA: MQTT غير متصل");
26
+ callback(err);
27
+ return returnPromise;
28
+ }
29
+
30
+ ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
31
+ ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1;
32
+
33
+ const otid = parseInt(generateOfflineThreadingID());
34
+
35
+ const taskPayload = {
36
+ thread_id: String(threadID),
37
+ otid,
38
+ source: 65544,
39
+ send_type: 5,
40
+ sync_group: 1,
41
+ forwarded_msg_id: String(messageID),
42
+ strip_forwarded_msg_caption: 0,
43
+ initiating_source: 1
44
+ };
45
+
46
+ const task = {
47
+ failure_count: null,
48
+ label: "46",
49
+ payload: JSON.stringify(taskPayload),
50
+ queue_name: String(threadID),
51
+ task_id: ctx.wsTaskNumber
52
+ };
53
+
54
+ const content = {
55
+ app_id: "2220391788200892",
56
+ payload: JSON.stringify({
57
+ data_trace_id: null,
58
+ epoch_id: parseInt(generateOfflineThreadingID()),
59
+ tasks: [task],
60
+ version_id: "25095469420099952"
61
+ }),
62
+ request_id: ctx.wsReqNumber,
63
+ type: 3
64
+ };
65
+
66
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, err => {
67
+ if (err) return callback(err);
68
+ callback(null, { success: true, messageID, threadID });
69
+ });
70
+
71
+ return returnPromise;
72
+ };
73
+ };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ const util = require("util");
4
+
5
+ module.exports = function() {
6
+ return function getEmojiUrl(c, size, pixelRatio) {
7
+ /*
8
+ Resolves Facebook Messenger emoji image asset URL for an emoji character.
9
+ Supported sizes are 32, 64, and 128.
10
+ Supported pixel ratios are '1.0' and '1.5' (possibly more; haven't tested)
11
+ */
12
+ const baseUrl = "https://static.xx.fbcdn.net/images/emoji.php/v8/z%s/%s";
13
+ pixelRatio = pixelRatio || "1.0";
14
+
15
+ const ending = util.format(
16
+ "%s/%s/%s.png",
17
+ pixelRatio,
18
+ size,
19
+ c.codePointAt(0).toString(16)
20
+ );
21
+ let base = 317426846;
22
+ for (let i = 0; i < ending.length; i++) {
23
+ base = (base << 5) - base + ending.charCodeAt(i);
24
+ }
25
+
26
+ const hashed = (base & 255).toString(16);
27
+ return util.format(baseUrl, hashed, ending);
28
+ };
29
+ };