stfca 1.0.27 → 1.1.27

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.
package/src/listenMqtt.js CHANGED
@@ -3,46 +3,219 @@
3
3
  var utils = require("../utils");
4
4
  var log = require("npmlog");
5
5
  var mqtt = require('mqtt');
6
- var websocket = require('websocket-stream');
7
- var HttpsProxyAgent = require('https-proxy-agent');
6
+ var WebSocket = require('ws');
7
+ var Transform = require('stream').Transform;
8
8
  const EventEmitter = require('events');
9
- const debugSeq = false;
9
+
10
+ // ─── ANSI colour helpers ───────────────────────────────────────────────────────
11
+ var C = {
12
+ reset: '\x1b[0m',
13
+ bold: '\x1b[1m',
14
+ dim: '\x1b[2m',
15
+ // foregrounds
16
+ black: '\x1b[30m',
17
+ red: '\x1b[31m',
18
+ green: '\x1b[32m',
19
+ yellow: '\x1b[33m',
20
+ blue: '\x1b[34m',
21
+ magenta: '\x1b[35m',
22
+ cyan: '\x1b[36m',
23
+ white: '\x1b[37m',
24
+ // bright foregrounds
25
+ bBlack: '\x1b[90m',
26
+ bRed: '\x1b[91m',
27
+ bGreen: '\x1b[92m',
28
+ bYellow: '\x1b[93m',
29
+ bBlue: '\x1b[94m',
30
+ bMagenta: '\x1b[95m',
31
+ bCyan: '\x1b[96m',
32
+ bWhite: '\x1b[97m',
33
+ // backgrounds
34
+ bgBlue: '\x1b[44m',
35
+ bgCyan: '\x1b[46m',
36
+ bgMagenta: '\x1b[45m',
37
+ bgGreen: '\x1b[42m',
38
+ bgBlack: '\x1b[40m',
39
+ };
40
+
41
+ // ─── MQTT Spinner ──────────────────────────────────────────────────────────────
42
+ var _mqttSpinner = null;
43
+
44
+ function startMqttSpinner(region) {
45
+ var frames = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
46
+ var fi = 0;
47
+ var regionStr = region ? (' ' + C.dim + C.bCyan + '[' + region.toUpperCase() + ']' + C.reset) : '';
48
+ process.stdout.write('\n');
49
+ _mqttSpinner = setInterval(function () {
50
+ var frame = frames[fi++ % frames.length];
51
+ process.stdout.write(
52
+ '\r ' +
53
+ C.bold + C.bCyan + frame + C.reset + ' ' +
54
+ C.cyan + 'ST-FCA' + C.reset + ' ' +
55
+ C.dim + 'connecting to MQTT' + C.reset +
56
+ regionStr +
57
+ C.dim + ' ...' + C.reset +
58
+ ' '
59
+ );
60
+ }, 80);
61
+ }
62
+
63
+ function stopMqttSpinner() {
64
+ if (_mqttSpinner) {
65
+ clearInterval(_mqttSpinner);
66
+ _mqttSpinner = null;
67
+ }
68
+ // erase the spinner line completely
69
+ process.stdout.write('\r\x1b[2K');
70
+ }
71
+
72
+ function printMqttBanner(region, autoReconnect) {
73
+ stopMqttSpinner();
74
+
75
+ var titleClr = C.bold + C.bGreen;
76
+ var labelClr = C.bold + C.bWhite;
77
+ var valClr = C.bYellow;
78
+ var accentClr = C.bold + C.bMagenta;
79
+ var urlClr = C.bBlue;
80
+ var rst = C.reset;
81
+
82
+ var regionVal = (region || '').toUpperCase();
83
+ var reconnTxt = autoReconnect ? 'Enabled (3s)' : 'Disabled';
84
+ var reconnClr = autoReconnect ? C.bGreen : C.bRed;
85
+ var reconnVal = reconnClr + reconnTxt + rst;
86
+
87
+ var rows = [
88
+ titleClr + ' ✅ ST-FCA MQTT Connected' + rst,
89
+ '',
90
+ labelClr + ' 📍 Region ' + rst + valClr + regionVal + rst,
91
+ labelClr + ' 🔄 Auto-reconnect ' + rst + reconnVal,
92
+ urlClr + ' 🌐 github.com/sheikhtamimlover/ST-BOT' + rst,
93
+ '',
94
+ accentClr + ' 💎 Author ST | Sheikh Tamim' + rst
95
+ ];
96
+
97
+ process.stdout.write('\n');
98
+ rows.forEach(function (line) {
99
+ console.log(line);
100
+ });
101
+ process.stdout.write('\n');
102
+ }
103
+
104
+ /**
105
+ * Facebook sends non-standard MQTT packets where PUBACK/SUBACK have
106
+ * non-zero reserved flag bits (e.g. 0x4F instead of 0x40).
107
+ * mqtt-packet strictly rejects these. This transform stream patches
108
+ * the first byte of each MQTT frame to clear the lower nibble (flags),
109
+ * keeping only the packet type (upper nibble).
110
+ *
111
+ * MQTT fixed header: byte[0] = (type << 4) | flags
112
+ * For PUBACK (type=4): valid = 0x40, FB may send 0x4F → we clear to 0x40
113
+ */
114
+ function createMqttPatchStream() {
115
+ var buf = null;
116
+
117
+ // Walk frame by frame. For types that must have flags=0 per the MQTT spec
118
+ // (CONNACK=2, PUBACK=4, SUBACK=9, UNSUBACK=11, PINGRESP=13), clear the
119
+ // lower nibble that Facebook sets to non-zero values.
120
+ var stream = new Transform({
121
+ transform: function (chunk, encoding, callback) {
122
+ if (!Buffer.isBuffer(chunk)) chunk = Buffer.from(chunk, encoding);
123
+
124
+ // Prepend any leftover bytes from the previous chunk
125
+ var out;
126
+ if (buf) {
127
+ out = Buffer.concat([buf, chunk]);
128
+ buf = null;
129
+ } else {
130
+ out = Buffer.from(chunk);
131
+ }
132
+
133
+ var i = 0;
134
+ while (i < out.length) {
135
+ var b = out[i];
136
+ var type = (b >> 4) & 0x0F;
137
+ var flags = b & 0x0F;
138
+ // Types that MUST have flags=0:
139
+ if (flags !== 0 && (type === 4 || type === 9 || type === 11 || type === 13 || type === 2)) {
140
+ out[i] = (b & 0xF0); // clear lower nibble
141
+ }
142
+ // Skip past this frame: read the varint length
143
+ i++;
144
+ var multiplier = 1;
145
+ var frameLen = 0;
146
+ var lenOk = false;
147
+ while (i < out.length) {
148
+ var lb = out[i++];
149
+ frameLen += (lb & 0x7F) * multiplier;
150
+ multiplier *= 128;
151
+ if ((lb & 0x80) === 0) { lenOk = true; break; }
152
+ if (multiplier > 128 * 128 * 128) break; // malformed
153
+ }
154
+ if (!lenOk) {
155
+ // Incomplete frame — save remainder for next chunk
156
+ buf = out.slice(i - 1);
157
+ out = out.slice(0, i - 1);
158
+ break;
159
+ }
160
+ i += frameLen;
161
+ }
162
+
163
+ callback(null, out);
164
+ },
165
+ flush: function (callback) {
166
+ if (buf && buf.length > 0) callback(null, buf);
167
+ else callback();
168
+ buf = null;
169
+ }
170
+ });
171
+ return stream;
172
+ }
173
+
10
174
  var identity = function () { };
