fca-smart-shankar 10.9.1 → 13.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 (169) hide show
  1. package/.replit +12 -3
  2. package/.upm/store.json +1 -1
  3. package/CHANGELOG.md +2 -0
  4. package/LICENSE-MIT +21 -0
  5. package/README.md +175 -30
  6. package/generated-icon.png +0 -0
  7. package/index.js +511 -414
  8. package/package.json +370 -85
  9. package/replit.nix +5 -0
  10. package/shankar-fca.json +4 -0
  11. package/src/addExternalModule.js +14 -5
  12. package/src/addUserToGroup.js +56 -20
  13. package/src/changeAdminStatus.js +44 -20
  14. package/src/changeArchivedStatus.js +25 -11
  15. package/src/changeAvatar.js +136 -0
  16. package/src/{changeAvt.js → changeAvatarV2.js} +3 -2
  17. package/src/changeBio.js +26 -15
  18. package/src/changeBlockedStatus.js +21 -8
  19. package/src/changeBlockedStatusMqtt.js +80 -0
  20. package/src/changeCover.js +73 -0
  21. package/src/changeGroupImage.js +53 -24
  22. package/src/changeName.js +79 -0
  23. package/src/changeNickname.js +27 -13
  24. package/src/changeThreadColor.js +22 -19
  25. package/src/changeThreadEmoji.js +24 -11
  26. package/src/changeUsername.js +59 -0
  27. package/src/createCommentPost.js +230 -0
  28. package/src/createNewGroup.js +38 -20
  29. package/src/createPoll.js +27 -16
  30. package/src/createPost.js +277 -0
  31. package/src/data/getThreadInfo.json +1 -0
  32. package/src/deleteMessage.js +24 -13
  33. package/src/deleteThread.js +25 -12
  34. package/src/editMessage.js +71 -53
  35. package/src/editMessageOld.js +67 -0
  36. package/src/follow.js +74 -0
  37. package/src/forwardAttachment.js +27 -15
  38. package/src/getAccess.js +112 -0
  39. package/src/getAvatarUser.js +78 -0
  40. package/src/getCurrentUserID.js +1 -1
  41. package/src/getEmojiUrl.js +10 -8
  42. package/src/getFriendsList.js +25 -15
  43. package/src/getMessage.js +813 -81
  44. package/src/getRegion.js +7 -0
  45. package/src/getThreadHistory.js +241 -98
  46. package/src/getThreadHistoryDeprecated.js +93 -0
  47. package/src/getThreadInfo.js +90 -287
  48. package/src/getThreadInfoDeprecated.js +80 -0
  49. package/src/getThreadList.js +214 -157
  50. package/src/getThreadListDeprecated.js +75 -0
  51. package/src/getThreadPictures.js +39 -19
  52. package/src/getUID.js +113 -50
  53. package/src/getUserID.js +18 -14
  54. package/src/getUserInfo.js +65 -71
  55. package/src/handleFriendRequest.js +24 -13
  56. package/src/handleMessageRequest.js +36 -20
  57. package/src/httpGet.js +34 -18
  58. package/src/httpPost.js +35 -18
  59. package/src/httpPostFormData.js +53 -24
  60. package/src/listenMqtt.js +680 -944
  61. package/src/listenNotification.js +85 -0
  62. package/src/logout.js +22 -15
  63. package/src/markAsDelivered.js +25 -15
  64. package/src/markAsRead.js +45 -27
  65. package/src/markAsReadAll.js +21 -14
  66. package/src/markAsSeen.js +28 -18
  67. package/src/muteThread.js +17 -12
  68. package/src/pinMessage.js +59 -0
  69. package/src/refreshFb_dtsg.js +89 -0
  70. package/src/removeUserFromGroup.js +47 -17
  71. package/src/resolvePhotoUrl.js +21 -13
  72. package/src/searchForThread.js +23 -13
  73. package/src/searchStickers.js +53 -0
  74. package/src/sendMessage.js +178 -117
  75. package/src/sendMessageMqtt.js +322 -0
  76. package/src/sendTypingIndicator.js +46 -16
  77. package/src/sendTypingIndicatorV2.js +28 -0
  78. package/src/setMessageReaction.js +33 -20
  79. package/src/setMessageReactionMqtt.js +62 -0
  80. package/src/setPostReaction.js +105 -95
  81. package/src/setProfileGuard.js +45 -0
  82. package/src/setStoryReaction.js +64 -0
  83. package/src/setTitle.js +34 -18
  84. package/src/shareContact.js +92 -37
  85. package/src/shareLink.js +5 -4
  86. package/src/stopListenMqtt.js +26 -0
  87. package/src/threadColors.js +110 -18
  88. package/src/unfriend.js +18 -9
  89. package/src/unsendMessage.js +31 -34
  90. package/src/uploadAttachment.js +94 -0
  91. package/test/data/shareAttach.js +1 -1
  92. package/test/test.js +1 -1
  93. package/utils.js +1393 -2918
  94. package/.cache/replit/env/latest +0 -56
  95. package/.cache/replit/env/latest.json +0 -1
  96. package/.cache/replit/modules/nodejs-14.res +0 -1
  97. package/.cache/replit/modules/replit.res +0 -1
  98. package/.cache/replit/modules/web.res +0 -1
  99. package/.cache/replit/modules.stamp +0 -0
  100. package/.cache/typescript/5.5/package.json +0 -1
  101. package/.config/configstore/update-notifier-npm.json +0 -4
  102. package/.gitattributes +0 -2
  103. package/Extra/Balancer.js +0 -49
  104. package/Extra/Bypass/956/index.js +0 -234
  105. package/Extra/Bypass/test/aaaa.json +0 -170
  106. package/Extra/Bypass/test/index.js +0 -188
  107. package/Extra/Database/index.js +0 -469
  108. package/Extra/ExtraAddons.js +0 -82
  109. package/Extra/ExtraFindUID.js +0 -62
  110. package/Extra/ExtraGetThread.js +0 -365
  111. package/Extra/ExtraScreenShot.js +0 -430
  112. package/Extra/ExtraUptimeRobot.js +0 -38
  113. package/Extra/Html/Classic/script.js +0 -119
  114. package/Extra/Html/Classic/style.css +0 -8
  115. package/Extra/Security/AES_256_GCM/index.js +0 -0
  116. package/Extra/Security/Base/Step_1.js +0 -6
  117. package/Extra/Security/Base/Step_2.js +0 -22
  118. package/Extra/Security/Base/Step_3.js +0 -22
  119. package/Extra/Security/Base/index.js +0 -191
  120. package/Extra/Security/Index.js +0 -5
  121. package/Extra/Security/Step_1.js +0 -6
  122. package/Extra/Security/Step_2.js +0 -22
  123. package/Extra/Security/Step_3.js +0 -22
  124. package/Extra/Src/Change_Environment.js +0 -24
  125. package/Extra/Src/Check_Update.js +0 -67
  126. package/Extra/Src/History.js +0 -115
  127. package/Extra/Src/Instant_Update.js +0 -65
  128. package/Extra/Src/Last-Run.js +0 -65
  129. package/Extra/Src/Premium.js +0 -81
  130. package/Extra/Src/Release_Memory.js +0 -160
  131. package/Extra/Src/Websocket.js +0 -213
  132. package/Extra/Src/image/checkmate.jpg +0 -0
  133. package/Extra/Src/test.js +0 -28
  134. package/Extra/Src/uuid.js +0 -137
  135. package/Func/AcceptAgreement.js +0 -31
  136. package/Func/ClearCache.js +0 -64
  137. package/Func/ReportV1.js +0 -54
  138. package/LICENSE +0 -678
  139. package/Language/index.json +0 -228
  140. package/Main.js +0 -1444
  141. package/SECURITY.md +0 -18
  142. package/broadcast.js +0 -44
  143. package/logger.js +0 -66
  144. package/src/Dev_Horizon_Data.js +0 -125
  145. package/src/Dev_getThreadInfoOLD.js +0 -422
  146. package/src/Dev_shareTest2.js +0 -68
  147. package/src/Dev_shareTest3.js +0 -71
  148. package/src/Premium.js +0 -25
  149. package/src/Screenshot.js +0 -83
  150. package/src/getAccessToken.js +0 -28
  151. package/src/getThreadInfoOLD.js +0 -422
  152. package/src/getThreadMain.js +0 -220
  153. package/src/getUserInfoMain.js +0 -65
  154. package/src/getUserInfoV2.js +0 -32
  155. package/src/getUserInfoV3.js +0 -63
  156. package/src/getUserInfoV4.js +0 -55
  157. package/src/getUserInfoV5.js +0 -61
  158. package/src/listenMqttV1.js +0 -846
  159. package/src/sendMqttMessage.js +0 -71
  160. package/src/unsendMqttMessage.js +0 -66
  161. package/test/Database_Test.js +0 -4
  162. package/test/Db2.js +0 -530
  163. package/test/Shankar_Database/A_README.md +0 -1
  164. package/test/Shankar_Database/Database.db +0 -0
  165. package/test/env/.env +0 -0
  166. package/test/example-db.db +0 -0
  167. package/test/memoryleak.js +0 -18
  168. package/test/testname.js +0 -1342
  169. package/test/testv2.js +0 -3
