@dongdev/fca-unofficial 2.0.6 → 2.0.8

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 (74) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/func/checkUpdate.js +9 -9
  3. package/func/logger.js +40 -104
  4. package/module/login.js +4 -4
  5. package/module/loginHelper.js +3 -3
  6. package/module/options.js +5 -9
  7. package/package.json +6 -6
  8. package/src/api/action/addExternalModule.js +5 -5
  9. package/src/api/action/changeAvatar.js +11 -10
  10. package/src/api/action/changeBio.js +7 -8
  11. package/src/api/action/getCurrentUserID.js +1 -1
  12. package/src/api/action/handleFriendRequest.js +5 -5
  13. package/src/api/action/logout.js +9 -8
  14. package/src/api/action/refreshFb_dtsg.js +17 -12
  15. package/src/api/action/setPostReaction.js +10 -11
  16. package/src/api/action/unfriend.js +3 -4
  17. package/src/api/http/httpGet.js +7 -8
  18. package/src/api/http/httpPost.js +7 -8
  19. package/src/api/http/postFormData.js +6 -5
  20. package/src/api/messaging/addUserToGroup.js +0 -1
  21. package/src/api/messaging/changeAdminStatus.js +108 -89
  22. package/src/api/messaging/changeArchivedStatus.js +6 -6
  23. package/src/api/messaging/changeBlockedStatus.js +3 -4
  24. package/src/api/messaging/changeGroupImage.js +72 -117
  25. package/src/api/messaging/changeNickname.js +59 -48
  26. package/src/api/messaging/changeThreadColor.js +61 -47
  27. package/src/api/messaging/changeThreadEmoji.js +106 -0
  28. package/src/api/messaging/createNewGroup.js +5 -5
  29. package/src/api/messaging/createPoll.js +36 -63
  30. package/src/api/messaging/deleteMessage.js +4 -4
  31. package/src/api/messaging/deleteThread.js +4 -4
  32. package/src/api/messaging/forwardAttachment.js +38 -47
  33. package/src/api/messaging/getFriendsList.js +5 -6
  34. package/src/api/messaging/getMessage.js +4 -9
  35. package/src/api/messaging/handleMessageRequest.js +5 -5
  36. package/src/api/messaging/markAsDelivered.js +5 -5
  37. package/src/api/messaging/markAsRead.js +7 -7
  38. package/src/api/messaging/markAsReadAll.js +3 -4
  39. package/src/api/messaging/markAsSeen.js +7 -7
  40. package/src/api/messaging/muteThread.js +3 -4
  41. package/src/api/messaging/removeUserFromGroup.js +82 -56
  42. package/src/api/messaging/resolvePhotoUrl.js +2 -3
  43. package/src/api/messaging/searchForThread.js +2 -3
  44. package/src/api/messaging/sendMessage.js +171 -101
  45. package/src/api/messaging/sendMessageMqtt.js +14 -12
  46. package/src/api/messaging/sendTypingIndicator.js +11 -11
  47. package/src/api/messaging/setMessageReaction.js +68 -82
  48. package/src/api/messaging/setTitle.js +77 -48
  49. package/src/api/messaging/shareContact.js +2 -4
  50. package/src/api/messaging/threadColors.js +0 -3
  51. package/src/api/messaging/unsendMessage.js +74 -37
  52. package/src/api/messaging/uploadAttachment.js +11 -9
  53. package/src/api/socket/core/connectMqtt.js +180 -0
  54. package/src/api/socket/core/getSeqID.js +25 -0
  55. package/src/api/socket/core/getTaskResponseData.js +22 -0
  56. package/src/api/socket/core/markDelivery.js +12 -0
  57. package/src/api/socket/core/parseDelta.js +351 -0
  58. package/src/api/socket/detail/buildStream.js +176 -68
  59. package/src/api/socket/detail/constants.js +24 -0
  60. package/src/api/socket/listenMqtt.js +80 -1005
  61. package/src/api/{messaging → threads}/getThreadHistory.js +5 -22
  62. package/src/api/threads/getThreadInfo.js +35 -248
  63. package/src/api/threads/getThreadList.js +20 -20
  64. package/src/api/threads/getThreadPictures.js +3 -4
  65. package/src/api/users/getUserID.js +5 -6
  66. package/src/api/users/getUserInfo.js +305 -73
  67. package/src/api/users/getUserInfoV2.js +134 -0
  68. package/src/database/models/user.js +32 -0
  69. package/src/database/userData.js +89 -0
  70. package/src/utils/constants.js +12 -2
  71. package/src/utils/format.js +1051 -0
  72. package/src/utils/request.js +75 -7
  73. package/src/api/threads/changeThreadEmoji.js +0 -55
  74. package/src/utils/index.js +0 -1497
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
3
  const log = require("npmlog");
