@dongdev/fca-unofficial 3.0.30 → 4.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 (104) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +224 -406
  3. package/dist/index.d.mts +1241 -0
  4. package/dist/index.d.ts +1241 -0
  5. package/dist/index.js +27749 -0
  6. package/dist/index.mjs +27713 -0
  7. package/docs/ARCHITECTURE.md +467 -0
  8. package/docs/DOCS.md +686 -0
  9. package/fca-config.example.json +33 -0
  10. package/package.json +33 -22
  11. package/test/fca.test.cjs +533 -0
  12. package/CHANGELOG.md +0 -293
  13. package/DOCS.md +0 -2712
  14. package/func/checkUpdate.js +0 -222
  15. package/func/logAdapter.js +0 -33
  16. package/func/logger.js +0 -48
  17. package/index.d.ts +0 -751
  18. package/index.js +0 -8
  19. package/module/config.js +0 -40
  20. package/module/login.js +0 -133
  21. package/module/loginHelper.js +0 -1296
  22. package/module/options.js +0 -44
  23. package/src/api/action/addExternalModule.js +0 -25
  24. package/src/api/action/changeAvatar.js +0 -137
  25. package/src/api/action/changeBio.js +0 -75
  26. package/src/api/action/enableAutoSaveAppState.js +0 -73
  27. package/src/api/action/getCurrentUserID.js +0 -7
  28. package/src/api/action/handleFriendRequest.js +0 -57
  29. package/src/api/action/logout.js +0 -76
  30. package/src/api/action/refreshFb_dtsg.js +0 -48
  31. package/src/api/action/setPostReaction.js +0 -106
  32. package/src/api/action/unfriend.js +0 -54
  33. package/src/api/http/httpGet.js +0 -46
  34. package/src/api/http/httpPost.js +0 -52
  35. package/src/api/http/postFormData.js +0 -47
  36. package/src/api/messaging/addUserToGroup.js +0 -68
  37. package/src/api/messaging/changeAdminStatus.js +0 -126
  38. package/src/api/messaging/changeArchivedStatus.js +0 -55
  39. package/src/api/messaging/changeBlockedStatus.js +0 -48
  40. package/src/api/messaging/changeGroupImage.js +0 -91
  41. package/src/api/messaging/changeNickname.js +0 -70
  42. package/src/api/messaging/changeThreadColor.js +0 -79
  43. package/src/api/messaging/changeThreadEmoji.js +0 -111
  44. package/src/api/messaging/createNewGroup.js +0 -88
  45. package/src/api/messaging/createPoll.js +0 -46
  46. package/src/api/messaging/createThemeAI.js +0 -98
  47. package/src/api/messaging/deleteMessage.js +0 -136
  48. package/src/api/messaging/deleteThread.js +0 -56
  49. package/src/api/messaging/editMessage.js +0 -68
  50. package/src/api/messaging/forwardAttachment.js +0 -57
  51. package/src/api/messaging/getEmojiUrl.js +0 -29
  52. package/src/api/messaging/getFriendsList.js +0 -82
  53. package/src/api/messaging/getMessage.js +0 -829
  54. package/src/api/messaging/getThemePictures.js +0 -62
  55. package/src/api/messaging/handleMessageRequest.js +0 -65
  56. package/src/api/messaging/markAsDelivered.js +0 -57
  57. package/src/api/messaging/markAsRead.js +0 -88
  58. package/src/api/messaging/markAsReadAll.js +0 -49
  59. package/src/api/messaging/markAsSeen.js +0 -61
  60. package/src/api/messaging/muteThread.js +0 -50
  61. package/src/api/messaging/removeUserFromGroup.js +0 -62
  62. package/src/api/messaging/resolvePhotoUrl.js +0 -43
  63. package/src/api/messaging/scheduler.js +0 -264
  64. package/src/api/messaging/searchForThread.js +0 -52
  65. package/src/api/messaging/sendMessage.js +0 -270
  66. package/src/api/messaging/sendTypingIndicator.js +0 -74
  67. package/src/api/messaging/setMessageReaction.js +0 -91
  68. package/src/api/messaging/setTitle.js +0 -124
  69. package/src/api/messaging/shareContact.js +0 -49
  70. package/src/api/messaging/threadColors.js +0 -128
  71. package/src/api/messaging/unsendMessage.js +0 -81
  72. package/src/api/messaging/uploadAttachment.js +0 -492
  73. package/src/api/socket/core/connectMqtt.js +0 -258
  74. package/src/api/socket/core/emitAuth.js +0 -103
  75. package/src/api/socket/core/getSeqID.js +0 -320
  76. package/src/api/socket/core/getTaskResponseData.js +0 -25
  77. package/src/api/socket/core/parseDelta.js +0 -377
  78. package/src/api/socket/detail/buildStream.js +0 -215
  79. package/src/api/socket/detail/constants.js +0 -28
  80. package/src/api/socket/listenMqtt.js +0 -377
  81. package/src/api/socket/middleware/index.js +0 -216
  82. package/src/api/threads/getThreadHistory.js +0 -664
  83. package/src/api/threads/getThreadInfo.js +0 -295
  84. package/src/api/threads/getThreadList.js +0 -293
  85. package/src/api/threads/getThreadPictures.js +0 -78
  86. package/src/api/users/getUserID.js +0 -65
  87. package/src/api/users/getUserInfo.js +0 -399
  88. package/src/api/users/getUserInfoV2.js +0 -134
  89. package/src/core/sendReqMqtt.js +0 -96
  90. package/src/database/models/index.js +0 -87
  91. package/src/database/models/thread.js +0 -50
  92. package/src/database/models/user.js +0 -46
  93. package/src/database/threadData.js +0 -98
  94. package/src/database/userData.js +0 -89
  95. package/src/remote/remoteClient.js +0 -123
  96. package/src/utils/broadcast.js +0 -51
  97. package/src/utils/client.js +0 -10
  98. package/src/utils/constants.js +0 -23
  99. package/src/utils/cookies.js +0 -68
  100. package/src/utils/format.js +0 -1174
  101. package/src/utils/headers.js +0 -115
  102. package/src/utils/loginParser.js +0 -365
  103. package/src/utils/messageFormat.js +0 -1173
  104. package/src/utils/request.js +0 -332
