fca-neokex-fix 1.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 (114) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/LICENSE +26 -0
  3. package/README.md +346 -0
  4. package/THEME_FEATURES.md +137 -0
  5. package/examples/README.md +131 -0
  6. package/examples/apply-ai-theme.js +127 -0
  7. package/examples/check-current-theme.js +74 -0
  8. package/examples/simple-bot.js +114 -0
  9. package/examples/test-bot.js +752 -0
  10. package/examples/test-logging.js +85 -0
  11. package/examples/theme-usage-example.js +53 -0
  12. package/index.js +2 -0
  13. package/package.json +105 -0
  14. package/src/apis/addExternalModule.js +24 -0
  15. package/src/apis/addUserToGroup.js +108 -0
  16. package/src/apis/changeAdminStatus.js +148 -0
  17. package/src/apis/changeArchivedStatus.js +61 -0
  18. package/src/apis/changeAvatar.js +103 -0
  19. package/src/apis/changeBio.js +69 -0
  20. package/src/apis/changeBlockedStatus.js +54 -0
  21. package/src/apis/changeGroupImage.js +136 -0
  22. package/src/apis/changeThreadColor.js +116 -0
  23. package/src/apis/comment.js +207 -0
  24. package/src/apis/createAITheme.js +129 -0
  25. package/src/apis/createNewGroup.js +79 -0
  26. package/src/apis/createPoll.js +73 -0
  27. package/src/apis/deleteMessage.js +44 -0
  28. package/src/apis/deleteThread.js +52 -0
  29. package/src/apis/editMessage.js +70 -0
  30. package/src/apis/emoji.js +124 -0
  31. package/src/apis/fetchThemeData.js +65 -0
  32. package/src/apis/follow.js +81 -0
  33. package/src/apis/forwardMessage.js +52 -0
  34. package/src/apis/friend.js +243 -0
  35. package/src/apis/gcmember.js +122 -0
  36. package/src/apis/gcname.js +123 -0
  37. package/src/apis/gcrule.js +119 -0
  38. package/src/apis/getAccess.js +111 -0
  39. package/src/apis/getBotInfo.js +88 -0
  40. package/src/apis/getBotInitialData.js +43 -0
  41. package/src/apis/getFriendsList.js +79 -0
  42. package/src/apis/getMessage.js +423 -0
  43. package/src/apis/getTheme.js +104 -0
  44. package/src/apis/getThemeInfo.js +96 -0
  45. package/src/apis/getThreadHistory.js +239 -0
  46. package/src/apis/getThreadInfo.js +257 -0
  47. package/src/apis/getThreadList.js +222 -0
  48. package/src/apis/getThreadPictures.js +58 -0
  49. package/src/apis/getUserID.js +83 -0
  50. package/src/apis/getUserInfo.js +495 -0
  51. package/src/apis/getUserInfoV2.js +146 -0
  52. package/src/apis/handleMessageRequest.js +50 -0
  53. package/src/apis/httpGet.js +63 -0
  54. package/src/apis/httpPost.js +89 -0
  55. package/src/apis/httpPostFormData.js +69 -0
  56. package/src/apis/listenMqtt.js +796 -0
  57. package/src/apis/listenSpeed.js +170 -0
  58. package/src/apis/logout.js +63 -0
  59. package/src/apis/markAsDelivered.js +47 -0
  60. package/src/apis/markAsRead.js +95 -0
  61. package/src/apis/markAsReadAll.js +41 -0
  62. package/src/apis/markAsSeen.js +70 -0
  63. package/src/apis/mqttDeltaValue.js +330 -0
  64. package/src/apis/muteThread.js +45 -0
  65. package/src/apis/nickname.js +132 -0
  66. package/src/apis/notes.js +163 -0
  67. package/src/apis/pinMessage.js +141 -0
  68. package/src/apis/produceMetaTheme.js +180 -0
  69. package/src/apis/realtime.js +161 -0
  70. package/src/apis/removeUserFromGroup.js +117 -0
  71. package/src/apis/resolvePhotoUrl.js +58 -0
  72. package/src/apis/searchForThread.js +154 -0
  73. package/src/apis/sendMessage.js +281 -0
  74. package/src/apis/sendMessageMqtt.js +188 -0
  75. package/src/apis/sendTypingIndicator.js +41 -0
  76. package/src/apis/setMessageReaction.js +27 -0
  77. package/src/apis/setMessageReactionMqtt.js +61 -0
  78. package/src/apis/setThreadTheme.js +260 -0
  79. package/src/apis/setThreadThemeMqtt.js +94 -0
  80. package/src/apis/share.js +107 -0
  81. package/src/apis/shareContact.js +66 -0
  82. package/src/apis/stickers.js +257 -0
  83. package/src/apis/story.js +181 -0
  84. package/src/apis/theme.js +233 -0
  85. package/src/apis/unfriend.js +47 -0
  86. package/src/apis/unsendMessage.js +17 -0
  87. package/src/database/appStateBackup.js +189 -0
  88. package/src/database/models/index.js +56 -0
  89. package/src/database/models/thread.js +31 -0
  90. package/src/database/models/user.js +32 -0
  91. package/src/database/threadData.js +101 -0
  92. package/src/database/userData.js +90 -0
  93. package/src/engine/client.js +91 -0
  94. package/src/engine/models/buildAPI.js +109 -0
  95. package/src/engine/models/loginHelper.js +326 -0
  96. package/src/engine/models/setOptions.js +53 -0
  97. package/src/utils/auth-helpers.js +149 -0
  98. package/src/utils/autoReLogin.js +169 -0
  99. package/src/utils/axios.js +290 -0
  100. package/src/utils/clients.js +270 -0
  101. package/src/utils/constants.js +396 -0
  102. package/src/utils/formatters/data/formatAttachment.js +370 -0
  103. package/src/utils/formatters/data/formatDelta.js +153 -0
  104. package/src/utils/formatters/index.js +159 -0
  105. package/src/utils/formatters/value/formatCookie.js +91 -0
  106. package/src/utils/formatters/value/formatDate.js +36 -0
  107. package/src/utils/formatters/value/formatID.js +16 -0
  108. package/src/utils/formatters.js +1067 -0
  109. package/src/utils/headers.js +199 -0
  110. package/src/utils/index.js +151 -0
  111. package/src/utils/monitoring.js +358 -0
  112. package/src/utils/rateLimiter.js +380 -0
  113. package/src/utils/tokenRefresh.js +311 -0
  114. package/src/utils/user-agents.js +238 -0
