@cexy/hoonfca 1.0.3 → 1.0.5

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 (135) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/DOCS.md +2636 -0
  3. package/LICENSE-MIT +21 -21
  4. package/README.md +632 -0
  5. package/func/checkUpdate.js +222 -0
  6. package/func/logger.js +48 -0
  7. package/index.d.ts +731 -605
  8. package/index.js +6 -777
  9. package/module/config.js +34 -0
  10. package/module/login.js +136 -0
  11. package/module/loginHelper.js +1034 -0
  12. package/module/options.js +45 -0
  13. package/package.json +53 -22
  14. package/src/api/action/addExternalModule.js +25 -0
  15. package/src/api/action/changeAvatar.js +137 -0
  16. package/src/{changeBio.js → api/action/changeBio.js} +75 -76
  17. package/src/api/action/enableAutoSaveAppState.js +73 -0
  18. package/src/{getCurrentUserID.js → api/action/getCurrentUserID.js} +7 -7
  19. package/src/{handleFriendRequest.js → api/action/handleFriendRequest.js} +57 -57
  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 +122 -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 +90 -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 +106 -0
  35. package/src/{createNewGroup.js → api/messaging/createNewGroup.js} +88 -88
  36. package/src/api/messaging/createPoll.js +43 -0
  37. package/src/api/messaging/createThemeAI.js +98 -0
  38. package/src/{deleteMessage.js → api/messaging/deleteMessage.js} +56 -56
  39. package/src/{deleteThread.js → api/messaging/deleteThread.js} +56 -56
  40. package/src/api/messaging/editMessage.js +68 -0
  41. package/src/api/messaging/forwardAttachment.js +51 -0
  42. package/src/{getEmojiUrl.js → api/messaging/getEmojiUrl.js} +8 -8
  43. package/src/{getFriendsList.js → api/messaging/getFriendsList.js} +82 -84
  44. package/src/api/messaging/getMessage.js +829 -0
  45. package/src/api/messaging/getThemePictures.js +62 -0
  46. package/src/api/messaging/handleMessageRequest.js +65 -0
  47. package/src/{markAsDelivered.js → api/messaging/markAsDelivered.js} +57 -58
  48. package/src/{markAsRead.js → api/messaging/markAsRead.js} +88 -88
  49. package/src/{markAsReadAll.js → api/messaging/markAsReadAll.js} +49 -50
  50. package/src/api/messaging/markAsSeen.js +61 -0
  51. package/src/{muteThread.js → api/messaging/muteThread.js} +50 -52
  52. package/src/api/messaging/removeUserFromGroup.js +106 -0
  53. package/src/{resolvePhotoUrl.js → api/messaging/resolvePhotoUrl.js} +43 -45
  54. package/src/api/messaging/scheduler.js +264 -0
  55. package/src/{searchForThread.js → api/messaging/searchForThread.js} +52 -53
  56. package/src/api/messaging/sendMessage.js +272 -0
  57. package/src/api/messaging/sendTypingIndicator.js +67 -0
  58. package/src/api/messaging/setMessageReaction.js +76 -0
  59. package/src/api/messaging/setTitle.js +119 -0
  60. package/src/{shareContact.js → api/messaging/shareContact.js} +49 -53
  61. package/src/api/messaging/threadColors.js +128 -0
  62. package/src/api/messaging/unsendMessage.js +81 -0
  63. package/src/api/messaging/uploadAttachment.js +94 -0
  64. package/src/api/socket/core/connectMqtt.js +255 -0
  65. package/src/api/socket/core/emitAuth.js +106 -0
  66. package/src/api/socket/core/getSeqID.js +40 -0
  67. package/src/api/socket/core/getTaskResponseData.js +22 -0
  68. package/src/api/socket/core/markDelivery.js +12 -0
  69. package/src/api/socket/core/parseDelta.js +391 -0
  70. package/src/api/socket/detail/buildStream.js +208 -0
  71. package/src/api/socket/detail/constants.js +24 -0
  72. package/src/api/socket/listenMqtt.js +364 -0
  73. package/src/api/socket/middleware/index.js +216 -0
  74. package/src/{getThreadHistory.js → api/threads/getThreadHistory.js} +664 -647
  75. package/src/api/threads/getThreadInfo.js +438 -0
  76. package/src/{getThreadList.js → api/threads/getThreadList.js} +293 -292
  77. package/src/{getThreadPictures.js → api/threads/getThreadPictures.js} +78 -79
  78. package/src/{getUserID.js → api/users/getUserID.js} +65 -66
  79. package/src/api/users/getUserInfo.js +327 -0
  80. package/src/api/users/getUserInfoV2.js +134 -0
  81. package/src/core/sendReqMqtt.js +96 -0
  82. package/src/database/models/index.js +87 -0
  83. package/src/database/models/thread.js +45 -0
  84. package/src/database/models/user.js +46 -0
  85. package/src/database/threadData.js +98 -0
  86. package/src/database/userData.js +89 -0
  87. package/src/utils/client.js +320 -0
  88. package/src/utils/constants.js +23 -0
  89. package/{utils.js → src/utils/format.js} +1115 -1447
  90. package/src/utils/headers.js +115 -0
  91. package/src/utils/request.js +305 -0
  92. package/.travis.yml +0 -6
  93. package/src/addExternalModule.js +0 -23
  94. package/src/addUserToGroup.js +0 -113
  95. package/src/changeAdminStatus.js +0 -95
  96. package/src/changeApprovalMode.js +0 -79
  97. package/src/changeArchivedStatus.js +0 -55
  98. package/src/changeBlockedStatus.js +0 -47
  99. package/src/changeBlockedStatusMqtt.js +0 -86
  100. package/src/changeGroupImage.js +0 -133
  101. package/src/changeNickname.js +0 -59
  102. package/src/changeThreadColor.js +0 -71
  103. package/src/changeThreadEmoji.js +0 -55
  104. package/src/createPoll.js +0 -130
  105. package/src/editMessage.js +0 -63
  106. package/src/forwardAttachment.js +0 -60
  107. package/src/forwardMessage.js +0 -63
  108. package/src/getGroupsList.js +0 -83
  109. package/src/getMarketplace.js +0 -84
  110. package/src/getNotifications.js +0 -86
  111. package/src/getPagesList.js +0 -83
  112. package/src/getStories.js +0 -88
  113. package/src/getThreadInfo.js +0 -222
  114. package/src/getUserInfo.js +0 -128
  115. package/src/handleMessageRequest.js +0 -65
  116. package/src/httpGet.js +0 -58
  117. package/src/httpPost.js +0 -58
  118. package/src/listenMqtt.js +0 -1018
  119. package/src/logout.js +0 -75
  120. package/src/markAsSeen.js +0 -61
  121. package/src/pinMessage.js +0 -61
  122. package/src/removeUserFromGroup.js +0 -79
  123. package/src/searchUsers.js +0 -89
  124. package/src/sendComment.js +0 -161
  125. package/src/sendMessage.js +0 -457
  126. package/src/sendTypingIndicator.js +0 -179
  127. package/src/setBio.js +0 -86
  128. package/src/setMessageReaction.js +0 -186
  129. package/src/setPostReaction.js +0 -71
  130. package/src/setTheme.js +0 -313
  131. package/src/setTitle.js +0 -90
  132. package/src/shareLink.js +0 -62
  133. package/src/threadColors.js +0 -57
  134. package/src/unfriend.js +0 -53
  135. package/src/unsendMessage.js +0 -104