@@ -3,195 +3,248 @@
3
3
  const utils = require("../utils");
4
4
  const log = require("npmlog");
5
5
 
6
- function createProfileUrl(url, username, id) {
7
- if (url) return url;
8
- return "https://www.facebook.com/" + (username || utils.formatID(id.toString()));
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
+ // @TODO verify this
14
+ locationCoordinates: reminder.location_coordinates,
15
+ locationPage: reminder.location_page,
16
+ eventStatus: reminder.lightweight_event_status.toLowerCase(),
17
+ note: reminder.note,
18
+ repeatMode: 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: reminder.event_reminder_members.edges.map(function (member) {
25
+ return {
26
+ memberID: member.node.id,
27
+ state: member.guest_list_state.toLowerCase(),
28
+ };
29
+ }),
30
+ };
9
31
  }
10
32
 
11
- function formatParticipants(participants) {
12
- return participants.edges.map((p) => {
13
- p = p.node.messaging_actor;
14
- switch (p["__typename"]) {
15
- case "User":
16
- return {
17
- accountType: p["__typename"],
18
- userID: utils.formatID(p.id.toString()), // do we need .toString()? when it is not a string?
19
- name: p.name,
20
- shortName: p.short_name,
21
- gender: p.gender,
22
- url: p.url, // how about making it profileURL
23
- profilePicture: p.big_image_src.uri,
24
- username: (p.username || null),
25
- // TODO: maybe better names for these?
26
- isViewerFriend: p.is_viewer_friend, // true/false
27
- isMessengerUser: p.is_messenger_user, // true/false
28
- isVerified: p.is_verified, // true/false
29
- isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
30
- isViewerCoworker: p.is_viewer_coworker, // true/false
31
- isEmployee: p.is_employee // null? when it is something other? can someone check?
32
- };
33
- case "Page":
34
- return {
35
- accountType: p["__typename"],
36
- userID: utils.formatID(p.id.toString()), // or maybe... pageID?
37
- name: p.name,
38
- url: p.url,
39
- profilePicture: p.big_image_src.uri,
40
- username: (p.username || null),
41
- // uhm... better names maybe?
42
- acceptsMessengerUserFeedback: p.accepts_messenger_user_feedback, // true/false
43
- isMessengerUser: p.is_messenger_user, // true/false
44
- isVerified: p.is_verified, // true/false
45
- isMessengerPlatformBot: p.is_messenger_platform_bot, // true/false
46
- isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
47
- };
48
- case "ReducedMessagingActor":
49
- case "UnavailableMessagingActor":
50
- return {
51
- accountType: p["__typename"],
52
- userID: utils.formatID(p.id.toString()),
53
- name: p.name,
54
- url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
55
- profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
56
- username: (p.username || null), // maybe we could use it to generate profile URL?
57
- isMessageBlockedByViewer: p.is_message_blocked_by_viewer, // true/false
58
- };
59
- default:
60
- log.warn("getThreadList", "Found participant with unsupported typename. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues\n" + JSON.stringify(p, null, 2));
61
- return {
62
- accountType: p["__typename"],
63
- userID: utils.formatID(p.id.toString()),
64
- name: p.name || `[unknown ${p["__typename"]}]`, // probably it will always be something... but fallback to [unknown], just in case
65
- };
66
- }
67
- });
68
- }
33
+ function formatThreadGraphQLResponse(messageThread) {
34
+ const threadID = messageThread.thread_key.thread_fbid
35
+ ? messageThread.thread_key.thread_fbid
36
+ : messageThread.thread_key.other_user_id;
69
37
 
70
- // "FF8C0077" -> "8C0077"
71
- function formatColor(color) {
72
- if (color && color.match(/^(?:[0-9a-fA-F]{8})$/g)) return color.slice(2);
73
- return color;
74
- }
38
+ // Remove me
39
+ const lastM = messageThread.last_message;
40
+ const snippetID =
41
+ lastM &&
42
+ lastM.nodes &&
43
+ lastM.nodes[0] &&
44
+ lastM.nodes[0].message_sender &&
45
+ lastM.nodes[0].message_sender.messaging_actor
46
+ ? lastM.nodes[0].message_sender.messaging_actor.id
47
+ : null;
48
+ const snippetText =
49
+ lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
50
+ const lastR = messageThread.last_read_receipt;
51
+ const lastReadTimestamp =
52
+ lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
53
+ ? lastR.nodes[0].timestamp_precise
54
+ : null;
75
55
 
76
- function getThreadName(t) {
77
- if (t.name || t.thread_key.thread_fbid) return t.name;
56
+ return {
57
+ threadID: threadID,
58
+ threadName: messageThread.name,
59
+ participantIDs: messageThread.all_participants.edges.map(
60
+ (d) => d.node.messaging_actor.id,
61
+ ),
62
+ userInfo: messageThread.all_participants.edges.map((d) => ({
63
+ id: d.node.messaging_actor.id,
64
+ name: d.node.messaging_actor.name,
65
+ firstName: d.node.messaging_actor.short_name,
66
+ vanity: d.node.messaging_actor.username,
67
+ url: d.node.messaging_actor.url,
68
+ thumbSrc: d.node.messaging_actor.big_image_src.uri,
69
+ profileUrl: d.node.messaging_actor.big_image_src.uri,
70
+ gender: d.node.messaging_actor.gender,
71
+ type: d.node.messaging_actor.__typename,
72
+ isFriend: d.node.messaging_actor.is_viewer_friend,
73
+ isBirthday: !!d.node.messaging_actor.is_birthday, //not sure?
74
+ })),
75
+ unreadCount: messageThread.unread_count,
76
+ messageCount: messageThread.messages_count,
77
+ timestamp: messageThread.updated_time_precise,
78
+ muteUntil: messageThread.mute_until,
79
+ isGroup: messageThread.thread_type == "GROUP",
80
+ isSubscribed: messageThread.is_viewer_subscribed,
81
+ isArchived: messageThread.has_viewer_archived,
82
+ folder: messageThread.folder,
83
+ cannotReplyReason: messageThread.cannot_reply_reason,
84
+ eventReminders: messageThread.event_reminders
85
+ ? messageThread.event_reminders.nodes.map(formatEventReminders)
86
+ : null,
87
+ emoji: messageThread.customization_info
88
+ ? messageThread.customization_info.emoji
89
+ : null,
90
+ color:
91
+ messageThread.customization_info &&
92
+ messageThread.customization_info.outgoing_bubble_color
93
+ ? messageThread.customization_info.outgoing_bubble_color.slice(2)
94
+ : null,
95
+ threadTheme: messageThread.thread_theme,
96
+ nicknames:
97
+ messageThread.customization_info &&
98
+ messageThread.customization_info.participant_customizations
99
+ ? messageThread.customization_info.participant_customizations.reduce(
100
+ function (res, val) {
101
+ if (val.nickname) res[val.participant_id] = val.nickname;
102
+ return res;
103
+ },
104
+ {},
105
+ )
106
+ : {},
107
+ adminIDs: messageThread.thread_admins,
108
+ approvalMode: Boolean(messageThread.approval_mode),
109
+ approvalQueue: messageThread.group_approval_queue.nodes.map((a) => ({
110
+ inviterID: a.inviter.id,
111
+ requesterID: a.requester.id,
112
+ timestamp: a.request_timestamp,
113
+ request_source: a.request_source, // @Undocumented
114
+ })),
78
115
 
79
- for (let po of t.all_participants.edges) {
80
- let p = po.node;
81
- if (p.messaging_actor.id === t.thread_key.other_user_id) return p.messaging_actor.name;
82
- }
83
- }
116
+ // @Undocumented
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,
84
121
 
85
- function mapNicknames(customizationInfo) {
86
- return (customizationInfo && customizationInfo.participant_customizations) ? customizationInfo.participant_customizations.map(u => {
87
- return {
88
- "userID": u.participant_id,
89
- "nickname": u.nickname
90
- };
91
- }) : [];
122
+ // @Legacy
123
+ name: messageThread.name,
124
+ snippet: snippetText,
125
+ snippetSender: snippetID,
126
+ snippetAttachments: [],
127
+ serverTimestamp: messageThread.updated_time_precise,
128
+ imageSrc: messageThread.image ? messageThread.image.uri : null,
129
+ isCanonicalUser: messageThread.is_canonical_neo_user,
130
+ isCanonical: messageThread.thread_type != "GROUP",
131
+ recipientsLoadable: true,
132
+ hasEmailParticipant: false,
133
+ readOnly: false,
134
+ canReply: messageThread.cannot_reply_reason == null,
135
+ lastMessageTimestamp: messageThread.last_message
136
+ ? messageThread.last_message.timestamp_precise
137
+ : null,
138
+ lastMessageType: "message",
139
+ lastReadTimestamp: lastReadTimestamp,
140
+ threadType: messageThread.thread_type == "GROUP" ? 2 : 1,
141
+
142
+ // update in Wed, 13 Jul 2022 19:41:12 +0700
143
+ inviteLink: {
144
+ enable: messageThread.joinable_mode
145
+ ? messageThread.joinable_mode.mode == 1
146
+ : false,
147
+ link: messageThread.joinable_mode
148
+ ? messageThread.joinable_mode.link
149
+ : null,
150
+ },
151
+ };
92
152
  }
93
153
 
94
154
  function formatThreadList(data) {
95
- return data.map(t => {
96
- let lastMessageNode = (t.last_message && t.last_message.nodes && t.last_message.nodes.length > 0) ? t.last_message.nodes[0] : null;
97
- return {
98
- threadID: t.thread_key ? utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id) : null, // shall never be null
99
- name: getThreadName(t),
100
- unreadCount: t.unread_count,
101
- messageCount: t.messages_count,
102
- imageSrc: t.image ? t.image.uri : null,
103
- emoji: t.customization_info ? t.customization_info.emoji : null,
104
- color: formatColor(t.customization_info ? t.customization_info.outgoing_bubble_color : null),
105
- nicknames: mapNicknames(t.customization_info),
106
- muteUntil: t.mute_until,
107
- participants: formatParticipants(t.all_participants),
108
- adminIDs: t.thread_admins.map(a => a.id),
109
- folder: t.folder,
110
- isGroup: t.thread_type === "GROUP",
111
- // rtc_call_data: t.rtc_call_data, // TODO: format and document this
112
- // isPinProtected: t.is_pin_protected, // feature from future? always false (2018-04-04)
113
- customizationEnabled: t.customization_enabled, // false for ONE_TO_ONE with Page or ReducedMessagingActor
114
- participantAddMode: t.participant_add_mode_as_string, // "ADD" if "GROUP" and null if "ONE_TO_ONE"
115
- montageThread: t.montage_thread ? Buffer.from(t.montage_thread.id, "base64").toString() : null, // base64 encoded string "message_thread:0000000000000000"
116
- // it is not userID nor any other ID known to me...
117
- // can somebody inspect it? where is it used?
118
- // probably Messenger Day uses it
119
- reactionsMuteMode: t.reactions_mute_mode,
120
- mentionsMuteMode: t.mentions_mute_mode,
121
- isArchived: t.has_viewer_archived,
122
- isSubscribed: t.is_viewer_subscribed,
123
- timestamp: t.updated_time_precise, // in miliseconds
124
- // isCanonicalUser: t.is_canonical_neo_user, // is it always false?
125
- // TODO: how about putting snippet in another object? current implementation does not handle every possibile message type etc.
126
- snippet: lastMessageNode ? lastMessageNode.snippet : null,
127
- snippetAttachments: lastMessageNode ? lastMessageNode.extensible_attachment : null, // TODO: not sure if it works
128
- snippetSender: lastMessageNode ? utils.formatID((lastMessageNode.message_sender.messaging_actor.id || "").toString()) : null,
129
- lastMessageTimestamp: lastMessageNode ? lastMessageNode.timestamp_precise : null, // timestamp in miliseconds
130
- lastReadTimestamp: (t.last_read_receipt && t.last_read_receipt.nodes.length > 0)
131
- ? (t.last_read_receipt.nodes[0] ? t.last_read_receipt.nodes[0].timestamp_precise : null)
132
- : null, // timestamp in miliseconds
133
- cannotReplyReason: t.cannot_reply_reason, // TODO: inspect possible values
134
- approvalMode: Boolean(t.approval_mode),
135
-
136
- // @Legacy
137
- participantIDs: formatParticipants(t.all_participants).map(participant => participant.userID),
138
- threadType: t.thread_type === "GROUP" ? 2 : 1 // "GROUP" or "ONE_TO_ONE"
139
- };
140
- });
155
+ // console.log(JSON.stringify(data.find(t => t.thread_key.thread_fbid === "5095817367161431"), null, 2));
156
+ return data.map((t) => formatThreadGraphQLResponse(t));
141
157
  }
