shadowx-fca 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/utils.js +230 -298
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadowx-fca",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Unofficial Facebook Chat API for Node.js with Auto-Update System - modify by Mueid Mursalin Rifat",
5
5
  "main": "index.js",
6
6
  "files": [
package/utils.js CHANGED
@@ -1,6 +1,6 @@
1
+
1
2
  // @ts-nocheck
2
3
  /* eslint-disable no-undef */
3
-
4
4
  /* eslint-disable no-prototype-builtins */
5
5
 
6
6
  "use strict";
@@ -14,7 +14,6 @@ var request = bluebird.promisify(require("request").defaults({ jar: true }));
14
14
  /**
15
15
  * @param {any} url
16
16
  */
17
-
18
17
  function setProxy(url) {
19
18
  if (typeof url == "undefined") return request = bluebird.promisify(require("request").defaults({ jar: true }));
20
19
  return request = bluebird.promisify(require("request").defaults({ jar: true, proxy: url }));
@@ -26,7 +25,6 @@ function setProxy(url) {
26
25
  * @param {{ region: any; }} [ctx]
27
26
  * @param {undefined} [customHeader]
28
27
  */
29
-
30
28
  function getHeaders(url, options, ctx, customHeader) {
31
29
  var headers = {
32
30
  "Content-Type": "application/x-www-form-urlencoded",
@@ -47,7 +45,6 @@ function getHeaders(url, options, ctx, customHeader) {
47
45
  /**
48
46
  * @param {{ _read: any; _readableState: any; }} obj
49
47
  */
50
-
51
48
  function isReadableStream(obj) {
52
49
  return (
53
50
  obj instanceof stream.Stream &&
@@ -64,9 +61,7 @@ function isReadableStream(obj) {
64
61
  * @param {any} options
65
62
  * @param {any} ctx
66
63
  */
67
-
68
64
  function get(url, jar, qs, options, ctx) {
69
- // I'm still confused about this
70
65
  if (getType(qs) === "Object")
71
66
  for (var prop in qs)
72
67
  if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") qs[prop] = JSON.stringify(qs[prop]);
@@ -103,16 +98,11 @@ function post(url, jar, form, options, ctx, customHeader) {
103
98
  /**
104
99
  * @param {any} url
105
100
  * @param {any} jar
106
- * @param {{ __user: any; __req: string; __rev: any; __a: number;
107
- // __af: siteData.features,
108
- fb_dtsg: any; jazoest: any; }} form
109
- * @param {{ __user: any; __req: string; __rev: any; __a: number;
110
- // __af: siteData.features,
111
- fb_dtsg: any; jazoest: any; }} qs
101
+ * @param {{ __user: any; __req: string; __rev: any; __a: number; fb_dtsg: any; jazoest: any; }} form
102
+ * @param {{ __user: any; __req: string; __rev: any; __a: number; fb_dtsg: any; jazoest: any; }} qs
112
103
  * @param {any} options
113
104
  * @param {any} ctx
114
105
  */
115
-
116
106
  function postFormData(url, jar, form, qs, options, ctx) {
117
107
  var headers = getHeaders(url, options, ctx);
118
108
  headers["Content-Type"] = "multipart/form-data";
@@ -136,7 +126,6 @@ function postFormData(url, jar, form, qs, options, ctx) {
136
126
  * @param {string | number | any[]} val
137
127
  * @param {number} [len]
138
128
  */
139
-
140
129
  function padZeros(val, len) {
141
130
  val = String(val);
142
131
  len = len || 2;
@@ -147,7 +136,6 @@ function padZeros(val, len) {
147
136
  /**
148
137
  * @param {any} clientID
149
138
  */
150
-
151
139
  function generateThreadingID(clientID) {
152
140
  var k = Date.now();
153
141
  var l = Math.floor(Math.random() * 4294967295);
@@ -158,7 +146,6 @@ function generateThreadingID(clientID) {
158
146
  /**
159
147
  * @param {string | any[]} data
160
148
  */
161
-
162
149
  function binaryToDecimal(data) {
163
150
  var ret = "";
164
151
  while (data !== "0") {
@@ -230,7 +217,6 @@ var j = {
230
217
  /**
231
218
  * @param {string | number | boolean} str
232
219
  */
233
-
234
220
  function presenceEncode(str) {
235
221
  return encodeURIComponent(str)
236
222
  .replace(/([_A-Z])|%../g, function (m, n) {
@@ -242,11 +228,9 @@ function presenceEncode(str) {
242
228
  });
243
229
  }
244
230
 
245
- // eslint-disable-next-line no-unused-vars
246
231
  /**
247
232
  * @param {string} str
248
233
  */
249
-
250
234
  function presenceDecode(str) {
251
235
  return decodeURIComponent(
252
236
  str.replace(/[_A-Z]/g, function (/** @type {string | number} */m) {
@@ -258,7 +242,6 @@ function presenceDecode(str) {
258
242
  /**
259
243
  * @param {string} userID
260
244
  */
261
-
262
245
  function generatePresence(userID) {
263
246
  var time = Date.now();
264
247
  return (
@@ -302,20 +285,10 @@ function generateAccessiblityCookie() {
302
285
  }
303
286
 
304
287
  function getGUID() {
305
- /** @type {number} */
306
-
307
288
  var sectionLength = Date.now();
308
- /** @type {string} */
309
-
310
289
  var id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
311
- /** @type {number} */
312
-
313
290
  var r = Math.floor((sectionLength + Math.random() * 16) % 16);
314
- /** @type {number} */
315
-
316
291
  sectionLength = Math.floor(sectionLength / 16);
317
- /** @type {string} */
318
-
319
292
  var _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
320
293
  return _guid;
321
294
  });
@@ -326,15 +299,7 @@ function getGUID() {
326
299
  * @param {{ mercury: any; blob_attachment: any; attach_type: any; sticker_attachment: any; extensible_attachment: { story_attachment: { target: { __typename: string; }; }; }; metadata: { stickerID: { toString: () => any; }; packID: { toString: () => any; }; spriteURI: any; spriteURI2x: any; width: any; height: any; frameCount: any; frameRate: any; framesPerRow: any; framesPerCol: any; fbid: { toString: () => any; }; url: any; dimensions: { split: (arg0: string) => any[]; width: any; height: any; }; duration: any; }; url: any; name: any; fileName: any; thumbnail_url: any; preview_url: any; preview_width: any; preview_height: any; large_preview_url: any; large_preview_width: any; large_preview_height: any; share: { share_id: { toString: () => any; }; title: any; description: any; source: any; media: { image: any; image_size: { width: any; height: any; }; playable: any; duration: any; animated_image_size: any; }; subattachments: any; uri: any; target: any; style_list: any; }; }} attachment1
327
300
  * @param {{ caption?: any; description?: any; id: any; is_malicious?: any; mime_type?: any; file_size?: any; filename?: any; image_data: any; href?: any; }} [attachment2]
328
301
  */
329
-
330
302
  function _formatAttachment(attachment1, attachment2) {
331
- // TODO: THIS IS REALLY BAD
332
- // This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
333
- // two attachment objects, but sometimes only one. They each contain part of the
334
- // data that you'd want so we merge them for convenience.
335
- // Instead of having a bunch of if statements guarding every access to image_data,
336
- // we set it to empty object and use the fact that it'll return undefined.
337
-
338
303
  attachment2 = attachment2 || { id: "", image_data: {} };
339
304
  attachment1 = attachment1.mercury ? attachment1.mercury : attachment1;
340
305
  var blob = attachment1.blob_attachment;
@@ -354,32 +319,27 @@ function _formatAttachment(attachment1, attachment2) {
354
319
 
355
320
  blob = attachment1.extensible_attachment;
356
321
  }
357
- // TODO: Determine whether "sticker", "photo", "file" etc are still used
358
- // KEEP IN SYNC WITH getThreadHistory
322
+
359
323
  switch (type) {
360
324
  case "sticker":
361
325
  return {
362
326
  type: "sticker",
363
327
  ID: attachment1.metadata.stickerID.toString(),
364
328
  url: attachment1.url,
365
-
366
329
  packID: attachment1.metadata.packID.toString(),
367
330
  spriteUrl: attachment1.metadata.spriteURI,
368
331
  spriteUrl2x: attachment1.metadata.spriteURI2x,
369
332
  width: attachment1.metadata.width,
370
333
  height: attachment1.metadata.height,
371
-
372
334
  caption: attachment2.caption,
373
335
  description: attachment2.description,
374
-
375
336
  frameCount: attachment1.metadata.frameCount,
376
337
  frameRate: attachment1.metadata.frameRate,
377
338
  framesPerRow: attachment1.metadata.framesPerRow,
378
339
  framesPerCol: attachment1.metadata.framesPerCol,
379
-
380
- stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
381
- spriteURI: attachment1.metadata.spriteURI, // @Legacy
382
- spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
340
+ stickerID: attachment1.metadata.stickerID.toString(),
341
+ spriteURI: attachment1.metadata.spriteURI,
342
+ spriteURI2x: attachment1.metadata.spriteURI2x
383
343
  };
384
344
  case "file":
385
345
  return {
@@ -387,13 +347,11 @@ function _formatAttachment(attachment1, attachment2) {
387
347
  filename: attachment1.name,
388
348
  ID: attachment2.id.toString(),
389
349
  url: attachment1.url,
390
-
391
350
  isMalicious: attachment2.is_malicious,
392
351
  contentType: attachment2.mime_type,
393
-
394
- name: attachment1.name, // @Legacy
395
- mimeType: attachment2.mime_type, // @Legacy
396
- fileSize: attachment2.file_size // @Legacy
352
+ name: attachment1.name,
353
+ mimeType: attachment2.mime_type,
354
+ fileSize: attachment2.file_size
397
355
  };
398
356
  case "photo":
399
357
  return {
@@ -401,94 +359,77 @@ function _formatAttachment(attachment1, attachment2) {
401
359
  ID: attachment1.metadata.fbid.toString(),
402
360
  filename: attachment1.fileName,
403
361
  thumbnailUrl: attachment1.thumbnail_url,
404
-
405
362
  previewUrl: attachment1.preview_url,
406
363
  previewWidth: attachment1.preview_width,
407
364
  previewHeight: attachment1.preview_height,
408
-
409
365
  largePreviewUrl: attachment1.large_preview_url,
410
366
  largePreviewWidth: attachment1.large_preview_width,
411
367
  largePreviewHeight: attachment1.large_preview_height,
412
-
413
- url: attachment1.metadata.url, // @Legacy
414
- width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
415
- height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
416
- name: attachment1.fileName // @Legacy
368
+ url: attachment1.metadata.url,
369
+ width: attachment1.metadata.dimensions.split(",")[0],
370
+ height: attachment1.metadata.dimensions.split(",")[1],
371
+ name: attachment1.fileName
417
372
  };
418
373
  case "animated_image":
419
374
  return {
420
375
  type: "animated_image",
421
376
  ID: attachment2.id.toString(),
422
377
  filename: attachment2.filename,
423
-
424
378
  previewUrl: attachment1.preview_url,
425
379
  previewWidth: attachment1.preview_width,
426
380
  previewHeight: attachment1.preview_height,
427
-
428
381
  url: attachment2.image_data.url,
429
382
  width: attachment2.image_data.width,
430
383
  height: attachment2.image_data.height,
431
-
432
- name: attachment1.name, // @Legacy
433
- facebookUrl: attachment1.url, // @Legacy
434
- thumbnailUrl: attachment1.thumbnail_url, // @Legacy
435
- mimeType: attachment2.mime_type, // @Legacy
436
- rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
437
- rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
438
- animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
439
- animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
440
- animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
441
- animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
384
+ name: attachment1.name,
385
+ facebookUrl: attachment1.url,
386
+ thumbnailUrl: attachment1.thumbnail_url,
387
+ mimeType: attachment2.mime_type,
388
+ rawGifImage: attachment2.image_data.raw_gif_image,
389
+ rawWebpImage: attachment2.image_data.raw_webp_image,
390
+ animatedGifUrl: attachment2.image_data.animated_gif_url,
391
+ animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url,
392
+ animatedWebpUrl: attachment2.image_data.animated_webp_url,
393
+ animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url
442
394
  };
443
395
  case "share":
444
396
  return {
445
397
  type: "share",
446
398
  ID: attachment1.share.share_id.toString(),
447
399
  url: attachment2.href,
448
-
449
400
  title: attachment1.share.title,
450
401
  description: attachment1.share.description,
451
402
  source: attachment1.share.source,
452
-
453
403
  image: attachment1.share.media.image,
454
404
  width: attachment1.share.media.image_size.width,
455
405
  height: attachment1.share.media.image_size.height,
456
406
  playable: attachment1.share.media.playable,
457
407
  duration: attachment1.share.media.duration,
458
-
459
408
  subattachments: attachment1.share.subattachments,
460
409
  properties: {},
461
-
462
- animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
463
- facebookUrl: attachment1.share.uri, // @Legacy
464
- target: attachment1.share.target, // @Legacy
465
- styleList: attachment1.share.style_list // @Legacy
410
+ animatedImageSize: attachment1.share.media.animated_image_size,
411
+ facebookUrl: attachment1.share.uri,
412
+ target: attachment1.share.target,
413
+ styleList: attachment1.share.style_list
466
414
  };
467
415
  case "video":
468
416
  return {
469
417
  type: "video",
470
418
  ID: attachment1.metadata.fbid.toString(),
471
419
  filename: attachment1.name,
472
-
473
420
  previewUrl: attachment1.preview_url,
474
421
  previewWidth: attachment1.preview_width,
475
422
  previewHeight: attachment1.preview_height,
476
-
477
423
  url: attachment1.url,
478
424
  width: attachment1.metadata.dimensions.width,
479
425
  height: attachment1.metadata.dimensions.height,
480
-
481
426
  duration: attachment1.metadata.duration,
482
427
  videoType: "unknown",
483
-
484
- thumbnailUrl: attachment1.thumbnail_url // @Legacy
428
+ thumbnailUrl: attachment1.thumbnail_url
485
429
  };
486
430
  case "error":
487
431
  return {
488
432
  type: "error",
489
-
490
- // Save error attachments because we're unsure of their format,
491
- // and whether there are cases they contain something useful for debugging.
492
433
  attachment1: attachment1,
493
434
  attachment2: attachment2
494
435
  };
@@ -498,72 +439,60 @@ function _formatAttachment(attachment1, attachment2) {
498
439
  ID: blob.legacy_attachment_id,
499
440
  filename: blob.filename,
500
441
  thumbnailUrl: blob.thumbnail.uri,
501
-
502
442
  previewUrl: blob.preview.uri,
503
443
  previewWidth: blob.preview.width,
504
444
  previewHeight: blob.preview.height,
505
-
506
445
  largePreviewUrl: blob.large_preview.uri,
507
446
  largePreviewWidth: blob.large_preview.width,
508
447
  largePreviewHeight: blob.large_preview.height,
509
-
510
- url: blob.large_preview.uri, // @Legacy
511
- width: blob.original_dimensions.x, // @Legacy
512
- height: blob.original_dimensions.y, // @Legacy
513
- name: blob.filename // @Legacy
448
+ url: blob.large_preview.uri,
449
+ width: blob.original_dimensions.x,
450
+ height: blob.original_dimensions.y,
451
+ name: blob.filename
514
452
  };
515
453
  case "MessageAnimatedImage":
516
454
  return {
517
455
  type: "animated_image",
518
456
  ID: blob.legacy_attachment_id,
519
457
  filename: blob.filename,
520
-
521
458
  previewUrl: blob.preview_image.uri,
522
459
  previewWidth: blob.preview_image.width,
523
460
  previewHeight: blob.preview_image.height,
524
-
525
461
  url: blob.animated_image.uri,
526
462
  width: blob.animated_image.width,
527
463
  height: blob.animated_image.height,
528
-
529
- thumbnailUrl: blob.preview_image.uri, // @Legacy
530
- name: blob.filename, // @Legacy
531
- facebookUrl: blob.animated_image.uri, // @Legacy
532
- rawGifImage: blob.animated_image.uri, // @Legacy
533
- animatedGifUrl: blob.animated_image.uri, // @Legacy
534
- animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
535
- animatedWebpUrl: blob.animated_image.uri, // @Legacy
536
- animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
464
+ thumbnailUrl: blob.preview_image.uri,
465
+ name: blob.filename,
466
+ facebookUrl: blob.animated_image.uri,
467
+ rawGifImage: blob.animated_image.uri,
468
+ animatedGifUrl: blob.animated_image.uri,
469
+ animatedGifPreviewUrl: blob.preview_image.uri,
470
+ animatedWebpUrl: blob.animated_image.uri,
471
+ animatedWebpPreviewUrl: blob.preview_image.uri
537
472
  };
538
473
  case "MessageVideo":
539
474
  return {
540
475
  type: "video",
541
476
  filename: blob.filename,
542
477
  ID: blob.legacy_attachment_id,
543
-
544
478
  previewUrl: blob.large_image.uri,
545
479
  previewWidth: blob.large_image.width,
546
480
  previewHeight: blob.large_image.height,
547
-
548
481
  url: blob.playable_url,
549
482
  width: blob.original_dimensions.x,
550
483
  height: blob.original_dimensions.y,
551
-
552
484
  duration: blob.playable_duration_in_ms,
553
485
  videoType: blob.video_type.toLowerCase(),
554
-
555
- thumbnailUrl: blob.large_image.uri // @Legacy
486
+ thumbnailUrl: blob.large_image.uri
556
487
  };
557
488
  case "MessageAudio":
558
489
  return {
559
490
  type: "audio",
560
491
  filename: blob.filename,
561
492
  ID: blob.url_shimhash,
562
-
563
493
  audioType: blob.audio_type,
564
494
  duration: blob.playable_duration_in_ms,
565
495
  url: blob.playable_url,
566
-
567
496
  isVoiceMail: blob.is_voicemail
568
497
  };
569
498
  case "StickerAttachment":
@@ -571,54 +500,43 @@ function _formatAttachment(attachment1, attachment2) {
571
500
  type: "sticker",
572
501
  ID: blob.id,
573
502
  url: blob.url,
574
-
575
503
  packID: blob.pack ? blob.pack.id : null,
576
504
  spriteUrl: blob.sprite_image,
577
505
  spriteUrl2x: blob.sprite_image_2x,
578
506
  width: blob.width,
579
507
  height: blob.height,
580
-
581
508
  caption: blob.label,
582
509
  description: blob.label,
583
-
584
510
  frameCount: blob.frame_count,
585
511
  frameRate: blob.frame_rate,
586
512
  framesPerRow: blob.frames_per_row,
587
513
  framesPerCol: blob.frames_per_column,
588
-
589
- stickerID: blob.id, // @Legacy
590
- spriteURI: blob.sprite_image, // @Legacy
591
- spriteURI2x: blob.sprite_image_2x // @Legacy
514
+ stickerID: blob.id,
515
+ spriteURI: blob.sprite_image,
516
+ spriteURI2x: blob.sprite_image_2x
592
517
  };
593
518
  case "MessageLocation":
594
519
  var urlAttach = blob.story_attachment.url;
595
520
  var mediaAttach = blob.story_attachment.media;
596
-
597
521
  var u = querystring.parse(url.parse(urlAttach).query).u;
598
522
  var where1 = querystring.parse(url.parse(u).query).where1;
599
523
  var address = where1.split(", ");
600
-
601
524
  var latitude;
602
525
  var longitude;
603
-
604
526
  try {
605
527
  latitude = Number.parseFloat(address[0]);
606
528
  longitude = Number.parseFloat(address[1]);
607
529
  } catch (err) {
608
530
  /* empty */
609
-
610
531
  }
611
-
612
532
  var imageUrl;
613
533
  var width;
614
534
  var height;
615
-
616
535
  if (mediaAttach && mediaAttach.image) {
617
536
  imageUrl = mediaAttach.image.uri;
618
537
  width = mediaAttach.image.width;
619
538
  height = mediaAttach.image.height;
620
539
  }
621
-
622
540
  return {
623
541
  type: "location",
624
542
  ID: blob.legacy_attachment_id,
@@ -629,22 +547,19 @@ function _formatAttachment(attachment1, attachment2) {
629
547
  height: height,
630
548
  url: u || urlAttach,
631
549
  address: where1,
632
-
633
- facebookUrl: blob.story_attachment.url, // @Legacy
634
- target: blob.story_attachment.target, // @Legacy
635
- styleList: blob.story_attachment.style_list // @Legacy
550
+ facebookUrl: blob.story_attachment.url,
551
+ target: blob.story_attachment.target,
552
+ styleList: blob.story_attachment.style_list
636
553
  };
637
554
  case "ExtensibleAttachment":
638
555
  return {
639
556
  type: "share",
640
557
  ID: blob.legacy_attachment_id,
641
558
  url: blob.story_attachment.url,
642
-
643
559
  title: blob.story_attachment.title_with_entities.text,
644
560
  description: blob.story_attachment.description &&
645
561
  blob.story_attachment.description.text,
646
562
  source: blob.story_attachment.source ? blob.story_attachment.source.text : null,
647
-
648
563
  image: blob.story_attachment.media &&
649
564
  blob.story_attachment.media.image &&
650
565
  blob.story_attachment.media.image.uri,
@@ -659,27 +574,23 @@ function _formatAttachment(attachment1, attachment2) {
659
574
  duration: blob.story_attachment.media &&
660
575
  blob.story_attachment.media.playable_duration_in_ms,
661
576
  playableUrl: blob.story_attachment.media == null ? null : blob.story_attachment.media.playable_url,
662
-
663
577
  subattachments: blob.story_attachment.subattachments,
664
578
  properties: blob.story_attachment.properties.reduce(function (/** @type {{ [x: string]: any; }} */obj, /** @type {{ key: string | number; value: { text: any; }; }} */cur) {
665
579
  obj[cur.key] = cur.value.text;
666
580
  return obj;
667
581
  }, {}),
668
-
669
- facebookUrl: blob.story_attachment.url, // @Legacy
670
- target: blob.story_attachment.target, // @Legacy
671
- styleList: blob.story_attachment.style_list // @Legacy
582
+ facebookUrl: blob.story_attachment.url,
583
+ target: blob.story_attachment.target,
584
+ styleList: blob.story_attachment.style_list
672
585
  };
673
586
  case "MessageFile":
674
587
  return {
675
588
  type: "file",
676
589
  filename: blob.filename,
677
590
  ID: blob.message_file_fbid,
678
-
679
591
  url: blob.url,
680
592
  isMalicious: blob.is_malicious,
681
593
  contentType: blob.content_type,
682
-
683
594
  name: blob.filename,
684
595
  mimeType: "",
685
596
  fileSize: -1
@@ -703,7 +614,6 @@ function _formatAttachment(attachment1, attachment2) {
703
614
  * @param {{ [x: string]: any; }} attachmentMap
704
615
  * @param {any} shareMap
705
616
  */
706
-
707
617
  function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
708
618
  attachmentMap = shareMap || attachmentMap;
709
619
  return attachments ?
@@ -719,19 +629,60 @@ function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
719
629
  }
720
630
 
721
631
  /**
722
- * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
632
+ * Extract mentions from message - supports legacy (data.prng) and new format (messageMetadata.data.data.Gb.asMap.data).
633
+ * @param {Object} m - Raw message object (NewMessage delta)
634
+ * @returns {Object} mentions - Map of userID -> mention text
723
635
  */
636
+ function getMentionsFromDeltaMessage(m) {
637
+ var body = m.body || "";
638
+ var mentions = {};
639
+ var mdata = [];
640
+ if (m.data && m.data.prng) {
641
+ try {
642
+ mdata = JSON.parse(m.data.prng);
643
+ } catch (e) {
644
+ mdata = [];
645
+ }
646
+ }
647
+ if (mdata.length > 0) {
648
+ for (var i = 0; i < mdata.length; i++) {
649
+ var id = mdata[i].i;
650
+ var o = parseInt(mdata[i].o, 10) || 0;
651
+ var l = parseInt(mdata[i].l, 10) || 0;
652
+ mentions[String(id)] = body.substring(o, o + l);
653
+ }
654
+ return mentions;
655
+ }
656
+ var md = m.messageMetadata;
657
+ if (md && md.data && md.data.data && md.data.data.Gb && md.data.data.Gb.asMap && md.data.data.Gb.asMap.data) {
658
+ var gbData = md.data.data.Gb.asMap.data;
659
+ for (var key in gbData) {
660
+ if (!Object.prototype.hasOwnProperty.call(gbData, key)) continue;
661
+ var entry = gbData[key];
662
+ if (entry && entry.asMap && entry.asMap.data) {
663
+ var d = entry.asMap.data;
664
+ var id = d.id && d.id.asLong ? String(d.id.asLong) : null;
665
+ var offset = parseInt((d.offset && d.offset.asLong) ? d.offset.asLong : 0, 10);
666
+ var len = parseInt((d.length && d.length.asLong) ? d.length.asLong : 0, 10);
667
+ if (id != null) {
668
+ mentions[id] = body.substring(offset, offset + len);
669
+ }
670
+ }
671
+ }
672
+ }
673
+ return mentions;
674
+ }
724
675
 
676
+ /**
677
+ * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
678
+ */
725
679
  function formatDeltaMessage(m) {
726
680
  var md = m.delta.messageMetadata;
727
- var mdata = m.delta.data === undefined ? [] : m.delta.data.prng === undefined ? [] : JSON.parse(m.delta.data.prng);
728
- var m_id = mdata.map(u => u.i);
729
- var m_offset = mdata.map(u => u.o);
730
- var m_length = mdata.map(u => u.l);
731
- var mentions = {};
732
681
  var body = m.delta.body || "";
682
+
683
+ // Use the new improved mention extraction function
684
+ var mentions = getMentionsFromDeltaMessage(m.delta);
733
685
  var args = body == "" ? [] : body.trim().split(/\s+/);
734
- for (var i = 0; i < m_id.length; i++) mentions[m_id[i]] = m.delta.body.substring(m_offset[i], m_offset[i] + m_length[i]);
735
686
 
736
687
  // Determine if this is a DM or group
737
688
  const otherUserFbId = md.threadKey.otherUserFbId;
@@ -750,7 +701,8 @@ function formatDeltaMessage(m) {
750
701
  timestamp: md.timestamp,
751
702
  isGroup: !!threadFbId,
752
703
  isSingleUser: isSingleUser,
753
- participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || []
704
+ participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || [],
705
+ isUnread: md.isUnread !== undefined ? md.isUnread : false
754
706
  };
755
707
  }
756
708
 
@@ -760,7 +712,6 @@ function formatID(id) {
760
712
  }
761
713
 
762
714
  function isDMThread(threadID) {
763
- // DM threads don't have 't_' prefix and are typically numeric user IDs
764
715
  return typeof threadID === 'string' && !threadID.includes('t_');
765
716
  }
766
717
 
@@ -828,7 +779,6 @@ function formatHistoryMessage(m) {
828
779
  /**
829
780
  * @param {{ type: any; }} m
830
781
  */
831
-
832
782
  function getAdminTextMessageType(m) {
833
783
  switch (m.type) {
834
784
  case "joinable_group_link_mode_change":
@@ -838,6 +788,7 @@ function getAdminTextMessageType(m) {
838
788
  case "change_thread_theme":
839
789
  return "log:thread-color";
840
790
  case "change_thread_icon":
791
+ case "change_thread_quick_reaction":
841
792
  return "log:thread-icon";
842
793
  case "change_thread_nickname":
843
794
  return "log:user-nickname";
@@ -852,13 +803,16 @@ function getAdminTextMessageType(m) {
852
803
  return "log:thread-call";
853
804
  case "pin_messages_v2":
854
805
  return "log:thread-pinned";
806
+ case "unpin_messages_v2":
807
+ return "log:unpin-message";
808
+ default:
809
+ return m.type;
855
810
  }
856
811
  }
857
812
 
858
813
  /**
859
814
  * @param {string} name
860
815
  */
861
-
862
816
  function getGenderByPhysicalMethod(name) {
863
817
  const female_name = [
864
818
  "Phương Chi",
@@ -2198,20 +2152,63 @@ function getGenderByPhysicalMethod(name) {
2198
2152
  }
2199
2153
 
2200
2154
  /**
2201
- * @param {{ [x: string]: { [x: string]: { [x: string]: any; }; }; class: any; untypedData: any; name: any; addedParticipants: any; leftParticipantFbId: any; messageMetadata: { threadKey: { threadFbId: any; otherUserFbId: any; }; adminText: any; actorFbId: any; }; participants: any; }} m
2155
+ * Extract mentions from message - supports legacy (data.prng) and new format (messageMetadata.data.data.Gb.asMap.data).
2156
+ * @param {Object} m - Raw message object (NewMessage delta)
2157
+ * @returns {Object} mentions - Map of userID -> mention text
2202
2158
  */
2159
+ function getMentionsFromDeltaMessage(m) {
2160
+ var body = m.body || "";
2161
+ var mentions = {};
2162
+ var mdata = [];
2163
+
2164
+ // Try legacy format (data.prng)
2165
+ if (m.data && m.data.prng) {
2166
+ try {
2167
+ mdata = JSON.parse(m.data.prng);
2168
+ } catch (e) {
2169
+ mdata = [];
2170
+ }
2171
+ }
2172
+
2173
+ if (mdata.length > 0) {
2174
+ for (var i = 0; i < mdata.length; i++) {
2175
+ var id = mdata[i].i;
2176
+ var o = parseInt(mdata[i].o, 10) || 0;
2177
+ var l = parseInt(mdata[i].l, 10) || 0;
2178
+ mentions[String(id)] = body.substring(o, o + l);
2179
+ }
2180
+ return mentions;
2181
+ }
2182
+
2183
+ // Try new format (messageMetadata.data.data.Gb.asMap.data)
2184
+ var md = m.messageMetadata;
2185
+ if (md && md.data && md.data.data && md.data.data.Gb &&
2186
+ md.data.data.Gb.asMap && md.data.data.Gb.asMap.data) {
2187
+ var gbData = md.data.data.Gb.asMap.data;
2188
+ for (var key in gbData) {
2189
+ if (!Object.prototype.hasOwnProperty.call(gbData, key)) continue;
2190
+ var entry = gbData[key];
2191
+ if (entry && entry.asMap && entry.asMap.data) {
2192
+ var d = entry.asMap.data;
2193
+ var id = d.id && d.id.asLong ? String(d.id.asLong) : null;
2194
+ var offset = parseInt((d.offset && d.offset.asLong) ? d.offset.asLong : 0, 10);
2195
+ var len = parseInt((d.length && d.length.asLong) ? d.length.asLong : 0, 10);
2196
+ if (id != null) {
2197
+ mentions[id] = body.substring(offset, offset + len);
2198
+ }
2199
+ }
2200
+ }
2201
+ }
2202
+ return mentions;
2203
+ }
2203
2204
 
2205
+ /**
2206
+ * @param {{ [x: string]: { [x: string]: { [x: string]: any; }; }; class: any; untypedData: any; name: any; addedParticipants: any; leftParticipantFbId: any; messageMetadata: { threadKey: { threadFbId: any; otherUserFbId: any; }; adminText: any; actorFbId: any; }; participants: any; }} m
2207
+ */
2204
2208
  function formatDeltaEvent(m) {
2205
2209
  var logMessageType;
2206
2210
  var logMessageData;
2207
2211
 
2208
- // log:thread-color => {theme_color}
2209
- // log:user-nickname => {participant_id, nickname}
2210
- // log:thread-icon => {thread_icon}
2211
- // log:thread-name => {name}
2212
- // log:subscribe => {addedParticipants - [Array]}
2213
- // log:unsubscribe => {leftParticipantFbId}
2214
- // console.log(m)
2215
2212
  switch (m.class) {
2216
2213
  case "JoinableMode":
2217
2214
  if (m.mode) return;
@@ -2248,16 +2245,46 @@ function formatDeltaEvent(m) {
2248
2245
  }
2249
2246
 
2250
2247
  /**
2251
- * @param {{ st: any; from: { toString: () => any; }; to: any; thread_fbid: any; hasOwnProperty: (arg0: string) => any; from_mobile: any; realtime_viewer_fbid: any; }} event
2248
+ * @param {{ delta: { messageMetadata: any; data: { prng: string; }; body: string; attachments: any; participants: any; }; }} m
2252
2249
  */
2250
+ function formatDeltaMessage(m) {
2251
+ var md = m.delta.messageMetadata;
2252
+ var body = m.delta.body || "";
2253
+
2254
+ // Use the new mention extraction function
2255
+ var mentions = getMentionsFromDeltaMessage(m.delta);
2256
+ var args = body == "" ? [] : body.trim().split(/\s+/);
2253
2257
 
2258
+ // Determine if this is a DM or group
2259
+ const otherUserFbId = md.threadKey.otherUserFbId;
2260
+ const threadFbId = md.threadKey.threadFbId;
2261
+ const isSingleUser = !!otherUserFbId && !threadFbId;
2262
+
2263
+ return {
2264
+ type: "message",
2265
+ senderID: formatID(md.actorFbId.toString()),
2266
+ threadID: formatID((threadFbId || otherUserFbId).toString()),
2267
+ messageID: md.messageId,
2268
+ args: args,
2269
+ body: body,
2270
+ attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
2271
+ mentions: mentions,
2272
+ timestamp: md.timestamp,
2273
+ isGroup: !!threadFbId,
2274
+ isSingleUser: isSingleUser,
2275
+ participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || [],
2276
+ isUnread: md.isUnread !== undefined ? md.isUnread : false
2277
+ };
2278
+ }
2279
+
2280
+ /**
2281
+ * @param {{ st: any; from: { toString: () => any; }; to: any; thread_fbid: any; hasOwnProperty: (arg0: string) => any; from_mobile: any; realtime_viewer_fbid: any; }} event
2282
+ */
2254
2283
  function formatTyp(event) {
2255
2284
  return {
2256
2285
  isTyping: !!event.st,
2257
2286
  from: event.from.toString(),
2258
2287
  threadID: formatID((event.to || event.thread_fbid || event.from).toString()),
2259
- // When receiving typ indication from mobile, `from_mobile` isn't set.
2260
- // If it is, we just use that value.
2261
2288
  fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
2262
2289
  userID: (event.realtime_viewer_fbid || event.from).toString(),
2263
2290
  type: "typ"
@@ -2267,22 +2294,18 @@ function formatTyp(event) {
2267
2294
  /**
2268
2295
  * @param {{ threadKey: { otherUserFbId: any; threadFbId: any; }; actorFbId: any; actionTimestampMs: any; }} delta
2269
2296
  */
2270
-
2271
- // function formatDeltaReadReceipt(delta) {
2272
- // // otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
2273
- // // In a group chat actorFbId is used for the reader and threadFbId for the thread.
2274
- // return {
2275
- // reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
2276
- // time: delta.actionTimestampMs,
2277
- // threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
2278
- // type: "read_receipt"
2279
- // };
2280
- // }
2297
+ function formatDeltaReadReceipt(delta) {
2298
+ return {
2299
+ reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
2300
+ time: delta.actionTimestampMs,
2301
+ threadID: formatID((delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()),
2302
+ type: "read_receipt"
2303
+ };
2304
+ }
2281
2305
 
2282
2306
  /**
2283
2307
  * @param {{ reader: { toString: () => any; }; time: any; thread_fbid: any; }} event
2284
2308
  */
2285
-
2286
2309
  function formatReadReceipt(event) {
2287
2310
  return {
2288
2311
  reader: event.reader.toString(),
@@ -2295,7 +2318,6 @@ function formatReadReceipt(event) {
2295
2318
  /**
2296
2319
  * @param {{ chat_ids: any[]; thread_fbids: any[]; timestamp: any; }} event
2297
2320
  */
2298
-
2299
2321
  function formatRead(event) {
2300
2322
  return {
2301
2323
  threadID: formatID(((event.chat_ids && event.chat_ids[0]) || (event.thread_fbids && event.thread_fbids[0])).toString()),
@@ -2309,7 +2331,6 @@ function formatRead(event) {
2309
2331
  * @param {string | any[]} startToken
2310
2332
  * @param {string} endToken
2311
2333
  */
2312
-
2313
2334
  function getFrom(str, startToken, endToken) {
2314
2335
  var start = str.indexOf(startToken) + startToken.length;
2315
2336
  if (start < startToken.length) return "";
@@ -2323,20 +2344,9 @@ function getFrom(str, startToken, endToken) {
2323
2344
  /**
2324
2345
  * @param {string} html
2325
2346
  */
2326
-
2327
2347
  function makeParsable(html) {
2328
- let withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/
2329
- , "");
2330
-
2331
- // (What the fuck FB, why windows style newlines?)
2332
- // So sometimes FB will send us base multiple objects in the same response.
2333
- // They're all valid JSON, one after the other, at the top level. We detect
2334
- // that and make it parse-able by JSON.parse.
2335
- // Ben - July 15th 2017
2336
- //
2337
- // It turns out that Facebook may insert random number of spaces before
2338
- // next object begins (issue #616)
2339
- // rav_kr - 2018-03-19
2348
+ let withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/ , "");
2349
+
2340
2350
  let maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
2341
2351
  if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
2342
2352
 
@@ -2346,7 +2356,6 @@ function makeParsable(html) {
2346
2356
  /**
2347
2357
  * @param {any} form
2348
2358
  */
2349
-
2350
2359
  function arrToForm(form) {
2351
2360
  return arrayToObject(form,
2352
2361
  function (/** @type {{ name: any; }} */v) {
@@ -2363,7 +2372,6 @@ function arrToForm(form) {
2363
2372
  * @param {{ (v: any): any; (arg0: any): string | number; }} getKey
2364
2373
  * @param {{ (v: any): any; (arg0: any): any; }} getValue
2365
2374
  */
2366
-
2367
2375
  function arrayToObject(arr, getKey, getValue) {
2368
2376
  return arr.reduce(function (/** @type {{ [x: string]: any; }} */
2369
2377
  acc, /** @type {any} */val) {
@@ -2386,26 +2394,10 @@ function generateTimestampRelative() {
2386
2394
  * @param {any} userID
2387
2395
  * @param {{ fb_dtsg: any; ttstamp: any; globalOptions: any; }} ctx
2388
2396
  */
2389
-
2390
2397
  function makeDefaults(html, userID, ctx) {
2391
2398
  var reqCounter = 1;
2392
2399
  var fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
2393
2400
 
2394
- // @Hack Ok we've done hacky things, this is definitely on top 5.
2395
- // We totally assume the object is flat and try parsing until a }.
2396
- // If it works though it's cool because we get a bunch of extra data things.
2397
- //
2398
- // Update: we don't need this. Leaving it in in case we ever do.
2399
- // Ben - July 15th 2017
2400
-
2401
- // var siteData = getFrom(html, "[\"SiteData\",[],", "},");
2402
- // try {
2403
- // siteData = JSON.parse(siteData + "}");
2404
- // } catch(e) {
2405
- // log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
2406
- // siteData = {};
2407
- // }
2408
-
2409
2401
  var ttstamp = "2";
2410
2402
  for (var i = 0; i < fb_dtsg.length; i++) ttstamp += fb_dtsg.charCodeAt(i);
2411
2403
  var revision = getFrom(html, 'revision":', ",");
@@ -2413,40 +2405,16 @@ function makeDefaults(html, userID, ctx) {
2413
2405
  /**
2414
2406
  * @param {{ [x: string]: any; hasOwnProperty: (arg0: string) => any; }} obj
2415
2407
  */
2416
-
2417
2408
  function mergeWithDefaults(obj) {
2418
- // @TODO This is missing a key called __dyn.
2419
- // After some investigation it seems like __dyn is some sort of set that FB
2420
- // calls BitMap. It seems like certain responses have a "define" key in the
2421
- // res.jsmods arrays. I think the code iterates over those and calls `set`
2422
- // on the bitmap for each of those keys. Then it calls
2423
- // bitmap.toCompressedString() which returns what __dyn is.
2424
- //
2425
- // So far the API has been working without this.
2426
- //
2427
- // Ben - July 15th 2017
2428
2409
  var newObj = {
2429
2410
  __user: userID,
2430
2411
  __req: (reqCounter++).toString(36),
2431
2412
  __rev: revision,
2432
2413
  __a: 1,
2433
- // __af: siteData.features,
2434
2414
  fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
2435
2415
  jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
2436
- // __spin_r: siteData.__spin_r,
2437
- // __spin_b: siteData.__spin_b,
2438
- // __spin_t: siteData.__spin_t,
2439
2416
  };
2440
2417
 
2441
- // @TODO this is probably not needed.
2442
- // Ben - July 15th 2017
2443
- // if (siteData.be_key) {
2444
- // newObj[siteData.be_key] = siteData.be_mode;
2445
- // }
2446
- // if (siteData.pkg_cohort_key) {
2447
- // newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
2448
- // }
2449
-
2450
2418
  if (!obj) return newObj;
2451
2419
  for (var prop in obj)
2452
2420
  if (obj.hasOwnProperty(prop))
@@ -2460,7 +2428,6 @@ function makeDefaults(html, userID, ctx) {
2460
2428
  * @param {any} form
2461
2429
  * @param {any} ctxx
2462
2430
  */
2463
-
2464
2431
  function postWithDefaults(url, jar, form, ctxx) {
2465
2432
  return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx);
2466
2433
  }
@@ -2471,7 +2438,6 @@ function makeDefaults(html, userID, ctx) {
2471
2438
  * @param {any} qs
2472
2439
  * @param {any} ctxx
2473
2440
  */
2474
-
2475
2441
  function getWithDefaults(url, jar, qs, ctxx) {
2476
2442
  return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
2477
2443
  }
@@ -2483,7 +2449,6 @@ function makeDefaults(html, userID, ctx) {
2483
2449
  * @param {any} qs
2484
2450
  * @param {any} ctxx
2485
2451
  */
2486
-
2487
2452
  function postFormDataWithDefault(url, jar, form, qs, ctxx) {
2488
2453
  return postFormData(url, jar, mergeWithDefaults(form), mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx);
2489
2454
  }
@@ -2500,7 +2465,6 @@ function makeDefaults(html, userID, ctx) {
2500
2465
  * @param {{ postFormData: (arg0: string, arg1: any, arg2: any, arg3: {}) => any; post: (arg0: string, arg1: any, arg2: any) => any; get: (arg0: any, arg1: any) => Promise<any>; }} defaultFuncs
2501
2466
  * @param {string | number} [retryCount]
2502
2467
  */
2503
-
2504
2468
  function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2505
2469
  if (retryCount == undefined) retryCount = 0;
2506
2470
  return function (data) {
@@ -2535,10 +2499,8 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2535
2499
  };
2536
2500
  }
2537
2501
 
2538
- // In some cases the response contains only a redirect URL which should be followed
2539
2502
  if (res.redirect && data.request.method === "GET") return defaultFuncs.get(res.redirect, ctx.jar).then(parseAndCheckLogin(ctx, defaultFuncs));
2540
2503
 
2541
- // TODO: handle multiple cookies?
2542
2504
  if (res.jsmods && res.jsmods.require && Array.isArray(res.jsmods.require[0]) && res.jsmods.require[0][0] === "Cookie") {
2543
2505
  res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace("_js_", "");
2544
2506
  var cookie = formatCookie(res.jsmods.require[0][3], "facebook");
@@ -2547,15 +2509,11 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2547
2509
  ctx.jar.setCookie(cookie2, "https://www.messenger.com");
2548
2510
  }
2549
2511
 
2550
- // On every request we check if we got a DTSG and we mutate the context so that we use the latest
2551
- // one for the next requests.
2552
2512
  if (res.jsmods && Array.isArray(res.jsmods.require)) {
2553
2513
  var arr = res.jsmods.require;
2554
2514
  for (var i in arr) {
2555
2515
  if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
2556
2516
  ctx.fb_dtsg = arr[i][3][0];
2557
-
2558
- // Update ttstamp since that depends on fb_dtsg
2559
2517
  ctx.ttstamp = "2";
2560
2518
  for (var j = 0; j < ctx.fb_dtsg.length; j++) ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
2561
2519
  }
@@ -2571,12 +2529,11 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount) {
2571
2529
  /**
2572
2530
  * @param {{ setCookie: (arg0: any, arg1: string) => void; }} jar
2573
2531
  */
2574
-
2575
2532
  function saveCookies(jar) {
2576
2533
  return function (/** @type {{ headers: { [x: string]: any[]; }; }} */res) {
2577
2534
  var cookies = res.headers["set-cookie"] || [];
2578
2535
  cookies.forEach(function (/** @type {string} */c) {
2579
- if (c.indexOf(".facebook.com") > -1) { // yo wtf is this?
2536
+ if (c.indexOf(".facebook.com") > -1) {
2580
2537
  jar.setCookie(c, "https://www.facebook.com");
2581
2538
  jar.setCookie(c.replace(/domain=\.facebook\.com/, "domain=.messenger.com"), "https://www.messenger.com");
2582
2539
  }
@@ -2586,25 +2543,14 @@ function saveCookies(jar) {
2586
2543
  }
2587
2544
 
2588
2545
  var NUM_TO_MONTH = [
2589
- "Jan",
2590
- "Feb",
2591
- "Mar",
2592
- "Apr",
2593
- "May",
2594
- "Jun",
2595
- "Jul",
2596
- "Aug",
2597
- "Sep",
2598
- "Oct",
2599
- "Nov",
2600
- "Dec"
2546
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2547
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2601
2548
  ];
2602
2549
  var NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2603
2550
 
2604
2551
  /**
2605
2552
  * @param {{ getUTCDate: () => any; getUTCHours: () => any; getUTCMinutes: () => any; getUTCSeconds: () => any; getUTCDay: () => string | number; getUTCMonth: () => string | number; getUTCFullYear: () => string; }} date
2606
2553
  */
2607
-
2608
2554
  function formatDate(date) {
2609
2555
  var d = date.getUTCDate();
2610
2556
  d = d >= 10 ? d : "0" + d;
@@ -2621,7 +2567,6 @@ function formatDate(date) {
2621
2567
  * @param {string[]} arr
2622
2568
  * @param {string} url
2623
2569
  */
2624
-
2625
2570
  function formatCookie(arr, url) {
2626
2571
  return arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com";
2627
2572
  }
@@ -2629,7 +2574,6 @@ function formatCookie(arr, url) {
2629
2574
  /**
2630
2575
  * @param {{ thread_fbid: { toString: () => any; }; participants: any[]; name: any; custom_nickname: any; snippet: any; snippet_attachments: any; snippet_sender: any; unread_count: any; message_count: any; image_src: any; timestamp: any; mute_until: any; is_canonical_user: any; is_canonical: any; is_subscribed: any; folder: any; is_archived: any; recipients_loadable: any; has_email_participant: any; read_only: any; can_reply: any; cannot_reply_reason: any; last_message_timestamp: any; last_read_timestamp: any; last_message_type: any; custom_like_icon: any; custom_color: any; admin_ids: any; thread_type: any; }} data
2631
2576
  */
2632
-
2633
2577
  function formatThread(data) {
2634
2578
  return {
2635
2579
  threadID: formatID(data.thread_fbid.toString()),
@@ -2668,7 +2612,6 @@ function formatThread(data) {
2668
2612
  /**
2669
2613
  * @param {any} obj
2670
2614
  */
2671
-
2672
2615
  function getType(obj) {
2673
2616
  return Object.prototype.toString.call(obj).slice(8, -1);
2674
2617
  }
@@ -2677,7 +2620,6 @@ function getType(obj) {
2677
2620
  * @param {{ lat: number; p: any; }} presence
2678
2621
  * @param {any} userID
2679
2622
  */
2680
-
2681
2623
  function formatProxyPresence(presence, userID) {
2682
2624
  if (presence.lat === undefined || presence.p === undefined) return null;
2683
2625
  return {
@@ -2692,7 +2634,6 @@ function formatProxyPresence(presence, userID) {
2692
2634
  * @param {{ la: number; a: any; }} presence
2693
2635
  * @param {any} userID
2694
2636
  */
2695
-
2696
2637
  function formatPresence(presence, userID) {
2697
2638
  return {
2698
2639
  type: "presence",
@@ -2705,16 +2646,7 @@ function formatPresence(presence, userID) {
2705
2646
  /**
2706
2647
  * @param {any} payload
2707
2648
  */
2708
-
2709
2649
  function decodeClientPayload(payload) {
2710
- /*
2711
- Special function which Client using to "encode" clients JSON payload
2712
- */
2713
-
2714
- /**
2715
- * @param {string | any[]} array
2716
- */
2717
-
2718
2650
  function Utf8ArrayToStr(array) {
2719
2651
  var out, i, len, c;
2720
2652
  var char2, char3;
@@ -2754,15 +2686,13 @@ function decodeClientPayload(payload) {
2754
2686
  /**
2755
2687
  * @param {{ getCookies: (arg0: string) => string | any[]; }} jar
2756
2688
  */
2757
-
2758
2689
  function getAppState(jar) {
2759
2690
  return jar.getCookies("https://www.facebook.com").concat(jar.getCookies("https://facebook.com")).concat(jar.getCookies("https://www.messenger.com"));
2760
2691
  }
2761
2692
 
2762
2693
  function getData_Path(Obj, Arr, Stt) {
2763
- //default stt = 0
2764
2694
  if (Arr.length === 0 && Obj != undefined) {
2765
- return Obj; //object
2695
+ return Obj;
2766
2696
  }
2767
2697
  else if (Obj == undefined) {
2768
2698
  return Stt;
@@ -2775,7 +2705,6 @@ function getData_Path(Obj, Arr, Stt) {
2775
2705
  return getData_Path(Obj[head], tail, Stt++);
2776
2706
  }
2777
2707
 
2778
-
2779
2708
  function setData_Path(obj, path, value) {
2780
2709
  if (!path.length) {
2781
2710
  return obj;
@@ -2818,8 +2747,10 @@ function getJazoest() {
2818
2747
  return result;
2819
2748
  }
2820
2749
 
2821
- function getEventTime() {
2822
- return Date.now();
2750
+ function getCurrentTimestamp() {
2751
+ const date = new Date();
2752
+ const unixTime = date.getTime();
2753
+ return unixTime;
2823
2754
  }
2824
2755
 
2825
2756
  function getSessionID() {
@@ -2878,27 +2809,23 @@ function cleanHTML(text) {
2878
2809
  return text;
2879
2810
  }
2880
2811
 
2881
- function delay(ms) {
2882
- return new Promise(resolve => setTimeout(resolve, ms));
2883
- }
2884
-
2885
2812
  module.exports = {
2886
2813
  cleanHTML,
2887
- isReadableStream: isReadableStream,
2888
- get: get,
2889
- post: post,
2890
- postFormData: postFormData,
2891
- generateThreadingID: generateThreadingID,
2892
- generateOfflineThreadingID: generateOfflineThreadingID,
2893
- getGUID: getGUID,
2894
- getFrom: getFrom,
2895
- makeParsable: makeParsable,
2896
- arrToForm: arrToForm,
2897
- getSignatureID: getSignatureID,
2814
+ isReadableStream,
2815
+ get,
2816
+ post,
2817
+ postFormData,
2818
+ generateThreadingID,
2819
+ generateOfflineThreadingID,
2820
+ getGUID,
2821
+ getFrom,
2822
+ makeParsable,
2823
+ arrToForm,
2824
+ getSignatureID,
2898
2825
  getJar: request.jar,
2899
- generateTimestampRelative: generateTimestampRelative,
2900
- makeDefaults: makeDefaults,
2901
- parseAndCheckLogin: parseAndCheckLogin,
2826
+ generateTimestampRelative,
2827
+ makeDefaults,
2828
+ parseAndCheckLogin,
2902
2829
  getGender: getGenderByPhysicalMethod,
2903
2830
  getData_Path,
2904
2831
  setData_Path,
@@ -2911,10 +2838,11 @@ module.exports = {
2911
2838
  formatMessage,
2912
2839
  formatDeltaEvent,
2913
2840
  formatDeltaMessage,
2841
+ getMentionsFromDeltaMessage,
2842
+ formatDeltaReadReceipt,
2914
2843
  formatProxyPresence,
2915
2844
  formatPresence,
2916
2845
  formatTyp,
2917
- // formatDeltaReadReceipt,
2918
2846
  formatCookie,
2919
2847
  formatThread,
2920
2848
  formatReadReceipt,
@@ -2928,8 +2856,12 @@ module.exports = {
2928
2856
  setProxy,
2929
2857
  isDMThread,
2930
2858
  getJazoest,
2931
- getEventTime,
2859
+ getCurrentTimestamp,
2932
2860
  getSessionID,
2933
2861
  getFormData,
2934
- delay
2862
+ presenceEncode,
2863
+ presenceDecode,
2864
+ padZeros,
2865
+ binaryToDecimal,
2866
+ arrayToObject
2935
2867
  };