ws-rapido 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 (84) hide show
  1. package/index.js +477 -0
  2. package/package.json +46 -0
  3. package/src/addExternalModule.js +25 -0
  4. package/src/addUserToGroup.js +115 -0
  5. package/src/changeAdminStatus.js +103 -0
  6. package/src/changeArchivedStatus.js +55 -0
  7. package/src/changeAvatar.js +136 -0
  8. package/src/changeAvatarV2.js +86 -0
  9. package/src/changeBio.js +76 -0
  10. package/src/changeBlockedStatus.js +49 -0
  11. package/src/changeBlockedStatusMqtt.js +80 -0
  12. package/src/changeCover.js +72 -0
  13. package/src/changeGroupImage.js +135 -0
  14. package/src/changeName.js +78 -0
  15. package/src/changeNickname.js +59 -0
  16. package/src/changeThreadColor.js +65 -0
  17. package/src/changeThreadEmoji.js +55 -0
  18. package/src/changeUsername.js +58 -0
  19. package/src/createCommentPost.js +229 -0
  20. package/src/createNewGroup.js +88 -0
  21. package/src/createPoll.js +71 -0
  22. package/src/createPost.js +275 -0
  23. package/src/data/getThreadInfo.json +1 -0
  24. package/src/deleteMessage.js +56 -0
  25. package/src/deleteThread.js +56 -0
  26. package/src/editMessage.js +76 -0
  27. package/src/follow.js +74 -0
  28. package/src/forwardAttachment.js +60 -0
  29. package/src/getAccess.js +111 -0
  30. package/src/getAvatarUser.js +78 -0
  31. package/src/getBotInitialData.js +43 -0
  32. package/src/getCtx.js +5 -0
  33. package/src/getCurrentUserID.js +7 -0
  34. package/src/getEmojiUrl.js +29 -0
  35. package/src/getFriendsList.js +83 -0
  36. package/src/getMessage.js +835 -0
  37. package/src/getOptions.js +5 -0
  38. package/src/getRegion.js +7 -0
  39. package/src/getThreadHistory.js +680 -0
  40. package/src/getThreadHistoryDeprecated.js +93 -0
  41. package/src/getThreadInfo.js +227 -0
  42. package/src/getThreadInfoDeprecated.js +80 -0
  43. package/src/getThreadList.js +269 -0
  44. package/src/getThreadListDeprecated.js +75 -0
  45. package/src/getThreadPictures.js +79 -0
  46. package/src/getUID.js +122 -0
  47. package/src/getUserID.js +66 -0
  48. package/src/getUserInfo.js +82 -0
  49. package/src/handleFriendRequest.js +57 -0
  50. package/src/handleMessageRequest.js +65 -0
  51. package/src/httpGet.js +64 -0
  52. package/src/httpPost.js +64 -0
  53. package/src/httpPostFormData.js +70 -0
  54. package/src/listenMqtt.js +674 -0
  55. package/src/listenNotification.js +85 -0
  56. package/src/logout.js +75 -0
  57. package/src/markAsDelivered.js +55 -0
  58. package/src/markAsRead.js +85 -0
  59. package/src/markAsReadAll.js +50 -0
  60. package/src/markAsSeen.js +61 -0
  61. package/src/muteThread.js +52 -0
  62. package/src/pinMessage.js +59 -0
  63. package/src/refreshFb_dtsg.js +89 -0
  64. package/src/removeUserFromGroup.js +79 -0
  65. package/src/resolvePhotoUrl.js +45 -0
  66. package/src/searchForThread.js +53 -0
  67. package/src/searchStickers.js +53 -0
  68. package/src/sendMessage.js +442 -0
  69. package/src/sendMessageMqtt.js +316 -0
  70. package/src/sendTypingIndicator.js +28 -0
  71. package/src/setMessageReaction.js +122 -0
  72. package/src/setMessageReactionMqtt.js +62 -0
  73. package/src/setPostReaction.js +108 -0
  74. package/src/setProfileGuard.js +44 -0
  75. package/src/setStoryReaction.js +64 -0
  76. package/src/setTitle.js +90 -0
  77. package/src/shareContact.js +110 -0
  78. package/src/shareLink.js +59 -0
  79. package/src/stopListenMqtt.js +23 -0
  80. package/src/threadColors.js +131 -0
  81. package/src/unfriend.js +52 -0
  82. package/src/unsendMessage.js +45 -0
  83. package/src/uploadAttachment.js +94 -0
  84. package/utils.js +1441 -0
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ // @NethWs3Dev
5
+
6
+ module.exports = function(defaultFuncs, api, ctx) {
7
+ return function getThreadHistory(threadID, amount, timestamp, 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
+ if (!callback) {
25
+ throw { error: "getThreadHistory: need callback" };
26
+ }
27
+
28
+ var form = {
29
+ client: "mercury"
30
+ };
31
+
32
+ api.getUserInfo(threadID, function(err, res) {
33
+ if (err) {
34
+ return callback(err);
35
+ }
36
+ var key = Object.keys(res).length > 0 ? "user_ids" : "thread_fbids";
37
+ form["messages[" + key + "][" + threadID + "][offset]"] = 0;
38
+ form["messages[" + key + "][" + threadID + "][timestamp]"] = timestamp;
39
+ form["messages[" + key + "][" + threadID + "][limit]"] = amount;
40
+
41
+ if (ctx.globalOptions.pageID)
42
+ form.request_user_id = ctx.globalOptions.pageID;
43
+
44
+ defaultFuncs
45
+ .post(
46
+ "https://www.facebook.com/ajax/mercury/thread_info.php",
47
+ ctx.jar,
48
+ form
49
+ )
50
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
51
+ .then(function(resData) {
52
+ if (resData.error) {
53
+ throw resData;
54
+ } else if (!resData.payload) {
55
+ throw { error: "Could not retrieve thread history." };
56
+ }
57
+
58
+ // Asking for message history from a thread with no message history
59
+ // will return undefined for actions here
60
+ if (!resData.payload.actions) {
61
+ resData.payload.actions = [];
62
+ }
63
+
64
+ var userIDs = {};
65
+ resData.payload.actions.forEach(function(v) {
66
+ userIDs[v.author.split(":").pop()] = "";
67
+ });
68
+
69
+ api.getUserInfo(Object.keys(userIDs), function(err, data) {
70
+ if (err) return callback(err); //callback({error: "Could not retrieve user information in getThreadHistory."});
71
+
72
+ resData.payload.actions.forEach(function(v) {
73
+ var sender = data[v.author.split(":").pop()];
74
+ if (sender) v.sender_name = sender.name;
75
+ else v.sender_name = "Facebook User";
76
+ v.sender_fbid = v.author;
77
+ delete v.author;
78
+ });
79
+
80
+ callback(
81
+ null,
82
+ resData.payload.actions.map(utils.formatHistoryMessage)
83
+ );
84
+ });
85
+ })
86
+ .catch(function(err) {
87
+ utils.error("getThreadHistory", err);
88
+ return callback(err);
89
+ });
90
+ });
91
+ return returnPromise;
92
+ };
93
+ };
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+ // @NethWs3Dev
5
+
6
+ function formatEventReminders(reminder) {
7
+ return {
8
+ reminderID: reminder.id,
9
+ eventCreatorID: reminder.lightweight_event_creator.id,
10
+ time: reminder.time,
11
+ eventType: reminder.lightweight_event_type.toLowerCase(),
12
+ locationName: reminder.location_name,
13
+ locationCoordinates: reminder.location_coordinates,
14
+ locationPage: reminder.location_page,
15
+ eventStatus: reminder.lightweight_event_status.toLowerCase(),
16
+ note: reminder.note,
17
+ repeatMode: reminder.repeat_mode.toLowerCase(),
18
+ eventTitle: reminder.event_title,
19
+ triggerMessage: reminder.trigger_message,
20
+ secondsToNotifyBefore: reminder.seconds_to_notify_before,
21
+ allowsRsvp: reminder.allows_rsvp,
22
+ relatedEvent: reminder.related_event,
23
+ members: reminder.event_reminder_members.edges.map(function (member) {
24
+ return {
25
+ memberID: member.node.id,
26
+ state: member.guest_list_state.toLowerCase(),
27
+ };
28
+ }),
29
+ };
30
+ }
31
+
32
+ function formatThreadGraphQLResponse(data) {
33
+ if (data.errors) return null; // Return null if there are errors
34
+ const messageThread = data.message_thread;
35
+ if (!messageThread) return null;
36
+
37
+ const threadID = messageThread.thread_key.thread_fbid
38
+ ? messageThread.thread_key.thread_fbid
39
+ : messageThread.thread_key.other_user_id;
40
+
41
+ const lastM = messageThread.last_message;
42
+ const snippetID =
43
+ lastM &&
44
+ lastM.nodes &&
45
+ lastM.nodes[0] &&
46
+ lastM.nodes[0].message_sender &&
47
+ lastM.nodes[0].message_sender.messaging_actor
48
+ ? lastM.nodes[0].message_sender.messaging_actor.id
49
+ : null;
50
+ const snippetText =
51
+ lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
52
+ const lastR = messageThread.last_read_receipt;
53
+ const lastReadTimestamp =
54
+ lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
55
+ ? lastR.nodes[0].timestamp_precise
56
+ : null;
57
+
58
+ return {
59
+ threadID: threadID,
60
+ threadName: messageThread.name,
61
+ participantIDs: messageThread.all_participants.edges.map(
62
+ (d) => d.node.messaging_actor.id,
63
+ ),
64
+ userInfo: messageThread.all_participants.edges.map((d) => ({
65
+ id: d.node.messaging_actor.id,
66
+ name: d.node.messaging_actor.name,
67
+ firstName: d.node.messaging_actor.short_name,
68
+ vanity: d.node.messaging_actor.username,
69
+ url: d.node.messaging_actor.url,
70
+ thumbSrc: d.node.messaging_actor.big_image_src.uri,
71
+ profileUrl: d.node.messaging_actor.big_image_src.uri,
72
+ gender: d.node.messaging_actor.gender,
73
+ type: d.node.messaging_actor.__typename,
74
+ isFriend: d.node.messaging_actor.is_viewer_friend,
75
+ isBirthday: !!d.node.messaging_actor.is_birthday,
76
+ })),
77
+ unreadCount: messageThread.unread_count,
78
+ messageCount: messageThread.messages_count,
79
+ timestamp: messageThread.updated_time_precise,
80
+ muteUntil: messageThread.mute_until,
81
+ isGroup: messageThread.thread_type == "GROUP",
82
+ isSubscribed: messageThread.is_viewer_subscribed,
83
+ isArchived: messageThread.has_viewer_archived,
84
+ folder: messageThread.folder,
85
+ cannotReplyReason: messageThread.cannot_reply_reason,
86
+ eventReminders: messageThread.event_reminders
87
+ ? messageThread.event_reminders.nodes.map(formatEventReminders)
88
+ : null,
89
+ emoji: messageThread.customization_info
90
+ ? messageThread.customization_info.emoji
91
+ : null,
92
+ color:
93
+ messageThread.customization_info &&
94
+ messageThread.customization_info.outgoing_bubble_color
95
+ ? messageThread.customization_info.outgoing_bubble_color.slice(2)
96
+ : null,
97
+ threadTheme: messageThread.thread_theme,
98
+ nicknames:
99
+ messageThread.customization_info &&
100
+ messageThread.customization_info.participant_customizations
101
+ ? messageThread.customization_info.participant_customizations.reduce(
102
+ function (res, val) {
103
+ if (val.nickname) res[val.participant_id] = val.nickname;
104
+ return res;
105
+ },
106
+ {},
107
+ )
108
+ : {},
109
+ adminIDs: messageThread.thread_admins,
110
+ approvalMode: Boolean(messageThread.approval_mode),
111
+ approvalQueue: messageThread.group_approval_queue.nodes.map((a) => ({
112
+ inviterID: a.inviter.id,
113
+ requesterID: a.requester.id,
114
+ timestamp: a.request_timestamp,
115
+ request_source: a.request_source,
116
+ })),
117
+ reactionsMuteMode: messageThread.reactions_mute_mode.toLowerCase(),
118
+ mentionsMuteMode: messageThread.mentions_mute_mode.toLowerCase(),
119
+ isPinProtected: messageThread.is_pin_protected,
120
+ relatedPageThread: messageThread.related_page_thread,
121
+ name: messageThread.name,
122
+ snippet: snippetText,
123
+ snippetSender: snippetID,
124
+ snippetAttachments: [],
125
+ serverTimestamp: messageThread.updated_time_precise,
126
+ imageSrc: messageThread.image ? messageThread.image.uri : null,
127
+ isCanonicalUser: messageThread.is_canonical_neo_user,
128
+ isCanonical: messageThread.thread_type != "GROUP",
129
+ recipientsLoadable: true,
130
+ hasEmailParticipant: false,
131
+ readOnly: false,
132
+ canReply: messageThread.cannot_reply_reason == null,
133
+ lastMessageTimestamp: messageThread.last_message
134
+ ? messageThread.last_message.timestamp_precise
135
+ : null,
136
+ lastMessageType: "message",
137
+ lastReadTimestamp: lastReadTimestamp,
138
+ threadType: messageThread.thread_type == "GROUP" ? 2 : 1,
139
+ inviteLink: {
140
+ enable: messageThread.joinable_mode
141
+ ? messageThread.joinable_mode.mode == 1
142
+ : false,
143
+ link: messageThread.joinable_mode
144
+ ? messageThread.joinable_mode.link
145
+ : null,
146
+ },
147
+ };
148
+ }
149
+
150
+ module.exports = function (defaultFuncs, api, ctx) {
151
+ return function getThreadInfoGraphQL(threadID, callback) {
152
+ let resolveFunc = function () {};
153
+ let rejectFunc = function () {};
154
+ const returnPromise = new Promise(function (resolve, reject) {
155
+ resolveFunc = resolve;
156
+ rejectFunc = reject;
157
+ });
158
+
159
+ if (
160
+ utils.getType(callback) != "Function" &&
161
+ utils.getType(callback) != "AsyncFunction"
162
+ ) {
163
+ callback = function (err, data) {
164
+ if (err) {
165
+ return rejectFunc(err);
166
+ }
167
+ resolveFunc(data);
168
+ };
169
+ }
170
+
171
+ if (utils.getType(threadID) !== "Array") {
172
+ threadID = [threadID];
173
+ }
174
+
175
+ let form = {};
176
+ threadID.map(function (t, i) {
177
+ form["o" + i] = {
178
+ doc_id: "3449967031715030",
179
+ query_params: {
180
+ id: t,
181
+ message_limit: 0,
182
+ load_messages: false,
183
+ load_read_receipts: false,
184
+ before: null,
185
+ },
186
+ };
187
+ });
188
+
189
+ form = {
190
+ queries: JSON.stringify(form),
191
+ batch_name: "MessengerGraphQLThreadFetcher",
192
+ };
193
+
194
+ defaultFuncs
195
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
196
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
197
+ .then(function (resData) {
198
+ if (resData.error) {
199
+ throw resData;
200
+ }
201
+
202
+ const threadInfos = {};
203
+ for (let i = resData.length - 2; i >= 0; i--) {
204
+ const threadInfo = formatThreadGraphQLResponse(
205
+ resData[i][Object.keys(resData[i])[0]].data,
206
+ );
207
+ if (threadInfo) { // Only add valid threadInfo
208
+ threadInfos[
209
+ threadInfo.threadID || threadID[threadID.length - 1 - i]
210
+ ] = threadInfo;
211
+ }
212
+ }
213
+
214
+ if (Object.values(threadInfos).length == 1) {
215
+ callback(null, Object.values(threadInfos)[0]);
216
+ } else {
217
+ callback(null, threadInfos);
218
+ }
219
+ })
220
+ .catch(function () {
221
+ // Do nothing on error
222
+ callback(null, null);
223
+ });
224
+
225
+ return returnPromise;
226
+ };
227
+ };
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ var utils = require("../utils");
4
+ // @NethWs3Dev
5
+
6
+ module.exports = function(defaultFuncs, api, ctx) {
7
+ return function getThreadInfo(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
+
15
+ if (!callback) {
16
+ callback = function (err, friendList) {
17
+ if (err) {
18
+ return rejectFunc(err);
19
+ }
20
+ resolveFunc(friendList);
21
+ };
22
+ }
23
+
24
+ var form = {
25
+ client: "mercury"
26
+ };
27
+
28
+ api.getUserInfo(threadID, function(err, userRes) {
29
+ if (err) {
30
+ return callback(err);
31
+ }
32
+ var key = Object.keys(userRes).length > 0 ? "user_ids" : "thread_fbids";
33
+ form["threads[" + key + "][0]"] = threadID;
34
+
35
+ if (ctx.globalOptions.pageId)
36
+ form.request_user_id = ctx.globalOptions.pageId;
37
+
38
+ defaultFuncs
39
+ .post(
40
+ "https://www.facebook.com/ajax/mercury/thread_info.php",
41
+ ctx.jar,
42
+ form
43
+ )
44
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
45
+ .then(function(resData) {
46
+ if (resData.error) {
47
+ throw resData;
48
+ } else if (!resData.payload) {
49
+ throw {
50
+ error: "Could not retrieve thread Info."
51
+ };
52
+ }
53
+ var threadData = resData.payload.threads[0];
54
+ var userData = userRes[threadID];
55
+
56
+ if (threadData == null) {
57
+ throw {
58
+ error: "ThreadData is null"
59
+ };
60
+ }
61
+
62
+ threadData.name =
63
+ userData != null && userData.name != null
64
+ ? userData.name
65
+ : threadData.name;
66
+ threadData.image_src =
67
+ userData != null && userData.thumbSrc != null
68
+ ? userData.thumbSrc
69
+ : threadData.image_src;
70
+
71
+ callback(null, utils.formatThread(threadData));
72
+ })
73
+ .catch(function(err) {
74
+ utils.error("getThreadInfo", err);
75
+ return callback(err);
76
+ });
77
+ });
78
+ return returnPromise;
79
+ };
80
+ };
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+
3
+ const utils = require("../utils");
4
+
5
+ function formatEventReminders(reminder) {
6
+ return {
7
+ reminderID: reminder.id,
8
+ eventCreatorID: reminder.lightweight_event_creator.id,
9
+ time: reminder.time,
10
+ eventType: reminder.lightweight_event_type.toLowerCase(),
11
+ locationName: reminder.location_name,
12
+ // @TODO verify this
13
+ locationCoordinates: reminder.location_coordinates,
14
+ locationPage: reminder.location_page,
15
+ eventStatus: reminder.lightweight_event_status.toLowerCase(),
16
+ note: reminder.note,
17
+ repeatMode: reminder.repeat_mode.toLowerCase(),
18
+ eventTitle: reminder.event_title,
19
+ triggerMessage: reminder.trigger_message,
20
+ secondsToNotifyBefore: reminder.seconds_to_notify_before,
21
+ allowsRsvp: reminder.allows_rsvp,
22
+ relatedEvent: reminder.related_event,
23
+ members: reminder.event_reminder_members.edges.map(function (member) {
24
+ return {
25
+ memberID: member.node.id,
26
+ state: member.guest_list_state.toLowerCase(),
27
+ };
28
+ }),
29
+ };
30
+ }
31
+
32
+ function formatThreadGraphQLResponse(messageThread) {
33
+ const threadID = messageThread.thread_key.thread_fbid
34
+ ? messageThread.thread_key.thread_fbid
35
+ : messageThread.thread_key.other_user_id;
36
+
37
+ // Remove me
38
+ const lastM = messageThread.last_message;
39
+ const snippetID =
40
+ lastM &&
41
+ lastM.nodes &&
42
+ lastM.nodes[0] &&
43
+ lastM.nodes[0].message_sender &&
44
+ lastM.nodes[0].message_sender.messaging_actor
45
+ ? lastM.nodes[0].message_sender.messaging_actor.id
46
+ : null;
47
+ const snippetText =
48
+ lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
49
+ const lastR = messageThread.last_read_receipt;
50
+ const lastReadTimestamp =
51
+ lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
52
+ ? lastR.nodes[0].timestamp_precise
53
+ : null;
54
+
55
+ return {
56
+ threadID: threadID,
57
+ threadName: messageThread.name,
58
+ participantIDs: messageThread.all_participants.edges.map(
59
+ (d) => d.node.messaging_actor.id,
60
+ ),
61
+ userInfo: messageThread.all_participants.edges.map((d) => ({
62
+ id: d.node.messaging_actor.id,
63
+ name: d.node.messaging_actor.name,
64
+ firstName: d.node.messaging_actor.short_name,
65
+ vanity: d.node.messaging_actor.username,
66
+ url: d.node.messaging_actor.url,
67
+ thumbSrc: d.node.messaging_actor.big_image_src.uri,
68
+ profileUrl: d.node.messaging_actor.big_image_src.uri,
69
+ gender: d.node.messaging_actor.gender,
70
+ type: d.node.messaging_actor.__typename,
71
+ isFriend: d.node.messaging_actor.is_viewer_friend,
72
+ isBirthday: !!d.node.messaging_actor.is_birthday, //not sure?
73
+ })),
74
+ unreadCount: messageThread.unread_count,
75
+ messageCount: messageThread.messages_count,
76
+ timestamp: messageThread.updated_time_precise,
77
+ muteUntil: messageThread.mute_until,
78
+ isGroup: messageThread.thread_type == "GROUP",
79
+ isSubscribed: messageThread.is_viewer_subscribed,
80
+ isArchived: messageThread.has_viewer_archived,
81
+ folder: messageThread.folder,
82
+ cannotReplyReason: messageThread.cannot_reply_reason,
83
+ eventReminders: messageThread.event_reminders
84
+ ? messageThread.event_reminders.nodes.map(formatEventReminders)
85
+ : null,
86
+ emoji: messageThread.customization_info
87
+ ? messageThread.customization_info.emoji
88
+ : null,
89
+ color:
90
+ messageThread.customization_info &&
91
+ messageThread.customization_info.outgoing_bubble_color
92
+ ? messageThread.customization_info.outgoing_bubble_color.slice(2)
93
+ : null,
94
+ threadTheme: messageThread.thread_theme,
95
+ nicknames:
96
+ messageThread.customization_info &&
97
+ messageThread.customization_info.participant_customizations
98
+ ? messageThread.customization_info.participant_customizations.reduce(
99
+ function (res, val) {
100
+ if (val.nickname) res[val.participant_id] = val.nickname;
101
+ return res;
102
+ },
103
+ {},
104
+ )
105
+ : {},
106
+ adminIDs: messageThread.thread_admins,
107
+ approvalMode: Boolean(messageThread.approval_mode),
108
+ approvalQueue: messageThread.group_approval_queue.nodes.map((a) => ({
109
+ inviterID: a.inviter.id,
110
+ requesterID: a.requester.id,
111
+ timestamp: a.request_timestamp,
112
+ request_source: a.request_source, // @Undocumented
113
+ })),
114
+
115
+ // @Undocumented
116
+ reactionsMuteMode: messageThread.reactions_mute_mode.toLowerCase(),
117
+ mentionsMuteMode: messageThread.mentions_mute_mode.toLowerCase(),
118
+ isPinProtected: messageThread.is_pin_protected,
119
+ relatedPageThread: messageThread.related_page_thread,
120
+
121
+ // @Legacy
122
+ name: messageThread.name,
123
+ snippet: snippetText,
124
+ snippetSender: snippetID,
125
+ snippetAttachments: [],
126
+ serverTimestamp: messageThread.updated_time_precise,
127
+ imageSrc: messageThread.image ? messageThread.image.uri : null,
128
+ isCanonicalUser: messageThread.is_canonical_neo_user,
129
+ isCanonical: messageThread.thread_type != "GROUP",
130
+ recipientsLoadable: true,
131
+ hasEmailParticipant: false,
132
+ readOnly: false,
133
+ canReply: messageThread.cannot_reply_reason == null,
134
+ lastMessageTimestamp: messageThread.last_message
135
+ ? messageThread.last_message.timestamp_precise
136
+ : null,
137
+ lastMessageType: "message",
138
+ lastReadTimestamp: lastReadTimestamp,
139
+ threadType: messageThread.thread_type == "GROUP" ? 2 : 1,
140
+
141
+ // update in Wed, 13 Jul 2022 19:41:12 +0700
142
+ inviteLink: {
143
+ enable: messageThread.joinable_mode
144
+ ? messageThread.joinable_mode.mode == 1
145
+ : false,
146
+ link: messageThread.joinable_mode
147
+ ? messageThread.joinable_mode.link
148
+ : null,
149
+ },
150
+ };
151
+ }
152
+
153
+ function formatThreadList(data) {
154
+ // console.log(JSON.stringify(data.find(t => t.thread_key.thread_fbid === "5095817367161431"), null, 2));
155
+ return data.map((t) => formatThreadGraphQLResponse(t));
156
+ }
157
+
158
+ module.exports = function (defaultFuncs, api, ctx) {
159
+ return function getThreadList(limit, timestamp, tags, callback) {
160
+ if (
161
+ !callback &&
162
+ (utils.getType(tags) === "Function" ||
163
+ utils.getType(tags) === "AsyncFunction")
164
+ ) {
165
+ callback = tags;
166
+ tags = [""];
167
+ }
168
+ if (
169
+ utils.getType(limit) !== "Number" ||
170
+ !Number.isInteger(limit) ||
171
+ limit <= 0
172
+ ) {
173
+ throw new utils.CustomError({
174
+ error: "getThreadList: limit must be a positive integer",
175
+ });
176
+ }
177
+ if (
178
+ utils.getType(timestamp) !== "Null" &&
179
+ (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
180
+ ) {
181
+ throw new utils.CustomError({
182
+ error: "getThreadList: timestamp must be an integer or null",
183
+ });
184
+ }
185
+ if (utils.getType(tags) === "String") {
186
+ tags = [tags];
187
+ }
188
+ if (utils.getType(tags) !== "Array") {
189
+ throw new utils.CustomError({
190
+ error: "getThreadList: tags must be an array",
191
+ message: "getThreadList: tags must be an array",
192
+ });
193
+ }
194
+
195
+ let resolveFunc = function () {};
196
+ let rejectFunc = function () {};
197
+ const returnPromise = new Promise(function (resolve, reject) {
198
+ resolveFunc = resolve;
199
+ rejectFunc = reject;
200
+ });
201
+
202
+ if (
203
+ utils.getType(callback) !== "Function" &&
204
+ utils.getType(callback) !== "AsyncFunction"
205
+ ) {
206
+ callback = function (err, data) {
207
+ if (err) {
208
+ return rejectFunc(err);
209
+ }
210
+ resolveFunc(data);
211
+ };
212
+ }
213
+
214
+ const form = {
215
+ av: ctx.i_userID || ctx.userID,
216
+ queries: JSON.stringify({
217
+ o0: {
218
+ // This doc_id was valid on 2020-07-20
219
+ // "doc_id": "3336396659757871",
220
+ doc_id: "3426149104143726",
221
+ query_params: {
222
+ limit: limit + (timestamp ? 1 : 0),
223
+ before: timestamp,
224
+ tags: tags,
225
+ includeDeliveryReceipts: true,
226
+ includeSeqID: false,
227
+ },
228
+ },
229
+ }),
230
+ batch_name: "MessengerGraphQLThreadlistFetcher",
231
+ };
232
+
233
+ defaultFuncs
234
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
235
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
236
+ .then((resData) => {
237
+ if (resData[resData.length - 1].error_results > 0) {
238
+ throw new utils.CustomError(resData[0].o0.errors);
239
+ }
240
+
241
+ if (resData[resData.length - 1].successful_results === 0) {
242
+ throw new utils.CustomError({
243
+ error: "getThreadList: there was no successful_results",
244
+ res: resData,
245
+ });
246
+ }
247
+
248
+ // When we ask for threads using timestamp from the previous request,
249
+ // we are getting the last thread repeated as the first thread in this response.
250
+ // .shift() gets rid of it
251
+ // It is also the reason for increasing limit by 1 when timestamp is set
252
+ // this way user asks for 10 threads, we are asking for 11,
253
+ // but after removing the duplicated one, it is again 10
254
+ if (timestamp) {
255
+ resData[0].o0.data.viewer.message_threads.nodes.shift();
256
+ }
257
+ callback(
258
+ null,
259
+ formatThreadList(resData[0].o0.data.viewer.message_threads.nodes),
260
+ );
261
+ })
262
+ .catch((err) => {
263
+ utils.error("getThreadList", err);
264
+ return callback(err);
265
+ });
266
+
267
+ return returnPromise;
268
+ };
269
+ };