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