@@ -1,25 +0,0 @@
1
- "use strict";
2
- /**
3
- * Maps /ls_resp task types to a normalized response shape for send_message_mqtt, set_message_reaction, edit_message.
4
- */
5
- module.exports = function getTaskResponseData(taskType, payload) {
6
- try {
7
- switch (taskType) {
8
- case "send_message_mqtt":
9
- return {
10
- type: taskType,
11
- threadID: payload.step[1][2][2][1][2],
12
- messageID: payload.step[1][2][2][1][3],
13
- payload: payload.step[1][2]
14
- };
15
- case "set_message_reaction":
16
- return { mid: payload.step[1][2][2][1][4] };
17
- case "edit_message":
18
- return { mid: payload.step[1][2][2][1][2] };
19
- default:
20
- return null;
21
- }
22
- } catch (e) {
23
- return null;
24
- }
25
- };
@@ -1,377 +0,0 @@
1
- "use strict";
2
- /**
3
- * Parses MQTT delta payloads into normalized events: NewMessage, ClientPayload (reactions, unsend, reply), read receipts, etc.
4
- */
5
- const { formatDeltaEvent, formatMessage, _formatAttachment, formatDeltaMessage, formatDeltaReadReceipt, formatID, getType, decodeClientPayload, getMentionsFromDeltaMessage } = require("../../../utils/format");
6
- const logger = require("../../../../func/logger");
7
-
8
- module.exports = function createParseDelta(deps) {
9
- const { parseAndCheckLogin } = deps;
10
- return function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
11
- if (delta.class === "NewMessage") {
12
- const resolveAttachmentUrl = i => {
13
- if (!delta.attachments || i === delta.attachments.length || getType(delta.attachments) !== "Array") {
14
- let fmtMsg;
15
- try {
16
- fmtMsg = formatDeltaMessage(delta);
17
- } catch (err) {
18
- return;
19
- }
20
- if (fmtMsg) {
21
- if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) return;
22
- if (typeof ctx._updateThreadFromMessage === "function") {
23
- try {
24
- ctx._updateThreadFromMessage(fmtMsg);
25
- } catch { }
26
- }
27
- globalCallback(null, fmtMsg);
28
- }
29
- } else {
30
- const attachment = delta.attachments[i];
31
- if (attachment && attachment.mercury && attachment.mercury.attach_type === "photo") {
32
- api.resolvePhotoUrl(attachment.fbid, (err, url) => {
33
- if (!err && attachment.mercury && attachment.mercury.metadata) {
34
- attachment.mercury.metadata.url = url;
35
- }
36
- resolveAttachmentUrl(i + 1);
37
- });
38
- } else {
39
- resolveAttachmentUrl(i + 1);
40
- }
41
- }
42
- };
43
- resolveAttachmentUrl(0);
44
- } else if (delta.class === "ClientPayload") {
45
- const clientPayload = decodeClientPayload(delta.payload);
46
- if (clientPayload && clientPayload.deltas) {
47
- for (const d of clientPayload.deltas) {
48
- if (d.deltaMessageReaction && !!ctx.globalOptions.listenEvents) {
49
- const messageReaction = {
50
- type: "message_reaction",
51
- threadID: (d.deltaMessageReaction.threadKey.threadFbId ? d.deltaMessageReaction.threadKey.threadFbId : d.deltaMessageReaction.threadKey.otherUserFbId).toString(),
52
- messageID: d.deltaMessageReaction.messageId,
53
- reaction: d.deltaMessageReaction.reaction,
54
- senderID: d.deltaMessageReaction.senderId.toString(),
55
- userID: d.deltaMessageReaction.userId.toString()
56
- };
57
- globalCallback(null, messageReaction);
58
- } else if (d.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
59
- const messageUnsend = {
60
- type: "message_unsend",
61
- threadID: (d.deltaRecallMessageData.threadKey.threadFbId ? d.deltaRecallMessageData.threadKey.threadFbId : d.deltaRecallMessageData.threadKey.otherUserFbId).toString(),
62
- messageID: d.deltaRecallMessageData.messageID,
63
- senderID: d.deltaRecallMessageData.senderID.toString(),
64
- deletionTimestamp: d.deltaRecallMessageData.deletionTimestamp,
65
- timestamp: d.deltaRecallMessageData.timestamp
66
- };
67
- globalCallback(null, messageUnsend);
68
- } else if (d.deltaMessageReply) {
69
- let callbackToReturn;
70
- try {
71
- const msg = d.deltaMessageReply.message;
72
- if (!msg || !msg.messageMetadata) {
73
- logger("parseDelta: deltaMessageReply.message or messageMetadata is missing", "warn");
74
- return;
75
- }
76
- const mentions = getMentionsFromDeltaMessage(msg);
77
- const msgMetadata = msg.messageMetadata;
78
- const threadKey = msgMetadata.threadKey || {};
79
- callbackToReturn = {
80
- type: "message_reply",
81
- threadID: (threadKey.threadFbId ? threadKey.threadFbId : threadKey.otherUserFbId || "").toString(),
82
- messageID: msgMetadata.messageId || "",
83
- senderID: (msgMetadata.actorFbId || "").toString(),
84
- attachments: (msg.attachments || []).map(att => {
85
- try {
86
- const mercury = JSON.parse(att.mercuryJSON);
87
- Object.assign(att, mercury);
88
- } catch (ex) {
89
- // Ignore parsing errors
90
- }
91
- return att;
92
- }).map(att => {
93
- let x;
94
- try {
95
- x = _formatAttachment(att);
96
- } catch (ex) {
97
- x = att;
98
- x.error = ex;
99
- x.type = "unknown";
100
- }
101
- return x;
102
- }),
103
- args: (msg.body || "").trim().split(/\s+/),
104
- body: msg.body || "",
105
- isGroup: !!threadKey.threadFbId,
106
- mentions,
107
- timestamp: parseInt(msgMetadata.timestamp || 0),
108
- participantIDs: (msg.participants || []).map(e => e.toString())
109
- };
110
- if (d.deltaMessageReply.repliedToMessage) {
111
- try {
112
- const repliedTo = d.deltaMessageReply.repliedToMessage;
113
- const rmentions = getMentionsFromDeltaMessage(repliedTo);
114
- const msgMetadata = repliedTo.messageMetadata;
115
- if (msgMetadata && msgMetadata.threadKey) {
116
- callbackToReturn.messageReply = {
117
- threadID: (msgMetadata.threadKey.threadFbId ? msgMetadata.threadKey.threadFbId : msgMetadata.threadKey.otherUserFbId || "").toString(),
118
- messageID: msgMetadata.messageId || "",
119
- senderID: (msgMetadata.actorFbId || "").toString(),
120
- attachments: (repliedTo.attachments || []).map(att => {
121
- let mercury;
122
- try {
123
- mercury = JSON.parse(att.mercuryJSON);
124
- Object.assign(att, mercury);
125
- } catch (ex) {
126
- mercury = {};
127
- }
128
- return att;
129
- }).map(att => {
130
- let x;
131
- try {
132
- x = _formatAttachment(att);
133
- } catch (ex) {
134
- x = att;
135
- x.error = ex;
136
- x.type = "unknown";
137
- }
138
- return x;
139
- }),
140
- args: (repliedTo.body || "").trim().split(/\s+/),
141
- body: repliedTo.body || "",
142
- isGroup: !!msgMetadata.threadKey.threadFbId,
143
- mentions: rmentions,
144
- timestamp: parseInt(msgMetadata.timestamp || 0),
145
- participantIDs: (repliedTo.participants || []).map(e => e.toString())
146
- };
147
- }
148
- } catch (err) {
149
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
150
- logger(`parseDelta message_reply repliedToMessage error: ${errMsg}`, "warn");
151
- }
152
- } else if (d.deltaMessageReply.replyToMessageId) {
153
- return defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
154
- av: ctx.globalOptions.pageID,
155
- queries: JSON.stringify({
156
- o0: {
157
- doc_id: "2848441488556444",
158
- query_params: {
159
- thread_and_message_id: {
160
- thread_id: callbackToReturn.threadID,
161
- message_id: d.deltaMessageReply.replyToMessageId.id
162
- }
163
- }
164
- }
165
- })
166
- }).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
167
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
168
- if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
169
- const fetchData = resData[0].o0.data.message;
170
- const mobj = {};
171
- for (const n in fetchData.message.ranges) {
172
- mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
173
- }
174
- callbackToReturn.messageReply = {
175
- type: "Message",
176
- threadID: callbackToReturn.threadID,
177
- messageID: fetchData.message_id,
178
- senderID: fetchData.message_sender.id.toString(),
179
- attachments: fetchData.message.blob_attachment.map(att => _formatAttachment({ blob_attachment: att })),
180
- args: (fetchData.message.text || "").trim().split(/\s+/) || [],
181
- body: fetchData.message.text || "",
182
- isGroup: callbackToReturn.isGroup,
183
- mentions: mobj,
184
- timestamp: parseInt(fetchData.timestamp_precise)
185
- };
186
- }).catch(err => {
187
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
188
- logger(`parseDelta message_reply fetch error: ${errMsg}`, "warn");
189
- }).finally(() => {
190
- if (callbackToReturn) {
191
- if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
192
- globalCallback(null, callbackToReturn);
193
- }
194
- });
195
- } else {
196
- if (callbackToReturn) callbackToReturn.delta = d;
197
- }
198
- } catch (err) {
199
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
200
- logger(`parseDelta message_reply error: ${errMsg}`, "warn");
201
- return;
202
- }
203
- if (callbackToReturn) {
204
- if (!ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID) return;
205
- globalCallback(null, callbackToReturn);
206
- }
207
- }
208
- }
209
- return;
210
- }
211
- }
212
- switch (delta.class) {
213
- case "ReadReceipt": {
214
- let fmtMsg;
215
- try {
216
- fmtMsg = formatDeltaReadReceipt(delta);
217
- } catch (err) {
218
- return;
219
- }
220
- globalCallback(null, fmtMsg);
221
- break;
222
- }
223
- case "AdminTextMessage": {
224
- switch (delta.type) {
225
- case "instant_game_dynamic_custom_update":
226
- case "accept_pending_thread":
227
- case "confirm_friend_request":
228
- case "shared_album_delete":
229
- case "shared_album_addition":
230
- case "pin_messages_v2":
231
- case "unpin_messages_v2":
232
- case "change_thread_theme":
233
- case "change_thread_nickname":
234
- case "change_thread_icon":
235
- case "change_thread_quick_reaction":
236
- case "change_thread_admins":
237
- case "group_poll":
238
- case "joinable_group_link_mode_change":
239
- case "magic_words":
240
- case "change_thread_approval_mode":
241
- case "messenger_call_log":
242
- case "participant_joined_group_call":
243
- case "rtc_call_log":
244
- case "update_vote": {
245
- let fmtMsg;
246
- try {
247
- fmtMsg = formatDeltaEvent(delta);
248
- } catch (err) {
249
- return;
250
- }
251
- globalCallback(null, fmtMsg);
252
- break;
253
- }
254
- }
255
- break;
256
- }
257
- case "ForcedFetch": {
258
- if (!delta.threadKey) return;
259
- const mid = delta.messageId;
260
- const tid = delta.threadKey.threadFbId;
261
- if (mid && tid) {
262
- const form = {
263
- av: ctx.globalOptions.pageID,
264
- queries: JSON.stringify({
265
- o0: {
266
- doc_id: "2848441488556444",
267
- query_params: {
268
- thread_and_message_id: {
269
- thread_id: tid.toString(),
270
- message_id: mid
271
- }
272
- }
273
- }
274
- })
275
- };
276
- defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form).then(parseAndCheckLogin(ctx, defaultFuncs)).then(resData => {
277
- if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
278
- if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
279
- const fetchData = resData[0].o0.data.message;
280
- if (getType(fetchData) === "Object") {
281
- switch (fetchData.__typename) {
282
- case "ThreadImageMessage":
283
- if ((!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) || !ctx.loggedIn) {} else {
284
- globalCallback(null, {
285
- type: "event",
286
- threadID: formatID(tid.toString()),
287
- logMessageType: "log:thread-image",
288
- logMessageData: {
289
- image: {
290
- attachmentID: fetchData.image_with_metadata && fetchData.image_with_metadata.legacy_attachment_id,
291
- width: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.x,
292
- height: fetchData.image_with_metadata && fetchData.image_with_metadata.original_dimensions.y,
293
- url: fetchData.image_with_metadata && fetchData.image_with_metadata.preview.uri
294
- }
295
- },
296
- logMessageBody: fetchData.snippet,
297
- timestamp: fetchData.timestamp_precise,
298
- author: fetchData.message_sender.id
299
- });
300
- }
301
- break;
302
- case "UserMessage": {
303
- const event = {
304
- type: "message",
305
- senderID: formatID(fetchData.message_sender.id),
306
- body: fetchData.message.text || "",
307
- threadID: formatID(tid.toString()),
308
- messageID: fetchData.message_id,
309
- attachments: [
310
- {
311
- type: "share",
312
- ID: fetchData.extensible_attachment.legacy_attachment_id,
313
- url: fetchData.extensible_attachment.story_attachment.url,
314
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
315
- description: fetchData.extensible_attachment.story_attachment.description.text,
316
- source: fetchData.extensible_attachment.story_attachment.source,
317
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
318
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
319
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
320
- playable: ((fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false),
321
- duration: ((fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0),
322
- subattachments: fetchData.extensible_attachment.subattachments,
323
- properties: fetchData.extensible_attachment.story_attachment.properties
324
- }
325
- ],
326
- mentions: {},
327
- timestamp: parseInt(fetchData.timestamp_precise),
328
- isGroup: fetchData.message_sender.id !== tid.toString()
329
- };
330
- globalCallback(null, event);
331
- break;
332
- }
333
- default:
334
- break;
335
- }
336
- } else {
337
- return;
338
- }
339
- }).catch(err => {
340
- const errMsg = err && err.message ? err.message : String(err || "Unknown error");
341
- logger(`parseDelta ForcedFetch error: ${errMsg}`, "warn");
342
- });
343
- }
344
- break;
345
- }
346
- case "ThreadName":
347
- case "ParticipantsAddedToGroupThread":
348
- case "ParticipantLeftGroupThread": {
349
- let formattedEvent;
350
- try {
351
- formattedEvent = formatDeltaEvent(delta);
352
- } catch (err) {
353
- return;
354
- }
355
- if (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) return;
356
- if (!ctx.loggedIn) return;
357
- globalCallback(null, formattedEvent);
358
- break;
359
- }
360
- case "NewMessage": {
361
- const hasLiveLocation = d => {
362
- const attachment = d.attachments && d.attachments[0] && d.attachments[0].mercury && d.attachments[0].mercury.extensible_attachment;
363
- const storyAttachment = attachment && attachment.story_attachment;
364
- return storyAttachment && storyAttachment.style_list && storyAttachment.style_list.includes("message_live_location");
365
- };
366
- if (delta.attachments && delta.attachments.length === 1 && hasLiveLocation(delta)) {
367
- delta.class = "UserLocation";
368
- try {
369
- const fmtMsg = formatDeltaEvent(delta);
370
- globalCallback(null, fmtMsg);
371
- } catch (err) {}
372
- }
373
- break;
374
- }
375
- }
376
- };
377
- };
@@ -1,215 +0,0 @@
1
- "use strict";
2
- /**
3
- * Builds a duplex stream over WebSocket for MQTT: proxy for writes, PassThrough for reads.
4
- * Handles ping/pong, liveness timeout, and clean shutdown.
5
- */
6
- const { Writable, PassThrough } = require("stream");
7
- const Duplexify = require("duplexify");
8
-
9
- const PING_INTERVAL_MS = 30000;
10
- const LIVENESS_CHECK_MS = 10000;
11
- const LIVENESS_MAX_IDLE_MS = 65000;
12
-
13
- function buildProxy() {
14
- let target = null;
15
- let ended = false;
16
- const Proxy = new Writable({
17
- autoDestroy: true,
18
- write(chunk, enc, cb) {
19
- if (ended || this.destroyed) return cb();
20
- const ws = target;
21
- if (ws && ws.readyState === 1) {
22
- try {
23
- ws.send(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk), cb);
24
- } catch (e) {
25
- cb(e);
26
- }
27
- } else cb();
28
- },
29
- writev(chunks, cb) {
30
- if (ended || this.destroyed) return cb();
31
- const ws = target;
32
- if (!ws || ws.readyState !== 1) return cb();
33
- try {
34
- for (const { chunk } of chunks) {
35
- ws.send(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
36
- }
37
- cb();
38
- } catch (e) {
39
- cb(e);
40
- }
41
- },
42
- final(cb) {
43
- ended = true;
44
- const ws = target;
45
- target = null;
46
- if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
47
- try {
48
- typeof ws.terminate === "function" ? ws.terminate() : ws.close();
49
- } catch { }
50
- }
51
- cb();
52
- }
53
- });
54
- Proxy.setTarget = ws => {
55
- if (ended) return;
56
- target = ws;
57
- };
58
- Proxy.hardEnd = () => {
59
- ended = true;
60
- target = null;
61
- };
62
- return Proxy;
63
- }
64
-
65
- function buildStream(options, WebSocket, Proxy) {
66
- const readable = new PassThrough();
67
- const Stream = Duplexify(undefined, undefined, Object.assign({ end: false, autoDestroy: true }, options));
68
- const NoopWritable = new Writable({ write(_c, _e, cb) { cb(); } });
69
- let ws = WebSocket;
70
- let pingTimer = null;
71
- let livenessTimer = null;
72
- let lastActivity = Date.now();
73
- let attached = false;
74
- let style = "prop";
75
- let closed = false;
76
-
77
- const toBuffer = d => {
78
- if (Buffer.isBuffer(d)) return d;
79
- if (d instanceof ArrayBuffer) return Buffer.from(d);
80
- if (ArrayBuffer.isView(d)) return Buffer.from(d.buffer, d.byteOffset, d.byteLength);
81
- return Buffer.from(String(d));
82
- };
83
-
84
- const swapToNoopWritable = () => {
85
- try { Stream.setWritable(NoopWritable); } catch { }
86
- };
87
-
88
- const onOpen = () => {
89
- if (closed) return;
90
- Proxy.setTarget(ws);
91
- Stream.setWritable(Proxy);
92
- Stream.setReadable(readable);
93
- Stream.emit("connect");
94
- lastActivity = Date.now();
95
- clearInterval(pingTimer);
96
- clearInterval(livenessTimer);
97
- pingTimer = setInterval(() => {
98
- if (!ws || ws.readyState !== 1) return;
99
- if (typeof ws.ping === "function") {
100
- try { ws.ping(); } catch { }
101
- } else {
102
- try { ws.send("ping"); } catch { }
103
- }
104
- }, PING_INTERVAL_MS);
105
- livenessTimer = setInterval(() => {
106
- if (!ws || ws.readyState !== 1) return;
107
- if (Date.now() - lastActivity > LIVENESS_MAX_IDLE_MS) {
108
- try { typeof ws.terminate === "function" ? ws.terminate() : ws.close(); } catch { }
109
- }
110
- }, LIVENESS_CHECK_MS);
111
- };
112
-
113
- const onMessage = data => {
114
- lastActivity = Date.now();
115
- readable.write(toBuffer(style === "dom" && data && data.data !== undefined ? data.data : data));
116
- };
117
-
118
- const onPong = () => {
119
- lastActivity = Date.now();
120
- };
121
-
122
- const cleanup = () => {
123
- if (closed) return;
124
- closed = true;
125
- clearInterval(pingTimer);
126
- clearInterval(livenessTimer);
127
- pingTimer = null;
128
- livenessTimer = null;
129
- Proxy.hardEnd();
130
- swapToNoopWritable();
131
- if (ws) {
132
- detach(ws);
133
- try {
134
- if (ws.readyState === 1) {
135
- typeof ws.terminate === "function" ? ws.terminate() : ws.close();
136
- }
137
- } catch { }
138
- ws = null;
139
- }
140
- readable.end();
141
- };
142
-
143
- const onError = err => {
144
- cleanup();
145
- Stream.destroy(err);
146
- };
147
-
148
- const onClose = () => {
149
- cleanup();
150
- Stream.end();
151
- if (!Stream.destroyed) Stream.destroy();
152
- };
153
-
154
- const attach = w => {
155
- if (attached || !w) return;
156
- attached = true;
157
- if (typeof w.on === "function" && typeof w.off === "function") {
158
- style = "node";
159
- w.on("open", onOpen);
160
- w.on("message", onMessage);
161
- w.on("error", onError);
162
- w.on("close", onClose);
163
- if (typeof w.on === "function") w.on("pong", onPong);
164
- } else if (typeof w.addEventListener === "function" && typeof w.removeEventListener === "function") {
165
- style = "dom";
166
- w.addEventListener("open", onOpen);
167
- w.addEventListener("message", onMessage);
168
- w.addEventListener("error", onError);
169
- w.addEventListener("close", onClose);
170
- } else {
171
- style = "prop";
172
- w.onopen = onOpen;
173
- w.onmessage = onMessage;
174
- w.onerror = onError;
175
- w.onclose = onClose;
176
- }
177
- };
178
-
179
- const detach = w => {
180
- if (!attached || !w) return;
181
- attached = false;
182
- if (style === "node" && typeof w.off === "function") {
183
- w.off("open", onOpen);
184
- w.off("message", onMessage);
185
- w.off("error", onError);
186
- w.off("close", onClose);
187
- if (typeof w.off === "function") w.off("pong", onPong);
188
- } else if (style === "dom" && typeof w.removeEventListener === "function") {
189
- w.removeEventListener("open", onOpen);
190
- w.removeEventListener("message", onMessage);
191
- w.removeEventListener("error", onError);
192
- w.removeEventListener("close", onClose);
193
- } else {
194
- w.onopen = null;
195
- w.onmessage = null;
196
- w.onerror = null;
197
- w.onclose = null;
198
- }
199
- };
200
-
201
- attach(ws);
202
- if (ws && ws.readyState === 1) onOpen();
203
-
204
- Stream.on("prefinish", swapToNoopWritable);
205
- Stream.on("finish", cleanup);
206
- Stream.on("close", cleanup);
207
- Proxy.on("close", swapToNoopWritable);
208
-
209
- return Stream;
210
- }
211
-
212
- module.exports = {
213
- buildProxy,
214
- buildStream
215
- };
@@ -1,28 +0,0 @@
1
- "use strict";
2
- /**
3
- * MQTT topic list for Facebook Messenger real-time connection.
4
- * Subscriptions are created in connectMqtt on "connect".
5
- */
6
- module.exports = {
7
- topics: [
8
- "/ls_req",
9
- "/ls_resp",
10
- "/legacy_web",
11
- "/webrtc",
12
- "/rtc_multi",
13
- "/onevc",
14
- "/br_sr",
15
- "/sr_res",
16
- "/t_ms",
17
- "/thread_typing",
18
- "/orca_typing_notifications",
19
- "/notify_disconnect",
20
- "/orca_presence",
21
- "/inbox",
22
- "/mercury",
23
- "/messaging_events",
24
- "/orca_message_notifications",
25
- "/pp",
26
- "/webrtc_response"
27
- ]
28
- };