11
175
  var form = {};
12
176
  var getSeqID = function () { };
177
+
13
178
  var topics = [
14
179
  "/legacy_web",
15
180
  "/webrtc",
16
181
  "/rtc_multi",
17
182
  "/onevc",
18
- "/br_sr", //Notification
19
- //Need to publish /br_sr right after this
183
+ "/br_sr",
20
184
  "/sr_res",
21
185
  "/t_ms",
22
186
  "/thread_typing",
23
187
  "/orca_typing_notifications",
24
188
  "/notify_disconnect",
25
- //Need to publish /messenger_sync_create_queue right after this
26
189
  "/orca_presence",
27
- //Will receive /sr_res right here.
28
-
29
190
  "/inbox",
30
191
  "/mercury",
31
192
  "/messaging_events",
32
193
  "/orca_message_notifications",
33
194
  "/pp",
34
195
  "/webrtc_response",
196
+ "/ls_resp"
35
197
  ];
36
198
 
199
+ function sanitizeHeaderValue(value) {
200
+ if (value === null || value === undefined) return "";
201
+ var str = String(value);
202
+ if (str.trim().startsWith("[") && str.trim().endsWith("]")) {
203
+ try {
204
+ var parsed = JSON.parse(str);
205
+ if (Array.isArray(parsed)) return "";
206
+ } catch (_) { }
207
+ }
208
+ str = str.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F\r\n\[\]]/g, "").trim();
209
+ return str;
210
+ }
211
+
37
212
  function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
38
- //Don't really know what this does but I think it's for the active state?
39
- //TODO: Move to ctx when implemented
40
213
  var chatOn = ctx.globalOptions.online;
41
214
  var foreground = false;
42
-
43
215
  var sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
44
216
  var GUID = utils.getGUID();