@@ -1,52 +1,50 @@
1
- "use strict";
2
-
3
- var utils = require("../utils");
4
- var log = require("npmlog");
5
-
6
- module.exports = function (defaultFuncs, api, ctx) {
7
- // muteSecond: -1=permanent mute, 0=unmute, 60=one minute, 3600=one hour, etc.
8
- return function muteThread(threadID, muteSeconds, callback) {
9
- var resolveFunc = function () {};
10
- var rejectFunc = function () {};
11
- var returnPromise = new Promise(function (resolve, reject) {
12
- resolveFunc = resolve;
13
- rejectFunc = reject;
14
- });
15
-
16
- if (!callback) {
17
- callback = function (err, friendList) {
18
- if (err) {
19
- return rejectFunc(err);
20
- }
21
- resolveFunc(friendList);
22
- };
23
- }
24
-
25
- var form = {
26
- thread_fbid: threadID,
27
- mute_settings: muteSeconds,
28
- };
29
-
30
- defaultFuncs
31
- .post(
32
- "https://www.facebook.com/ajax/mercury/change_mute_thread.php",
33
- ctx.jar,
34
- form,
35
- )
36
- .then(utils.saveCookies(ctx.jar))
37
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
38
- .then(function (resData) {
39
- if (resData.error) {
40
- throw resData;
41
- }
42
-
43
- return callback();
44
- })
45
- .catch(function (err) {
46
- log.error("muteThread", err);
47
- return callback(err);
48
- });
49
-
50
- return returnPromise;
51
- };
52
- };
1
+ "use strict";
2
+ const log = require("npmlog");
3
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
4
+ module.exports = function(defaultFuncs, api, ctx) {
5
+ // muteSecond: -1=permanent mute, 0=unmute, 60=one minute, 3600=one hour, etc.
6
+ return function muteThread(threadID, muteSeconds, 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 form = {
24
+ thread_fbid: threadID,
25
+ mute_settings: muteSeconds
26
+ };
27
+
28
+ defaultFuncs
29
+ .post(
30
+ "https://www.facebook.com/ajax/mercury/change_mute_thread.php",
31
+ ctx.jar,
32
+ form
33
+ )
34
+ .then(saveCookies(ctx.jar))
35
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
36
+ .then(function(resData) {
37
+ if (resData.error) {
38
+ throw resData;
39
+ }
40
+
41
+ return callback();
42
+ })
43
+ .catch(function(err) {
44
+ log.error("muteThread", err);
45
+ return callback(err);
46
+ });
47
+
48
+ return returnPromise;
49
+ };
50
+ };
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+
3
+ const { getType } = require("../../utils/format");
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const log = require("npmlog");
6
+
7
+ module.exports = function (defaultFuncs, api, ctx) {
8
+ function removeUserFromGroupNoMqtt(userID, threadID, callback) {
9
+ if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) throw { error: "please pass a threadID as a second argument." };
10
+ if (getType(threadID) !== "Number" && getType(threadID) !== "String") throw { error: "threadID should be of type Number or String and not " + getType(threadID) + "." };
11
+ if (getType(userID) !== "Number" && getType(userID) !== "String") throw { error: "userID should be of type Number or String and not " + getType(userID) + "." };
12
+ var resolveFunc = function () { };
13
+ var rejectFunc = function () { };
14
+ var returnPromise = new Promise(function (resolve, reject) {
15
+ resolveFunc = resolve;
16
+ rejectFunc = reject;
17
+ });
18
+ if (!callback) {
19
+ callback = function (err, data) {
20
+ if (err) return rejectFunc(err);
21
+ resolveFunc(data);
22
+ };
23
+ }
24
+ var form = {
25
+ uid: userID,
26
+ tid: threadID
27
+ };
28
+ defaultFuncs
29
+ .post("https://www.facebook.com/chat/remove_participants", ctx.jar, form)
30
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
31
+ .then(function (resData) {
32
+ if (!resData) throw { error: "Remove from group failed." };
33
+ if (resData.error) throw resData;
34
+ return callback();
35
+ })
36
+ .catch(function (err) {
37
+ log.error("removeUserFromGroup", err);
38
+ return callback(err);
39
+ });
40
+ return returnPromise;
41
+ };
42
+ function removeUserFromGroupMqtt(userID, threadID, callback) {
43
+ if (!ctx.mqttClient) {
44
+ throw new Error("Not connected to MQTT");
45
+ }
46
+ if (!callback && (getType(threadID) === "Function" || getType(threadID) === "AsyncFunction")) throw { error: "please pass a threadID as a second argument." };
47
+ if (getType(threadID) !== "Number" && getType(threadID) !== "String") throw { error: "threadID should be of type Number or String and not " + getType(threadID) + "." };
48
+ if (getType(userID) !== "Number" && getType(userID) !== "String") throw { error: "userID should be of type Number or String and not " + getType(userID) + "." };
49
+ var resolveFunc = function () { };
50
+ var rejectFunc = function () { };
51
+ var returnPromise = new Promise(function (resolve, reject) {
52
+ resolveFunc = resolve;
53
+ rejectFunc = reject;
54
+ });
55
+ if (!callback) {
56
+ callback = function (err, data) {
57
+ if (err) return rejectFunc(err);
58
+ resolveFunc(data);
59
+ };
60
+ }
61
+ let count_req = 0;
62
+ var form = JSON.stringify({
63
+ "app_id": "2220391788200892",
64
+ "payload": JSON.stringify({
65
+ epoch_id: generateOfflineThreadingID(),
66
+ tasks: [
67
+ {
68
+ failure_count: null,
69
+ label: '140',
70
+ payload: JSON.stringify({
71
+ "thread_id": threadID,
72
+ "contact_id": userID,
73
+ "sync_group": 1
74
+ }),
75
+ queue_name: 'remove_participant_v2',
76
+ task_id: Math.random() * 1001 << 0
77
+ }
78
+ ],
79
+ version_id: '8798795233522156'
80
+ }),
81
+ "request_id": ++count_req,
82
+ "type": 3
83
+ });
84
+ mqttClient.publish('/ls_req', form, (err, data) => {
85
+ if (err) {
86
+ callback(err, null);
87
+ rejectFunc(false);
88
+ } else {
89
+ callback(null, true);
90
+ resolveFunc(true);
91
+ }
92
+ });
93
+ return returnPromise;
94
+ };
95
+ return function removeUserFromGroup(userID, threadID, callback) {
96
+ if (ctx.mqttClient) {
97
+ try {
98
+ removeUserFromGroupMqtt(userID, threadID, callback);
99
+ } catch (e) {
100
+ removeUserFromGroupNoMqtt(userID, threadID, callback);
101
+ }
102
+ } else {
103
+ removeUserFromGroupNoMqtt(userID, threadID, callback);
104
+ }
105
+ };
106
+ };
@@ -1,45 +1,43 @@
1
- "use strict";
2
-
3
- var utils = require("../utils");
4
- var log = require("npmlog");
5
-
6
- module.exports = function (defaultFuncs, api, ctx) {
7
- return function resolvePhotoUrl(photoID, 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
-
15
- if (!callback) {
16
- callback = function (err, friendList) {
17
- if (err) {
18
- return rejectFunc(err);
19
- }
20
- resolveFunc(friendList);
21
- };
22
- }
23
-
24
- defaultFuncs
25
- .get("https://www.facebook.com/mercury/attachments/photo", ctx.jar, {
26
- photo_id: photoID,
27
- })
28
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
29
- .then((resData) => {
30
- if (resData.error) {
31
- throw resData;
32
- }
33
-
34
- var photoUrl = resData.jsmods.require[0][3][0];
35
-
36
- return callback(null, photoUrl);
37
- })
38
- .catch((err) => {
39
- log.error("resolvePhotoUrl", err);
40
- return callback(err);
41
- });
42
-
43
- return returnPromise;
44
- };
45
- };
1
+ "use strict";
2
+ const log = require("npmlog");
3
+ const { parseAndCheckLogin, saveCookies } = require("../../utils/client");
4
+ module.exports = function(defaultFuncs, api, ctx) {
5
+ return function resolvePhotoUrl(photoID, callback) {
6
+ let resolveFunc = function() {};
7
+ let rejectFunc = function() {};
8
+ const returnPromise = new Promise(function(resolve, reject) {
9
+ resolveFunc = resolve;
10
+ rejectFunc = reject;
11
+ });
12
+
13
+ if (!callback) {
14
+ callback = function(err, friendList) {
15
+ if (err) {
16
+ return rejectFunc(err);
17
+ }
18
+ resolveFunc(friendList);
19
+ };
20
+ }
21
+
22
+ defaultFuncs
23
+ .get("https://www.facebook.com/mercury/attachments/photo", ctx.jar, {
24
+ photo_id: photoID
25
+ })
26
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
27
+ .then(resData => {
28
+ if (resData.error) {
29
+ throw resData;
30
+ }
31
+
32
+ const photoUrl = resData.jsmods.require[0][3][0];
33
+
34
+ return callback(null, photoUrl);
35
+ })
36
+ .catch(err => {
37
+ log.error("resolvePhotoUrl", err);
38
+ return callback(err);
39
+ });
40
+
41
+ return returnPromise;
42
+ };
43
+ };
@@ -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
+ }
@@ -1,53 +1,52 @@
1
- "use strict";
2
-
3
- var utils = require("../utils");
4
-
5
- module.exports = function (defaultFuncs, api, ctx) {
6
- return function searchForThread(name, callback) {
7
- var resolveFunc = function () {};
8
- var rejectFunc = function () {};
9
- var 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
- var 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(utils.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(utils.formatThread),
48
- );
49
- });
50
-
51
- return returnPromise;
52
- };
53
- };
1
+ "use strict";
2
+
3
+ const { parseAndCheckLogin } = require("../../utils/client");
4
+ module.exports = function(defaultFuncs, api, ctx) {
5
+ return function searchForThread(name, callback) {
6
+ let resolveFunc = function() {};
7
+ let rejectFunc = function() {};
8
+ const returnPromise = new Promise(function(resolve, reject) {
9
+ resolveFunc = resolve;
10
+ rejectFunc = reject;
11
+ });
12
+
13
+ if (!callback) {
14
+ callback = function(err, friendList) {
15
+ if (err) {
16
+ return rejectFunc(err);
17
+ }
18
+ resolveFunc(friendList);
19
+ };
20
+ }
21
+
22
+ const tmpForm = {
23
+ client: "web_messenger",
24
+ query: name,
25
+ offset: 0,
26
+ limit: 21,
27
+ index: "fbid"
28
+ };
29
+
30
+ defaultFuncs
31
+ .post(
32
+ "https://www.facebook.com/ajax/mercury/search_threads.php",
33
+ ctx.jar,
34
+ tmpForm
35
+ )
36
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
37
+ .then(function(resData) {
38
+ if (resData.error) {
39
+ throw resData;
40
+ }
41
+ if (!resData.payload.mercury_payload.threads) {
42
+ return callback({ error: "Could not find thread `" + name + "`." });
43
+ }
44
+ return callback(
45
+ null,
46
+ resData.payload.mercury_payload.threads.map(utils.formatThread)
47
+ );
48
+ });
49
+
50
+ return returnPromise;
51
+ };
52
+ };