@@ -0,0 +1,370 @@
1
+ "use strict";
2
+
3
+ const url = require("url");
4
+ const querystring = require("querystring");
5
+ const { getType } = require("../../constants");
6
+
7
+ function getExtension(original_extension, fullFileName = "") {
8
+ if (original_extension) {
9
+ return original_extension;
10
+ } else {
11
+ const extension = fullFileName.split(".").pop();
12
+ return (extension === fullFileName) ? "" : extension;
13
+ }
14
+ }
15
+
16
+ function _formatAttachment(attachment1, attachment2) {
17
+ const blob_attachment = attachment1.mercury || attachment1.blob_attachment || attachment1.sticker_attachment;
18
+ let type_attachment = blob_attachment && blob_attachment.__typename ? blob_attachment.__typename : attachment1.attach_type;
19
+
20
+ if (type_attachment == null && attachment1.id != null && attachment1.extensible_attachment == null) {
21
+ return {
22
+ type: "share",
23
+ ID: attachment1.id,
24
+ url: attachment1.href,
25
+ title: "Shared Content",
26
+ description: "Unsupported shared content.",
27
+ source: null,
28
+ isUnrecognized: true
29
+ };
30
+ }
31
+
32
+ if (!attachment1.attach_type && attachment1.imageMetadata) {
33
+ return {
34
+ type: 'photo',
35
+ ID: attachment1.fbid,
36
+ filename: attachment1.filename,
37
+ fileSize: Number(attachment1.fileSize || 0),
38
+ mimeType: attachment1.mimeType,
39
+ width: attachment1.imageMetadata.width,
40
+ height: attachment1.imageMetadata.height,
41
+ url: null,
42
+ thumbnailUrl: null,
43
+ previewUrl: null,
44
+ largePreviewUrl: null,
45
+ name: attachment1.filename
46
+ };
47
+ }
48
+
49
+ attachment2 = attachment2 || { id: "", image_data: {} };
50
+ attachment1 = attachment1.mercury || attachment1;
51
+ let blob = attachment1.blob_attachment || attachment1.sticker_attachment;
52
+ let type = blob && blob.__typename ? blob.__typename : attachment1.attach_type;
53
+
54
+ if (!type && attachment1.sticker_attachment) {
55
+ type = "StickerAttachment";
56
+ blob = attachment1.sticker_attachment;
57
+ } else if (!type && attachment1.extensible_attachment) {
58
+ if (attachment1.extensible_attachment.story_attachment?.target?.__typename === "MessageLocation") {
59
+ type = "MessageLocation";
60
+ } else {
61
+ type = "ExtensibleAttachment";
62
+ }
63
+ blob = attachment1.extensible_attachment;
64
+ }
65
+
66
+ switch (type) {
67
+ case "sticker":
68
+ return {
69
+ type: "sticker",
70
+ ID: attachment1.metadata?.stickerID?.toString() || "",
71
+ url: attachment1.url || null,
72
+ packID: attachment1.metadata?.packID?.toString() || "",
73
+ spriteUrl: attachment1.metadata?.spriteURI || null,
74
+ spriteUrl2x: attachment1.metadata?.spriteURI2x || null,
75
+ width: attachment1.metadata?.width || 0,
76
+ height: attachment1.metadata?.height || 0,
77
+ caption: attachment2?.caption || null,
78
+ description: attachment2?.description || null,
79
+ frameCount: attachment1.metadata?.frameCount || 0,
80
+ frameRate: attachment1.metadata?.frameRate || 0,
81
+ framesPerRow: attachment1.metadata?.framesPerRow || 0,
82
+ framesPerCol: attachment1.metadata?.framesPerCol || 0,
83
+ stickerID: attachment1.metadata?.stickerID?.toString() || "",
84
+ spriteURI: attachment1.metadata?.spriteURI || null,
85
+ spriteURI2x: attachment1.metadata?.spriteURI2x || null
86
+ };
87
+ case "file":
88
+ return {
89
+ type: "file",
90
+ filename: attachment1.name || "",
91
+ ID: attachment2?.id?.toString() || "",
92
+ url: attachment1.url || null,
93
+ isMalicious: attachment2?.is_malicious || false,
94
+ contentType: attachment2?.mime_type || "",
95
+ name: attachment1.name || "",
96
+ mimeType: attachment2?.mime_type || "",
97
+ fileSize: attachment2?.file_size || 0
98
+ };
99
+ case "photo":
100
+ const dimensions = attachment1.metadata?.dimensions?.split(",") || ["0", "0"];
101
+ return {
102
+ type: "photo",
103
+ ID: attachment1.metadata?.fbid?.toString() || "",
104
+ filename: attachment1.fileName || "",
105
+ thumbnailUrl: attachment1.thumbnail_url || null,
106
+ previewUrl: attachment1.preview_url || null,
107
+ previewWidth: attachment1.preview_width || 0,
108
+ previewHeight: attachment1.preview_height || 0,
109
+ largePreviewUrl: attachment1.large_preview_url || null,
110
+ largePreviewWidth: attachment1.large_preview_width || 0,
111
+ largePreviewHeight: attachment1.large_preview_height || 0,
112
+ url: attachment1.metadata?.url || null,
113
+ width: dimensions[0] || "0",
114
+ height: dimensions[1] || "0",
115
+ name: attachment1.fileName || ""
116
+ };
117
+ case "animated_image":
118
+ return {
119
+ type: "animated_image",
120
+ ID: attachment2?.id?.toString() || "",
121
+ filename: attachment2?.filename || "",
122
+ previewUrl: attachment1?.preview_url || null,
123
+ previewWidth: attachment1?.preview_width || 0,
124
+ previewHeight: attachment1?.preview_height || 0,
125
+ url: attachment2?.image_data?.url || null,
126
+ width: attachment2?.image_data?.width || 0,
127
+ height: attachment2?.image_data?.height || 0,
128
+ name: attachment1?.name || "",
129
+ facebookUrl: attachment1?.url || null,
130
+ thumbnailUrl: attachment1?.thumbnail_url || null,
131
+ mimeType: attachment2?.mime_type || "",
132
+ rawGifImage: attachment2?.image_data?.raw_gif_image || null,
133
+ rawWebpImage: attachment2?.image_data?.raw_webp_image || null,
134
+ animatedGifUrl: attachment2?.image_data?.animated_gif_url || null,
135
+ animatedGifPreviewUrl: attachment2?.image_data?.animated_gif_preview_url || null,
136
+ animatedWebpUrl: attachment2?.image_data?.animated_webp_url || null,
137
+ animatedWebpPreviewUrl: attachment2?.image_data?.animated_webp_preview_url || null
138
+ };
139
+ case "share":
140
+ return {
141
+ type: "share",
142
+ ID: attachment1.share?.share_id?.toString() || "",
143
+ url: attachment2?.href || null,
144
+ title: attachment1.share?.title || null,
145
+ description: attachment1.share?.description || null,
146
+ source: attachment1.share?.source || null,
147
+ image: attachment1.share?.media?.image || null,
148
+ width: attachment1.share?.media?.image_size?.width || null,
149
+ height: attachment1.share?.media?.image_size?.height || null,
150
+ playable: attachment1.share?.media?.playable || false,
151
+ duration: attachment1.share?.media?.duration || 0,
152
+ subattachments: attachment1.share?.subattachments || [],
153
+ properties: {},
154
+ animatedImageSize: attachment1.share?.media?.animated_image_size || null,
155
+ facebookUrl: attachment1.share?.uri || null,
156
+ target: attachment1.share?.target || null,
157
+ styleList: attachment1.share?.style_list || null
158
+ };
159
+ case "video":
160
+ return {
161
+ type: "video",
162
+ ID: attachment1.metadata?.fbid?.toString() || "",
163
+ filename: attachment1.name || "",
164
+ previewUrl: attachment1.preview_url || null,
165
+ previewWidth: attachment1.preview_width || 0,
166
+ previewHeight: attachment1.preview_height || 0,
167
+ url: attachment1.url || null,
168
+ width: attachment1.metadata?.dimensions?.width || 0,
169
+ height: attachment1.metadata?.dimensions?.height || 0,
170
+ duration: attachment1.metadata?.duration || 0,
171
+ videoType: "unknown",
172
+ thumbnailUrl: attachment1.thumbnail_url || null
173
+ };
174
+ case "error":
175
+ return {
176
+ type: "error",
177
+ attachment1: attachment1,
178
+ attachment2: attachment2
179
+ };
180
+ case "MessageImage":
181
+ return {
182
+ type: "photo",
183
+ ID: blob.legacy_attachment_id,
184
+ filename: blob.filename,
185
+ thumbnailUrl: blob.thumbnail.uri,
186
+ previewUrl: blob.preview.uri,
187
+ previewWidth: blob.preview.width,
188
+ previewHeight: blob.preview.height,
189
+ largePreviewUrl: blob.large_preview.uri,
190
+ largePreviewWidth: blob.large_preview.width,
191
+ largePreviewHeight: blob.large_preview.height,
192
+ url: blob.large_preview.uri,
193
+ width: blob.original_dimensions.x,
194
+ height: blob.original_dimensions.y,
195
+ name: blob.filename
196
+ };
197
+ case "MessageAnimatedImage":
198
+ return {
199
+ type: "animated_image",
200
+ ID: blob.legacy_attachment_id,
201
+ filename: blob.filename,
202
+ previewUrl: blob.preview_image.uri,
203
+ previewWidth: blob.preview_image.width,
204
+ previewHeight: blob.preview_image.height,
205
+ url: blob.animated_image.uri,
206
+ width: blob.animated_image.width,
207
+ height: blob.animated_image.height,
208
+ thumbnailUrl: blob.preview_image.uri,
209
+ name: blob.filename,
210
+ facebookUrl: blob.animated_image.uri,
211
+ rawGifImage: blob.animated_image.uri,
212
+ animatedGifUrl: blob.animated_image.uri,
213
+ animatedGifPreviewUrl: blob.preview_image.uri,
214
+ animatedWebpUrl: blob.animated_image.uri,
215
+ animatedWebpPreviewUrl: blob.preview_image.uri
216
+ };
217
+ case "MessageVideo":
218
+ return {
219
+ type: "video",
220
+ filename: blob.filename,
221
+ ID: blob.legacy_attachment_id,
222
+ previewUrl: blob.large_image.uri,
223
+ previewWidth: blob.large_image.width,
224
+ previewHeight: blob.large_image.height,
225
+ url: blob.playable_url,
226
+ width: blob.original_dimensions.x,
227
+ height: blob.original_dimensions.y,
228
+ duration: blob.playable_duration_in_ms,
229
+ videoType: blob.video_type.toLowerCase(),
230
+ thumbnailUrl: blob.large_image.uri
231
+ };
232
+ case "MessageFile":
233
+ return {
234
+ type: "file",
235
+ filename: blob.filename,
236
+ ID: blob.message_file_fbid,
237
+ url: blob.url,
238
+ isMalicious: blob.is_malicious,
239
+ contentType: blob.content_type,
240
+ name: blob.filename,
241
+ mimeType: blob.content_type || "",
242
+ fileSize: -1
243
+ };
244
+ case "MessageAudio":
245
+ return {
246
+ type: "audio",
247
+ filename: blob.filename,
248
+ ID: blob.url_shimhash,
249
+ audioType: blob.audio_type,
250
+ duration: blob.playable_duration_in_ms,
251
+ url: blob.playable_url,
252
+ isVoiceMail: blob.is_voicemail
253
+ };
254
+ case "Sticker":
255
+ case "StickerAttachment":
256
+ return {
257
+ type: "sticker",
258
+ ID: blob.id,
259
+ url: blob.url,
260
+ packID: blob.pack ? blob.pack.id : null,
261
+ spriteUrl: blob.sprite_image,
262
+ spriteUrl2x: blob.sprite_image_2x,
263
+ width: blob.width,
264
+ height: blob.height,
265
+ caption: blob.label,
266
+ description: blob.label,
267
+ frameCount: blob.frame_count,
268
+ frameRate: blob.frame_rate,
269
+ framesPerRow: blob.frames_per_row,
270
+ framesPerCol: blob.frames_per_column,
271
+ stickerID: blob.id,
272
+ spriteURI: blob.sprite_image,
273
+ spriteURI2x: blob.sprite_image_2x
274
+ };
275
+ case "MessageLocation":
276
+ const urlAttach = blob.story_attachment.url;
277
+ const mediaAttach = blob.story_attachment.media;
278
+
279
+ let u, where1, address, latitude, longitude, imageUrl, width, height;
280
+
281
+ try {
282
+ u = querystring.parse(url.parse(urlAttach).query).u;
283
+ where1 = querystring.parse(url.parse(u).query).where1;
284
+ address = where1.split(", ");
285
+ latitude = Number.parseFloat(address[0]);
286
+ longitude = Number.parseFloat(address[1]);
287
+ } catch (err) {
288
+ latitude = undefined;
289
+ longitude = undefined;
290
+ }
291
+
292
+ if (mediaAttach && mediaAttach.image) {
293
+ imageUrl = mediaAttach.image.uri;
294
+ width = mediaAttach.image.width;
295
+ height = mediaAttach.image.height;
296
+ }
297
+
298
+ return {
299
+ type: "location",
300
+ ID: blob.legacy_attachment_id,
301
+ latitude: latitude,
302
+ longitude: longitude,
303
+ image: imageUrl,
304
+ width: width,
305
+ height: height,
306
+ url: u || urlAttach,
307
+ address: where1,
308
+ facebookUrl: blob.story_attachment.url,
309
+ target: blob.story_attachment.target,
310
+ styleList: blob.story_attachment.style_list
311
+ };
312
+ case "ExtensibleAttachment":
313
+ const story = blob.story_attachment;
314
+ return {
315
+ type: "share",
316
+ ID: blob.legacy_attachment_id,
317
+ url: story?.url || null,
318
+ title: story?.title_with_entities?.text || null,
319
+ description: story?.description?.text || null,
320
+ source: story?.source?.text || null,
321
+ image: story?.media?.image?.uri || null,
322
+ width: story?.media?.image?.width || null,
323
+ height: story?.media?.image?.height || null,
324
+ playable: story?.media?.is_playable || false,
325
+ duration: story?.media?.playable_duration_in_ms || 0,
326
+ playableUrl: story?.media?.playable_url || null,
327
+ subattachments: story?.subattachments || [],
328
+ properties: (story?.properties || []).reduce((obj, cur) => {
329
+ if (cur && cur.key && cur.value) {
330
+ obj[cur.key] = cur.value.text || cur.value;
331
+ }
332
+ return obj;
333
+ }, {}),
334
+ facebookUrl: story?.url || null,
335
+ target: story?.target || null,
336
+ styleList: story?.style_list || null
337
+ };
338
+ default:
339
+ try {
340
+ throw new Error(
341
+ "Unrecognized attachment type: " + type +
342
+ "\nattachment1: " + JSON.stringify(attachment1, null, 2) +
343
+ "\nattachment2: " + JSON.stringify(attachment2, null, 2)
344
+ );
345
+ } catch (err) {
346
+ return {
347
+ type: "unknown",
348
+ error: err.message,
349
+ rawAttachment1: attachment1,
350
+ rawAttachment2: attachment2
351
+ };
352
+ }
353
+ }
354
+ }
355
+
356
+ function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
357
+ attachmentMap = shareMap || attachmentMap;
358
+ return attachments ?
359
+ attachments.map((val, i) => {
360
+ if (!attachmentMap || !attachmentIds || !attachmentMap[attachmentIds[i]]) {
361
+ return _formatAttachment(val);
362
+ }
363
+ return _formatAttachment(val, attachmentMap[attachmentIds[i]]);
364
+ }) : [];
365
+ }
366
+
367
+ module.exports = {
368
+ _formatAttachment,
369
+ formatAttachment
370
+ };
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+
3
+ const formatID = require('../value/formatID');
4
+ const { _formatAttachment } = require('./formatAttachment');
5
+
6
+ function getAdminTextMessageType(type) {
7
+ switch (type) {
8
+ case 'unpin_messages_v2': return 'log:unpin-message';
9
+ case 'pin_messages_v2': return 'log:pin-message';
10
+ case "change_thread_theme": return "log:thread-color";
11
+ case "change_thread_icon":
12
+ case 'change_thread_quick_reaction': return "log:thread-icon";
13
+ case "change_thread_nickname": return "log:user-nickname";
14
+ case "change_thread_admins": return "log:thread-admins";
15
+ case "group_poll": return "log:thread-poll";
16
+ case "change_thread_approval_mode": return "log:thread-approval-mode";
17
+ case "messenger_call_log":
18
+ case "participant_joined_group_call": return "log:thread-call";
19
+ default: return type;
20
+ }
21
+ }
22
+
23
+ function formatDeltaMessage(m) {
24
+ const md = m.delta.messageMetadata;
25
+ const mentions = {};
26
+
27
+ // Try multiple sources for mentions data (Facebook changed format multiple times)
28
+ let mdata = [];
29
+
30
+ // Method 1: data.prng (old format)
31
+ if (m.delta.data?.prng) {
32
+ try {
33
+ mdata = JSON.parse(m.delta.data.prng);
34
+ } catch (e) {}
35
+ }
36
+
37
+ // Method 2: data.mentions (newer format)
38
+ if (mdata.length === 0 && m.delta.data?.mentions) {
39
+ try {
40
+ mdata = JSON.parse(m.delta.data.mentions);
41
+ } catch (e) {}
42
+ }
43
+
44
+ // Method 3: messageMetadata.ranges (latest format)
45
+ if (mdata.length === 0 && md.ranges) {
46
+ try {
47
+ mdata = md.ranges.map(r => ({
48
+ i: r.entity?.id || r.mentionID || r.id,
49
+ o: r.offset,
50
+ l: r.length
51
+ }));
52
+ } catch (e) {}
53
+ }
54
+
55
+ // Method 4: delta.mentions directly
56
+ if (mdata.length === 0 && m.delta.mentions) {
57
+ try {
58
+ if (Array.isArray(m.delta.mentions)) {
59
+ mdata = m.delta.mentions.map(mention => ({
60
+ i: mention.id || mention.i,
61
+ o: mention.offset || mention.o,
62
+ l: mention.length || mention.l
63
+ }));
64
+ }
65
+ } catch (e) {}
66
+ }
67
+
68
+ // Build mentions object
69
+ for (const mention of mdata) {
70
+ if (mention.i && m.delta.body) {
71
+ mentions[mention.i] = m.delta.body.substring(mention.o, mention.o + mention.l);
72
+ }
73
+ }
74
+
75
+ const messageReply = m.delta.messageReply ? {
76
+ messageID: m.delta.messageReply.messageID,
77
+ senderID: formatID(m.delta.messageReply.senderID),
78
+ body: m.delta.messageReply.body,
79
+ attachments: m.delta.messageReply.attachments,
80
+ timestamp: m.delta.messageReply.timestamp,
81
+ isReply: true
82
+ } : null;
83
+
84
+ return {
85
+ type: "message",
86
+ senderID: formatID(md.actorFbId.toString()),
87
+ body: m.delta.body || "",
88
+ threadID: formatID((md.threadKey.threadFbId || md.threadKey.otherUserFbId).toString()),
89
+ messageID: md.messageId,
90
+ offlineThreadingId: md.offlineThreadingId,
91
+ attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
92
+ mentions: mentions,
93
+ timestamp: md.timestamp,
94
+ isGroup: !!md.threadKey.threadFbId,
95
+ participantIDs: m.delta.participants,
96
+ messageReply: messageReply
97
+ };
98
+ }
99
+
100
+ function formatDeltaEvent(m) {
101
+ let logMessageType;
102
+ let logMessageData;
103
+
104
+ switch (m.class) {
105
+ case "AdminTextMessage":
106
+ logMessageData = m.untypedData;
107
+ logMessageType = getAdminTextMessageType(m.type);
108
+ break;
109
+ case "ThreadName":
110
+ logMessageType = "log:thread-name";
111
+ logMessageData = { name: m.name };
112
+ break;
113
+ case "ParticipantsAddedToGroupThread":
114
+ logMessageType = "log:subscribe";
115
+ logMessageData = { addedParticipants: m.addedParticipants };
116
+ break;
117
+ case "ParticipantLeftGroupThread":
118
+ logMessageType = "log:unsubscribe";
119
+ logMessageData = { leftParticipantFbId: m.leftParticipantFbId };
120
+ break;
121
+ default:
122
+ logMessageType = m.class;
123
+ logMessageData = m;
124
+ }
125
+
126
+ return {
127
+ type: "event",
128
+ threadID: formatID((m.messageMetadata.threadKey.threadFbId || m.messageMetadata.threadKey.otherUserFbId).toString()),
129
+ messageID: m.messageMetadata.messageId.toString(),
130
+ logMessageType,
131
+ logMessageData,
132
+ logMessageBody: m.messageMetadata.adminText,
133
+ timestamp: m.messageMetadata.timestamp,
134
+ author: m.messageMetadata.actorFbId,
135
+ participantIDs: m.participants
136
+ };
137
+ }
138
+
139
+ function formatDeltaReadReceipt(delta) {
140
+ return {
141
+ reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
142
+ time: delta.actionTimestampMs,
143
+ threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
144
+ type: "read_receipt"
145
+ };
146
+ }
147
+
148
+ module.exports = {
149
+ formatDeltaMessage,
150
+ formatDeltaEvent,
151
+ formatDeltaReadReceipt,
152
+ getAdminTextMessageType
153
+ };
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+
3
+ const stream = require("stream");
4
+ const formatID = require('./value/formatID');
5
+ const formatDate = require('./value/formatDate');
6
+ const formatCookie = require('./value/formatCookie');
7
+ const { _formatAttachment, formatAttachment } = require('./data/formatAttachment');
8
+ const { formatDeltaMessage, formatDeltaEvent, formatDeltaReadReceipt, getAdminTextMessageType } = require('./data/formatDelta');
9
+
10
+ function isReadableStream(obj) {
11
+ return obj instanceof stream.Stream && typeof obj._read == "function" && typeof obj._readableState == "object";
12
+ }
13
+
14
+ function decodeClientPayload(payload) {
15
+ return JSON.parse(String.fromCharCode.apply(null, payload));
16
+ }
17
+
18
+ function formatMessage(m) {
19
+ const originalMessage = m.message ? m.message : m;
20
+ const obj = {
21
+ type: "message",
22
+ senderName: originalMessage.sender_name,
23
+ senderID: formatID(originalMessage.sender_fbid.toString()),
24
+ participantNames: originalMessage.group_thread_info?.participant_names || [originalMessage.sender_name.split(" ")[0]],
25
+ participantIDs: originalMessage.group_thread_info?.participant_ids.map(v => formatID(v.toString())) || [formatID(originalMessage.sender_fbid)],
26
+ body: originalMessage.body || "",
27
+ threadID: formatID((originalMessage.thread_fbid || originalMessage.other_user_fbid).toString()),
28
+ threadName: originalMessage.group_thread_info?.name || originalMessage.sender_name,
29
+ location: originalMessage.coordinates || null,
30
+ messageID: originalMessage.mid?.toString() || originalMessage.message_id,
31
+ attachments: formatAttachment(originalMessage.attachments, originalMessage.attachmentIds, originalMessage.attachment_map, originalMessage.share_map),
32
+ timestamp: originalMessage.timestamp,
33
+ tags: originalMessage.tags,
34
+ reactions: originalMessage.reactions || [],
35
+ isUnread: originalMessage.is_unread
36
+ };
37
+ if (m.type === "pages_messaging") obj.pageID = m.realtime_viewer_fbid.toString();
38
+ obj.isGroup = obj.participantIDs.length > 2;
39
+ return obj;
40
+ }
41
+
42
+ function formatEvent(m) {
43
+ const originalMessage = m.message ? m.message : m;
44
+ let logMessageType = originalMessage.log_message_type;
45
+ let logMessageData;
46
+ if (logMessageType === "log:generic-admin-text") {
47
+ logMessageData = originalMessage.log_message_data.untypedData;
48
+ logMessageType = getAdminTextMessageType(originalMessage.log_message_data.message_type);
49
+ } else {
50
+ logMessageData = originalMessage.log_message_data;
51
+ }
52
+ return {
53
+ ...formatMessage(originalMessage),
54
+ type: "event",
55
+ logMessageType,
56
+ logMessageData,
57
+ logMessageBody: originalMessage.log_message_body
58
+ };
59
+ }
60
+
61
+ function formatHistoryMessage(m) {
62
+ return m.action_type === "ma-type:log-message" ? formatEvent(m) : formatMessage(m);
63
+ }
64
+
65
+ function formatTyp(event) {
66
+ return {
67
+ isTyping: !!event.st,
68
+ from: event.from.toString(),
69
+ threadID: formatID((event.to || event.thread_fbid || event.from).toString()),
70
+ fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
71
+ userID: (event.realtime_viewer_fbid || event.from).toString(),
72
+ type: "typ"
73
+ };
74
+ }
75
+
76
+ function formatReadReceipt(event) {
77
+ return {
78
+ reader: event.reader.toString(),
79
+ time: event.time,
80
+ threadID: formatID((event.thread_fbid || event.reader).toString()),
81
+ type: "read_receipt"
82
+ };
83
+ }
84
+
85
+ function formatRead(event) {
86
+ return {
87
+ threadID: formatID(((event.chat_ids && event.chat_ids[0]) || (event.thread_fbids && event.thread_fbids[0])).toString()),
88
+ time: event.timestamp,
89
+ type: "read"
90
+ };
91
+ }
92
+
93
+ function formatThread(data) {
94
+ return {
95
+ threadID: formatID(data.thread_fbid.toString()),
96
+ participants: data.participants.map(p => formatID(p)),
97
+ participantIDs: data.participants.map(p => formatID(p)),
98
+ name: data.name,
99
+ nicknames: data.custom_nickname,
100
+ snippet: data.snippet,
101
+ snippetSender: formatID((data.snippet_sender || "").toString()),
102
+ unreadCount: data.unread_count,
103
+ messageCount: data.message_count,
104
+ imageSrc: data.image_src,
105
+ timestamp: data.timestamp,
106
+ muteUntil: data.mute_until,
107
+ isGroup: data.thread_type === 2,
108
+ isArchived: data.is_archived,
109
+ canReply: data.can_reply,
110
+ lastMessageTimestamp: data.last_message_timestamp,
111
+ lastReadTimestamp: data.last_read_timestamp,
112
+ emoji: data.custom_like_icon,
113
+ color: data.custom_color,
114
+ adminIDs: data.admin_ids,
115
+ threadType: data.thread_type
116
+ };
117
+ }
118
+
119
+ function formatPresence(presence, userID) {
120
+ return {
121
+ type: "presence",
122
+ timestamp: presence.la * 1000,
123
+ userID: userID,
124
+ statuses: presence.a
125
+ };
126
+ }
127
+
128
+ function formatProxyPresence(presence, userID) {
129
+ if (presence.lat === undefined || presence.p === undefined) return null;
130
+ return {
131
+ type: "presence",
132
+ timestamp: presence.lat * 1000,
133
+ userID: userID,
134
+ statuses: presence.p
135
+ };
136
+ }
137
+
138
+ module.exports = {
139
+ isReadableStream,
140
+ formatID,
141
+ formatDate,
142
+ formatCookie,
143
+ formatAttachment,
144
+ _formatAttachment,
145
+ formatDeltaMessage,
146
+ formatMessage,
147
+ formatEvent,
148
+ formatHistoryMessage,
149
+ getAdminTextMessageType,
150
+ formatDeltaEvent,
151
+ formatTyp,
152
+ formatDeltaReadReceipt,
153
+ formatReadReceipt,
154
+ formatRead,
155
+ formatThread,
156
+ formatProxyPresence,
157
+ formatPresence,
158
+ decodeClientPayload,
159
+ };