45
- const username = {
217
+
218
+ var username = {
46
219
  u: ctx.userID,
47
220
  s: sessionID,
48
221
  chat_on: chatOn,
@@ -63,89 +236,138 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
63
236
  p: null,
64
237
  php_override: ""
65
238
  };
66
- var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
67
239
 
240
+ var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; ");
68
241
  var host;
69
- if (ctx.mqttEndpoint) host = `${ctx.mqttEndpoint}&sid=${sessionID}&cid=${GUID}`;
70
- else if (ctx.region) host = `wss://edge-chat.facebook.com/chat?region=${ctx.region.toLocaleLowerCase()}&sid=${sessionID}&cid=${GUID}`;
71
- else host = `wss://edge-chat.facebook.com/chat?sid=${sessionID}&cid=${GUID}`;
242
+ if (ctx.mqttEndpoint) {
243
+ // Ensure no duplicate sid/cid — strip any existing ones then append fresh
244
+ var baseEndpoint = ctx.mqttEndpoint
245
+ .replace(/[?&]sid=[^&]*/g, '')
246
+ .replace(/[?&]cid=[^&]*/g, '');
247
+ // Re-attach the ? if it was stripped along with the first param
248
+ if (baseEndpoint.indexOf('?') === -1 && ctx.mqttEndpoint.indexOf('?') !== -1) {
249
+ baseEndpoint = baseEndpoint.replace(/&/, '?');
250
+ }
251
+ var sep = baseEndpoint.indexOf('?') === -1 ? '?' : '&';
252
+ host = baseEndpoint + sep + "sid=" + sessionID + "&cid=" + GUID;
253
+ } else if (ctx.region) {
254
+ host = "wss://edge-chat.facebook.com/chat?region=" + ctx.region.toLowerCase() + "&sid=" + sessionID + "&cid=" + GUID;
255
+ } else {
256
+ host = "wss://edge-chat.facebook.com/chat?sid=" + sessionID + "&cid=" + GUID;
257
+ }
258
+
259
+ var ua = ctx.globalOptions.userAgent ||
260
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15";
261
+
262
+ var wsHeaders = {
263
+ Cookie: sanitizeHeaderValue(cookies),
264
+ Origin: "https://www.facebook.com",
265
+ "User-Agent": sanitizeHeaderValue(ua),
266
+ Referer: "https://www.facebook.com/",
267
+ Host: "edge-chat.facebook.com",
268
+ Connection: "Upgrade",
269
+ Upgrade: "websocket",
270
+ "Sec-WebSocket-Version": "13",
271
+ "Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits",
272
+ "Accept-Language": "en-US,en;q=0.9",
273
+ "Accept-Encoding": "gzip, deflate, br",
274
+ "Cache-Control": "no-cache",
275
+ Pragma: "no-cache"
276
+ };
277
+
278
+ if (ctx.region) wsHeaders["X-MSGR-Region"] = sanitizeHeaderValue(ctx.region);
72
279
 
73
- const options = {
74
- clientId: 'mqttwsclient',
75
- protocolId: 'MQIsdp',
280
+ var wsOptions = {
281
+ headers: wsHeaders,
282
+ origin: "https://www.facebook.com",
283
+ protocolVersion: 13,
284
+ binaryType: "arraybuffer"
285
+ };
286
+
287
+ if (typeof ctx.globalOptions.proxy !== "undefined") {
288
+ var { HttpsProxyAgent } = require('https-proxy-agent');
289
+ wsOptions.agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
290
+ }
291
+
292
+ var mqttOptions = {
293
+ clientId: "mqttwsclient",
294
+ protocolId: "MQIsdp",
76
295
  protocolVersion: 3,
77
296
  username: JSON.stringify(username),
78
297
  clean: true,
79
- wsOptions: {
80
- headers: {
81
- Cookie: cookies,
82
- Origin: 'https://www.facebook.com',
83
- 'User-Agent': ctx.globalOptions.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36',
84
- Referer: 'https://www.facebook.com/',
85
- Host: new URL(host).hostname,
86
- },
87
- origin: 'https://www.facebook.com',
88
- protocolVersion: 13,
89
- binaryType: 'arraybuffer',
90
- },
91
- keepalive: 60,
298
+ keepalive: 30,
92
299
  reschedulePings: true,
93
- reconnectPeriod: 3,
300
+ reconnectPeriod: 0,
301
+ connectTimeout: 12000
94
302
  };
95
303
 
96
- if (typeof ctx.globalOptions.proxy != "undefined") {
97
- var agent = new HttpsProxyAgent(ctx.globalOptions.proxy);
98
- options.wsOptions.agent = agent;
304
+ // Use MqttClient with a proper Duplex:
305
+ // Write side: mqtt duplex.write → wsStream.write → WebSocket (send to FB)
306
+ // Read side: WebSocket msg → wsStream readable → patcher (fix FB header bits) → duplex.push mqtt reads
307
+ function buildStream() {
308
+ var Duplex = require('stream').Duplex;
309
+ var ws = new WebSocket(host, wsOptions);
310
+ ws.on('error', function () { }); // suppress unhandled ws errors
311
+
312
+ var wsStream = WebSocket.createWebSocketStream(ws, { objectMode: false });
313
+ var patcher = createMqttPatchStream();
314
+
315
+ // Wire: wsStream readable → patcher → push into duplex
316
+ wsStream.pipe(patcher);
317
+
318
+ var duplex = new Duplex({
319
+ read: function () { },
320
+ write: function (chunk, enc, cb) {
321
+ wsStream.write(chunk, enc, cb);
322
+ },
323
+ final: function (cb) {
324
+ wsStream.end(cb);
325
+ },
326
+ destroy: function (err, cb) {
327
+ try { wsStream.destroy(err); } catch (_) { }
328
+ cb(err);
329
+ }
330
+ });
331
+
332
+ patcher.on('data', function (data) {
333
+ if (!duplex.destroyed) duplex.push(data);
334
+ });
335
+ patcher.on('end', function () {
336
+ if (!duplex.destroyed) duplex.push(null);
337
+ });
338
+ patcher.on('error', function (e) {
339
+ if (!duplex.destroyed) duplex.destroy(e);
340
+ });
341
+ wsStream.on('error', function (e) {
342
+ if (!duplex.destroyed) duplex.destroy(e);
343
+ });
344
+
345
+ return duplex;
99
346
  }
100
347
 
101
- ctx.mqttClient = new mqtt.Client(_ => websocket(host, options.wsOptions), options);
348
+ startMqttSpinner(ctx.region);
102
349
 
350
+ ctx.mqttClient = new mqtt.MqttClient(buildStream, mqttOptions);
103
351
  global.mqttClient = ctx.mqttClient;
104
352
 
353
+ var mqttClient = ctx.mqttClient;
354
+
105
355
  mqttClient.on('error', function (err) {
356
+ stopMqttSpinner();
106
357
  log.error("listenMqtt", err);
107
358
  mqttClient.end();
108
359
  if (ctx.globalOptions.autoReconnect) getSeqID();
109
360
  else globalCallback({ type: "stop_listen", error: "Connection refused: Server unavailable" }, null);
110
361
  });
111
362
 
363
+ mqttClient.on('close', function () { });
364
+ mqttClient.on('offline', function () { });
365
+ mqttClient.on('reconnect', function () { });
366
+
112
367
  mqttClient.on('connect', function () {
113
- topics.forEach(topicsub => mqttClient.subscribe(topicsub));
114
-
115
- // Display connection success message with branding and loading animation
116
- const messages = [
117
- '\n✅ ST-FCA MQTT Connected',
118
- `📍 Region: ${ctx.region || 'PNB'}`,
119
- `🔄 Auto-reconnect: ${ctx.globalOptions.autoReconnect ? 'Enabled' : 'Disabled'}${ctx.globalOptions.autoReconnect ? ' (reconnects every 3s on disconnect)' : ''}`,
120
- `⏱️ MQTT Restart Interval: ${ctx.globalOptions.restartListenMqtt?.enable ? `${ctx.globalOptions.restartListenMqtt.timeRestart / 1000}s` : 'Disabled'}`,
121
- '� This FCA is specially for ST BOT',
122
- '🌐 GitHub: https://github.com/sheikhtamimlover/ST-BOT',
123
- '📱 Owner IG: https://www.instagram.com/sheikh.tamim_lover',
124
- '�🎨 Maintained & Enhanced by ST | Sheikh Tamim\n'
125
- ];
126
-
127
- let index = 0;
128
- const displayMessages = () => {
129
- if (index < messages.length) {
130
- const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
131
- let frameIndex = 0;
132
-
133
- const loadingInterval = setInterval(() => {
134
- process.stdout.write(`\r${frames[frameIndex]} Loading...`);
135
- frameIndex = (frameIndex + 1) % frames.length;
136
- }, 80);
137
-
138
- setTimeout(() => {
139
- clearInterval(loadingInterval);
140
- process.stdout.write('\r' + ' '.repeat(20) + '\r');
141
- console.log(messages[index]);
142
- index++;
143
- displayMessages();
144
- }, 500);
145
- }
146
- };
368
+ topics.forEach(function (topic) { mqttClient.subscribe(topic); });
147
369
 
148
- displayMessages();
370
+ printMqttBanner(ctx.region, ctx.globalOptions.autoReconnect);
149
371
 
150
372
  var topic;
151
373
  var queue = {
@@ -160,8 +382,7 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
160
382
  topic = "/messenger_sync_get_diffs";
161
383
  queue.last_seq_id = ctx.lastSeqId;
162
384
  queue.sync_token = ctx.syncToken;
163
- }
164
- else {
385
+ } else {
165
386
  topic = "/messenger_sync_create_queue";
166
387
  queue.initial_titan_sequence_id = ctx.lastSeqId;
167
388
  queue.device_params = null;
@@ -176,23 +397,21 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
176
397
 
177
398
  ctx.tmsWait = function () {
178
399
  clearTimeout(rTimeout);
179
- ctx.globalOptions.emitReady ? globalCallback({
180
- type: "ready",
181
- error: null
182
- }) : "";
400
+ if (ctx.globalOptions.emitReady) globalCallback({ type: "ready", error: null });
183
401
  delete ctx.tmsWait;
184
402
  };
185
403
  });
186
404
 
187
- mqttClient.on('message', function (topic, message, _packet) {
405
+ mqttClient.on('message', function (topic, message) {
406
+ var jsonMessage;
188
407
  try {
189
- var jsonMessage = JSON.parse(message);
190
- }
191
- catch (ex) {
408
+ jsonMessage = JSON.parse(message.toString());
409
+ } catch (ex) {
192
410
  return log.error("listenMqtt", ex);
193
411
  }
412
+
194
413
  if (topic === "/t_ms") {
195
- if (ctx.tmsWait && typeof ctx.tmsWait == "function") ctx.tmsWait();
414
+ if (ctx.tmsWait && typeof ctx.tmsWait === "function") ctx.tmsWait();
196
415
 
197
416
  if (jsonMessage.firstDeltaSeqId && jsonMessage.syncToken) {
198
417
  ctx.lastSeqId = jsonMessage.firstDeltaSeqId;
@@ -201,13 +420,11 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
201
420
 
202
421
  if (jsonMessage.lastIssuedSeqId) ctx.lastSeqId = parseInt(jsonMessage.lastIssuedSeqId);
203
422
 
204
- //If it contains more than 1 delta
205
423
  for (var i in jsonMessage.deltas) {
206
424
  var delta = jsonMessage.deltas[i];
207
425
  parseDelta(defaultFuncs, api, ctx, globalCallback, { "delta": delta });
208
426
  }
209
- }
210
- else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
427
+ } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") {
211
428
  var typ = {
212
429
  type: "typ",
213
430
  isTyping: !!jsonMessage.state,
@@ -215,17 +432,13 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
215
432
  threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString())
216
433
  };
217
434
  (function () { globalCallback(null, typ); })();
218
- }
219
- else if (topic === "/orca_presence") {
435
+ } else if (topic === "/orca_presence") {
220
436
  if (!ctx.globalOptions.updatePresence) {
221
437
  for (var i in jsonMessage.list) {
222
438
  var data = jsonMessage.list[i];
223
- var userID = data["u"];
224
-
225
439
  var presence = {
226
440
  type: "presence",
227
- userID: userID.toString(),
228
- //Convert to ms
441
+ userID: data["u"].toString(),
229
442
  timestamp: data["l"] * 1000,
230
443
  statuses: data["p"]
231
444
  };
@@ -233,57 +446,43 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
233
446
  }
234
447
  }
235
448
  }
236
-
237
449
  });
238
450
 
239
451
  mqttClient.on('close', function () { });
240
452
  }
241
453
 
242
- function attachImgbbUrlToAttachment(api, attachment) {
243
- if (!api || !api.uploadImageToImgbb || !attachment || attachment.type !== "photo" || !attachment.url) return;
244
- api.uploadImageToImgbb(attachment.url).then((result) => {
245
- if (result && result.data) {
246
- attachment.imgbbUrl = result.data.url || result.data.display_url || (result.data.image && result.data.image.url);
247
- }
248
- }).catch(() => { });
454
+ function attachImageUrlToAttachment(api, attachment) {
455
+ if (!attachment || attachment.type !== "photo" || !attachment.url) return;
456
+ if (api && api._imgUpload) {
457
+ api._imgUpload(attachment.url).then(function (url) {
458
+ if (url) attachment.imgUrl = url;
459
+ }).catch(function () { });
460
+ }
249
461
  }
250
462
 
251
463
  function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
252
464
  if (v.delta.class == "NewMessage") {
253
- //Not tested for pages
254
465
  if (ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue) return;
255
466
 
256
467
  (function resolveAttachmentUrl(i) {
257
468
  if (i == (v.delta.attachments || []).length) {
258
- let fmtMsg;
469
+ var fmtMsg;
259
470
  try {
260
471
  fmtMsg = utils.formatDeltaMessage(v);
261
- // Detect if it's a DM or group thread - enhanced detection
262
- const otherUserFbId = v.delta.messageMetadata.threadKey.otherUserFbId;
263
- const threadFbId = v.delta.messageMetadata.threadKey.threadFbId;
264
-
265
- // A thread is a DM if it has otherUserFbId and no threadFbId
472
+ var otherUserFbId = v.delta.messageMetadata.threadKey.otherUserFbId;
473
+ var threadFbId = v.delta.messageMetadata.threadKey.threadFbId;
266
474
  fmtMsg.isSingleUser = !!otherUserFbId && !threadFbId;
267
475
  fmtMsg.isGroup = !!threadFbId;
268
-
269
- // Store thread type in context for sendMessage to use
270
476
  if (!ctx.threadTypes) ctx.threadTypes = {};
271
477
  ctx.threadTypes[fmtMsg.threadID] = fmtMsg.isSingleUser ? 'dm' : 'group';
272
478
  if (fmtMsg.attachments && Array.isArray(fmtMsg.attachments)) {
273
- fmtMsg.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
479
+ fmtMsg.attachments.forEach(function (att) { attachImageUrlToAttachment(api, att); });
274
480
  }
275
481
  } catch (err) {
276
- return globalCallback({
277
- error: "Problem parsing message object.",
278
- detail: err,
279
- res: v,
280
- type: "parse_error"
281
- });
482
+ return globalCallback({ error: "Problem parsing message object.", detail: err, res: v, type: "parse_error" });
282
483
  }
283
- if (fmtMsg) {
284
- if (ctx.globalOptions.autoMarkDelivery) {
285
- markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
286
- }
484
+ if (fmtMsg && ctx.globalOptions.autoMarkDelivery) {
485
+ markDelivery(ctx, api, fmtMsg.threadID, fmtMsg.messageID);
287
486
  }
288
487
  return !ctx.globalOptions.selfListen &&
289
488
  (fmtMsg.senderID === ctx.i_userID || fmtMsg.senderID === ctx.userID) ?
@@ -291,16 +490,10 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
291
490
  (function () { globalCallback(null, fmtMsg); })();
292
491
  } else {
293
492
  if (v.delta.attachments[i].mercury.attach_type == "photo") {
294
- api.resolvePhotoUrl(
295
- v.delta.attachments[i].fbid,
296
- (err, url) => {
297
- if (!err)
298
- v.delta.attachments[
299
- i
300
- ].mercury.metadata.url = url;
301
- return resolveAttachmentUrl(i + 1);
302
- }
303
- );
493
+ api.resolvePhotoUrl(v.delta.attachments[i].fbid, function (err, url) {
494
+ if (!err) v.delta.attachments[i].mercury.metadata.url = url;
495
+ return resolveAttachmentUrl(i + 1);
496
+ });
304
497
  } else {
305
498
  return resolveAttachmentUrl(i + 1);
306
499
  }
@@ -324,8 +517,7 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
324
517
  userID: delta.deltaMessageReaction.userId.toString()
325
518
  });
326
519
  })();
327
- }
328
- else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
520
+ } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) {
329
521
  (function () {
330
522
  globalCallback(null, {
331
523
  type: "message_unsend",
@@ -336,21 +528,17 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
336
528
  timestamp: delta.deltaRecallMessageData.timestamp
337
529
  });
338
530
  })();
339
- }
340
- else if (delta.deltaMessageReply) {
341
- //Mention block - #1
531
+ } else if (delta.deltaMessageReply) {
342
532
  var mdata = delta.deltaMessageReply.message === undefined ? [] :
343
533
  delta.deltaMessageReply.message.data === undefined ? [] :
344
534
  delta.deltaMessageReply.message.data.prng === undefined ? [] :
345
535
  JSON.parse(delta.deltaMessageReply.message.data.prng);
346
- var m_id = mdata.map(u => u.i);
347
- var m_offset = mdata.map(u => u.o);
348
- var m_length = mdata.map(u => u.l);
349
-
536
+ var m_id = mdata.map(function (u) { return u.i; });
537
+ var m_offset = mdata.map(function (u) { return u.o; });
538
+ var m_length = mdata.map(function (u) { return u.l; });
350
539
  var mentions = {};
351
-
352
540
  for (var i = 0; i < m_id.length; i++) mentions[m_id[i]] = (delta.deltaMessageReply.message.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
353
- //Mention block - 1#
541
+
354
542
  var callbackToReturn = {
355
543
  type: "message_reply",
356
544
  threadID: (delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey.otherUserFbId).toString(),
@@ -360,16 +548,10 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
360
548
  var mercury = JSON.parse(att.mercuryJSON);
361
549
  Object.assign(att, mercury);
362
550
  return att;
363
- }).map(att => {
551
+ }).map(function (att) {
364
552
  var x;
365
- try {
366
- x = utils._formatAttachment(att);
367
- }
368
- catch (ex) {
369
- x = att;
370
- x.error = ex;
371
- x.type = "unknown";
372
- }
553
+ try { x = utils._formatAttachment(att); }
554
+ catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
373
555
  return x;
374
556
  }),
375
557
  args: (delta.deltaMessageReply.message.body || "").trim().split(/\s+/),
@@ -377,26 +559,24 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
377
559
  isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId,
378
560
  mentions: mentions,
379
561
  timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp,
380
- participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(e => e.toString())
562
+ participantIDs: (delta.deltaMessageReply.message.messageMetadata.cid.canonicalParticipantFbids || delta.deltaMessageReply.message.participants || []).map(function (e) { return e.toString(); })
381
563
  };
564
+
382
565
  if (callbackToReturn.attachments && Array.isArray(callbackToReturn.attachments)) {
383
- callbackToReturn.attachments.forEach(att => attachImgbbUrlToAttachment(api, att));
566
+ callbackToReturn.attachments.forEach(function (att) { attachImageUrlToAttachment(api, att); });
384
567
  }
385
568
 
386
569
  if (delta.deltaMessageReply.repliedToMessage) {
387
- //Mention block - #2
388
570
  mdata = delta.deltaMessageReply.repliedToMessage === undefined ? [] :
389
571
  delta.deltaMessageReply.repliedToMessage.data === undefined ? [] :
390
572
  delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] :
391
573
  JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng);
392
- m_id = mdata.map(u => u.i);
393
- m_offset = mdata.map(u => u.o);
394
- m_length = mdata.map(u => u.l);
395
-
574
+ m_id = mdata.map(function (u) { return u.i; });
575
+ m_offset = mdata.map(function (u) { return u.o; });
576
+ m_length = mdata.map(function (u) { return u.l; });
396
577
  var rmentions = {};
397
-
398
578
  for (var i = 0; i < m_id.length; i++) rmentions[m_id[i]] = (delta.deltaMessageReply.repliedToMessage.body || "").substring(m_offset[i], m_offset[i] + m_length[i]);
399
- //Mention block - 2#
579
+
400
580
  callbackToReturn.messageReply = {
401
581
  threadID: (delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.otherUserFbId).toString(),
402
582
  messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId,
@@ -405,17 +585,11 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
405
585
  var mercury = JSON.parse(att.mercuryJSON);
406
586
  Object.assign(att, mercury);
407
587
  return att;
408
- }).map(att => {
588
+ }).map(function (att) {
409
589
  var x;
410
- try {
411
- x = utils._formatAttachment(att);
412
- }
413
- catch (ex) {
414
- x = att;
415
- x.error = ex;
416
- x.type = "unknown";
417
- }
418
- attachImgbbUrlToAttachment(api, x);
590
+ try { x = utils._formatAttachment(att); }
591
+ catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
592
+ attachImageUrlToAttachment(api, x);
419
593
  return x;
420
594
  }),