142
158
 
143
159
  module.exports = function (defaultFuncs, api, ctx) {
144
160
  return function getThreadList(limit, timestamp, tags, callback) {
145
- if (!callback && (utils.getType(tags) === "Function" || utils.getType(tags) === "AsyncFunction")) {
161
+ if (
162
+ !callback &&
163
+ (utils.getType(tags) === "Function" ||
164
+ utils.getType(tags) === "AsyncFunction")
165
+ ) {
146
166
  callback = tags;
147
167
  tags = [""];
148
168
  }
149
- if (utils.getType(limit) !== "Number" || !Number.isInteger(limit) || limit <= 0) throw { error: "getThreadList: limit must be a positive integer" };
150
-
151
- if (utils.getType(timestamp) !== "Null" && (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))) throw { error: "getThreadList: timestamp must be an integer or null" };
152
-
153
- if (utils.getType(tags) === "String") tags = [tags];
154
- if (utils.getType(tags) !== "Array") throw { error: "getThreadList: tags must be an array" };
169
+ if (
170
+ utils.getType(limit) !== "Number" ||
171
+ !Number.isInteger(limit) ||
172
+ limit <= 0
173
+ ) {
174
+ throw new utils.CustomError({
175
+ error: "getThreadList: limit must be a positive integer",
176
+ });
177
+ }
178
+ if (
179
+ utils.getType(timestamp) !== "Null" &&
180
+ (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
181
+ ) {
182
+ throw new utils.CustomError({
183
+ error: "getThreadList: timestamp must be an integer or null",
184
+ });
185
+ }
186
+ if (utils.getType(tags) === "String") {
187
+ tags = [tags];
188
+ }
189
+ if (utils.getType(tags) !== "Array") {
190
+ throw new utils.CustomError({
191
+ error: "getThreadList: tags must be an array",
192
+ message: "getThreadList: tags must be an array",
193
+ });
194
+ }
155
195
 
156
- var resolveFunc = function () { };
157
- var rejectFunc = function () { };
158
- var returnPromise = new Promise(function (resolve, reject) {
196
+ let resolveFunc = function () {};
197
+ let rejectFunc = function () {};
198
+ const returnPromise = new Promise(function (resolve, reject) {
159
199
  resolveFunc = resolve;
160
200
  rejectFunc = reject;
161
201
  });
162
202
 
163
- if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
203
+ if (
204
+ utils.getType(callback) !== "Function" &&
205
+ utils.getType(callback) !== "AsyncFunction"
206
+ ) {
164
207
  callback = function (err, data) {
165
- if (err) return rejectFunc(err);
208
+ if (err) {
209
+ return rejectFunc(err);
210
+ }
166
211
  resolveFunc(data);
167
212
  };
168
213
  }
169
214
 
170
215
  const form = {
171
- "av": ctx.globalOptions.pageID,
172
- "queries": JSON.stringify({
173
- "o0": {
216
+ av: ctx.i_userID || ctx.userID,
217
+ queries: JSON.stringify({
218
+ o0: {
174
219
  // This doc_id was valid on 2020-07-20
175
- "doc_id": "3336396659757871",
176
- "query_params": {
177
- "limit": limit + (timestamp ? 1 : 0),
178
- "before": timestamp,
179
- "tags": tags,
180
- "includeDeliveryReceipts": true,
181
- "includeSeqID": false
182
- }
183
- }
220
+ // "doc_id": "3336396659757871",
221
+ doc_id: "3426149104143726",
222
+ query_params: {
223
+ limit: limit + (timestamp ? 1 : 0),
224
+ before: timestamp,
225
+ tags: tags,
226
+ includeDeliveryReceipts: true,
227
+ includeSeqID: false,
228
+ },
229
+ },
184
230
  }),
185
- "batch_name": "MessengerGraphQLThreadlistFetcher"
231
+ batch_name: "MessengerGraphQLThreadlistFetcher",
186
232
  };
187
233
 
188
234
  defaultFuncs
189
235
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
190
236
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
191
237
  .then((resData) => {
192
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
238
+ if (resData[resData.length - 1].error_results > 0) {
239
+ throw new utils.CustomError(resData[0].o0.errors);
240
+ }
193
241
 
194
- if (resData[resData.length - 1].successful_results === 0) throw { error: "getThreadList: there was no successful_results", res: resData };
242
+ if (resData[resData.length - 1].successful_results === 0) {
243
+ throw new utils.CustomError({
244
+ error: "getThreadList: there was no successful_results",
245
+ res: resData,
246
+ });
247
+ }
195
248
 
196
249
  // When we ask for threads using timestamp from the previous request,
197
250
  // we are getting the last thread repeated as the first thread in this response.
@@ -199,12 +252,16 @@ module.exports = function (defaultFuncs, api, ctx) {
199
252
  // It is also the reason for increasing limit by 1 when timestamp is set
200
253
  // this way user asks for 10 threads, we are asking for 11,
201
254
  // but after removing the duplicated one, it is again 10
202
- if (timestamp) resData[0].o0.data.viewer.message_threads.nodes.shift();
203
-
204
- callback(null, formatThreadList(resData[0].o0.data.viewer.message_threads.nodes));
255
+ if (timestamp) {
256
+ resData[0].o0.data.viewer.message_threads.nodes.shift();
257
+ }
258
+ callback(
259
+ null,
260
+ formatThreadList(resData[0].o0.data.viewer.message_threads.nodes),
261
+ );
205
262
  })
206
263
  .catch((err) => {
207
- log.error("getThreadList", "Lỗi: getThreadList Có Thể Do Bạn Spam Quá Nhiều, Hãy Thử Lại !");
264
+ log.error("getThreadList", err);
208
265
  return callback(err);
209
266
  });
210
267
 
@@ -0,0 +1,75 @@
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 getThreadList(start, end, type, callback) {
8
+ if (utils.getType(callback) === "Undefined") {
9
+ if (utils.getType(end) !== "Number") {
10
+ throw {
11
+ error: "Please pass a number as a second argument."
12
+ };
13
+ } else if (
14
+ utils.getType(type) === "Function" ||
15
+ utils.getType(type) === "AsyncFunction"
16
+ ) {
17
+ callback = type;
18
+ type = "inbox"; //default to inbox
19
+ } else if (utils.getType(type) !== "String") {
20
+ throw {
21
+ error:
22
+ "Please pass a String as a third argument. Your options are: inbox, pending, and archived"
23
+ };
24
+ } else {
25
+ throw {
26
+ error: "getThreadList: need callback"
27
+ };
28
+ }
29
+ }
30
+
31
+ if (type === "archived") {
32
+ type = "action:archived";
33
+ } else if (type !== "inbox" && type !== "pending" && type !== "other") {
34
+ throw {
35
+ error:
36
+ "type can only be one of the following: inbox, pending, archived, other"
37
+ };
38
+ }
39
+
40
+ if (end <= start) end = start + 20;
41
+
42
+ var form = {
43
+ client: "mercury"
44
+ };
45
+
46
+ form[type + "[offset]"] = start;
47
+ form[type + "[limit]"] = end - start;
48
+
49
+ if (ctx.globalOptions.pageID) {
50
+ form.request_user_id = ctx.globalOptions.pageID;
51
+ }
52
+
53
+ defaultFuncs
54
+ .post(
55
+ "https://www.facebook.com/ajax/mercury/threadlist_info.php",
56
+ ctx.jar,
57
+ form
58
+ )
59
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
60
+ .then(function(resData) {
61
+ if (resData.error) {
62
+ throw resData;
63
+ }
64
+ log.verbose("getThreadList", JSON.stringify(resData.payload.threads));
65
+ return callback(
66
+ null,
67
+ (resData.payload.threads || []).map(utils.formatThread)
68
+ );
69
+ })
70
+ .catch(function(err) {
71
+ log.error("getThreadList", err);
72
+ return callback(err);
73
+ });
74
+ };
75
+ };
@@ -1,55 +1,75 @@
1
1
  "use strict";
2
2
 
3
- var utils = require("../utils");
4
- var log = require("npmlog");
3
+ const utils = require("../utils");
4
+ const log = require("npmlog");
5
5
 
6
6
  module.exports = function (defaultFuncs, api, ctx) {
7
7
  return function getThreadPictures(threadID, offset, limit, callback) {
8
- var resolveFunc = function () { };
9
- var rejectFunc = function () { };
10
- var returnPromise = new Promise(function (resolve, reject) {
8
+ let resolveFunc = function () {};
9
+ let rejectFunc = function () {};
10
+ const returnPromise = new Promise(function (resolve, reject) {
11
11
  resolveFunc = resolve;
12
12
  rejectFunc = reject;
13
13
  });
14
14
 
15
15
  if (!callback) {
16
- callback = function (err, data) {
17
- if (err) return rejectFunc(err);
18
- resolveFunc(data);
16
+ callback = function (err, friendList) {
17
+ if (err) {
18
+ return rejectFunc(err);
19
+ }
20
+ resolveFunc(friendList);
19
21
  };
20
22
  }
21
23
 
22
- var form = {
24
+ let form = {
23
25
  thread_id: threadID,
24
26
  offset: offset,
25
- limit: limit
27
+ limit: limit,
26
28
  };
27
29
 
28
30
  defaultFuncs
29
- .post("https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", ctx.jar, form)
31
+ .post(
32
+ "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
33
+ ctx.jar,
34
+ form,
35
+ )
30
36
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
31
37
  .then(function (resData) {
32
- if (resData.error) throw resData;
38
+ if (resData.error) {
39
+ throw resData;
40
+ }
33
41
  return Promise.all(
34
42
  resData.payload.imagesData.map(function (image) {
35
43
  form = {
36
44
  thread_id: threadID,
37
- image_id: image.fbid
45
+ image_id: image.fbid,
38
46
  };
39
47
  return defaultFuncs
40
- .post("https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php", ctx.jar, form)
48
+ .post(
49
+ "https://www.facebook.com/ajax/messaging/attachments/sharedphotos.php",
50
+ ctx.jar,
51
+ form,
52
+ )
41
53
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
42
54
  .then(function (resData) {
43
- if (resData.error) throw resData;
55
+ if (resData.error) {
56
+ throw resData;
57
+ }
44
58
  // the response is pretty messy
45
- var queryThreadID = resData.jsmods.require[0][3][1].query_metadata.query_path[0].message_thread;
46
- var imageData = resData.jsmods.require[0][3][1].query_results[queryThreadID].message_images.edges[0].node.image2;
59
+ const queryThreadID =
60
+ resData.jsmods.require[0][3][1].query_metadata.query_path[0]
61
+ .message_thread;
62
+ const imageData =
63
+ resData.jsmods.require[0][3][1].query_results[queryThreadID]
64
+ .message_images.edges[0].node.image2;
47
65
  return imageData;
48
66
  });
49
- })
67
+ }),
50
68
  );
51
69
  })
52
- .then(resData => callback(null, resData))
70
+ .then(function (resData) {
71
+ callback(null, resData);
72
+ })
53
73
  .catch(function (err) {
54
74
  log.error("Error in getThreadPictures", err);
55
75
  callback(err);