@cexy/hoonfca 1.0.7 → 2.0.1

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 (191) hide show
  1. package/LICENSE +3 -0
  2. package/examples/login-with-cookies.js +102 -0
  3. package/examples/verify.js +70 -0
  4. package/index.js +2 -8
  5. package/package.json +82 -61
  6. package/src/{api/action → apis}/addExternalModule.js +24 -25
  7. package/src/apis/addUserToGroup.js +108 -0
  8. package/src/apis/changeAdminStatus.js +148 -0
  9. package/src/apis/changeArchivedStatus.js +61 -0
  10. package/src/apis/changeAvatar.js +103 -0
  11. package/src/apis/changeBio.js +69 -0
  12. package/src/apis/changeBlockedStatus.js +54 -0
  13. package/src/apis/changeGroupImage.js +136 -0
  14. package/src/apis/changeThreadColor.js +116 -0
  15. package/src/apis/changeThreadEmoji.js +53 -0
  16. package/src/apis/comment.js +207 -0
  17. package/src/apis/createAITheme.js +129 -0
  18. package/src/apis/createNewGroup.js +79 -0
  19. package/src/apis/createPoll.js +73 -0
  20. package/src/apis/deleteMessage.js +44 -0
  21. package/src/apis/deleteThread.js +52 -0
  22. package/src/apis/e2ee.js +17 -0
  23. package/src/apis/editMessage.js +70 -0
  24. package/src/apis/emoji.js +124 -0
  25. package/src/apis/fetchThemeData.js +82 -0
  26. package/src/apis/follow.js +81 -0
  27. package/src/apis/forwardMessage.js +52 -0
  28. package/src/apis/friend.js +243 -0
  29. package/src/apis/gcmember.js +122 -0
  30. package/src/apis/gcname.js +123 -0
  31. package/src/apis/gcrule.js +119 -0
  32. package/src/apis/getAccess.js +111 -0
  33. package/src/apis/getBotInfo.js +88 -0
  34. package/src/apis/getBotInitialData.js +43 -0
  35. package/src/apis/getFriendsList.js +79 -0
  36. package/src/apis/getMessage.js +423 -0
  37. package/src/apis/getTheme.js +95 -0
  38. package/src/apis/getThemeInfo.js +116 -0
  39. package/src/apis/getThreadHistory.js +239 -0
  40. package/src/apis/getThreadInfo.js +267 -0
  41. package/src/apis/getThreadList.js +232 -0
  42. package/src/apis/getThreadPictures.js +58 -0
  43. package/src/apis/getUserID.js +117 -0
  44. package/src/apis/getUserInfo.js +513 -0
  45. package/src/{api/users → apis}/getUserInfoV2.js +146 -134
  46. package/src/apis/handleMessageRequest.js +50 -0
  47. package/src/apis/httpGet.js +63 -0
  48. package/src/apis/httpPost.js +89 -0
  49. package/src/apis/httpPostFormData.js +69 -0
  50. package/src/apis/listenMqtt.js +1236 -0
  51. package/src/apis/listenSpeed.js +179 -0
  52. package/src/apis/logout.js +87 -0
  53. package/src/apis/markAsDelivered.js +47 -0
  54. package/src/{api/messaging → apis}/markAsRead.js +99 -88
  55. package/src/apis/markAsReadAll.js +40 -0
  56. package/src/apis/markAsSeen.js +70 -0
  57. package/src/apis/mqttDeltaValue.js +278 -0
  58. package/src/apis/muteThread.js +45 -0
  59. package/src/apis/nickname.js +132 -0
  60. package/src/apis/notes.js +163 -0
  61. package/src/apis/pinMessage.js +150 -0
  62. package/src/apis/produceMetaTheme.js +180 -0
  63. package/src/apis/realtime.js +182 -0
  64. package/src/apis/removeUserFromGroup.js +117 -0
  65. package/src/apis/resolvePhotoUrl.js +58 -0
  66. package/src/apis/searchForThread.js +154 -0
  67. package/src/apis/sendMessage.js +354 -0
  68. package/src/apis/sendMessageMqtt.js +249 -0
  69. package/src/apis/sendTypingIndicator.js +91 -0
  70. package/src/apis/setMessageReaction.js +27 -0
  71. package/src/apis/setMessageReactionMqtt.js +61 -0
  72. package/src/apis/setThreadTheme.js +260 -0
  73. package/src/apis/setThreadThemeMqtt.js +94 -0
  74. package/src/apis/share.js +107 -0
  75. package/src/apis/shareContact.js +66 -0
  76. package/src/apis/stickers.js +257 -0
  77. package/src/apis/story.js +181 -0
  78. package/src/apis/theme.js +233 -0
  79. package/src/apis/unfriend.js +47 -0
  80. package/src/apis/unsendMessage.js +17 -0
  81. package/src/engine/client.js +92 -0
  82. package/src/engine/models/buildAPI.js +152 -0
  83. package/src/engine/models/loginHelper.js +519 -0
  84. package/src/engine/models/setOptions.js +88 -0
  85. package/src/security/e2ee.js +109 -0
  86. package/src/types/index.d.ts +498 -0
  87. package/src/utils/antiSuspension.js +506 -0
  88. package/src/utils/auth-helpers.js +149 -0
  89. package/src/utils/autoReLogin.js +336 -0
  90. package/src/utils/axios.js +436 -0
  91. package/src/utils/cache.js +54 -0
  92. package/src/utils/clients.js +282 -0
  93. package/src/utils/constants.js +410 -23
  94. package/src/utils/formatters/data/formatAttachment.js +370 -0
  95. package/src/utils/formatters/data/formatDelta.js +109 -0
  96. package/src/utils/formatters/index.js +159 -0
  97. package/src/utils/formatters/value/formatCookie.js +91 -0
  98. package/src/utils/formatters/value/formatDate.js +36 -0
  99. package/src/utils/formatters/value/formatID.js +16 -0
  100. package/src/utils/formatters.js +1373 -0
  101. package/src/utils/headers.js +214 -99
  102. package/src/utils/index.js +153 -0
  103. package/src/utils/monitoring.js +333 -0
  104. package/src/utils/rateLimiter.js +319 -0
  105. package/src/utils/tokenRefresh.js +657 -0
  106. package/src/utils/user-agents.js +238 -0
  107. package/src/utils/validation.js +157 -0
  108. package/CHANGELOG.md +0 -181
  109. package/DOCS.md +0 -2636
  110. package/LICENSE-MIT +0 -21
  111. package/README.md +0 -632
  112. package/func/checkUpdate.js +0 -233
  113. package/func/logger.js +0 -48
  114. package/index.d.ts +0 -746
  115. package/module/config.js +0 -67
  116. package/module/login.js +0 -154
  117. package/module/loginHelper.js +0 -1034
  118. package/module/options.js +0 -54
  119. package/src/api/action/changeAvatar.js +0 -137
  120. package/src/api/action/changeBio.js +0 -75
  121. package/src/api/action/enableAutoSaveAppState.js +0 -73
  122. package/src/api/action/getCurrentUserID.js +0 -7
  123. package/src/api/action/handleFriendRequest.js +0 -57
  124. package/src/api/action/logout.js +0 -76
  125. package/src/api/action/refreshFb_dtsg.js +0 -48
  126. package/src/api/action/setPostReaction.js +0 -106
  127. package/src/api/action/unfriend.js +0 -54
  128. package/src/api/http/httpGet.js +0 -46
  129. package/src/api/http/httpPost.js +0 -52
  130. package/src/api/http/postFormData.js +0 -47
  131. package/src/api/messaging/addUserToGroup.js +0 -68
  132. package/src/api/messaging/changeAdminStatus.js +0 -122
  133. package/src/api/messaging/changeArchivedStatus.js +0 -55
  134. package/src/api/messaging/changeBlockedStatus.js +0 -48
  135. package/src/api/messaging/changeGroupImage.js +0 -90
  136. package/src/api/messaging/changeNickname.js +0 -70
  137. package/src/api/messaging/changeThreadColor.js +0 -79
  138. package/src/api/messaging/changeThreadEmoji.js +0 -106
  139. package/src/api/messaging/createNewGroup.js +0 -88
  140. package/src/api/messaging/createPoll.js +0 -43
  141. package/src/api/messaging/createThemeAI.js +0 -98
  142. package/src/api/messaging/deleteMessage.js +0 -56
  143. package/src/api/messaging/deleteThread.js +0 -56
  144. package/src/api/messaging/editMessage.js +0 -68
  145. package/src/api/messaging/forwardAttachment.js +0 -51
  146. package/src/api/messaging/getEmojiUrl.js +0 -29
  147. package/src/api/messaging/getFriendsList.js +0 -82
  148. package/src/api/messaging/getMessage.js +0 -829
  149. package/src/api/messaging/getThemePictures.js +0 -62
  150. package/src/api/messaging/handleMessageRequest.js +0 -65
  151. package/src/api/messaging/markAsDelivered.js +0 -57
  152. package/src/api/messaging/markAsReadAll.js +0 -49
  153. package/src/api/messaging/markAsSeen.js +0 -61
  154. package/src/api/messaging/muteThread.js +0 -50
  155. package/src/api/messaging/removeUserFromGroup.js +0 -106
  156. package/src/api/messaging/resolvePhotoUrl.js +0 -43
  157. package/src/api/messaging/scheduler.js +0 -264
  158. package/src/api/messaging/searchForThread.js +0 -52
  159. package/src/api/messaging/sendMessage.js +0 -272
  160. package/src/api/messaging/sendTypingIndicator.js +0 -67
  161. package/src/api/messaging/setMessageReaction.js +0 -76
  162. package/src/api/messaging/setTitle.js +0 -119
  163. package/src/api/messaging/shareContact.js +0 -49
  164. package/src/api/messaging/threadColors.js +0 -128
  165. package/src/api/messaging/unsendMessage.js +0 -81
  166. package/src/api/messaging/uploadAttachment.js +0 -94
  167. package/src/api/socket/core/connectMqtt.js +0 -255
  168. package/src/api/socket/core/emitAuth.js +0 -106
  169. package/src/api/socket/core/getSeqID.js +0 -40
  170. package/src/api/socket/core/getTaskResponseData.js +0 -22
  171. package/src/api/socket/core/markDelivery.js +0 -12
  172. package/src/api/socket/core/parseDelta.js +0 -391
  173. package/src/api/socket/detail/buildStream.js +0 -208
  174. package/src/api/socket/detail/constants.js +0 -24
  175. package/src/api/socket/listenMqtt.js +0 -364
  176. package/src/api/socket/middleware/index.js +0 -216
  177. package/src/api/threads/getThreadHistory.js +0 -664
  178. package/src/api/threads/getThreadInfo.js +0 -438
  179. package/src/api/threads/getThreadList.js +0 -293
  180. package/src/api/threads/getThreadPictures.js +0 -78
  181. package/src/api/users/getUserID.js +0 -65
  182. package/src/api/users/getUserInfo.js +0 -327
  183. package/src/core/sendReqMqtt.js +0 -96
  184. package/src/database/models/index.js +0 -87
  185. package/src/database/models/thread.js +0 -45
  186. package/src/database/models/user.js +0 -46
  187. package/src/database/threadData.js +0 -98
  188. package/src/database/userData.js +0 -89
  189. package/src/utils/client.js +0 -320
  190. package/src/utils/format.js +0 -1115
  191. package/src/utils/request.js +0 -305