421
595
  args: (delta.deltaMessageReply.repliedToMessage.body || "").trim().split(/\s+/),
@@ -424,14 +598,12 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
424
598
  mentions: rmentions,
425
599
  timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp
426
600
  };
427
- }
428
- else if (delta.deltaMessageReply.replyToMessageId) {
601
+ } else if (delta.deltaMessageReply.replyToMessageId) {
429
602
  return defaultFuncs
430
603
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, {
431
604
  "av": ctx.globalOptions.pageID,
432
605
  "queries": JSON.stringify({
433
606
  "o0": {
434
- //Using the same doc_id as forcedFetch
435
607
  "doc_id": "2848441488556444",
436
608
  "query_params": {
437
609
  "thread_and_message_id": {
@@ -443,28 +615,21 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
443
615
  })
444
616
  })
445
617
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
446
- .then((resData) => {
618
+ .then(function (resData) {
447
619
  if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
448
620
  if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
449
621
  var fetchData = resData[0].o0.data.message;
450
622
  var mobj = {};
451
623
  for (var n in fetchData.message.ranges) mobj[fetchData.message.ranges[n].entity.id] = (fetchData.message.text || "").substr(fetchData.message.ranges[n].offset, fetchData.message.ranges[n].length);
452
-
453
624
  callbackToReturn.messageReply = {
454
625
  threadID: callbackToReturn.threadID,
455
626
  messageID: fetchData.message_id,
456
627
  senderID: fetchData.message_sender.id.toString(),
457
- attachments: fetchData.message.blob_attachment.map(att => {
628
+ attachments: fetchData.message.blob_attachment.map(function (att) {
458
629
  var x;
459
- try {
460
- x = utils._formatAttachment({ blob_attachment: att });
461
- }
462
- catch (ex) {
463
- x = att;
464
- x.error = ex;
465
- x.type = "unknown";
466
- }
467
- attachImgbbUrlToAttachment(api, x);
630
+ try { x = utils._formatAttachment({ blob_attachment: att }); }
631
+ catch (ex) { x = att; x.error = ex; x.type = "unknown"; }
632
+ attachImageUrlToAttachment(api, x);
468
633
  return x;
469
634
  }),
470
635
  args: (fetchData.message.text || "").trim().split(/\s+/) || [],
@@ -474,16 +639,16 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
474
639
  timestamp: parseInt(fetchData.timestamp_precise)
475
640
  };
476
641
  })
477
- .catch(err => log.error("forcedFetch", err))
642
+ .catch(function (err) { log.error("forcedFetch", err); })
478
643
  .finally(function () {
479
644
  if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
480
645
  !ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
481
646
  });
647
+ } else {
648
+ callbackToReturn.delta = delta;
482
649
  }
483
- else callbackToReturn.delta = delta;
484
650
 
485
651
  if (ctx.globalOptions.autoMarkDelivery) markDelivery(ctx, api, callbackToReturn.threadID, callbackToReturn.messageID);
486
-
487
652
  return !ctx.globalOptions.selfListen && callbackToReturn.senderID === ctx.userID ? undefined : (function () { globalCallback(null, callbackToReturn); })();
488
653
  }
489
654
  }
@@ -492,22 +657,17 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
492
657
  }
493
658
 
494
659
  if (v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents) return;
660
+
495
661
  switch (v.delta.class) {
496
662
  case "JoinableMode": {
497
- let fmtMsg;
498
- try {
499
- fmtMsg = utils.formatDeltaEvent(v.delta);
500
- } catch (err) {
501
- return globalCallback({
502
- error: "Lỗi gòi!!",
503
- detail: err,
504
- res: v.delta,
505
- type: "parse_error"
506
- });
663
+ var fmtMsg;
664
+ try { fmtMsg = utils.formatDeltaEvent(v.delta); }
665
+ catch (err) {
666
+ return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
507
667
  }
508
668
  return globalCallback(null, fmtMsg);
509
669
  }
510
- case "AdminTextMessage":
670
+ case "AdminTextMessage": {
511
671
  switch (v.delta.type) {
512
672
  case 'confirm_friend_request':
513
673
  case 'shared_album_delete':
@@ -524,58 +684,44 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
524
684
  case "magic_words":
525
685
  case "change_thread_approval_mode":
526
686
  case "messenger_call_log":
527
- case "participant_joined_group_call":
687
+ case "participant_joined_group_call": {
528
688
  var fmtMsg;
529
- try {
530
- fmtMsg = utils.formatDeltaEvent(v.delta);
531
- }
689
+ try { fmtMsg = utils.formatDeltaEvent(v.delta); }
532
690
  catch (err) {
533
- return globalCallback({
534
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
535
- detail: err,
536
- res: v.delta,
537
- type: "parse_error"
538
- });
691
+ return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
539
692
  }
540
693
  return (function () { globalCallback(null, fmtMsg); })();
541
- default:
542
- // console.log(v.delta)
543
- return;
694
+ }
695
+ default: return;
544
696
  }
545
- //For group images
546
- case "ForcedFetch":
697
+ }
698
+ case "ForcedFetch": {
547
699
  if (!v.delta.threadKey) return;
548
700
  var mid = v.delta.messageId;
549
701
  var tid = v.delta.threadKey.threadFbId;
550
702
  if (mid && tid) {
551
- const form = {
703
+ var fetchForm = {
552
704
  "av": ctx.globalOptions.pageID,
553
705
  "queries": JSON.stringify({
554
706
  "o0": {
555
- //This doc_id is valid as of March 25, 2020
556
707
  "doc_id": "2848441488556444",
557
708
  "query_params": {
558
709
  "thread_and_message_id": {
559
710
  "thread_id": tid.toString(),
560
- "message_id": mid,
711
+ "message_id": mid
561
712
  }
562
713
  }
563
714
  }
564
715
  })
565
716
  };
566
-
567
717
  defaultFuncs
568
- .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
718
+ .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, fetchForm)
569
719
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
570
- .then((resData) => {
720
+ .then(function (resData) {
571
721
  if (resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
572
-
573
722
  if (resData[resData.length - 1].successful_results === 0) throw { error: "forcedFetch: there was no successful_results", res: resData };
574
-
575
723
  var fetchData = resData[0].o0.data.message;
576
-
577
724
  if (utils.getType(fetchData) == "Object") {
578
- log.info("forcedFetch", fetchData);
579
725
  switch (fetchData.__typename) {
580
726
  case "ThreadImageMessage":
581
727
  (!ctx.globalOptions.selfListen && fetchData.message_sender.id.toString() === ctx.userID) ||
@@ -596,35 +742,6 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
596
742
  })();
597
743
  break;
598
744
  case "UserMessage":
599
- log.info("ff-Return", {
600
- type: "message",
601
- senderID: utils.formatID(fetchData.message_sender.id),
602
- body: fetchData.message.text || "",
603
- threadID: utils.formatID(tid.toString()),
604
- messageID: fetchData.message_id,
605
- attachments: [{
606
- type: "share",
607
- ID: fetchData.extensible_attachment.legacy_attachment_id,
608
- url: fetchData.extensible_attachment.story_attachment.url,
609
-
610
- title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
611
- description: fetchData.extensible_attachment.story_attachment.description.text,
612
- source: fetchData.extensible_attachment.story_attachment.source,
613
-
614
- image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
615
- width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
616
- height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
617
- playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
618
- duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
619
-
620
- subattachments: fetchData.extensible_attachment.subattachments,
621
- properties: fetchData.extensible_attachment.story_attachment.properties,
622
- }],
623
- mentions: {},
624
- timestamp: parseInt(fetchData.timestamp_precise),
625
- participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
626
- isGroup: (fetchData.message_sender.id != tid.toString())
627
- });
628
745
  globalCallback(null, {
629
746
  type: "message",
630
747
  senderID: utils.formatID(fetchData.message_sender.id),
@@ -635,178 +752,64 @@ function parseDelta(defaultFuncs, api, ctx, globalCallback, v) {
635
752
  type: "share",
636
753
  ID: fetchData.extensible_attachment.legacy_attachment_id,
637
754
  url: fetchData.extensible_attachment.story_attachment.url,
638
-
639
755
  title: fetchData.extensible_attachment.story_attachment.title_with_entities.text,
640
756
  description: fetchData.extensible_attachment.story_attachment.description.text,
641
757
  source: fetchData.extensible_attachment.story_attachment.source,
642
-
643
758
  image: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).uri,
644
759
  width: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).width,
645
760
  height: ((fetchData.extensible_attachment.story_attachment.media || {}).image || {}).height,
646
761
  playable: (fetchData.extensible_attachment.story_attachment.media || {}).is_playable || false,
647
762
  duration: (fetchData.extensible_attachment.story_attachment.media || {}).playable_duration_in_ms || 0,
648
-
649
763
  subattachments: fetchData.extensible_attachment.subattachments,
650
764
  properties: fetchData.extensible_attachment.story_attachment.properties,
651
765
  }],
652
766
  mentions: {},
653
767
  timestamp: parseInt(fetchData.timestamp_precise),
654
- participantIDs: (fetchData.participants || (fetchData.messageMetadata ? fetchData.messageMetadata.cid ? fetchData.messageMetadata.cid.canonicalParticipantFbids : fetchData.messageMetadata.participantIds : []) || []),
655
768
  isGroup: (fetchData.message_sender.id != tid.toString())
656
769
  });
770
+ break;
657
771
  }
658
- }
659
- else log.error("forcedFetch", fetchData);
772
+ } else log.error("forcedFetch", fetchData);
660
773
  })
661
- .catch((err) => log.error("forcedFetch", err));
774
+ .catch(function (err) { log.error("forcedFetch", err); });
662
775
  }
663
776
  break;
777
+ }
664
778
  case "ThreadName":
665
779
  case "ParticipantsAddedToGroupThread":
666
- case "ParticipantLeftGroupThread":
780
+ case "ParticipantLeftGroupThread": {
667
781
  var formattedEvent;
668
- try {
669
- formattedEvent = utils.formatDeltaEvent(v.delta);
670
- }
782
+ try { formattedEvent = utils.formatDeltaEvent(v.delta); }
671
783
  catch (err) {
672
- return globalCallback({
673
- error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.",
674
- detail: err,
675
- res: v.delta,
676
- type: "parse_error"
677
- });
784
+ return globalCallback({ error: "Problem parsing message object.", detail: err, res: v.delta, type: "parse_error" });
678
785
  }
679
786
  return (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) || !ctx.loggedIn ? undefined : (function () { globalCallback(null, formattedEvent); })();
787
+ }
680
788
  }
681
789
  }
