fca-riyad 37.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 (242) hide show
  1. package/CHANGELOG.md +325 -0
  2. package/DOCS.md +2712 -0
  3. package/README.md +410 -0
  4. package/func/checkUpdate.js +7 -0
  5. package/func/logAdapter.js +33 -0
  6. package/func/logger.js +48 -0
  7. package/index.d.ts +751 -0
  8. package/index.js +22 -0
  9. package/module/config.js +40 -0
  10. package/module/login.js +133 -0
  11. package/module/loginHelper.js +1359 -0
  12. package/module/options.js +44 -0
  13. package/package.json +95 -0
  14. package/src/api/action/addExternalModule.js +25 -0
  15. package/src/api/action/changeAvatar.js +137 -0
  16. package/src/api/action/changeBio.js +75 -0
  17. package/src/api/action/enableAutoSaveAppState.js +73 -0
  18. package/src/api/action/getCurrentUserID.js +7 -0
  19. package/src/api/action/handleFriendRequest.js +57 -0
  20. package/src/api/action/logout.js +76 -0
  21. package/src/api/action/refreshFb_dtsg.js +48 -0
  22. package/src/api/action/setPostReaction.js +106 -0
  23. package/src/api/action/unfriend.js +54 -0
  24. package/src/api/http/httpGet.js +46 -0
  25. package/src/api/http/httpPost.js +52 -0
  26. package/src/api/http/postFormData.js +47 -0
  27. package/src/api/messaging/addUserToGroup.js +68 -0
  28. package/src/api/messaging/changeAdminStatus.js +126 -0
  29. package/src/api/messaging/changeArchivedStatus.js +55 -0
  30. package/src/api/messaging/changeBlockedStatus.js +48 -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 +79 -0
  34. package/src/api/messaging/changeThreadEmoji.js +111 -0
  35. package/src/api/messaging/createNewGroup.js +88 -0
  36. package/src/api/messaging/createPoll.js +46 -0
  37. package/src/api/messaging/createThemeAI.js +98 -0
  38. package/src/api/messaging/deleteMessage.js +136 -0
  39. package/src/api/messaging/deleteThread.js +56 -0
  40. package/src/api/messaging/editMessage.js +90 -0
  41. package/src/api/messaging/forwardAttachment.js +57 -0
  42. package/src/api/messaging/forwardMessage.js +134 -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/handleMessageRequest.js +65 -0
  48. package/src/api/messaging/markAsDelivered.js +57 -0
  49. package/src/api/messaging/markAsRead.js +88 -0
  50. package/src/api/messaging/markAsReadAll.js +49 -0
  51. package/src/api/messaging/markAsSeen.js +61 -0
  52. package/src/api/messaging/muteThread.js +50 -0
  53. package/src/api/messaging/pinMessage.js +115 -0
  54. package/src/api/messaging/removeUserFromGroup.js +62 -0
  55. package/src/api/messaging/resolvePhotoUrl.js +43 -0
  56. package/src/api/messaging/scheduler.js +264 -0
  57. package/src/api/messaging/searchForThread.js +53 -0
  58. package/src/api/messaging/sendBroadcast.js +93 -0
  59. package/src/api/messaging/sendMessage.js +269 -0
  60. package/src/api/messaging/sendTypingIndicator.js +74 -0
  61. package/src/api/messaging/sessionGuard.js +130 -0
  62. package/src/api/messaging/setMessageReaction.js +95 -0
  63. package/src/api/messaging/setTitle.js +124 -0
  64. package/src/api/messaging/shareContact.js +49 -0
  65. package/src/api/messaging/threadColors.js +128 -0
  66. package/src/api/messaging/unsendMessage.js +81 -0
  67. package/src/api/messaging/uploadAttachment.js +492 -0
  68. package/src/api/socket/OldMessage.js +186 -0
  69. package/src/api/socket/core/connectMqtt.js +269 -0
  70. package/src/api/socket/core/emitAuth.js +103 -0
  71. package/src/api/socket/core/getSeqID.js +321 -0
  72. package/src/api/socket/core/getTaskResponseData.js +25 -0
  73. package/src/api/socket/core/parseDelta.js +387 -0
  74. package/src/api/socket/detail/buildStream.js +215 -0
  75. package/src/api/socket/detail/constants.js +28 -0
  76. package/src/api/socket/e2ee/crypto.js +173 -0
  77. package/src/api/socket/e2ee/e2ee/crypto.js +173 -0
  78. package/src/api/socket/e2ee/e2ee/index.js +421 -0
  79. package/src/api/socket/e2ee/e2ee/proto/ArmadilloApplication.proto +281 -0
  80. package/src/api/socket/e2ee/e2ee/proto/ArmadilloICDC.proto +14 -0
  81. package/src/api/socket/e2ee/e2ee/proto/ConsumerApplication.proto +232 -0
  82. package/src/api/socket/e2ee/e2ee/proto/MessageApplication.proto +82 -0
  83. package/src/api/socket/e2ee/e2ee/proto/MessageTransport.proto +77 -0
  84. package/src/api/socket/e2ee/e2ee/proto/WACommon.proto +66 -0
  85. package/src/api/socket/e2ee/e2ee/proto/WAMediaTransport.proto +176 -0
  86. package/src/api/socket/e2ee/e2ee/proto/proto-writer.ts +76 -0
  87. package/src/api/socket/e2ee/e2ee/protocol.js +196 -0
  88. package/src/api/socket/e2ee/e2ee/ratchet.js +219 -0
  89. package/src/api/socket/e2ee/e2ee/store.js +182 -0
  90. package/src/api/socket/e2ee/e2ee/vendor/fb-e2ee.cjs +9162 -0
  91. package/src/api/socket/e2ee/e2ee/vendor/proto/ArmadilloApplication.proto +281 -0
  92. package/src/api/socket/e2ee/e2ee/vendor/proto/ArmadilloICDC.proto +14 -0
  93. package/src/api/socket/e2ee/e2ee/vendor/proto/ConsumerApplication.proto +232 -0
  94. package/src/api/socket/e2ee/e2ee/vendor/proto/MessageApplication.proto +82 -0
  95. package/src/api/socket/e2ee/e2ee/vendor/proto/MessageTransport.proto +77 -0
  96. package/src/api/socket/e2ee/e2ee/vendor/proto/WACommon.proto +66 -0
  97. package/src/api/socket/e2ee/e2ee/vendor/proto/WAMediaTransport.proto +176 -0
  98. package/src/api/socket/e2ee/e2ee/vendor/proto/proto-writer.ts +76 -0
  99. package/src/api/socket/e2ee/index.js +437 -0
  100. package/src/api/socket/e2ee/proto/ArmadilloApplication.proto +281 -0
  101. package/src/api/socket/e2ee/proto/ArmadilloICDC.proto +14 -0
  102. package/src/api/socket/e2ee/proto/ConsumerApplication.proto +232 -0
  103. package/src/api/socket/e2ee/proto/MessageApplication.proto +82 -0
  104. package/src/api/socket/e2ee/proto/MessageTransport.proto +77 -0
  105. package/src/api/socket/e2ee/proto/WACommon.proto +66 -0
  106. package/src/api/socket/e2ee/proto/WAMediaTransport.proto +176 -0
  107. package/src/api/socket/e2ee/proto/proto-writer.ts +76 -0
  108. package/src/api/socket/e2ee/protocol.js +196 -0
  109. package/src/api/socket/e2ee/ratchet.js +219 -0
  110. package/src/api/socket/e2ee/store.js +182 -0
  111. package/src/api/socket/e2ee/vendor/fb-e2ee.cjs +9162 -0
  112. package/src/api/socket/e2ee/vendor/proto/ArmadilloApplication.proto +281 -0
  113. package/src/api/socket/e2ee/vendor/proto/ArmadilloICDC.proto +14 -0
  114. package/src/api/socket/e2ee/vendor/proto/ConsumerApplication.proto +232 -0
  115. package/src/api/socket/e2ee/vendor/proto/MessageApplication.proto +82 -0
  116. package/src/api/socket/e2ee/vendor/proto/MessageTransport.proto +77 -0
  117. package/src/api/socket/e2ee/vendor/proto/WACommon.proto +66 -0
  118. package/src/api/socket/e2ee/vendor/proto/WAMediaTransport.proto +176 -0
  119. package/src/api/socket/e2ee/vendor/proto/proto-writer.ts +76 -0
  120. package/src/api/socket/listenE2EE.js +75 -0
  121. package/src/api/socket/listenMqtt.js +388 -0
  122. package/src/api/socket/middleware/index.js +216 -0
  123. package/src/api/socket/sendMessage.js +309 -0
  124. package/src/api/socket/sendMessageMqtt.js +69 -0
  125. package/src/api/threads/getThreadHistory.js +664 -0
  126. package/src/api/threads/getThreadInfo.js +296 -0
  127. package/src/api/threads/getThreadList.js +293 -0
  128. package/src/api/threads/getThreadPictures.js +78 -0
  129. package/src/api/users/getUserID.js +65 -0
  130. package/src/api/users/getUserInfo.js +402 -0
  131. package/src/api/users/getUserInfoV2.js +134 -0
  132. package/src/app/MessengerBot.js +209 -0
  133. package/src/app/MessengerContext.js +32 -0
  134. package/src/app/createFcaClient.js +136 -0
  135. package/src/app/threadInfoRealtimeSync.js +284 -0
  136. package/src/core/sendReqMqtt.js +96 -0
  137. package/src/database/helpers.js +53 -0
  138. package/src/database/models/index.js +88 -0
  139. package/src/database/models/thread.js +50 -0
  140. package/src/database/models/user.js +46 -0
  141. package/src/database/threadData.js +94 -0
  142. package/src/database/userData.js +98 -0
  143. package/src/remote/remoteClient.js +123 -0
  144. package/src/utils/broadcast.js +51 -0
  145. package/src/utils/client.js +10 -0
  146. package/src/utils/constants.js +23 -0
  147. package/src/utils/cookies.js +68 -0
  148. package/src/utils/format/attachment.js +357 -0
  149. package/src/utils/format/cookie.js +9 -0
  150. package/src/utils/format/date.js +50 -0
  151. package/src/utils/format/decode.js +44 -0
  152. package/src/utils/format/delta.js +194 -0
  153. package/src/utils/format/ids.js +64 -0
  154. package/src/utils/format/index.js +64 -0
  155. package/src/utils/format/message.js +88 -0
  156. package/src/utils/format/presence.js +132 -0
  157. package/src/utils/format/readTyp.js +44 -0
  158. package/src/utils/format/thread.js +42 -0
  159. package/src/utils/format/utils.js +141 -0
  160. package/src/utils/headers.js +115 -0
  161. package/src/utils/loginParser/autoLogin.js +125 -0
  162. package/src/utils/loginParser/helpers.js +43 -0
  163. package/src/utils/loginParser/index.js +10 -0
  164. package/src/utils/loginParser/parseAndCheckLogin.js +220 -0
  165. package/src/utils/loginParser/textUtils.js +28 -0
  166. package/src/utils/nexca-logger.js +144 -0
  167. package/src/utils/nexca-utils.js +686 -0
  168. package/src/utils/request/client.js +26 -0
  169. package/src/utils/request/config.js +23 -0
  170. package/src/utils/request/defaults.js +46 -0
  171. package/src/utils/request/helpers.js +46 -0
  172. package/src/utils/request/index.js +17 -0
  173. package/src/utils/request/methods.js +163 -0
  174. package/src/utils/request/proxy.js +21 -0
  175. package/src/utils/request/retry.js +77 -0
  176. package/src/utils/request/sanitize.js +49 -0
  177. package/src/utils/versionCheck.js +47 -0
  178. package/src/vendor/fca-unofficial/.github/workflows/nodejs.yml +26 -0
  179. package/src/vendor/fca-unofficial/.github/workflows/npmpublish.yml +30 -0
  180. package/src/vendor/fca-unofficial/.travis.yml +6 -0
  181. package/src/vendor/fca-unofficial/DOCS.md +1731 -0
  182. package/src/vendor/fca-unofficial/LICENSE-MIT +21 -0
  183. package/src/vendor/fca-unofficial/README.md +225 -0
  184. package/src/vendor/fca-unofficial/index.js +619 -0
  185. package/src/vendor/fca-unofficial/package.json +76 -0
  186. package/src/vendor/fca-unofficial/src/addExternalModule.js +19 -0
  187. package/src/vendor/fca-unofficial/src/addUserToGroup.js +113 -0
  188. package/src/vendor/fca-unofficial/src/changeAdminStatus.js +79 -0
  189. package/src/vendor/fca-unofficial/src/changeArchivedStatus.js +55 -0
  190. package/src/vendor/fca-unofficial/src/changeBio.js +77 -0
  191. package/src/vendor/fca-unofficial/src/changeBlockedStatus.js +47 -0
  192. package/src/vendor/fca-unofficial/src/changeGroupImage.js +129 -0
  193. package/src/vendor/fca-unofficial/src/changeNickname.js +59 -0
  194. package/src/vendor/fca-unofficial/src/changeThreadColor.js +71 -0
  195. package/src/vendor/fca-unofficial/src/changeThreadEmoji.js +55 -0
  196. package/src/vendor/fca-unofficial/src/createNewGroup.js +86 -0
  197. package/src/vendor/fca-unofficial/src/createPoll.js +71 -0
  198. package/src/vendor/fca-unofficial/src/deleteMessage.js +56 -0
  199. package/src/vendor/fca-unofficial/src/deleteThread.js +56 -0
  200. package/src/vendor/fca-unofficial/src/forwardAttachment.js +60 -0
  201. package/src/vendor/fca-unofficial/src/getCurrentUserID.js +7 -0
  202. package/src/vendor/fca-unofficial/src/getEmojiUrl.js +29 -0
  203. package/src/vendor/fca-unofficial/src/getFriendsList.js +84 -0
  204. package/src/vendor/fca-unofficial/src/getThreadHistory.js +645 -0
  205. package/src/vendor/fca-unofficial/src/getThreadHistoryDeprecated.js +93 -0
  206. package/src/vendor/fca-unofficial/src/getThreadInfo.js +201 -0
  207. package/src/vendor/fca-unofficial/src/getThreadInfoDeprecated.js +80 -0
  208. package/src/vendor/fca-unofficial/src/getThreadList.js +238 -0
  209. package/src/vendor/fca-unofficial/src/getThreadListDeprecated.js +75 -0
  210. package/src/vendor/fca-unofficial/src/getThreadPictures.js +79 -0
  211. package/src/vendor/fca-unofficial/src/getUserID.js +66 -0
  212. package/src/vendor/fca-unofficial/src/getUserInfo.js +72 -0
  213. package/src/vendor/fca-unofficial/src/handleFriendRequest.js +61 -0
  214. package/src/vendor/fca-unofficial/src/handleMessageRequest.js +65 -0
  215. package/src/vendor/fca-unofficial/src/httpGet.js +52 -0
  216. package/src/vendor/fca-unofficial/src/httpPost.js +52 -0
  217. package/src/vendor/fca-unofficial/src/listenMqtt.js +788 -0
  218. package/src/vendor/fca-unofficial/src/logout.js +75 -0
  219. package/src/vendor/fca-unofficial/src/markAsDelivered.js +58 -0
  220. package/src/vendor/fca-unofficial/src/markAsRead.js +80 -0
  221. package/src/vendor/fca-unofficial/src/markAsReadAll.js +50 -0
  222. package/src/vendor/fca-unofficial/src/markAsSeen.js +59 -0
  223. package/src/vendor/fca-unofficial/src/muteThread.js +52 -0
  224. package/src/vendor/fca-unofficial/src/removeUserFromGroup.js +79 -0
  225. package/src/vendor/fca-unofficial/src/resolvePhotoUrl.js +45 -0
  226. package/src/vendor/fca-unofficial/src/searchForThread.js +53 -0
  227. package/src/vendor/fca-unofficial/src/sendMessage.js +459 -0
  228. package/src/vendor/fca-unofficial/src/sendTypingIndicator.js +103 -0
  229. package/src/vendor/fca-unofficial/src/setMessageReaction.js +117 -0
  230. package/src/vendor/fca-unofficial/src/setPostReaction.js +76 -0
  231. package/src/vendor/fca-unofficial/src/setTitle.js +86 -0
  232. package/src/vendor/fca-unofficial/src/threadColors.js +57 -0
  233. package/src/vendor/fca-unofficial/src/unfriend.js +52 -0
  234. package/src/vendor/fca-unofficial/src/unsendMessage.js +49 -0
  235. package/src/vendor/fca-unofficial/test/data/shareAttach.js +146 -0
  236. package/src/vendor/fca-unofficial/test/data/something.mov +0 -0
  237. package/src/vendor/fca-unofficial/test/data/test.png +0 -0
  238. package/src/vendor/fca-unofficial/test/data/test.txt +7 -0
  239. package/src/vendor/fca-unofficial/test/example-config.json +18 -0
  240. package/src/vendor/fca-unofficial/test/test-page.js +140 -0
  241. package/src/vendor/fca-unofficial/test/test.js +385 -0
  242. package/src/vendor/fca-unofficial/utils.js +1358 -0
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ const logger = require("../../../func/logger");
3
+
4
+ /**
5
+ * Message Scheduler System
6
+ * Allows scheduling messages to be sent at a specific time in the future
7
+ */
8
+ module.exports = function (defaultFuncs, api, ctx) {
9
+ // Initialize scheduler on first call
10
+ if (!ctx._scheduler) {
11
+ ctx._scheduler = createSchedulerInstance(api);
12
+ }
13
+
14
+ return ctx._scheduler;
15
+ };
16
+
17
+ function createSchedulerInstance(api) {
18
+ const scheduledMessages = new Map(); // Map<id, ScheduledMessage>
19
+ let nextId = 1;
20
+
21
+ /**
22
+ * Scheduled Message Object
23
+ * @typedef {Object} ScheduledMessage
24
+ * @property {string} id - Unique identifier
25
+ * @property {string|Object} message - Message content
26
+ * @property {string|string[]} threadID - Target thread ID(s)
27
+ * @property {number} timestamp - When to send (Unix timestamp in ms)
28
+ * @property {number} createdAt - When scheduled (Unix timestamp in ms)
29
+ * @property {Object} options - Additional options (replyMessageID, isGroup, etc.)
30
+ * @property {Function} callback - Optional callback when sent
31
+ * @property {NodeJS.Timeout} timeout - Timeout reference
32
+ * @property {boolean} cancelled - Whether cancelled
33
+ */
34
+
35
+ /**
36
+ * Schedule a message to be sent at a specific time
37
+ * @param {string|Object} message - Message content
38
+ * @param {string|string[]} threadID - Target thread ID(s)
39
+ * @param {Date|number|string} when - When to send (Date, timestamp, or ISO string)
40
+ * @param {Object} [options] - Additional options
41
+ * @param {string} [options.replyMessageID] - Message ID to reply to
42
+ * @param {boolean} [options.isGroup] - Whether it's a group chat
43
+ * @param {Function} [options.callback] - Callback when sent
44
+ * @returns {string} Scheduled message ID
45
+ */
46
+ function scheduleMessage(message, threadID, when, options = {}) {
47
+ let timestamp;
48
+
49
+ // Parse when parameter
50
+ if (when instanceof Date) {
51
+ timestamp = when.getTime();
52
+ } else if (typeof when === "number") {
53
+ timestamp = when;
54
+ } else if (typeof when === "string") {
55
+ timestamp = new Date(when).getTime();
56
+ } else {
57
+ throw new Error("Invalid 'when' parameter. Must be Date, number (timestamp), or ISO string");
58
+ }
59
+
60
+ // Validate timestamp
61
+ if (isNaN(timestamp)) {
62
+ throw new Error("Invalid date/time");
63
+ }
64
+
65
+ const now = Date.now();
66
+ if (timestamp <= now) {
67
+ throw new Error("Scheduled time must be in the future");
68
+ }
69
+
70
+ const id = `scheduled_${nextId++}_${Date.now()}`;
71
+ const delay = timestamp - now;
72
+
73
+ // Create scheduled message object
74
+ const scheduled = {
75
+ id,
76
+ message,
77
+ threadID,
78
+ timestamp,
79
+ createdAt: now,
80
+ options: {
81
+ replyMessageID: options.replyMessageID,
82
+ isGroup: options.isGroup,
83
+ callback: options.callback
84
+ },
85
+ cancelled: false
86
+ };
87
+
88
+ // Set timeout to send message
89
+ scheduled.timeout = setTimeout(() => {
90
+ if (scheduled.cancelled) return;
91
+
92
+ try {
93
+ logger(`Sending scheduled message ${id}`, "info");
94
+
95
+ // Send message
96
+ api.sendMessage(
97
+ message,
98
+ threadID,
99
+ scheduled.options.callback || (() => {}),
100
+ scheduled.options.replyMessageID,
101
+ scheduled.options.isGroup
102
+ ).then(() => {
103
+ logger(`Scheduled message ${id} sent successfully`, "info");
104
+ scheduledMessages.delete(id);
105
+ }).catch(err => {
106
+ logger(`Error sending scheduled message ${id}: ${err && err.message ? err.message : String(err)}`, "error");
107
+ if (scheduled.options.callback) {
108
+ scheduled.options.callback(err);
109
+ }
110
+ scheduledMessages.delete(id);
111
+ });
112
+ } catch (err) {
113
+ logger(`Error in scheduled message ${id}: ${err && err.message ? err.message : String(err)}`, "error");
114
+ scheduledMessages.delete(id);
115
+ }
116
+ }, delay);
117
+
118
+ scheduledMessages.set(id, scheduled);
119
+ logger(`Message scheduled: ${id} (in ${Math.round(delay / 1000)}s)`, "info");
120
+
121
+ return id;
122
+ }
123
+
124
+ /**
125
+ * Cancel a scheduled message
126
+ * @param {string} id - Scheduled message ID
127
+ * @returns {boolean} True if cancelled, false if not found
128
+ */
129
+ function cancelScheduledMessage(id) {
130
+ const scheduled = scheduledMessages.get(id);
131
+ if (!scheduled) {
132
+ return false;
133
+ }
134
+
135
+ if (scheduled.cancelled) {
136
+ return false; // Already cancelled
137
+ }
138
+
139
+ clearTimeout(scheduled.timeout);
140
+ scheduled.cancelled = true;
141
+ scheduledMessages.delete(id);
142
+ logger(`Scheduled message ${id} cancelled`, "info");
143
+ return true;
144
+ }
145
+
146
+ /**
147
+ * Get scheduled message info
148
+ * @param {string} id - Scheduled message ID
149
+ * @returns {ScheduledMessage|null} Scheduled message or null if not found
150
+ */
151
+ function getScheduledMessage(id) {
152
+ const scheduled = scheduledMessages.get(id);
153
+ if (!scheduled || scheduled.cancelled) {
154
+ return null;
155
+ }
156
+
157
+ // Return a copy without internal properties
158
+ return {
159
+ id: scheduled.id,
160
+ message: scheduled.message,
161
+ threadID: scheduled.threadID,
162
+ timestamp: scheduled.timestamp,
163
+ createdAt: scheduled.createdAt,
164
+ options: { ...scheduled.options },
165
+ timeUntilSend: scheduled.timestamp - Date.now()
166
+ };
167
+ }
168
+
169
+ /**
170
+ * List all scheduled messages
171
+ * @returns {ScheduledMessage[]} Array of scheduled messages
172
+ */
173
+ function listScheduledMessages() {
174
+ const now = Date.now();
175
+ const list = [];
176
+
177
+ for (const scheduled of scheduledMessages.values()) {
178
+ if (scheduled.cancelled) continue;
179
+
180
+ list.push({
181
+ id: scheduled.id,
182
+ message: scheduled.message,
183
+ threadID: scheduled.threadID,
184
+ timestamp: scheduled.timestamp,
185
+ createdAt: scheduled.createdAt,
186
+ options: { ...scheduled.options },
187
+ timeUntilSend: scheduled.timestamp - now
188
+ });
189
+ }
190
+
191
+ // Sort by timestamp
192
+ return list.sort((a, b) => a.timestamp - b.timestamp);
193
+ }
194
+
195
+ /**
196
+ * Cancel all scheduled messages
197
+ * @returns {number} Number of cancelled messages
198
+ */
199
+ function cancelAllScheduledMessages() {
200
+ let count = 0;
201
+ for (const id of scheduledMessages.keys()) {
202
+ if (cancelScheduledMessage(id)) {
203
+ count++;
204
+ }
205
+ }
206
+ logger(`Cancelled ${count} scheduled messages`, "info");
207
+ return count;
208
+ }
209
+
210
+ /**
211
+ * Get count of scheduled messages
212
+ * @returns {number} Count
213
+ */
214
+ function getScheduledCount() {
215
+ return scheduledMessages.size;
216
+ }
217
+
218
+ /**
219
+ * Clear expired/cancelled messages from memory
220
+ */
221
+ function cleanup() {
222
+ const now = Date.now();
223
+ let cleaned = 0;
224
+
225
+ for (const [id, scheduled] of scheduledMessages.entries()) {
226
+ if (scheduled.cancelled || scheduled.timestamp < now) {
227
+ scheduledMessages.delete(id);
228
+ cleaned++;
229
+ }
230
+ }
231
+
232
+ if (cleaned > 0) {
233
+ logger(`Cleaned up ${cleaned} scheduled messages`, "info");
234
+ }
235
+ }
236
+
237
+ // Auto cleanup every 5 minutes
238
+ const cleanupInterval = setInterval(cleanup, 5 * 60 * 1000);
239
+
240
+ /**
241
+ * Destroy scheduler and cleanup all resources
242
+ * @returns {number} Number of cancelled messages
243
+ */
244
+ function destroy() {
245
+ clearInterval(cleanupInterval);
246
+ const count = cancelAllScheduledMessages();
247
+ logger("Scheduler destroyed and all resources cleaned up", "info");
248
+ return count;
249
+ }
250
+
251
+ // Return scheduler API
252
+ return {
253
+ scheduleMessage,
254
+ cancelScheduledMessage,
255
+ getScheduledMessage,
256
+ listScheduledMessages,
257
+ cancelAllScheduledMessages,
258
+ getScheduledCount,
259
+ cleanup,
260
+ destroy,
261
+ // Cleanup interval reference for manual cleanup if needed
262
+ _cleanupInterval: cleanupInterval
263
+ };
264
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ const { parseAndCheckLogin } = require("../../utils/client");
4
+ const { formatThread } = require("../../utils/format");
5
+ module.exports = function(defaultFuncs, api, ctx) {
6
+ return function searchForThread(name, callback) {
7
+ let resolveFunc = function() {};
8
+ let rejectFunc = function() {};
9
+ const returnPromise = new Promise(function(resolve, reject) {
10
+ resolveFunc = resolve;
11
+ rejectFunc = reject;
12
+ });
13
+
14
+ if (!callback) {
15
+ callback = function(err, friendList) {
16
+ if (err) {
17
+ return rejectFunc(err);
18
+ }
19
+ resolveFunc(friendList);
20
+ };
21
+ }
22
+
23
+ const tmpForm = {
24
+ client: "web_messenger",
25
+ query: name,
26
+ offset: 0,
27
+ limit: 21,
28
+ index: "fbid"
29
+ };
30
+
31
+ defaultFuncs
32
+ .post(
33
+ "https://www.facebook.com/ajax/mercury/search_threads.php",
34
+ ctx.jar,
35
+ tmpForm
36
+ )
37
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
38
+ .then(function(resData) {
39
+ if (resData.error) {
40
+ throw resData;
41
+ }
42
+ if (!resData.payload.mercury_payload.threads) {
43
+ return callback({ error: "Could not find thread `" + name + "`." });
44
+ }
45
+ return callback(
46
+ null,
47
+ resData.payload.mercury_payload.threads.map(formatThread)
48
+ );
49
+ });
50
+
51
+ return returnPromise;
52
+ };
53
+ };
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ var logger = require("../../utils/nexca-logger");
4
+
5
+ /**
6
+ * sendBroadcast — Send a message to multiple threads in parallel
7
+ * with rate limiting and per-thread delivery tracking.
8
+ *
9
+ * Usage:
10
+ * api.sendBroadcast(msg, threadIDs, [options], [callback])
11
+ *
12
+ * Options:
13
+ * delay {number} ms between each send (default: 1000)
14
+ * parallel {number} max concurrent sends (default: 3)
15
+ * onEach {function(err, result, threadID)} called after each individual send
16
+ *
17
+ * Returns:
18
+ * Promise<{ sent: string[], failed: { id, error }[], total: number }>
19
+ */
20
+ module.exports = function (defaultFuncs, api, ctx) {
21
+ return function sendBroadcast(msg, threadIDs, options, callback) {
22
+ if (typeof options === "function") {
23
+ callback = options;
24
+ options = {};
25
+ }
26
+ options = options || {};
27
+
28
+ var delay = typeof options.delay === "number" ? options.delay : 1000;
29
+ var parallel = typeof options.parallel === "number" ? options.parallel : 3;
30
+ var onEach = typeof options.onEach === "function" ? options.onEach : null;
31
+
32
+ if (!Array.isArray(threadIDs) || threadIDs.length === 0) {
33
+ var err = new Error("sendBroadcast: threadIDs must be a non-empty array.");
34
+ if (typeof callback === "function") return callback(err);
35
+ return Promise.reject(err);
36
+ }
37
+
38
+ var sent = [];
39
+ var failed = [];
40
+ var ids = threadIDs.slice();
41
+
42
+ logger.info("Broadcast", "Sending to " + ids.length + " threads [parallel=" + parallel + " delay=" + delay + "ms]");
43
+
44
+ function sleep(ms) {
45
+ return new Promise(function (res) { setTimeout(res, ms); });
46
+ }
47
+
48
+ async function sendOne(id) {
49
+ try {
50
+ var info = await api.sendMessage(msg, String(id));
51
+ sent.push(String(id));
52
+ if (onEach) onEach(null, info, id);
53
+ logger.success("Broadcast", "→ " + id + " [" + sent.length + "/" + ids.length + "]");
54
+ } catch (e) {
55
+ failed.push({ id: String(id), error: e.message || String(e) });
56
+ if (onEach) onEach(e, null, id);
57
+ logger.warn("Broadcast", "✘ " + id + ": " + (e.message || e));
58
+ }
59
+ }
60
+
61
+ var promise = (async function () {
62
+ var i = 0;
63
+ while (i < ids.length) {
64
+ var batch = ids.slice(i, i + parallel);
65
+ var tasks = batch.map(function (id, idx) {
66
+ return sleep(idx * delay).then(function () { return sendOne(id); });
67
+ });
68
+ await Promise.all(tasks);
69
+ i += parallel;
70
+ if (i < ids.length) await sleep(delay);
71
+ }
72
+
73
+ var result = {
74
+ sent: sent,
75
+ failed: failed,
76
+ total: ids.length
77
+ };
78
+
79
+ logger.success(
80
+ "Broadcast",
81
+ "Done — " + sent.length + " sent, " + failed.length + " failed out of " + ids.length
82
+ );
83
+
84
+ return result;
85
+ })();
86
+
87
+ if (typeof callback === "function") {
88
+ promise.then(function (r) { callback(null, r); }).catch(function (e) { callback(e); });
89
+ }
90
+
91
+ return promise;
92
+ };
93
+ };
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Create by Donix-VN (DongDev)
3
+ * Modified by Riyad
4
+ * Don't change credit
5
+ * Send a message using MQTT.
6
+ * @param {string} text - The text of the message to send.
7
+ * @param {string} threadID - The ID of the thread to send the message to.
8
+ * @param {string} [msgReplace] - Optional. The message ID of the message to replace.
9
+ * @param {Array<Buffer|Stream>} [attachments] - Optional. The attachments to send with the message.
10
+ * @param {function} [callback] - Optional. The callback function to call when the message is sent.
11
+ * @returns {Promise<object>} A promise that resolves with the bodies of the sent message.
12
+ */
13
+
14
+ "use strict";
15
+ const log = require("../../../func/logAdapter");
16
+ const { getType } = require("../../utils/format");
17
+ const { isReadableStream } = require("../../utils/constants");
18
+ const { generateOfflineThreadingID } = require("../../utils/format");
19
+
20
+ module.exports = function (defaultFuncs, api, ctx) {
21
+ const uploadAttachment = require("./uploadAttachment")(defaultFuncs, api, ctx);
22
+ const hasLinks = s => typeof s === "string" && /(https?:\/\/|www\.|t\.me\/|fb\.me\/|youtu\.be\/|facebook\.com\/|youtube\.com\/)/i.test(s);
23
+ const emojiSizes = { small: 1, medium: 2, large: 3 };
24
+
25
+ function extractIdsFromPayload(payload) {
26
+ let messageID = null;
27
+ let threadID = null;
28
+ function walk(n) {
29
+ if (Array.isArray(n)) {
30
+ if (n[0] === 5 && (n[1] === "replaceOptimsiticMessage" || n[1] === "replaceOptimisticMessage")) {
31
+ messageID = String(n[3]);
32
+ }
33
+ if (n[0] === 5 && n[1] === "writeCTAIdToThreadsTable") {
34
+ const a = n[2];
35
+ if (Array.isArray(a) && a[0] === 19) threadID = String(a[1]);
36
+ }
37
+ for (const x of n) walk(x);
38
+ }
39
+ }
40
+ walk(payload?.step);
41
+ return { threadID, messageID };
42
+ }
43
+
44
+ function publishWithAck(content, text, reqID, callback) {
45
+ return new Promise((resolve, reject) => {
46
+ if (!ctx.mqttClient || typeof ctx.mqttClient.on !== "function" || typeof ctx.mqttClient.publish !== "function") {
47
+ const err = new Error("MQTT client is not initialized");
48
+ log.error("sendMessageMqtt", err);
49
+ callback && callback(err);
50
+ return reject(err);
51
+ }
52
+
53
+ if (typeof ctx.mqttClient.setMaxListeners === "function") {
54
+ ctx.mqttClient.setMaxListeners(0);
55
+ }
56
+
57
+ let done = false;
58
+ const cleanup = () => {
59
+ if (done) return;
60
+ done = true;
61
+ ctx.mqttClient.removeListener("message", handleRes);
62
+ };
63
+ const handleRes = (topic, message) => {
64
+ if (topic !== "/ls_resp") return;
65
+ let jsonMsg;
66
+ try {
67
+ jsonMsg = JSON.parse(message.toString());
68
+ jsonMsg.payload = JSON.parse(jsonMsg.payload);
69
+ } catch {
70
+ return;
71
+ }
72
+ if (jsonMsg.request_id !== reqID) return;
73
+ const { threadID, messageID } = extractIdsFromPayload(jsonMsg.payload);
74
+ const bodies = { body: text || null, messageID, threadID };
75
+ cleanup();
76
+ callback && callback(undefined, bodies);
77
+ resolve(bodies);
78
+ };
79
+ ctx.mqttClient.on("message", handleRes);
80
+ ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 0, retain: false }, err => {
81
+ if (err) {
82
+ cleanup();
83
+ callback && callback(err);
84
+ reject(err);
85
+ }
86
+ });
87
+ setTimeout(() => {
88
+ if (done) return;
89
+ cleanup();
90
+ const err = { error: "Timeout waiting for ACK" };
91
+ callback && callback(err);
92
+ reject(err);
93
+ }, 15000);
94
+ });
95
+ }
96
+
97
+ function buildMentionData(msg, baseBody) {
98
+ if (!msg.mentions || !Array.isArray(msg.mentions) || !msg.mentions.length) return null;
99
+ const base = typeof baseBody === "string" ? baseBody : "";
100
+ const ids = [];
101
+ const offsets = [];
102
+ const lengths = [];
103
+ const types = [];
104
+ let cursor = 0;
105
+ for (const m of msg.mentions) {
106
+ const raw = String(m.tag || "");
107
+ const name = raw.replace(/^@+/, "");
108
+ const start = Number.isInteger(m.fromIndex) ? m.fromIndex : cursor;
109
+ let idx = base.indexOf(raw, start);
110
+ let adj = 0;
111
+ if (idx === -1) {
112
+ idx = base.indexOf(name, start);
113
+ adj = 0;
114
+ } else {
115
+ adj = raw.length - name.length;
116
+ }
117
+ if (idx < 0) {
118
+ idx = 0;
119
+ adj = 0;
120
+ }
121
+ const off = idx + adj;
122
+ ids.push(String(m.id || 0));
123
+ offsets.push(off);
124
+ lengths.push(name.length);
125
+ types.push("p");
126
+ cursor = off + name.length;
127
+ }
128
+ return {
129
+ mention_ids: ids.join(","),
130
+ mention_offsets: offsets.join(","),
131
+ mention_lengths: lengths.join(","),
132
+ mention_types: types.join(",")
133
+ };
134
+ }
135
+
136
+ function coerceMsg(x) {
137
+ if (x == null) return { body: "" };
138
+ if (typeof x === "string") return { body: x };
139
+ if (typeof x === "object") return x;
140
+ return { body: String(x) };
141
+ }
142
+
143
+ return async function sendMessageMqtt(msg, threadID, callback, replyToMessage) {
144
+ if (typeof threadID === "function") return threadID({ error: "Pass a threadID as a second argument." });
145
+ if (typeof callback === "string" && !replyToMessage) {
146
+ replyToMessage = callback;
147
+ callback = () => { };
148
+ }
149
+ if (typeof callback !== "function") callback = () => { };
150
+ if (!threadID) {
151
+ const err = { error: "threadID is required" };
152
+ callback(err);
153
+ throw err;
154
+ }
155
+
156
+ const m = coerceMsg(msg);
157
+ const baseBody = m.body != null ? String(m.body) : "";
158
+ const reqID = Math.floor(100 + Math.random() * 900);
159
+ const epoch = (BigInt(Date.now()) << 22n).toString();
160
+
161
+ const payload0 = {
162
+ thread_id: String(threadID),
163
+ otid: generateOfflineThreadingID(),
164
+ source: 2097153,
165
+ send_type: 1,
166
+ sync_group: 1,
167
+ mark_thread_read: 1,
168
+ text: baseBody === "" ? null : baseBody,
169
+ initiating_source: 0,
170
+ skip_url_preview_gen: 1,
171
+ text_has_links: hasLinks(baseBody) ? 1 : 0,
172
+ multitab_env: 0,
173
+ metadata_dataclass: JSON.stringify({ media_accessibility_metadata: { alt_text: null } })
174
+ };
175
+
176
+ const mentionData = buildMentionData(m, baseBody);
177
+ if (mentionData) payload0.mention_data = mentionData;
178
+
179
+ if (m.sticker) {
180
+ payload0.send_type = 2;
181
+ payload0.sticker_id = m.sticker;
182
+ }
183
+
184
+ if (m.emoji) {
185
+ const size = !isNaN(m.emojiSize) ? Number(m.emojiSize) : emojiSizes[m.emojiSize || "small"] || 1;
186
+ payload0.send_type = 1;
187
+ payload0.text = m.emoji;
188
+ payload0.hot_emoji_size = Math.min(3, Math.max(1, size));
189
+ }
190
+
191
+ if (m.location && m.location.latitude != null && m.location.longitude != null) {
192
+ payload0.send_type = 1;
193
+ payload0.location_data = {
194
+ coordinates: { latitude: m.location.latitude, longitude: m.location.longitude },
195
+ is_current_location: !!m.location.current,
196
+ is_live_location: !!m.location.live
197
+ };
198
+ }
199
+
200
+ if (replyToMessage) {
201
+ payload0.reply_metadata = { reply_source_id: replyToMessage, reply_source_type: 1, reply_type: 0 };
202
+ }
203
+
204
+ if (m.attachment) {
205
+ payload0.send_type = 3;
206
+ if (payload0.text === "") payload0.text = null;
207
+ payload0.attachment_fbids = [];
208
+ let list = m.attachment;
209
+ if (getType(list) !== "Array") list = [list];
210
+ const idsFromPairs = [];
211
+ const streams = [];
212
+ for (const it of list) {
213
+ if (Array.isArray(it) && typeof it[0] === "string") {
214
+ idsFromPairs.push(String(it[1]));
215
+ } else if (isReadableStream(it)) {
216
+ streams.push(it);
217
+ }
218
+ }
219
+ if (idsFromPairs.length) payload0.attachment_fbids.push(...idsFromPairs);
220
+ if (streams.length) {
221
+ try {
222
+ const files = await uploadAttachment(streams);
223
+ for (const file of files) {
224
+ const id = file.video_id || file.image_id || file.audio_id || file.file_id || file.gif_id || file.fbid || file.id || file.upload_id;
225
+ if (id) payload0.attachment_fbids.push(String(id));
226
+ }
227
+ } catch (err) {
228
+ log.error("uploadAttachment", err);
229
+ callback(err);
230
+ throw err;
231
+ }
232
+ }
233
+ }
234
+
235
+ const content = {
236
+ app_id: "2220391788200892",
237
+ payload: {
238
+ tasks: [
239
+ {
240
+ label: "46",
241
+ payload: payload0,
242
+ queue_name: String(threadID),
243
+ task_id: 400,
244
+ failure_count: null
245
+ },
246
+ {
247
+ label: "21",
248
+ payload: {
249
+ thread_id: String(threadID),
250
+ last_read_watermark_ts: Date.now(),
251
+ sync_group: 1
252
+ },
253
+ queue_name: String(threadID),
254
+ task_id: 401,
255
+ failure_count: null
256
+ }
257
+ ],
258
+ epoch_id: epoch,
259
+ version_id: "24804310205905615",
260
+ data_trace_id: "#" + Buffer.from(String(Math.random())).toString("base64").replace(/=+$/g, "")
261
+ },
262
+ request_id: reqID,
263
+ type: 3
264
+ };
265
+ content.payload.tasks.forEach(t => (t.payload = JSON.stringify(t.payload)));
266
+ content.payload = JSON.stringify(content.payload);
267
+ return publishWithAck(content, baseBody, reqID, callback);
268
+ };
269
+ };