@@ -1,438 +0,0 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const logger = require("../../../func/logger");
4
- const { parseAndCheckLogin } = require("../../utils/client");
5
- const { formatID, getType } = require("../../utils/format");
6
-
7
- function formatEventReminders(reminder) {
8
- return {
9
- reminderID: reminder?.id,
10
- eventCreatorID: reminder?.lightweight_event_creator?.id,
11
- time: reminder?.time,
12
- eventType: String(reminder?.lightweight_event_type || "").toLowerCase(),
13
- locationName: reminder?.location_name,
14
- locationCoordinates: reminder?.location_coordinates,
15
- locationPage: reminder?.location_page,
16
- eventStatus: String(reminder?.lightweight_event_status || "").toLowerCase(),
17
- note: reminder?.note,
18
- repeatMode: String(reminder?.repeat_mode || "").toLowerCase(),
19
- eventTitle: reminder?.event_title,
20
- triggerMessage: reminder?.trigger_message,
21
- secondsToNotifyBefore: reminder?.seconds_to_notify_before,
22
- allowsRsvp: reminder?.allows_rsvp,
23
- relatedEvent: reminder?.related_event,
24
- members: Array.isArray(reminder?.event_reminder_members?.edges) ? reminder.event_reminder_members.edges.map(m => ({
25
- memberID: m?.node?.id,
26
- state: String(m?.guest_list_state || "").toLowerCase(),
27
- })) : [],
28
- };
29
- }
30
-
31
- function formatThreadGraphQLResponse(data) {
32
- if (!data) return null;
33
- if (data?.errors) return null;
34
- const t = data.message_thread;
35
- if (!t) return null;
36
- const threadID = t?.thread_key?.thread_fbid || t?.thread_key?.other_user_id || null;
37
- const lastM = t?.last_message;
38
- const lastNode = Array.isArray(lastM?.nodes) && lastM.nodes[0] ? lastM.nodes[0] : null;
39
- const snippetID = lastNode?.message_sender?.messaging_actor?.id || null;
40
- const snippetText = lastNode?.snippet || null;
41
- const lastRNode = Array.isArray(t?.last_read_receipt?.nodes) && t.last_read_receipt.nodes[0] ? t.last_read_receipt.nodes[0] : null;
42
- const lastReadTimestamp = lastRNode?.timestamp_precise || null;
43
- const participants = Array.isArray(t?.all_participants?.edges) ? t.all_participants.edges : [];
44
- const approvals = Array.isArray(t?.group_approval_queue?.nodes) ? t.group_approval_queue.nodes : [];
45
- const customInfo = t?.customization_info || {};
46
- const bubble = customInfo?.outgoing_bubble_color;
47
- const participantCustoms = Array.isArray(customInfo?.participant_customizations) ? customInfo.participant_customizations : [];
48
- const nicknames = participantCustoms.reduce((res, val) => {
49
- if (val?.nickname && val?.participant_id) res[val.participant_id] = val.nickname;
50
- return res;
51
- }, {});
52
- return {
53
- threadID,
54
- threadName: t?.name || null,
55
- participantIDs: participants.map(d => d?.node?.messaging_actor?.id).filter(Boolean),
56
- userInfo: participants.map(d => ({
57
- id: d?.node?.messaging_actor?.id || null,
58
- name: d?.node?.messaging_actor?.name || null,
59
- firstName: d?.node?.messaging_actor?.short_name || null,
60
- vanity: d?.node?.messaging_actor?.username || null,
61
- url: d?.node?.messaging_actor?.url || null,
62
- thumbSrc: d?.node?.messaging_actor?.big_image_src?.uri || null,
63
- profileUrl: d?.node?.messaging_actor?.big_image_src?.uri || null,
64
- gender: d?.node?.messaging_actor?.gender || null,
65
- type: d?.node?.messaging_actor?.__typename || null,
66
- isFriend: !!d?.node?.messaging_actor?.is_viewer_friend,
67
- isBirthday: !!d?.node?.messaging_actor?.is_birthday,
68
- })),
69
- unreadCount: t?.unread_count ?? 0,
70
- messageCount: t?.messages_count ?? 0,
71
- timestamp: t?.updated_time_precise || null,
72
- muteUntil: t?.mute_until || null,
73
- isGroup: t?.thread_type === "GROUP",
74
- isSubscribed: !!t?.is_viewer_subscribed,
75
- isArchived: !!t?.has_viewer_archived,
76
- folder: t?.folder || null,
77
- cannotReplyReason: t?.cannot_reply_reason || null,
78
- eventReminders: Array.isArray(t?.event_reminders?.nodes) ? t.event_reminders.nodes.map(formatEventReminders) : [],
79
- emoji: customInfo?.emoji || null,
80
- color: bubble ? String(bubble).slice(2) : null,
81
- threadTheme: t?.thread_theme || null,
82
- nicknames,
83
- adminIDs: Array.isArray(t?.thread_admins) ? t.thread_admins : [],
84
- approvalMode: !!t?.approval_mode,
85
- approvalQueue: approvals.map(a => ({
86
- inviterID: a?.inviter?.id || null,
87
- requesterID: a?.requester?.id || null,
88
- timestamp: a?.request_timestamp || null,
89
- request_source: a?.request_source || null,
90
- })),
91
- reactionsMuteMode: String(t?.reactions_mute_mode || "").toLowerCase(),
92
- mentionsMuteMode: String(t?.mentions_mute_mode || "").toLowerCase(),
93
- isPinProtected: !!t?.is_pin_protected,
94
- relatedPageThread: t?.related_page_thread || null,
95
- name: t?.name || null,
96
- snippet: snippetText,
97
- snippetSender: snippetID,
98
- snippetAttachments: [],
99
- serverTimestamp: t?.updated_time_precise || null,
100
- imageSrc: t?.image?.uri || null,
101
- isCanonicalUser: !!t?.is_canonical_neo_user,
102
- isCanonical: t?.thread_type !== "GROUP",
103
- recipientsLoadable: true,
104
- hasEmailParticipant: false,
105
- readOnly: false,
106
- canReply: t?.cannot_reply_reason == null,
107
- lastMessageTimestamp: t?.last_message ? t.last_message.timestamp_precise : null,
108
- lastMessageType: "message",
109
- lastReadTimestamp,
110
- threadType: t?.thread_type === "GROUP" ? 2 : 1,
111
- inviteLink: {
112
- enable: t?.joinable_mode ? t.joinable_mode.mode == 1 : false,
113
- link: t?.joinable_mode ? t.joinable_mode.link : null,
114
- },
115
- };
116
- }
117
-
118
- const queue = [];
119
- let isProcessingQueue = false;
120
- const processingThreads = new Set();
121
- const queuedThreads = new Set();
122
- const cooldown = new Map();
123
- const inflight = new Map();
124
- let loopStarted = false;
125
-
126
- module.exports = function (defaultFuncs, api, ctx) {
127
- const getMultiInfo = async function (threadIDs) {
128
- const buildQueries = () => {
129
- const form = {};
130
- threadIDs.forEach((x, y) => {
131
- form["o" + y] = {
132
- doc_id: "3449967031715030",
133
- query_params: {
134
- id: x,
135
- message_limit: 0,
136
- load_messages: false,
137
- load_read_receipts: false,
138
- before: null,
139
- },
140
- };
141
- });
142
- return {
143
- queries: JSON.stringify(form),
144
- batch_name: "MessengerGraphQLThreadFetcher",
145
- };
146
- };
147
- const maxAttempts = 3;
148
- let lastErr = null;
149
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
150
- try {
151
- const Submit = buildQueries();
152
- const resData = await defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, Submit).then(parseAndCheckLogin(ctx, defaultFuncs));
153
- if (!Array.isArray(resData) || resData.length === 0) throw new Error("EmptyGraphBatch");
154
- const tail = resData[resData.length - 1];
155
- if (tail?.error_results && tail.error_results !== 0) throw new Error("GraphErrorResults");
156
- const body = resData.slice(0, -1).sort((a, b) => Object.keys(a)[0].localeCompare(Object.keys(b)[0]));
157
- const out = [];
158
- body.forEach((x, y) => out.push(formatThreadGraphQLResponse(x["o" + y]?.data)));
159
- const valid = out.some(d => !!d && !!d.threadID);
160
- if (!valid) throw new Error("GraphNoData");
161
- return { Success: true, Data: out };
162
- } catch (e) {
163
- lastErr = e;
164
- if (attempt < maxAttempts) await new Promise(r => setTimeout(r, 300 * attempt));
165
- }
166
- }
167
- return { Success: false, Data: null, Error: lastErr ? String(lastErr.message || lastErr) : "Unknown" };
168
- };
169
-
170
- const dbFiles = fs.readdirSync(path.join(__dirname, "../../database")).filter(f => path.extname(f) === ".js").reduce((acc, file) => {
171
- acc[path.basename(file, ".js")] = require(path.join(__dirname, "../../database", file))(api);
172
- return acc;
173
- }, {});
174
- const { threadData, userData } = dbFiles;
175
- const { create, get, update, getAll } = threadData;
176
- const { update: updateUser } = userData;
177
-
178
- function isValidThread(d) {
179
- return d && d.threadID;
180
- }
181
-
182
- async function upsertUsersFromThreadInfo(info) {
183
- try {
184
- if (!info || !Array.isArray(info.userInfo) || info.userInfo.length === 0) return;
185
- const tasks = info.userInfo.filter(u => u && u.id).map(u => {
186
- const data = {
187
- id: u.id,
188
- name: u.name || null,
189
- firstName: u.firstName || null,
190
- vanity: u.vanity || null,
191
- url: u.url || null,
192
- thumbSrc: u.thumbSrc || null,
193
- profileUrl: u.profileUrl || null,
194
- gender: u.gender || null,
195
- type: u.type || null,
196
- isFriend: !!u.isFriend,
197
- isBirthday: !!u.isBirthday,
198
- };
199
- return updateUser(u.id, { data });
200
- });
201
- await Promise.allSettled(tasks);
202
- } catch (e) {
203
- logger(`upsertUsers error: ${e?.message || e}`, "warn");
204
- }
205
- }
206
-
207
- async function createOrUpdateThread(id, data) {
208
- const existing = await get(id);
209
- if (existing) {
210
- await update(id, { data });
211
- return "update";
212
- } else {
213
- await create(id, { data });
214
- return "create";
215
- }
216
- }
217
-
218
- async function fetchThreadInfo(tID, isNew) {
219
- try {
220
- const response = await getMultiInfo([tID]);
221
- if (!response.Success || !response.Data || !isValidThread(response.Data[0])) {
222
- cooldown.set(tID, Date.now() + 5 * 60 * 1000);
223
- logger(`GraphQL empty for ${tID}, cooldown applied`, "warn");
224
- return;
225
- }
226
- const threadInfo = response.Data[0];
227
- await upsertUsersFromThreadInfo(threadInfo);
228
- const op = await createOrUpdateThread(tID, threadInfo);
229
- logger(`${op === "create" ? "Success create data thread" : "Success update data thread"}: ${tID}`, "info");
230
- } catch (err) {
231
- cooldown.set(tID, Date.now() + 5 * 60 * 1000);
232
- logger(`fetchThreadInfo error ${tID}: ${err?.message || err}`, "error");
233
- } finally {
234
- queuedThreads.delete(tID);
235
- }
236
- }
237
-
238
- async function checkAndUpdateThreads() {
239
- try {
240
- const allThreads = await getAll("threadID");
241
- const existingThreadIDs = new Set(allThreads.map(t => t.threadID));
242
- const now = Date.now();
243
- for (const t of existingThreadIDs) {
244
- const cd = cooldown.get(t);
245
- if (cd && now < cd) continue;
246
- const result = await get(t);
247
- if (!result) continue;
248
- const lastUpdated = new Date(result.updatedAt).getTime();
249
- if ((now - lastUpdated) / (1000 * 60) > 10 && !queuedThreads.has(t)) {
250
- queuedThreads.add(t);
251
- queue.push(() => fetchThreadInfo(t, false));
252
- }
253
- }
254
- } catch (err) {
255
- logger(`checkAndUpdateThreads error: ${err?.message || err}`, "error");
256
- }
257
- }
258
-
259
- async function processQueue() {
260
- if (isProcessingQueue) return;
261
- isProcessingQueue = true;
262
- while (queue.length > 0) {
263
- const task = queue.shift();
264
- try {
265
- await task();
266
- } catch (err) {
267
- logger(`Queue processing error: ${err?.message || err}`, "error");
268
- }
269
- }
270
- isProcessingQueue = false;
271
- }
272
-
273
- if (!loopStarted) {
274
- loopStarted = true;
275
- setInterval(() => {
276
- checkAndUpdateThreads();
277
- processQueue();
278
- }, 10000);
279
- }
280
-
281
- return async function getThreadInfoGraphQL(threadID, callback) {
282
- let resolveFunc = function () { };
283
- let rejectFunc = function () { };
284
- const returnPromise = new Promise(function (resolve, reject) {
285
- resolveFunc = resolve;
286
- rejectFunc = reject;
287
- });
288
- if (getType(callback) != "Function" && getType(callback) != "AsyncFunction") {
289
- callback = function (err, data) {
290
- if (err) return rejectFunc(err);
291
- resolveFunc(data);
292
- };
293
- }
294
- if (getType(threadID) !== "Array") threadID = [threadID];
295
- const tid = String(threadID[0]);
296
- try {
297
- const cd = cooldown.get(tid);
298
- if (cd && Date.now() < cd) {
299
- const cachedCd = await get(tid);
300
- if (cachedCd?.data && isValidThread(cachedCd.data)) {
301
- await upsertUsersFromThreadInfo(cachedCd.data);
302
- callback(null, cachedCd.data);
303
- return returnPromise;
304
- }
305
- const stub = {
306
- threadID: tid,
307
- threadName: null,
308
- participantIDs: [],
309
- userInfo: [],
310
- unreadCount: 0,
311
- messageCount: 0,
312
- timestamp: null,
313
- muteUntil: null,
314
- isGroup: false,
315
- isSubscribed: false,
316
- isArchived: false,
317
- folder: null,
318
- cannotReplyReason: null,
319
- eventReminders: [],
320
- emoji: null,
321
- color: null,
322
- threadTheme: null,
323
- nicknames: {},
324
- adminIDs: [],
325
- approvalMode: false,
326
- approvalQueue: [],
327
- reactionsMuteMode: "",
328
- mentionsMuteMode: "",
329
- isPinProtected: false,
330
- relatedPageThread: null,
331
- name: null,
332
- snippet: null,
333
- snippetSender: null,
334
- snippetAttachments: [],
335
- serverTimestamp: null,
336
- imageSrc: null,
337
- isCanonicalUser: false,
338
- isCanonical: true,
339
- recipientsLoadable: false,
340
- hasEmailParticipant: false,
341
- readOnly: false,
342
- canReply: false,
343
- lastMessageTimestamp: null,
344
- lastMessageType: "message",
345
- lastReadTimestamp: null,
346
- threadType: 1,
347
- inviteLink: { enable: false, link: null },
348
- __status: "cooldown",
349
- };
350
- await createOrUpdateThread(tid, stub);
351
- callback(null, stub);
352
- return returnPromise;
353
- }
354
-
355
- const cached = await get(tid);
356
- if (cached?.data && isValidThread(cached.data)) {
357
- await upsertUsersFromThreadInfo(cached.data);
358
- callback(null, cached.data);
359
- return returnPromise;
360
- }
361
-
362
- if (inflight.has(tid)) {
363
- inflight.get(tid).then(data => callback(null, data)).catch(err => callback(err));
364
- return returnPromise;
365
- }
366
-
367
- const p = (async () => {
368
- processingThreads.add(tid);
369
- const response = await getMultiInfo([tid]);
370
- if (response.Success && response.Data && isValidThread(response.Data[0])) {
371
- const data = response.Data[0];
372
- await upsertUsersFromThreadInfo(data);
373
- await createOrUpdateThread(tid, data);
374
- return data;
375
- } else {
376
- const stub = {
377
- threadID: tid,
378
- threadName: null,
379
- participantIDs: [],
380
- userInfo: [],
381
- unreadCount: 0,
382
- messageCount: 0,
383
- timestamp: null,
384
- muteUntil: null,
385
- isGroup: false,
386
- isSubscribed: false,
387
- isArchived: false,
388
- folder: null,
389
- cannotReplyReason: null,
390
- eventReminders: [],
391
- emoji: null,
392
- color: null,
393
- threadTheme: null,
394
- nicknames: {},
395
- adminIDs: [],
396
- approvalMode: false,
397
- approvalQueue: [],
398
- reactionsMuteMode: "",
399
- mentionsMuteMode: "",
400
- isPinProtected: false,
401
- relatedPageThread: null,
402
- name: null,
403
- snippet: null,
404
- snippetSender: null,
405
- snippetAttachments: [],
406
- serverTimestamp: null,
407
- imageSrc: null,
408
- isCanonicalUser: false,
409
- isCanonical: true,
410
- recipientsLoadable: false,
411
- hasEmailParticipant: false,
412
- readOnly: false,
413
- canReply: false,
414
- lastMessageTimestamp: null,
415
- lastMessageType: "message",
416
- lastReadTimestamp: null,
417
- threadType: 1,
418
- inviteLink: { enable: false, link: null },
419
- __status: "unavailable",
420
- };
421
- cooldown.set(tid, Date.now() + 5 * 60 * 1000);
422
- await createOrUpdateThread(tid, stub);
423
- return stub;
424
- }
425
- })()
426
- .finally(() => {
427
- processingThreads.delete(tid);
428
- inflight.delete(tid);
429
- });
430
-
431
- inflight.set(tid, p);
432
- p.then(data => callback(null, data)).catch(err => callback(err));
433
- } catch (err) {
434
- callback(err);
435
- }
436
- return returnPromise;
437
- };
438
- };