5
-
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { getAdminTextMessageType } = require("../../utils/format");
6
6
  function getExtension(original_extension, filename = "") {
7
7
  if (original_extension) {
8
8
  return original_extension;
@@ -51,23 +51,6 @@ function formatAttachmentsGraphQLResponse(attachment) {
51
51
  logo: attachment.attribution_app.square_logo
52
52
  }
53
53
  : null
54
-
55
- // @TODO No idea what this is, should we expose it?
56
- // Ben - July 15th 2017
57
- // renderAsSticker: attachment.render_as_sticker,
58
-
59
- // This is _not_ the real URI, this is still just a large preview.
60
- // To get the URL we'll need to support a POST query to
61
- //
62
- // https://www.facebook.com/webgraphql/query/
63
- //
64
- // With the following query params:
65
- //
66
- // query_id:728987990612546
67
- // variables:{"id":"100009069356507","photoID":"10213724771692996"}
68
- // dpr:1
69
- //
70
- // No special form though.
71
54
  };
72
55
  case "MessageAnimatedImage":
73
56
  return {
@@ -601,7 +584,7 @@ function formatMessagesGraphQLResponse(data) {
601
584
  eventData: formatEventData(d.extensible_message_admin_text),
602
585
 
603
586
  // @Legacy
604
- logMessageType: utils.getAdminTextMessageType(
587
+ logMessageType: getAdminTextMessageType(
605
588
  d.extensible_message_admin_text_type
606
589
  ),
607
590
  logMessageData: d.extensible_message_admin_text // Maybe different?
@@ -639,7 +622,7 @@ module.exports = function(defaultFuncs, api, ctx) {
639
622
  // `queries` has to be a string. I couldn't tell from the dev console. This
640
623
  // took me a really long time to figure out. I deserve a cookie for this.
641
624
  const form = {
642
- av: ctx.globalOptions.pageID,
625
+ av: ctx.userID,
643
626
  queries: JSON.stringify({
644
627
  o0: {
645
628
  // This doc_id was valid on February 2nd 2017.
@@ -657,7 +640,7 @@ module.exports = function(defaultFuncs, api, ctx) {
657
640
 
658
641
  defaultFuncs
659
642
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
660
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
643
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
661
644
  .then(function(resData) {
662
645
  if (resData.error) {
663
646
  throw resData;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
- const log = require("npmlog");
5
3
  const fs = require("fs");
6
4
  const path = require("path");
7
5
  const logger = require("../../../func/logger");
6
+ const { parseAndCheckLogin } = require("../../utils/client");
7
+ const { formatID, getType } = require("../../utils/format");
8
8
 
9
9
  function formatEventReminders(reminder) {
10
10
  return {
@@ -149,7 +149,7 @@ module.exports = function (defaultFuncs, api, ctx) {
149
149
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
150
150
  try {
151
151
  const Submit = buildQueries();
152
- const resData = await defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, Submit).then(utils.parseAndCheckLogin(ctx, defaultFuncs));
152
+ const resData = await defaultFuncs.post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, Submit).then(parseAndCheckLogin(ctx, defaultFuncs));
153
153
  if (!Array.isArray(resData) || resData.length === 0) throw new Error("EmptyGraphBatch");
154
154
  const tail = resData[resData.length - 1];
155
155
  if (tail?.error_results && tail.error_results !== 0) throw new Error("GraphErrorResults");
@@ -171,13 +171,39 @@ module.exports = function (defaultFuncs, api, ctx) {
171
171
  acc[path.basename(file, ".js")] = require(path.join(__dirname, "../../database", file))(api);
172
172
  return acc;
173
173
  }, {});
174
- const { threadData } = dbFiles;
174
+ const { threadData, userData } = dbFiles;
175
175
  const { create, get, update, getAll } = threadData;
176
+ const { update: updateUser } = userData;
176
177
 
177
178
  function isValidThread(d) {
178
179
  return d && d.threadID;
179
180
  }
180
181
 
182
+ async function upsertUsersFromThreadInfo(info) {
183
+ try {
184
+ if (!info || !Array.isArray(info.userInfo) || info.userInfo.length === 0) return;
185
+ const tasks = info.userInfo.filter(u => u && u.id).map(u => {
186
+ const data = {
187
+ id: u.id,
188
+ name: u.name || null,
189
+ firstName: u.firstName || null,
190
+ vanity: u.vanity || null,
191
+ url: u.url || null,
192
+ thumbSrc: u.thumbSrc || null,
193
+ profileUrl: u.profileUrl || null,
194
+ gender: u.gender || null,
195
+ type: u.type || null,
196
+ isFriend: !!u.isFriend,
197
+ isBirthday: !!u.isBirthday,
198
+ };
199
+ return updateUser(u.id, { data });
200
+ });
201
+ await Promise.allSettled(tasks);
202
+ } catch (e) {
203
+ logger(`upsertUsers error: ${e?.message || e}`, "warn");
204
+ }
205
+ }
206
+
181
207
  async function fetchThreadInfo(tID, isNew) {
182
208
  try {
183
209
  const response = await getMultiInfo([tID]);
@@ -187,6 +213,7 @@ module.exports = function (defaultFuncs, api, ctx) {
187
213
  return;
188
214
  }
189
215
  const threadInfo = response.Data[0];
216
+ await upsertUsersFromThreadInfo(threadInfo);
190
217
  if (isNew) {
191
218
  await create(tID, { data: threadInfo });
192
219
  logger(`Success create data thread: ${tID}`, "info");
@@ -250,16 +277,17 @@ module.exports = function (defaultFuncs, api, ctx) {
250
277
  resolveFunc = resolve;
251
278
  rejectFunc = reject;
252
279
  });
253
- if (utils.getType(callback) != "Function" && utils.getType(callback) != "AsyncFunction") {
280
+ if (getType(callback) != "Function" && getType(callback) != "AsyncFunction") {
254
281
  callback = function (err, data) {
255
282
  if (err) return rejectFunc(err);
256
283
  resolveFunc(data);
257
284
  };
258
285
  }
259
- if (utils.getType(threadID) !== "Array") threadID = [threadID];
286
+ if (getType(threadID) !== "Array") threadID = [threadID];
260
287
  try {
261
288
  const cached = await get(threadID[0]);
262
289
  if (cached?.data && isValidThread(cached.data)) {
290
+ await upsertUsersFromThreadInfo(cached.data);
263
291
  callback(null, cached.data);
264
292
  return returnPromise;
265
293
  }
@@ -269,6 +297,7 @@ module.exports = function (defaultFuncs, api, ctx) {
269
297
  const response = await getMultiInfo(threadID);
270
298
  if (response.Success && response.Data && isValidThread(response.Data[0])) {
271
299
  const data = response.Data[0];
300
+ await upsertUsersFromThreadInfo(data);
272
301
  await create(threadID[0], { data });
273
302
  callback(null, data);
274
303
  } else {
@@ -328,245 +357,3 @@ module.exports = function (defaultFuncs, api, ctx) {
328
357
  return returnPromise;
329
358
  };
330
359
  };
331
-
332
- // "use strict";
333
-
334
- // const utils = require("../../utils");
335
- // const log = require("npmlog");
336
-
337
- // function formatEventReminders(reminder) {
338
- // return {
339
- // reminderID: reminder.id,
340
- // eventCreatorID: reminder.lightweight_event_creator.id,
341
- // time: reminder.time,
342
- // eventType: reminder.lightweight_event_type.toLowerCase(),
343
- // locationName: reminder.location_name,
344
- // // @TODO verify this
345
- // locationCoordinates: reminder.location_coordinates,
346
- // locationPage: reminder.location_page,
347
- // eventStatus: reminder.lightweight_event_status.toLowerCase(),
348
- // note: reminder.note,
349
- // repeatMode: reminder.repeat_mode.toLowerCase(),
350
- // eventTitle: reminder.event_title,
351
- // triggerMessage: reminder.trigger_message,
352
- // secondsToNotifyBefore: reminder.seconds_to_notify_before,
353
- // allowsRsvp: reminder.allows_rsvp,
354
- // relatedEvent: reminder.related_event,
355
- // members: reminder.event_reminder_members.edges.map(function(member) {
356
- // return {
357
- // memberID: member.node.id,
358
- // state: member.guest_list_state.toLowerCase()
359
- // };
360
- // })
361
- // };
362
- // }
363
-
364
- // function formatThreadGraphQLResponse(data) {
365
- // if (data.errors) return data.errors;
366
- // const messageThread = data.message_thread;
367
- // if (!messageThread) return null;
368
- // const threadID = messageThread.thread_key.thread_fbid
369
- // ? messageThread.thread_key.thread_fbid
370
- // : messageThread.thread_key.other_user_id;
371
-
372
- // // Remove me
373
- // const lastM = messageThread.last_message;
374
- // const snippetID =
375
- // lastM &&
376
- // lastM.nodes &&
377
- // lastM.nodes[0] &&
378
- // lastM.nodes[0].message_sender &&
379
- // lastM.nodes[0].message_sender.messaging_actor
380
- // ? lastM.nodes[0].message_sender.messaging_actor.id
381
- // : null;
382
- // const snippetText =
383
- // lastM && lastM.nodes && lastM.nodes[0] ? lastM.nodes[0].snippet : null;
384
- // const lastR = messageThread.last_read_receipt;
385
- // const lastReadTimestamp =
386
- // lastR && lastR.nodes && lastR.nodes[0] && lastR.nodes[0].timestamp_precise
387
- // ? lastR.nodes[0].timestamp_precise
388
- // : null;
389
-
390
- // return {
391
- // threadID: threadID,
392
- // threadName: messageThread.name,
393
- // participantIDs: messageThread.all_participants.edges.map(
394
- // d => d.node.messaging_actor.id
395
- // ),
396
- // userInfo: messageThread.all_participants.edges.map(d => ({
397
- // id: d.node.messaging_actor.id,
398
- // name: d.node.messaging_actor.name,
399
- // firstName: d.node.messaging_actor.short_name,
400
- // vanity: d.node.messaging_actor.username,
401
- // url: d.node.messaging_actor.url,
402
- // thumbSrc: d.node.messaging_actor.big_image_src.uri,
403
- // profileUrl: d.node.messaging_actor.big_image_src.uri,
404
- // gender: d.node.messaging_actor.gender,
405
- // type: d.node.messaging_actor.__typename,
406
- // isFriend: d.node.messaging_actor.is_viewer_friend,
407
- // isBirthday: !!d.node.messaging_actor.is_birthday //not sure?
408
- // })),
409
- // unreadCount: messageThread.unread_count,
410
- // messageCount: messageThread.messages_count,
411
- // timestamp: messageThread.updated_time_precise,
412
- // muteUntil: messageThread.mute_until,
413
- // isGroup: messageThread.thread_type == "GROUP",
414
- // isSubscribed: messageThread.is_viewer_subscribed,
415
- // isArchived: messageThread.has_viewer_archived,
416
- // folder: messageThread.folder,
417
- // cannotReplyReason: messageThread.cannot_reply_reason,
418
- // eventReminders: messageThread.event_reminders
419
- // ? messageThread.event_reminders.nodes.map(formatEventReminders)
420
- // : null,
421
- // emoji: messageThread.customization_info
422
- // ? messageThread.customization_info.emoji
423
- // : null,
424
- // color:
425
- // messageThread.customization_info &&
426
- // messageThread.customization_info.outgoing_bubble_color
427
- // ? messageThread.customization_info.outgoing_bubble_color.slice(2)
428
- // : null,
429
- // threadTheme: messageThread.thread_theme,
430
- // nicknames:
431
- // messageThread.customization_info &&
432
- // messageThread.customization_info.participant_customizations
433
- // ? messageThread.customization_info.participant_customizations.reduce(
434
- // function(res, val) {
435
- // if (val.nickname) res[val.participant_id] = val.nickname;
436
- // return res;
437
- // },
438
- // {}
439
- // )
440
- // : {},
441
- // adminIDs: messageThread.thread_admins,
442
- // approvalMode: Boolean(messageThread.approval_mode),
443
- // approvalQueue: messageThread.group_approval_queue.nodes.map(a => ({
444
- // inviterID: a.inviter.id,
445
- // requesterID: a.requester.id,
446
- // timestamp: a.request_timestamp,
447
- // request_source: a.request_source // @Undocumented
448
- // })),
449
-
450
- // // @Undocumented
451
- // reactionsMuteMode: messageThread.reactions_mute_mode.toLowerCase(),
452
- // mentionsMuteMode: messageThread.mentions_mute_mode.toLowerCase(),
453
- // isPinProtected: messageThread.is_pin_protected,
454
- // relatedPageThread: messageThread.related_page_thread,
455
-
456
- // // @Legacy
457
- // name: messageThread.name,
458
- // snippet: snippetText,
459
- // snippetSender: snippetID,
460
- // snippetAttachments: [],
461
- // serverTimestamp: messageThread.updated_time_precise,
462
- // imageSrc: messageThread.image ? messageThread.image.uri : null,
463
- // isCanonicalUser: messageThread.is_canonical_neo_user,
464
- // isCanonical: messageThread.thread_type != "GROUP",
465
- // recipientsLoadable: true,
466
- // hasEmailParticipant: false,
467
- // readOnly: false,
468
- // canReply: messageThread.cannot_reply_reason == null,
469
- // lastMessageTimestamp: messageThread.last_message
470
- // ? messageThread.last_message.timestamp_precise
471
- // : null,
472
- // lastMessageType: "message",
473
- // lastReadTimestamp: lastReadTimestamp,
474
- // threadType: messageThread.thread_type == "GROUP" ? 2 : 1,
475
-
476
- // // update in Wed, 13 Jul 2022 19:41:12 +0700
477
- // inviteLink: {
478
- // enable: messageThread.joinable_mode
479
- // ? messageThread.joinable_mode.mode == 1
480
- // : false,
481
- // link: messageThread.joinable_mode
482
- // ? messageThread.joinable_mode.link
483
- // : null
484
- // }
485
- // };
486
- // }
487
-
488
- // module.exports = function(defaultFuncs, api, ctx) {
489
- // return function getThreadInfoGraphQL(threadID, callback) {
490
- // let resolveFunc = function() {};
491
- // let rejectFunc = function() {};
492
- // const returnPromise = new Promise(function(resolve, reject) {
493
- // resolveFunc = resolve;
494
- // rejectFunc = reject;
495
- // });
496
-
497
- // if (
498
- // utils.getType(callback) != "Function" &&
499
- // utils.getType(callback) != "AsyncFunction"
500
- // ) {
501
- // callback = function(err, data) {
502
- // if (err) {
503
- // return rejectFunc(err);
504
- // }
505
- // resolveFunc(data);
506
- // };
507
- // }
508
-
509
- // if (utils.getType(threadID) !== "Array") {
510
- // threadID = [threadID];
511
- // }
512
-
513
- // let form = {};
514
- // // `queries` has to be a string. I couldn't tell from the dev console. This
515
- // // took me a really long time to figure out. I deserve a cookie for this.
516
- // threadID.map(function(t, i) {
517
- // form["o" + i] = {
518
- // doc_id: "3449967031715030",
519
- // query_params: {
520
- // id: t,
521
- // message_limit: 0,
522
- // load_messages: false,
523
- // load_read_receipts: false,
524
- // before: null
525
- // }
526
- // };
527
- // });
528
-
529
- // form = {
530
- // queries: JSON.stringify(form),
531
- // batch_name: "MessengerGraphQLThreadFetcher"
532
- // };
533
-
534
- // defaultFuncs
535
- // .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
536
- // .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
537
- // .then(function(resData) {
538
- // if (resData.error) {
539
- // throw resData;
540
- // }
541
- // // This returns us an array of things. The last one is the success /
542
- // // failure one.
543
- // // @TODO What do we do in this case?
544
- // // if (resData[resData.length - 1].error_results !== 0) {
545
- // // throw resData[0].o0.errors[0];
546
- // // }
547
- // // if (!resData[0].o0.data.message_thread) {
548
- // // throw new Error("can't find this thread");
549
- // // }
550
- // const threadInfos = {};
551
- // for (let i = resData.length - 2; i >= 0; i--) {
552
- // const threadInfo = formatThreadGraphQLResponse(
553
- // resData[i][Object.keys(resData[i])[0]].data
554
- // );
555
- // threadInfos[
556
- // threadInfo?.threadID || threadID[threadID.length - 1 - i]
557
- // ] = threadInfo;
558
- // }
559
- // if (Object.values(threadInfos).length == 1) {
560
- // callback(null, Object.values(threadInfos)[0]);
561
- // } else {
562
- // callback(null, threadInfos);
563
- // }
564
- // })
565
- // .catch(function(err) {
566
- // log.error("getThreadInfoGraphQL", err);
567
- // return callback(err);
568
- // });
569
-
570
- // return returnPromise;
571
- // };
572
- // };
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
3
  const log = require("npmlog");
5
-
4
+ const { parseAndCheckLogin } = require("../../utils/client");
5
+ const { formatID, getType } = require("../../utils/format");
6
6
  function createProfileUrl(url, username, id) {
7
7
  if (url) return url;
8
8
  return (
9
- "https://www.facebook.com/" + (username || utils.formatID(id.toString()))
9
+ "https://www.facebook.com/" + (username || formatID(id.toString()))
10
10
  );
11
11
  }
12
12
 
@@ -17,7 +17,7 @@ function formatParticipants(participants) {
17
17
  case "User":
18
18
  return {
19
19
  accountType: p["__typename"],
20
- userID: utils.formatID(p.id.toString()), // do we need .toString()? when it is not a string?
20
+ userID: formatID(p.id.toString()), // do we need .toString()? when it is not a string?
21
21
  name: p.name,
22
22
  shortName: p.short_name,
23
23
  gender: p.gender,
@@ -35,7 +35,7 @@ function formatParticipants(participants) {
35
35
  case "Page":
36
36
  return {
37
37
  accountType: p["__typename"],
38
- userID: utils.formatID(p.id.toString()), // or maybe... pageID?
38
+ userID: formatID(p.id.toString()), // or maybe... pageID?
39
39
  name: p.name,
40
40
  url: p.url,
41
41
  profilePicture: p.big_image_src.uri,
@@ -51,7 +51,7 @@ function formatParticipants(participants) {
51
51
  case "UnavailableMessagingActor":
52
52
  return {
53
53
  accountType: p["__typename"],
54
- userID: utils.formatID(p.id.toString()),
54
+ userID: formatID(p.id.toString()),
55
55
  name: p.name,
56
56
  url: createProfileUrl(p.url, p.username, p.id), // in this case p.url is null all the time
57
57
  profilePicture: p.big_image_src.uri, // in this case it is default facebook photo, we could determine gender using it
@@ -66,7 +66,7 @@ function formatParticipants(participants) {
66
66
  );
67
67
  return {
68
68
  accountType: p["__typename"],
69
- userID: utils.formatID(p.id.toString()),
69
+ userID: formatID(p.id.toString()),
70
70
  name: p.name || `[unknown ${p["__typename"]}]` // probably it will always be something... but fallback to [unknown], just in case
71
71
  };
72
72
  }
@@ -108,7 +108,7 @@ function formatThreadList(data) {
108
108
  : null;
109
109
  return {
110
110
  threadID: t.thread_key
111
- ? utils.formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id)
111
+ ? formatID(t.thread_key.thread_fbid || t.thread_key.other_user_id)
112
112
  : null, // shall never be null
113
113
  name: getThreadName(t),
114
114
  unreadCount: t.unread_count,
@@ -140,7 +140,7 @@ function formatThreadList(data) {
140
140
  ? lastMessageNode.extensible_attachment
141
141
  : null, // TODO: not sure if it works
142
142
  snippetSender: lastMessageNode
143
- ? utils.formatID(
143
+ ? formatID(
144
144
  (lastMessageNode.message_sender.messaging_actor.id || "").toString()
145
145
  )
146
146
  : null,
@@ -171,25 +171,25 @@ module.exports = function(defaultFuncs, api, ctx) {
171
171
  return function getThreadList(limit, timestamp, tags, callback) {
172
172
  if (
173
173
  !callback &&
174
- (utils.getType(tags) === "Function" ||
175
- utils.getType(tags) === "AsyncFunction")
174
+ (getType(tags) === "Function" ||
175
+ getType(tags) === "AsyncFunction")
176
176
  ) {
177
177
  callback = tags;
178
178
  tags = [""];
179
179
  }
180
180
  if (
181
- utils.getType(limit) !== "Number" ||
181
+ getType(limit) !== "Number" ||
182
182
  !Number.isInteger(limit) ||
183
183
  limit <= 0
184
184
  )
185
185
  throw { error: "getThreadList: limit must be a positive integer" };
186
186
  if (
187
- utils.getType(timestamp) !== "Null" &&
188
- (utils.getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
187
+ getType(timestamp) !== "Null" &&
188
+ (getType(timestamp) !== "Number" || !Number.isInteger(timestamp))
189
189
  )
190
190
  throw { error: "getThreadList: timestamp must be an integer or null" };
191
- if (utils.getType(tags) === "String") tags = [tags];
192
- if (utils.getType(tags) !== "Array")
191
+ if (getType(tags) === "String") tags = [tags];
192
+ if (getType(tags) !== "Array")
193
193
  throw { error: "getThreadList: tags must be an array" };
194
194
  var resolveFunc = function() {};
195
195
  var rejectFunc = function() {};
@@ -198,8 +198,8 @@ module.exports = function(defaultFuncs, api, ctx) {
198
198
  rejectFunc = reject;
199
199
  });
200
200
  if (
201
- utils.getType(callback) !== "Function" &&
202
- utils.getType(callback) !== "AsyncFunction"
201
+ getType(callback) !== "Function" &&
202
+ getType(callback) !== "AsyncFunction"
203
203
  ) {
204
204
  callback = function(err, data) {
205
205
  if (err) return rejectFunc(err);
@@ -207,7 +207,7 @@ module.exports = function(defaultFuncs, api, ctx) {
207
207
  };
208
208
  }
209
209
  const form = {
210
- av: ctx.globalOptions.pageID,
210
+ av: ctx.userID,
211
211
  queries: JSON.stringify({
212
212
  o0: {
213
213
  doc_id: "3336396659757871",
@@ -224,7 +224,7 @@ module.exports = function(defaultFuncs, api, ctx) {
224
224
  };
225
225
  defaultFuncs
226
226
  .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form)
227
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
227
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
228
228
  .then(resData => {
229
229
  if (resData[resData.length - 1].error_results > 0)
230
230
  throw resData[0].o0.errors;
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
3
  const log = require("npmlog");
5
-
4
+ const { parseAndCheckLogin } = require("../../utils/client");
6
5
  module.exports = function(defaultFuncs, api, ctx) {
7
6
  return function getThreadPictures(threadID, offset, limit, callback) {
8
7
  let resolveFunc = function() {};
@@ -33,7 +32,7 @@ module.exports = function(defaultFuncs, api, ctx) {
33
32
  ctx.jar,
34
33
  form
35
34
  )
36
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
35
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
37
36
  .then(function(resData) {
38
37
  if (resData.error) {
39
38
  throw resData;
@@ -50,7 +49,7 @@ module.exports = function(defaultFuncs, api, ctx) {
50
49
  ctx.jar,
51
50
  form
52
51
  )
53
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
52
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
54
53
  .then(function(resData) {
55
54
  if (resData.error) {
56
55
  throw resData;
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
 
3
- const utils = require("../../utils");
4
3
  const log = require("npmlog");
5
-
4
+ const { formatID } = require("../../utils/format");
6
5
  function formatData(data) {
7
6
  return {
8
- userID: utils.formatID(data.uid.toString()),
7
+ userID: formatID(data.uid.toString()),
9
8
  photoUrl: data.photo,
10
9
  indexRank: data.index_rank,
11
10
  name: data.text,
@@ -37,16 +36,16 @@ module.exports = function(defaultFuncs, api, ctx) {
37
36
 
38
37
  const form = {
39
38
  value: name.toLowerCase(),
40
- viewer: ctx.i_userID || ctx.userID,
39
+ viewer: ctx.userID,
41
40
  rsp: "search",
42
41
  context: "search",
43
42
  path: "/home.php",
44
- request_id: utils.getGUID()
43
+ request_id: ctx.clientId
45
44
  };
46
45
 
47
46
  defaultFuncs
48
47
  .get("https://www.facebook.com/ajax/typeahead/search.php", ctx.jar, form)
49
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
48
+ .then(parseAndCheckLogin(ctx, defaultFuncs))
50
49
  .then(function(resData) {
51
50
  if (resData.error) {
52
51
  throw resData;