682
790
 
683
791
  function markDelivery(ctx, api, threadID, messageID) {
684
792
  if (threadID && messageID) {
685
- api.markAsDelivered(threadID, messageID, (err) => {
793
+ api.markAsDelivered(threadID, messageID, function (err) {
686
794
  if (err) log.error("markAsDelivered", err);
687
- else {
688
- if (ctx.globalOptions.autoMarkRead) {
689
- api.markAsRead(threadID, (err) => {
690
- if (err) log.error("markAsDelivered", err);
691
- });
692
- }
795
+ else if (ctx.globalOptions.autoMarkRead) {
796
+ api.markAsRead(threadID, function (err) {
797
+ if (err) log.error("markAsDelivered", err);
798
+ });
693
799
  }
694
800
  });
695
801
  }
696
802
  }
697
803
 
698
804
  module.exports = function (defaultFuncs, api, ctx) {
699
- let globalCallback = identity;
700
- // function getSeqID() {
701
- // ctx.t_mqttCalled = false;
702
- // async function attemptRequest(retries = 3) {
703
- // try {
704
- // if (!ctx.fb_dtsg) {
705
- // const dtsg = await api.getFreshDtsg();
706
- // if (!dtsg) {
707
- // if (retries > 0) {
708
- // logger.Warning("Failed to get fb_dtsg, retrying...");
709
- // await utils.sleep(2000); // Longer delay for token retry
710
- // return attemptRequest(retries - 1);
711
- // }
712
- // throw { error: "Could not obtain fb_dtsg after multiple attempts" };
713
- // }
714
- // ctx.fb_dtsg = dtsg;
715
- // }
716
-
717
- // const form = {
718
- // av: ctx.userID,
719
- // fb_dtsg: ctx.fb_dtsg,
720
- // queries: JSON.stringify({
721
- // o0: {
722
- // doc_id: '3336396659757871',
723
- // query_params: {
724
- // limit: 1,
725
- // before: null,
726
- // tags: ['INBOX'],
727
- // includeDeliveryReceipts: false,
728
- // includeSeqID: true
729
- // }
730
- // }
731
- // }),
732
- // __user: ctx.userID,
733
- // __a: '1',
734
- // __req: '8',
735
- // __hs: '19577.HYP:comet_pkg.2.1..2.1',
736
- // dpr: '1',
737
- // fb_api_caller_class: 'RelayModern',
738
- // fb_api_req_friendly_name: 'MessengerGraphQLThreadlistFetcher'
739
- // };
740
-
741
- // const headers = {
742
- // 'Content-Type': 'application/x-www-form-urlencoded',
743
- // 'Referer': 'https://www.facebook.com/',
744
- // 'Origin': 'https://www.facebook.com',
745
- // 'sec-fetch-site': 'same-origin',
746
- // 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
747
- // 'Cookie': ctx.jar.getCookieString('https://www.facebook.com'),
748
- // 'accept': '*/*',
749
- // 'accept-encoding': 'gzip, deflate, br'
750
- // };
751
-
752
- // const resData = await defaultFuncs
753
- // .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form, { headers })
754
- // .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
755
-
756
- // if (debugSeq) {
757
- // console.log('GraphQL SeqID Response:', JSON.stringify(resData, null, 2));
758
- // }
759
-
760
- // if (resData.error === 1357004 || resData.error === 1357001) {
761
- // if (retries > 0) {
762
- // logger.Warning("Session error, refreshing token and retrying...");
763
- // ctx.fb_dtsg = null; // Force new token
764
- // await utils.sleep(2000);
765
- // return attemptRequest(retries - 1);
766
- // }
767
- // throw { error: "Session refresh failed after retries" };
768
- // }
769
-
770
- // if (!Array.isArray(resData)) {
771
- // throw { error: "Invalid response format", res: resData };
772
- // }
773
-
774
- // const seqID = resData[0]?.o0?.data?.viewer?.message_threads?.sync_sequence_id;
775
- // if (!seqID) {
776
- // throw { error: "Missing sync_sequence_id", res: resData };
777
- // }
778
-
779
- // ctx.lastSeqId = seqID;
780
- // if (debugSeq) {
781
- // console.log('Got SeqID:', ctx.lastSeqId);
782
- // }
783
-
784
- // return listenMqtt(defaultFuncs, api, ctx, globalCallback);
785
-
786
- // } catch (err) {
787
- // if (retries > 0) {
788
- // console.log("Request failed, retrying...");
789
-
790
- // return attemptRequest(retries - 1);
791
- // }
792
- // throw err;
793
- // }
794
- // }
795
-
796
- // return attemptRequest()
797
- // .catch((err) => {
798
- // log.error("getSeqId", err);
799
- // if (utils.getType(err) == "Object" && err.error === "Not logged in") ctx.loggedIn = false;
800
- // return globalCallback(err);
801
- // });
802
- // }
805
+ var globalCallback = identity;
803
806
 
804
807
  getSeqID = function getSeqID() {
805
808
  ctx.t_mqttCalled = false;
806
809
  defaultFuncs
807
810
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
808
811
  .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
809
- .then((resData) => {
812
+ .then(function (resData) {
810
813
  if (utils.getType(resData) != "Array") throw { error: "Not logged in", res: resData };
811
814
  if (resData && resData[resData.length - 1].error_results > 0) throw resData[0].o0.errors;
812
815
  if (resData[resData.length - 1].successful_results === 0) throw { error: "getSeqId: there was no successful_results", res: resData };
@@ -815,7 +818,7 @@ module.exports = function (defaultFuncs, api, ctx) {
815
818
  listenMqtt(defaultFuncs, api, ctx, globalCallback);
816
819
  } else throw { error: "getSeqId: no sync_sequence_id found.", res: resData };
817
820
  })
818
- .catch((err) => {
821
+ .catch(function (err) {
819
822
  log.error("getSeqId", err);
820
823
  if (utils.getType(err) == "Object" && err.error === "Not logged in") ctx.loggedIn = false;
821
824
  return globalCallback(err);
@@ -825,8 +828,7 @@ module.exports = function (defaultFuncs, api, ctx) {
825
828
  return function (callback) {
826
829
  class MessageEmitter extends EventEmitter {
827
830
  stopListening(callback) {
828
-
829
- callback = callback || (() => { });
831
+ callback = callback || (function () { });
830
832
  globalCallback = identity;
831
833
  if (ctx.mqttClient) {
832
834
  ctx.mqttClient.unsubscribe("/webrtc");
@@ -841,23 +843,19 @@ module.exports = function (defaultFuncs, api, ctx) {
841
843
  }
842
844
 
843
845
  async stopListeningAsync() {
844
- return new Promise((resolve) => {
846
+ return new Promise(function (resolve) {
845
847
  this.stopListening(resolve);
846
- });
848
+ }.bind(this));
847
849
  }
848
850
  }
849
851
 
850
- const msgEmitter = new MessageEmitter();
852
+ var msgEmitter = new MessageEmitter();
851
853
  globalCallback = (callback || function (error, message) {
852
- if (error) {
853
- return msgEmitter.emit("error", error);
854
- }
854
+ if (error) return msgEmitter.emit("error", error);
855
855
  msgEmitter.emit("message", message);
856
856
  });
857
857
 
858
- // Reset some stuff
859
- if (!ctx.firstListen)
860
- ctx.lastSeqId = null;
858
+ if (!ctx.firstListen) ctx.lastSeqId = null;
861
859
  ctx.syncToken = undefined;
862
860
  ctx.t_mqttCalled = false;
863
861
 
@@ -883,8 +881,8 @@ module.exports = function (defaultFuncs, api, ctx) {
883
881
  listenMqtt(defaultFuncs, api, ctx, globalCallback);
884
882
  }
885
883
 
886
- api.stopListening = msgEmitter.stopListening;
887
- api.stopListeningAsync = msgEmitter.stopListeningAsync;
884
+ api.stopListening = msgEmitter.stopListening.bind(msgEmitter);
885
+ api.stopListeningAsync = msgEmitter.stopListeningAsync.bind(msgEmitter);
888
886
  return msgEmitter;
889
887
  };
890
- };
888
+ };